Skip to content

Commit 41ff810

Browse files
sudip-khanalsandeshit
authored andcommitted
feat(alert-system): update related montandon event query
1 parent 231d067 commit 41ff810

7 files changed

Lines changed: 79 additions & 28 deletions

File tree

alert_system/admin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ class LoadItemAdmin(admin.ModelAdmin):
4949
class AlertEmailThreadAdmin(admin.ModelAdmin):
5050
list_display = (
5151
"user",
52-
"parent_guid",
52+
"parent_event_id",
5353
"root_email_message_id",
5454
)
5555
search_fields = (
56-
"parent_guid",
56+
"parent_event_id",
5757
"root_email_message_id",
5858
"user__username",
5959
)

alert_system/email_processing.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,15 @@ def send_alert_email_notification(
6666
if not is_reply:
6767
thread = AlertEmailThread.objects.create(
6868
user=user,
69-
parent_guid=load_item.parent_guid,
69+
parent_event_id=load_item.parent_event_id,
7070
root_email_message_id=message_id,
7171
root_message_sent_at=timezone.now(),
7272
)
7373
email_log.thread = thread
7474
email_log.save(update_fields=["thread"])
7575
logger.info(
76-
f"Alert Email thread created for user [{user.get_full_name()}] " f"with parent_guid [{load_item.parent_guid}]"
76+
f"Alert Email thread created for user [{user.get_full_name()}] "
77+
f"with parent event [{load_item.parent_event_id}]"
7778
)
7879

7980
logger.info(f"Alert email sent to [{user.get_full_name()}] for LoadItem ID [{load_item.id}]")
@@ -127,7 +128,7 @@ def process_email_alert(load_item_id: int) -> None:
127128
existing_threads = {
128129
thread.user_id: thread
129130
for thread in AlertEmailThread.objects.filter(
130-
parent_guid=load_item.parent_guid,
131+
parent_event_id=load_item.parent_event_id,
131132
user_id__in=user_ids,
132133
)
133134
}

alert_system/factories.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77

88
class LoadItemFactory(factory.django.DjangoModelFactory):
9-
guid = factory.LazyFunction(lambda: str(uuid4()))
9+
parent_event_id = factory.LazyFunction(lambda: str(uuid4()))
10+
event_id = factory.LazyFunction(lambda: str(uuid4()))
11+
event_url = factory.Sequence(lambda n: f"https://test-events.com/event/{n}")
1012

1113
class Meta:
1214
model = LoadItem
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Generated by Django 4.2.30 on 2026-05-18 08:24
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('alert_system', '0001_initial'),
10+
]
11+
12+
operations = [
13+
migrations.RemoveConstraint(
14+
model_name='alertemailthread',
15+
name='unique_user_guid',
16+
),
17+
migrations.RemoveIndex(
18+
model_name='alertemailthread',
19+
name='alert_syste_parent__737a31_idx',
20+
),
21+
migrations.RenameField(
22+
model_name='alertemailthread',
23+
old_name='parent_guid',
24+
new_name='parent_event_id',
25+
),
26+
migrations.AddIndex(
27+
model_name='alertemailthread',
28+
index=models.Index(fields=['parent_event_id', 'user'], name='alert_syste_parent__7efaa4_idx'),
29+
),
30+
migrations.AddConstraint(
31+
model_name='alertemailthread',
32+
constraint=models.UniqueConstraint(fields=('parent_event_id', 'user'), name='unique_user_parent_event'),
33+
),
34+
]

alert_system/models.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,8 @@ class AlertEmailThread(models.Model):
280280
on_delete=models.CASCADE,
281281
related_name="alert_email_threads",
282282
)
283-
284-
parent_guid = models.CharField(
283+
# NOTE: parent_event_id field is same field form the LoadItem model.
284+
parent_event_id = models.CharField(
285285
help_text=_("Identifier linking related LoadItems into the same email thread."),
286286
)
287287

@@ -304,13 +304,13 @@ class Meta:
304304
verbose_name = _("Email Thread")
305305
verbose_name_plural = _("Email Threads")
306306
ordering = ["-id"]
307-
constraints = [models.UniqueConstraint(fields=["parent_guid", "user"], name="unique_user_guid")]
307+
constraints = [models.UniqueConstraint(fields=["parent_event_id", "user"], name="unique_user_parent_event")]
308308
indexes = [
309-
models.Index(fields=["parent_guid", "user"]),
309+
models.Index(fields=["parent_event_id", "user"]),
310310
]
311311

312312
def __str__(self):
313-
return f"Thread: {self.user.get_full_name()}-{self.parent_guid}"
313+
return f"Thread: {self.user.get_full_name()}-{self.parent_event_id}"
314314

315315

316316
class AlertEmailLog(models.Model):

alert_system/tests.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def setUp(self):
6060
)
6161

6262
self.eligible_item = LoadItemFactory.create(
63-
parent_guid=str(uuid4()),
63+
parent_event_id=str(uuid4()),
6464
connector=self.connector,
6565
item_eligible=True,
6666
is_past_event=False,
@@ -107,7 +107,7 @@ def test_sent_email_for_eligible_item(self, mock_send_notification):
107107
self.assertIsNotNone(log.email_sent_at)
108108

109109
self.assertEqual(thread.user, self.user1)
110-
self.assertEqual(thread.parent_guid, self.eligible_item.parent_guid)
110+
self.assertEqual(thread.parent_event_id, self.eligible_item.parent_event_id)
111111
self.assertEqual(thread.root_email_message_id, log.message_id)
112112
self.assertEqual(log.thread, thread)
113113

@@ -121,7 +121,7 @@ def test_sent_email_to_multiple_users(self, mock_send_notification):
121121
logs = AlertEmailLog.objects.filter(item=self.eligible_item, status=AlertEmailLog.Status.SENT)
122122
self.assertEqual(logs.count(), 2)
123123

124-
threads = AlertEmailThread.objects.filter(parent_guid=self.eligible_item.parent_guid)
124+
threads = AlertEmailThread.objects.filter(parent_event_id=self.eligible_item.parent_event_id)
125125
self.assertEqual(threads.count(), 2)
126126

127127
self.assertEqual(mock_send_notification.call_count, 2)
@@ -217,7 +217,7 @@ def test_reply_email_for_existing_thread(self, mock_send_notification):
217217
)
218218

219219
initial_item = LoadItemFactory.create(
220-
parent_guid=str(uuid4()),
220+
parent_event_id=str(uuid4()),
221221
connector=self.connector,
222222
item_eligible=True,
223223
is_past_event=False,
@@ -231,7 +231,7 @@ def test_reply_email_for_existing_thread(self, mock_send_notification):
231231

232232
thread = AlertEmailThreadFactory.create(
233233
user=user,
234-
parent_guid=initial_item.parent_guid,
234+
parent_event_id=initial_item.parent_event_id,
235235
root_email_message_id=str(uuid4()),
236236
root_message_sent_at=timezone.now(),
237237
)
@@ -247,7 +247,7 @@ def test_reply_email_for_existing_thread(self, mock_send_notification):
247247
)
248248

249249
update_item = LoadItemFactory.create(
250-
parent_guid=initial_item.parent_guid,
250+
parent_event_id=initial_item.parent_event_id,
251251
connector=self.connector,
252252
item_eligible=True,
253253
is_past_event=False,
@@ -267,17 +267,17 @@ def test_reply_email_for_existing_thread(self, mock_send_notification):
267267

268268
mock_send_notification.assert_called_once()
269269

270-
threads = AlertEmailThread.objects.filter(parent_guid=initial_item.parent_guid)
270+
threads = AlertEmailThread.objects.filter(parent_event_id=initial_item.parent_event_id)
271271
self.assertEqual(threads.count(), 1)
272272

273273
@mock.patch("alert_system.email_processing.send_notification")
274274
def test_reply_email_to_multiple_users(self, mock_send_notification):
275275

276-
parent_guid = str(uuid4())
276+
parent_event_id = str(uuid4())
277277

278278
# Create initial item
279279
initial_item = LoadItemFactory.create(
280-
parent_guid=parent_guid,
280+
parent_event_id=parent_event_id,
281281
connector=self.connector,
282282
item_eligible=True,
283283
is_past_event=False,
@@ -292,14 +292,14 @@ def test_reply_email_to_multiple_users(self, mock_send_notification):
292292
# Create threads for both users
293293
thread1 = AlertEmailThreadFactory.create(
294294
user=self.user1,
295-
parent_guid=parent_guid,
295+
parent_event_id=parent_event_id,
296296
root_email_message_id="message-id-1",
297297
root_message_sent_at=timezone.now(),
298298
)
299299

300300
thread2 = AlertEmailThreadFactory.create(
301301
user=self.user2,
302-
parent_guid=parent_guid,
302+
parent_event_id=parent_event_id,
303303
root_email_message_id="message-id-2",
304304
root_message_sent_at=timezone.now(),
305305
)
@@ -325,7 +325,7 @@ def test_reply_email_to_multiple_users(self, mock_send_notification):
325325
)
326326

327327
related_item = LoadItemFactory.create(
328-
parent_guid=parent_guid,
328+
parent_event_id=parent_event_id,
329329
connector=self.connector,
330330
item_eligible=True,
331331
is_past_event=False,
@@ -350,7 +350,7 @@ def test_reply_email_to_multiple_users(self, mock_send_notification):
350350
@mock.patch("alert_system.email_processing.send_notification")
351351
def test_duplicate_reply(self, mock_send_notification):
352352

353-
parent_guid = str(uuid4())
353+
parent_event_id = str(uuid4())
354354

355355
user = UserFactory.create()
356356
country = CountryFactory.create(
@@ -366,7 +366,7 @@ def test_duplicate_reply(self, mock_send_notification):
366366
)
367367

368368
LoadItemFactory.create(
369-
parent_guid=parent_guid,
369+
parent_event_id=parent_event_id,
370370
connector=self.connector,
371371
item_eligible=True,
372372
is_past_event=False,
@@ -380,13 +380,13 @@ def test_duplicate_reply(self, mock_send_notification):
380380

381381
thread = AlertEmailThreadFactory.create(
382382
user=user,
383-
parent_guid=parent_guid,
383+
parent_event_id=parent_event_id,
384384
root_email_message_id="root-123",
385385
root_message_sent_at=timezone.now(),
386386
)
387387

388388
update_item = LoadItemFactory.create(
389-
parent_guid=parent_guid,
389+
parent_event_id=parent_event_id,
390390
connector=self.connector,
391391
item_eligible=True,
392392
is_past_event=False,

alert_system/utils.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,26 @@
1111
logger = logging.getLogger(__name__)
1212

1313

14+
def get_latest_episode_load_item(load_item: LoadItem) -> LoadItem:
15+
"""
16+
Given a load_item, return the sibling LoadItem with the highest
17+
episode_number for the same parent_event_id.
18+
Falls back to the original load_item if no siblings exist.
19+
"""
20+
latest = LoadItem.objects.filter(parent_event_id=load_item.parent_event_id).order_by("-episode_number").first()
21+
return latest or load_item
22+
23+
1424
def get_alert_email_context(load_item: LoadItem, user: User):
1525

1626
country_names = []
1727

1828
if load_item.country_codes:
1929
country_names = list(Country.objects.filter(iso3__in=load_item.country_codes).values_list("name", flat=True))
30+
31+
# Fetch related_montandon_events from the latest episode
32+
latest_episode_item = get_latest_episode_load_item(load_item)
33+
2034
email_context = {
2135
"user_name": user.get_full_name(),
2236
"event_title": load_item.event_title,
@@ -26,7 +40,7 @@ def get_alert_email_context(load_item: LoadItem, user: User):
2640
"total_buildings_exposed": load_item.total_buildings_exposed,
2741
"hazard_types": load_item.connector.dtype,
2842
"related_go_events": load_item.related_go_events.all(),
29-
"related_montandon_events": load_item.related_montandon_events.filter(item_eligible=True).order_by(
43+
"related_montandon_events": latest_episode_item.related_montandon_events.filter(item_eligible=True).order_by(
3044
"-total_people_exposed"
3145
),
3246
"frontend_url": settings.GO_WEB_URL,

0 commit comments

Comments
 (0)