Skip to content
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
2 changes: 1 addition & 1 deletion assets
Submodule assets updated 1 files
+60 −0 openapi-schema.yaml
72 changes: 71 additions & 1 deletion dref/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2252,6 +2252,48 @@ class Meta(BaseDref3Serializer.Meta):
model = DrefFinalReport


# Flatten the DREF's scalar contact fields into an api.EventContact-shaped list
# for the emergency page. Integrity contact is intentionally excluded.
DREF_EMERGENCY_CONTACT_GROUPS = (
("national_society_contact", "National Society Contact"),
("ifrc_appeal_manager", "IFRC Appeal Manager"),
("ifrc_project_manager", "IFRC Project Manager"),
("ifrc_emergency", "IFRC Emergency"),
("media_contact", "Media Contact"),
)


def get_dref_emergency_contacts(obj):
contacts = []
for prefix, ctype in DREF_EMERGENCY_CONTACT_GROUPS:
name = getattr(obj, f"{prefix}_name", None)
title = getattr(obj, f"{prefix}_title", None)
email = getattr(obj, f"{prefix}_email", None)
phone = getattr(obj, f"{prefix}_phone_number", None)
if not any([name, title, email, phone]):
continue
contacts.append(
{
"id": f"{obj.id}-{prefix}",
"ctype": ctype,
"name": name or "",
"title": title or "",
"email": email or "",
"phone": phone or "",
}
)
return contacts


class EmergencyDrefContactSerializer(serializers.Serializer):
id = serializers.CharField()
ctype = serializers.CharField()
name = serializers.CharField()
title = serializers.CharField()
email = serializers.CharField()
phone = serializers.CharField()


# NOTE: This serializer is only used for the emergency page in GO,
# which has a very specific and limited use case.
# It is not intended to be a general-purpose serializer for DREF objects,
Expand All @@ -2265,6 +2307,7 @@ class EmergencyDrefFinalReportSerializer(serializers.ModelSerializer):
cover_image_file = DrefFileSerializer(source="cover_image", read_only=True)
proposed_action = ProposedActionSerializer(many=True, required=False)
disaster_type_details = DisasterTypeSerializer(source="disaster_type", read_only=True)
dref_contacts = serializers.SerializerMethodField()

class Meta:
model = DrefFinalReport
Expand Down Expand Up @@ -2293,6 +2336,7 @@ class Meta:
"number_of_people_targeted",
"number_of_people_affected",
"total_targeted_population",
"people_targeted_with_early_actions",
"estimated_number_of_affected_male",
"estimated_number_of_affected_female",
"estimated_number_of_affected_girls_under_18",
Expand All @@ -2308,8 +2352,13 @@ class Meta:
"date_of_approval",
"created_at",
"modified_at",
"dref_contacts",
)

@extend_schema_field(EmergencyDrefContactSerializer(many=True))
def get_dref_contacts(self, obj):
return get_dref_emergency_contacts(obj)


class TimelineEmergencyDrefOperationalUpdateSerializer(serializers.ModelSerializer):
class Meta:
Expand All @@ -2318,6 +2367,8 @@ class Meta:
"id",
"summary_of_change",
"date_of_approval",
# fallback timeline date when date_of_approval is unset
"modified_at",
"operational_update_number",
"total_targeted_population",
"total_dref_allocation",
Expand All @@ -2331,6 +2382,7 @@ class EmergencyDrefOperationalUpdateSerializer(serializers.ModelSerializer):
planned_interventions = PlannedInterventionSerializer(many=True, read_only=True)
cover_image_file = DrefFileSerializer(source="cover_image", required=False, allow_null=True)
disaster_type_details = DisasterTypeSerializer(source="disaster_type", read_only=True)
dref_contacts = serializers.SerializerMethodField()

class Meta:
model = DrefOperationalUpdate
Expand Down Expand Up @@ -2362,12 +2414,18 @@ class Meta:
"number_of_people_targeted",
"number_of_people_affected",
"total_targeted_population",
"people_targeted_with_early_actions",
"estimated_number_of_affected_male",
"estimated_number_of_affected_female",
"estimated_number_of_affected_girls_under_18",
"estimated_number_of_affected_boys_under_18",
"dref_contacts",
)

@extend_schema_field(EmergencyDrefContactSerializer(many=True))
def get_dref_contacts(self, obj):
return get_dref_emergency_contacts(obj)


class EmergencyDrefSerializer(serializers.ModelSerializer):
status_display = serializers.CharField(source="get_status_display", read_only=True)
Expand All @@ -2387,6 +2445,8 @@ class EmergencyDrefSerializer(serializers.ModelSerializer):
# Timeline of operational updates
timeline_operational_updates = serializers.SerializerMethodField()

dref_contacts = serializers.SerializerMethodField()

class Meta:
model = Dref
fields = (
Expand Down Expand Up @@ -2422,6 +2482,7 @@ class Meta:
"amount_requested",
"total_cost",
"total_targeted_population",
"people_targeted_with_early_actions",
"estimated_number_of_affected_male",
"estimated_number_of_affected_female",
"estimated_number_of_affected_girls_under_18",
Expand All @@ -2435,17 +2496,26 @@ class Meta:
# For Response Type
"event_date",
"timeline_operational_updates",
# Contacts
"dref_contacts",
)

@extend_schema_field(TimelineEmergencyDrefOperationalUpdateSerializer(many=True))
def get_timeline_operational_updates(self, obj):
ops_updates = DrefOperationalUpdate.objects.filter(dref=obj).order_by("operational_update_number")
ops_updates = DrefOperationalUpdate.objects.filter(
dref=obj,
status=Dref.Status.APPROVED,
).order_by("operational_update_number")
serializer = TimelineEmergencyDrefOperationalUpdateSerializer(
ops_updates,
many=True,
)
return serializer.data

@extend_schema_field(EmergencyDrefContactSerializer(many=True))
def get_dref_contacts(self, obj):
return get_dref_emergency_contacts(obj)

@extend_schema_field(EmergencyDrefOperationalUpdateSerializer())
def get_operational_update_details(self, obj):
if not obj.operational_update_id:
Expand Down
11 changes: 10 additions & 1 deletion dref/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.conf import settings
from django.contrib.postgres.aggregates import ArrayAgg
from django.db import models
from django.utils import timezone

from api.models import Event
from dref.models import Dref, DrefFinalReport, DrefOperationalUpdate
Expand Down Expand Up @@ -57,7 +58,7 @@ def get_dref_users():


def create_event_from_dref(dref: Dref) -> Event:
event = Event.objects.create(
create_kwargs = dict(
name=dref.title,
dtype=dref.disaster_type,
summary=dref.event_description or dref.event_scope or "",
Expand All @@ -67,6 +68,14 @@ def create_event_from_dref(dref: Dref) -> Event:
source=Event.EventSource.DREF,
)

# Dref.DisasterCategory and api.AlertLevel share the same 0/1/2 indices, so
# the value maps directly with no remap.
if dref.disaster_category is not None:
create_kwargs["ifrc_severity_level"] = dref.disaster_category
create_kwargs["ifrc_severity_level_update_date"] = dref.date_of_approval or timezone.now()

event = Event.objects.create(**create_kwargs)

country = getattr(dref, "country", None)
if country:
event.countries.add(dref.country)
Expand Down
20 changes: 18 additions & 2 deletions dref/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ def get_approved(self, request, pk=None, version=None):
raise serializers.ValidationError(gettext("Must be finalized before it can be approved."))

operational_update.status = Dref.Status.APPROVED
operational_update.save(update_fields=["status"])
operational_update.date_of_approval = timezone.now().date()
operational_update.save(update_fields=["status", "date_of_approval"])
serializer = DrefOperationalUpdateSerializer(operational_update, context={"request": request})
return response.Response(serializer.data)

Expand Down Expand Up @@ -367,7 +368,22 @@ class CompletedDrefOperationsViewSet(viewsets.ReadOnlyModelViewSet):
DenyGuestUserPermission,
]
filterset_class = CompletedDrefOperationsFilterSet
queryset = DrefFinalReport.objects.filter(status=Dref.Status.APPROVED).order_by("-created_at").distinct()
queryset = (
DrefFinalReport.objects.filter(status=Dref.Status.APPROVED)
.select_related("country", "dref", "dref__country")
.prefetch_related(
# MiniDrefSerializer.operational_update_details reads this prefetched
# attr; without it DRF silently drops the field.
Prefetch(
"dref__drefoperationalupdate_set",
queryset=DrefOperationalUpdate.objects.select_related("country").order_by("-created_at"),
to_attr="prefetched_operational_updates",
),
"dref__dreffinalreport__country",
)
.order_by("-created_at")
.distinct()
)

def get_queryset(self):
user = self.request.user
Expand Down
Loading