Skip to content

Commit a40688d

Browse files
committed
feat(api): add new api endpoint for emergency
- Add new emergency api for. - Attach latest field report. - Add test case for emergency endpoint.
1 parent 89231d1 commit a40688d

6 files changed

Lines changed: 177 additions & 6 deletions

File tree

api/drf_views.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
Export,
9090
ExternalPartner,
9191
FieldReport,
92+
KeyFigure,
9293
MainContact,
9394
Profile,
9495
Region,
@@ -122,6 +123,7 @@
122123
CountrySupportingPartnerSerializer,
123124
CountryTableauSerializer,
124125
DeploymentsByEventSerializer,
126+
DetailEmergencySerializer,
125127
DetailEventSerializer,
126128
DisasterTypeSerializer,
127129
DistrictSerializer,
@@ -1544,11 +1546,12 @@ def get_queryset(self):
15441546
return CountrySupportingPartner.objects.select_related("country")
15451547

15461548

1547-
class EmergencyViewset(viewsets.ReadOnlyModelViewSet):
1549+
class EmergencyViewset(ReadOnlyVisibilityViewset):
15481550
queryset = Event.objects.all()
15491551
lookup_field = "id"
15501552
serializer_class = DetailEmergencySerializer
15511553
filterset_class = EventFilter
1554+
visibility_model_class = Event
15521555

15531556
def get_queryset(self):
15541557
return (
@@ -1566,9 +1569,21 @@ def get_queryset(self):
15661569
Prefetch("contacts", queryset=EventContact.objects.all()),
15671570
)
15681571
.annotate(
1572+
first_field_report_id=Subquery(
1573+
FieldReport.objects.filter(event=OuterRef("pk"))
1574+
.order_by(
1575+
"fr_num",
1576+
"updated_at",
1577+
)
1578+
.values("id")[:1]
1579+
),
15691580
latest_field_report_id=Subquery(
1570-
FieldReport.objects.filter(event=OuterRef("pk")).order_by("-created_at").values("id")[:1]
1581+
FieldReport.objects.filter(event=OuterRef("pk"))
1582+
.order_by(
1583+
"-fr_num",
1584+
"-updated_at",
1585+
)
1586+
.values("id")[:1]
15711587
),
1572-
appeal_id=Subquery(Appeal.objects.filter(event=OuterRef("pk")).order_by("-created_at").values("id")[:1]),
15731588
)
15741589
)

api/factories/event.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
AppealHistory,
1313
AppealType,
1414
Event,
15+
EventContact,
1516
EventFeaturedDocument,
1617
EventLink,
1718
)
@@ -133,3 +134,9 @@ class AppealHistoryFactory(factory.django.DjangoModelFactory):
133134

134135
class Meta:
135136
model = AppealHistory
137+
138+
139+
class EventContactFactory(factory.django.DjangoModelFactory):
140+
141+
class Meta:
142+
model = EventContact

api/serializers.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2196,7 +2196,7 @@ def create_event(self, report):
21962196
summary=report.description or "",
21972197
disaster_start_date=report.start_date,
21982198
auto_generated=True,
2199-
source=Event.EventSources.NEW_REPORT,
2199+
source=Event.EventSource.NEW_REPORT,
22002200
visibility=report.visibility,
22012201
**{TRANSLATOR_ORIGINAL_LANGUAGE_FIELD_NAME: django_get_language()},
22022202
)
@@ -2601,3 +2601,53 @@ class CountrySupportingPartnerSerializer(serializers.ModelSerializer):
26012601
class Meta:
26022602
model = CountrySupportingPartner
26032603
fields = "__all__"
2604+
2605+
2606+
class DetailEmergencySerializer(serializers.ModelSerializer):
2607+
contacts = EventContactSerializer(many=True, read_only=True)
2608+
key_figures = KeyFigureSerializer(many=True, read_only=True)
2609+
countries = MiniCountrySerializer(many=True, read_only=True)
2610+
ifrc_severity_level_display = serializers.CharField(source="get_ifrc_severity_level_display", read_only=True)
2611+
visibility_display = serializers.CharField(source="get_visibility_display", read_only=True)
2612+
source_display = serializers.CharField(source="get_source_display", read_only=True)
2613+
# NOTE: Populated from Queryset using Annotate
2614+
first_field_report_id = serializers.IntegerField(read_only=True)
2615+
latest_field_report_id = serializers.IntegerField(read_only=True)
2616+
2617+
class Meta:
2618+
model = Event
2619+
fields = (
2620+
"name",
2621+
"dtype",
2622+
"countries",
2623+
"summary",
2624+
"disaster_start_date",
2625+
"auto_generated",
2626+
"source",
2627+
"source_display",
2628+
"key_figures",
2629+
"is_featured",
2630+
"is_featured_region",
2631+
"hide_attached_field_reports",
2632+
"hide_field_report_map",
2633+
"id",
2634+
"slug",
2635+
"ifrc_severity_level",
2636+
"ifrc_severity_level_display",
2637+
"ifrc_severity_level_update_date",
2638+
"parent_event",
2639+
"emergency_response_contact_email",
2640+
"visibility",
2641+
"visibility_display",
2642+
"contacts",
2643+
"num_injured",
2644+
"num_dead",
2645+
"num_missing",
2646+
"num_affected",
2647+
"num_displaced",
2648+
"created_at",
2649+
"updated_at",
2650+
"previous_update",
2651+
"first_field_report_id",
2652+
"latest_field_report_id",
2653+
)

api/test_views.py

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import re
22
import uuid
3-
from datetime import timedelta
3+
from datetime import datetime, timedelta
44
from unittest.mock import patch
55

66
from django.contrib.auth.models import User
@@ -10,9 +10,11 @@
1010
from django.utils import timezone
1111

1212
import api.models as models
13+
from api.factories.disaster_type import DisasterTypeFactory
1314
from api.factories.event import (
1415
AppealFactory,
1516
AppealType,
17+
EventContactFactory,
1618
EventFactory,
1719
EventFeaturedDocumentFactory,
1820
EventLinkFactory,
@@ -1042,3 +1044,97 @@ def test_ifrc_user_sees_all(self):
10421044
]
10431045
),
10441046
)
1047+
1048+
1049+
class EmergencyViewTestCase(APITestCase):
1050+
def setUp(self):
1051+
super().setUp()
1052+
self.disaster_type = DisasterTypeFactory.create(
1053+
name="Flood",
1054+
)
1055+
1056+
self.event1 = EventFactory.create(
1057+
dtype=self.disaster_type,
1058+
source=models.Event.EventSource.GDACS,
1059+
slug="test1",
1060+
parent_event=None,
1061+
)
1062+
self.contact = EventContactFactory.create(
1063+
event=self.event1,
1064+
)
1065+
1066+
self.field_report1 = FieldReportFactory.create(
1067+
event=self.event1,
1068+
created_at=timezone.make_aware(datetime(2024, 1, 1)),
1069+
updated_at=timezone.make_aware(datetime(2026, 1, 1)),
1070+
fr_num=50,
1071+
)
1072+
1073+
self.field_report2 = FieldReportFactory.create(
1074+
event=self.event1,
1075+
created_at=timezone.make_aware(datetime(2024, 1, 1)),
1076+
updated_at=timezone.make_aware(datetime(2025, 1, 1)),
1077+
fr_num=20,
1078+
)
1079+
1080+
self.event2 = EventFactory.create(
1081+
dtype=self.disaster_type,
1082+
source=models.Event.EventSource.WHO,
1083+
slug="test2",
1084+
parent_event=None,
1085+
)
1086+
1087+
self.event3 = EventFactory.create(
1088+
dtype=self.disaster_type,
1089+
source=models.Event.EventSource.APPEAL_ADMIN,
1090+
slug="test3",
1091+
parent_event=None,
1092+
)
1093+
self.appeal2 = AppealFactory.create(
1094+
event=self.event3,
1095+
dtype=self.disaster_type,
1096+
num_beneficiaries=9000,
1097+
amount_requested=10000,
1098+
amount_funded=1899999,
1099+
)
1100+
1101+
self.url = "/api/v2/emergency/"
1102+
1103+
def test_get_emergency_list(self):
1104+
response = self.client.get(self.url)
1105+
self.assert_200(response)
1106+
self.assertEqual(response.data["count"], 2)
1107+
1108+
def test_retrive_emergency_detail(self):
1109+
url = f"/api/v2/emergency/{self.event1.id}/"
1110+
response = self.client.get(url)
1111+
self.assert_200(response)
1112+
self.assertEqual(response.data["id"], self.event1.id)
1113+
self.assertEqual(response.data["slug"], self.event1.slug)
1114+
self.assertEqual(response.data["name"], self.event1.name)
1115+
self.assertEqual(response.data["source"], models.Event.EventSource.GDACS)
1116+
1117+
# first field report id check
1118+
self.assertEqual(response.data["first_field_report_id"], self.field_report2.id)
1119+
# latest check field report
1120+
self.assertEqual(response.data["latest_field_report_id"], self.field_report1.id)
1121+
1122+
# Filter Tests
1123+
def test_filter_by_source(self):
1124+
url = f"{self.url}?source=120"
1125+
response = self.client.get(url)
1126+
self.assert_200(response)
1127+
self.assertEqual(response.data["count"], 1)
1128+
self.assertEqual(response.data["results"][0]["source"], models.Event.EventSource.WHO)
1129+
1130+
def test_filter_by_appeal_source(self):
1131+
url = f"{self.url}?source=150"
1132+
response = self.client.get(url)
1133+
self.assert_200(response)
1134+
self.assertEqual(response.data["count"], 1)
1135+
self.assertEqual(response.data["results"][0]["source"], models.Event.EventSource.APPEAL_ADMIN)
1136+
1137+
def test_filter_by_source_no_match(self):
1138+
url = f"{self.url}?source=500"
1139+
response = self.client.get(url)
1140+
self.assert_400(response)

assets

main/urls.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@
8888
router.register(r"admin2", api_views.Admin2Viewset, basename="admin2")
8989
router.register(r"district", api_views.DistrictViewset, basename="district")
9090
router.register(r"district_rmd", api_views.DistrictRMDViewset, basename="district_rmd")
91+
92+
router.register(r"emergency", api_views.EmergencyViewset, basename="emergency")
93+
9194
router.register(r"domainwhitelist", registration_views.DomainWhitelistViewset)
9295
router.register(r"eru", deployment_views.ERUViewset, basename="eru")
9396
router.register(

0 commit comments

Comments
 (0)