Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Molnix Status for Surge Alerts filtering #2213

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions api/management/commands/sync_molnix.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@
from api.molnix_utils import MolnixApi
from deployments.models import MolnixTag, MolnixTagGroup, Personnel, PersonnelDeployment
from main.sentry import SentryMonitor
from notifications.models import SurgeAlert, SurgeAlertCategory, SurgeAlertType
from notifications.models import (
SurgeAlert,
SurgeAlertCategory,
SurgeAlertStatus,
SurgeAlertType,
)

CRON_NAME = "sync_molnix"

Expand Down Expand Up @@ -470,14 +475,13 @@ def sync_open_positions(molnix_positions, molnix_api, countries):
# print(json.dumps(position, indent=2))
go_alert.molnix_id = position["id"]
go_alert.message = position["name"]
go_alert.molnix_status = position["status"]
go_alert.molnix_status = SurgeAlert.parse_molnix_status(position["status"])
go_alert.event = event
go_alert.country = country
go_alert.opens = get_datetime(position["opens"])
go_alert.closes = get_datetime(position["closes"])
go_alert.start = get_datetime(position["start"])
go_alert.end = get_datetime(position["end"])
go_alert.is_active = position["status"] == "active"
go_alert.save()
add_tags_to_obj(go_alert, position["tags"])
if created:
Expand All @@ -486,7 +490,7 @@ def sync_open_positions(molnix_positions, molnix_api, countries):
successful_updates += 1

# Find existing active alerts that are not in the current list from Molnix
existing_alerts = SurgeAlert.objects.filter(is_active=True).exclude(molnix_id__isnull=True)
existing_alerts = SurgeAlert.objects.filter(molnix_status=SurgeAlertStatus.OPEN).exclude(molnix_id__isnull=True)
existing_alert_ids = [e.molnix_id for e in existing_alerts]
inactive_alerts = list(set(existing_alert_ids) - set(molnix_ids))

Expand All @@ -498,15 +502,10 @@ def sync_open_positions(molnix_positions, molnix_api, countries):
position = molnix_api.get_position(alert.molnix_id)
if not position:
warnings.append("Position id %d not found in Molnix API" % alert.molnix_id)
if position and position["status"] == "unfilled":
alert.molnix_status = position["status"]
if position and position["status"]:
alert.molnix_status = SurgeAlert.parse_molnix_status(position["status"])
if position and position["closes"]:
alert.closes = get_datetime(position["closes"])
if position and position["status"] == "archived":
alert.molnix_status = position["status"]
alert.is_active = False
else:
alert.is_active = False
alert.save()

marked_inactive = len(inactive_alerts)
Expand Down
2 changes: 0 additions & 2 deletions deploy/helm/ifrcgo-helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,6 @@ cronjobs:
schedule: '0 9 * * *'
- command: 'ingest_country_plan_file'
schedule: '1 0 * * *'
- command: 'update_surge_alert_status'
schedule: '1 */12 * * *'
- command: 'fdrs_annual_income'
schedule: '0 0 * * 0'
- command: 'FDRS_INCOME'
Expand Down
1 change: 0 additions & 1 deletion main/sentry.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ class SentryMonitor(models.TextChoices):
UPDATE_PROJECT_STATUS = "update_project_status", "1 3 * * *"
USER_REGISTRATION_REMINDER = "user_registration_reminder", "0 9 * * *"
INGEST_COUNTRY_PLAN_FILE = "ingest_country_plan_file", "1 0 * * *"
UPDATE_SURGE_ALERT_STATUS = "update_surge_alert_status", "1 */12 * * *"
FDRS_ANNUAL_INCOME = "fdrs_annual_income", "0 0 * * 0"
FDRS_INCOME = "FDRS_INCOME", "0 0 * * 0"
INGEST_ACAPS = "ingest_acaps", "0 1 * * 0"
Expand Down
8 changes: 4 additions & 4 deletions notifications/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class SurgeAlertAdmin(CompareVersionAdmin, RegionRestrictedAdmin, TranslationAdm

@admin.display(description="std")
def std(self, obj):
return obj.is_stood_down
return obj.molnix_status == models.SurgeAlertStatus.STOOD_DOWN

std.boolean = True
country_in = "event__countries__in"
Expand All @@ -22,9 +22,9 @@ def std(self, obj):
"message",
"event__name",
)
readonly_fields = ("molnix_id", "is_stood_down")
list_display = ("__str__", "message", "start", "molnix_id", "molnix_status", "status", "std")
list_filter = ("molnix_status", "status", "is_stood_down")
readonly_fields = ("molnix_id",)
list_display = ("__str__", "message", "start", "molnix_id", "molnix_status", "std")
list_filter = ("molnix_status",)


class SubscriptionAdmin(CompareVersionAdmin):
Expand Down
17 changes: 12 additions & 5 deletions notifications/drf_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,21 @@ class SurgeAlertFilter(filters.FilterSet):
help_text="Molnix_tag names, comma separated",
widget=CSVWidget,
)
status = filters.NumberFilter(field_name="status", lookup_expr="exact")
molnix_status = CharInFilter(
label="molnix status",
field_name="molnix_status",
lookup_expr="in",
help_text="Molnix status value, comma separated",
widget=CSVWidget,
)

class Meta:
model = SurgeAlert
fields = {
"created_at": ("exact", "gt", "gte", "lt", "lte"),
"start": ("exact", "gt", "gte", "lt", "lte"),
"end": ("exact", "gt", "gte", "lt", "lte"),
"is_stood_down": ("exact",),
"is_active": ("exact",),
"molnix_id": ("exact", "in"),
"molnix_status": ("exact", "in"),
"message": ("exact", "in"),
"country": ("exact", "in"),
"country__name": ("exact", "in"),
Expand All @@ -63,7 +66,7 @@ class SurgeAlertViewset(viewsets.ReadOnlyModelViewSet):
authentication_classes = (TokenAuthentication,)
queryset = SurgeAlert.objects.prefetch_related("molnix_tags", "molnix_tags__groups").select_related("event", "country").all()
filterset_class = SurgeAlertFilter
ordering_fields = ("created_at", "atype", "category", "event", "is_stood_down", "status", "opens")
ordering_fields = ("created_at", "atype", "category", "event", "molnix_status", "opens")
search_fields = (
"operation",
"message",
Expand All @@ -76,6 +79,10 @@ def get_serializer_class(self):
# return UnauthenticatedSurgeAlertSerializer
return SurgeAlertSerializer

def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(molnix_id__isnull=False).exclude(molnix_tags__name="NO_GO")


# def get_queryset(self):
# # limit = 14 # days
Expand Down
5 changes: 3 additions & 2 deletions notifications/factories.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import factory
from factory import fuzzy

from .models import SurgeAlert
from .models import SurgeAlert, SurgeAlertStatus


class SurgeAlertFactory(factory.django.DjangoModelFactory):
class Meta:
model = SurgeAlert

message = fuzzy.FuzzyText(length=100)
molnix_id = fuzzy.FuzzyInteger(low=1)
atype = fuzzy.FuzzyInteger(low=1)
category = fuzzy.FuzzyInteger(low=1)
molnix_status = fuzzy.FuzzyChoice(choices=["active", "inactive"])
molnix_status = fuzzy.FuzzyChoice(choices=SurgeAlertStatus)

@factory.post_generation
def molnix_tags(self, create, extracted, **_):
Expand Down
55 changes: 0 additions & 55 deletions notifications/management/commands/update_surge_alert_status.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 4.2.13 on 2024-07-16 08:46

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("notifications", "0014_surgealert_status"),
]

operations = [
migrations.RemoveField(
model_name="surgealert",
name="molnix_status",
),
migrations.RenameField(
model_name="surgealert",
old_name="status",
new_name="molnix_status",
),
migrations.RemoveField(
model_name="surgealert",
name="is_active",
),
migrations.RemoveField(
model_name="surgealert",
name="is_stood_down",
),
]
39 changes: 18 additions & 21 deletions notifications/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,45 +49,42 @@ class SurgeAlert(models.Model):
# ID in Molnix system, if parsed from Molnix.
molnix_id = models.IntegerField(blank=True, null=True)

# Status field from Molnix - `unfilled` denotes Stood-Down
molnix_status = models.CharField(blank=True, null=True, max_length=32)

# It depends on molnix_status. Check "save" method below.
is_stood_down = models.BooleanField(verbose_name=_("is stood down?"), default=False)
opens = models.DateTimeField(blank=True, null=True)
closes = models.DateTimeField(blank=True, null=True)
start = models.DateTimeField(blank=True, null=True)
end = models.DateTimeField(blank=True, null=True)
molnix_tags = models.ManyToManyField(MolnixTag, blank=True)

# Set to inactive when position is no longer in Molnix
is_active = models.BooleanField(default=True)

# Don't set `auto_now_add` so we can modify it on save
created_at = models.DateTimeField(verbose_name=_("created at"))
status = models.IntegerField(choices=SurgeAlertStatus.choices, verbose_name=_("alert status"), default=SurgeAlertStatus.OPEN)
molnix_status = models.IntegerField(
choices=SurgeAlertStatus.choices, verbose_name=_("alert status"), default=SurgeAlertStatus.OPEN
)

class Meta:
ordering = ["-created_at"]
verbose_name = _("Surge Alert")
verbose_name_plural = _("Surge Alerts")

def save(self, *args, **kwargs):
@staticmethod
def parse_molnix_status(status_raw: str) -> SurgeAlertStatus:
"""
If the alert status is marked as stood_down, then the status is Stood Down.
If the closing timestamp (closes) is earlier than the current date, the status is displayed as Closed.
Otherwise, it is displayed as Open.
A position_status of active should be shown as Open
A position_status of archived should be shown as Closed
A position_status of unfilled should be shown as Stood Down
If the position_status is non other than active, archived, unfilled then show Closed.
"""
# On save, if `created` is not set, make it the current time
molnix_status_dict = {
"active": SurgeAlertStatus.OPEN,
"unfilled": SurgeAlertStatus.STOOD_DOWN,
"archived": SurgeAlertStatus.CLOSED,
}

return molnix_status_dict.get(status_raw.lower(), SurgeAlertStatus.CLOSED)

def save(self, *args, **kwargs):
if (not self.id and not self.created_at) or (self.created_at > timezone.now()):
self.created_at = timezone.now()
self.is_stood_down = self.molnix_status == "unfilled"
if self.is_stood_down:
self.status = SurgeAlertStatus.STOOD_DOWN
elif self.closes and self.closes < timezone.now():
self.status = SurgeAlertStatus.CLOSED
else:
self.status = SurgeAlertStatus.OPEN
return super(SurgeAlert, self).save(*args, **kwargs)

def __str__(self):
Expand Down
12 changes: 5 additions & 7 deletions notifications/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@


class SurgeAlertSerializer(ModelSerializer):
event = SurgeEventSerializer()
country = MiniCountrySerializer()
event = SurgeEventSerializer(required=False)
country = MiniCountrySerializer(required=False)
atype_display = serializers.CharField(source="get_atype_display", read_only=True)
status_display = serializers.CharField(source="get_status_display", read_only=True)
molnix_status_display = serializers.CharField(source="get_molnix_status_display", read_only=True)
category_display = serializers.CharField(source="get_category_display", read_only=True)
molnix_tags = MolnixTagSerializer(many=True, read_only=True)

Expand All @@ -41,10 +41,8 @@ class Meta:
"closes",
"start",
"end",
"is_active",
"is_stood_down",
"status",
"status_display",
"molnix_status",
"molnix_status_display",
)


Expand Down
Loading