diff --git a/api/admin.py b/api/admin.py index 9dab94449..f9c13c14c 100644 --- a/api/admin.py +++ b/api/admin.py @@ -381,6 +381,8 @@ def changeform_view(self, request, object_id=None, form_url="", extra_context=No "auto_generated_source", "created_at", "updated_at", + "auto_generated_external_source", + "auto_generated_external_source_id", ) # Set severity level from GET parameter @@ -634,7 +636,15 @@ def assist(self, obj): "districts", ) - readonly_fields = ("report_date", "created_at", "updated_at", "summary", "fr_num") + readonly_fields = ( + "report_date", + "created_at", + "updated_at", + "summary", + "fr_num", + "external_source", + "external_source_id", + ) list_filter = [MembershipFilter, "ns_request_assistance"] actions = [ "create_events", diff --git a/api/migrations/0232_event_auto_generated_external_source_and_more.py b/api/migrations/0232_event_auto_generated_external_source_and_more.py new file mode 100644 index 000000000..57f613a86 --- /dev/null +++ b/api/migrations/0232_event_auto_generated_external_source_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 5.2.14 on 2026-06-10 04:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0231_alter_export_export_type'), + ] + + operations = [ + migrations.AddField( + model_name='event', + name='auto_generated_external_source', + field=models.CharField(blank=True, help_text='External source or system from which the original event data originated.', max_length=100, null=True, verbose_name='external source'), + ), + migrations.AddField( + model_name='event', + name='auto_generated_external_source_id', + field=models.CharField(blank=True, help_text='Unique identifier of the event record in the external source system.', max_length=100, null=True, verbose_name='external source ID'), + ), + migrations.AddField( + model_name='fieldreport', + name='external_source', + field=models.CharField(blank=True, help_text='External source system from which this field report created.', max_length=100, null=True, verbose_name='external source'), + ), + migrations.AddField( + model_name='fieldreport', + name='external_source_id', + field=models.CharField(blank=True, help_text='Unique identifier of this field report in the external source system.', max_length=100, null=True, verbose_name='external source ID'), + ), + ] diff --git a/api/models.py b/api/models.py index 8bfcffea9..772ceaba4 100644 --- a/api/models.py +++ b/api/models.py @@ -828,7 +828,22 @@ class Event(models.Model): auto_generated_source = models.CharField( verbose_name=_("auto generated source"), max_length=50, null=True, blank=True, editable=False ) - + # External system or source from which the event data originated + auto_generated_external_source = models.CharField( + verbose_name=_("external source"), + max_length=100, + null=True, + blank=True, + help_text=_("External source or system from which the original event data originated."), + ) + # Identifier of the originating event record in the external system + auto_generated_external_source_id = models.CharField( + verbose_name=_("external source ID"), + max_length=100, + null=True, + blank=True, + help_text=_("Unique identifier of the event record in the external source system."), + ) # Meant to give the organization a way of highlighting certain, important events. is_featured = models.BooleanField(default=False, verbose_name=_("is featured on home page")) @@ -2473,7 +2488,22 @@ class RecentAffected(models.IntegerChoices): default=0, help_text='Key/value pairs', ) - + # External system from which this Field Report created. + external_source = models.CharField( + verbose_name=_("external source"), + max_length=100, + null=True, + blank=True, + help_text=_("External source system from which this field report created."), + ) + # Identifier of the report in the external system. + external_source_id = models.CharField( + verbose_name=_("external source ID"), + max_length=100, + null=True, + blank=True, + help_text=_("Unique identifier of this field report in the external source system."), + ) # start_date is now what the user explicitly sets while filling the Field Report form. start_date = models.DateTimeField(verbose_name=_("start date"), blank=True, null=True) diff --git a/api/serializers.py b/api/serializers.py index 351749947..46a05bd38 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -2219,6 +2219,8 @@ def create_event(self, report): disaster_start_date=report.start_date, auto_generated=True, auto_generated_source=SOURCES["new_report"], + auto_generated_external_source=report.external_source or None, + auto_generated_external_source_id=report.external_source_id or None, visibility=report.visibility, **{TRANSLATOR_ORIGINAL_LANGUAGE_FIELD_NAME: django_get_language()}, ) diff --git a/api/test_views.py b/api/test_views.py index 246ab9a2b..b395574ec 100644 --- a/api/test_views.py +++ b/api/test_views.py @@ -12,6 +12,8 @@ from django.utils import timezone import api.models as models +from api.factories.country import CountryFactory +from api.factories.disaster_type import DisasterTypeFactory from api.factories.event import ( AppealFactory, AppealType, @@ -20,6 +22,7 @@ EventLinkFactory, ) from api.factories.field_report import FieldReportFactory +from api.factories.region import RegionFactory from api.models import Profile, VisibilityChoices from deployments.factories.user import UserFactory from dref.models import DrefFile @@ -542,6 +545,88 @@ def test_create_and_update(self): # ) +class FieldReportEventCreationTest(APITestCase): + + def setUp(self): + self.user = UserFactory() + self.region = RegionFactory.create(name=1) + self.country1 = CountryFactory(name="test abc", region=self.region) + self.country2 = CountryFactory(name="test xyz", region=self.region) + self.disaster_type = DisasterTypeFactory.create(name="disaster 1") + self.url = "/api/v2/field-report/" + + # Test 1 without external source + def test_event_creation(self): + data = { + "countries": [self.country1.id, self.country2.id], + "dtype": self.disaster_type.id, + "summary": "test", + "description": "this is a test description", + "num_assisted": 100, + "visibility": 2, + } + self.client.force_authenticate(self.user) + response = self.client.post( + self.url, + data=data, + format="json", + ) + self.assert_201(response) + field_report_id = response.data["id"] + + field_report = models.FieldReport.objects.get(id=field_report_id) + self.assertIsNotNone(field_report.event) + + event = field_report.event + self.assertEqual(event.name, field_report.summary) + self.assertEqual(event.dtype, field_report.dtype) + self.assertTrue(event.auto_generated) + + self.assertIn(self.country1, event.countries.all()) + self.assertIn(self.country2, event.countries.all()) + self.assertIn(self.region, event.regions.all()) + + self.assertIsNone(event.auto_generated_external_source) + self.assertIsNone(event.auto_generated_external_source_id) + + # Test with external source + def test_event_creation_with_external_source(self): + + external_source_id = str(uuid.uuid4()) + data = { + "countries": [self.country1.id, self.country2.id], + "dtype": self.disaster_type.id, + "summary": "test", + "description": "this is a test description", + "num_assisted": 100, + "visibility": 2, + "external_source": "mrcs", + "external_source_id": external_source_id, + } + self.client.force_authenticate(self.user) + response = self.client.post( + self.url, + data=data, + format="json", + ) + self.assert_201(response) + field_report_id = response.data["id"] + field_report = models.FieldReport.objects.get(id=field_report_id) + + self.assertIsNotNone(field_report.event) + + event = field_report.event + self.assertEqual(event.name, field_report.summary) + self.assertTrue(event.auto_generated) + + self.assertEqual(event.auto_generated_external_source, "mrcs") + self.assertEqual(event.auto_generated_external_source_id, external_source_id) + + self.assertIn(self.country1, event.countries.all()) + self.assertIn(self.country2, event.countries.all()) + self.assertIn(self.region, event.regions.all()) + + class VisibilityTest(APITestCase): def test_country_snippet_visibility(self): country = models.Country.objects.create(name="1") diff --git a/assets b/assets index 1465dfa11..b482b0d23 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 1465dfa118f2d7e880e23bb846393ad918f57ec8 +Subproject commit b482b0d23b5b639e1814a1c8a1598f6a808dec43