|
25 | 25 | from deployments.models import ERU, Personnel, PersonnelDeployment |
26 | 26 | from main.sentry import SentryMonitor |
27 | 27 | from notifications.hello import get_hello |
28 | | -from notifications.models import RecordType, Subscription, SubscriptionType, SurgeAlert |
| 28 | +from notifications.models import ( |
| 29 | + NotificationGUID, |
| 30 | + RecordType, |
| 31 | + Subscription, |
| 32 | + SubscriptionType, |
| 33 | + SurgeAlert, |
| 34 | +) |
29 | 35 | from notifications.notification import send_notification |
30 | 36 | from utils.elasticsearch import construct_es_data |
31 | 37 |
|
32 | | -time_5_minutes = timedelta(minutes=5) |
| 38 | +# avoid skipping new entities that were created during 2 consecutive runs, scheduled to every 5 minutes: |
| 39 | +time_9_minutes = timedelta(minutes=9) |
33 | 40 | time_1_day = timedelta(days=1) |
34 | 41 | time_1_week = timedelta(days=7) # for digest mode |
35 | 42 | digest_time = int(10314) # weekday - hour - min for digest timing (5 minutes once a week, Monday dawn) |
@@ -72,23 +79,23 @@ class Command(BaseCommand): |
72 | 79 |
|
73 | 80 | # Digest mode duration is 5 minutes once a week |
74 | 81 | def is_digest_mode(self): |
75 | | - today = datetime.utcnow().replace(tzinfo=timezone.utc) |
| 82 | + today = datetime.now(timezone.utc) |
76 | 83 | weekdayhourmin = int(today.strftime("%w%H%M")) |
77 | 84 | return digest_time <= weekdayhourmin and weekdayhourmin < digest_time + 5 |
78 | 85 |
|
79 | 86 | def is_daily_checkup_time(self): |
80 | | - today = datetime.utcnow().replace(tzinfo=timezone.utc) |
| 87 | + today = datetime.now(timezone.utc) |
81 | 88 | hourmin = int(today.strftime("%H%M")) |
82 | 89 | return daily_retro <= hourmin and hourmin < daily_retro + 5 |
83 | 90 |
|
84 | | - def diff_5_minutes(self): |
85 | | - return datetime.utcnow().replace(tzinfo=timezone.utc) - time_5_minutes |
| 91 | + def diff_9_minutes(self): |
| 92 | + return datetime.now(timezone.utc) - time_9_minutes |
86 | 93 |
|
87 | 94 | def diff_1_day(self): |
88 | | - return datetime.utcnow().replace(tzinfo=timezone.utc) - time_1_day |
| 95 | + return datetime.now(timezone.utc) - time_1_day |
89 | 96 |
|
90 | 97 | def diff_1_week(self): |
91 | | - return datetime.utcnow().replace(tzinfo=timezone.utc) - time_1_week |
| 98 | + return datetime.now(timezone.utc) - time_1_week |
92 | 99 |
|
93 | 100 | def gather_country_and_region(self, records): |
94 | 101 | # Appeals only, since these have a single country/region |
@@ -337,7 +344,7 @@ def get_record_display(self, rtype, count): |
337 | 344 | return display |
338 | 345 |
|
339 | 346 | def get_weekly_digest_data(self, field): |
340 | | - today = datetime.utcnow().replace(tzinfo=timezone.utc) |
| 347 | + today = datetime.now(timezone.utc) |
341 | 348 | if field == "dref": |
342 | 349 | return Appeal.objects.filter(end_date__gt=today, atype=0).count() |
343 | 350 | elif field == "ea": |
@@ -709,6 +716,11 @@ def construct_template_record(self, rtype, record): |
709 | 716 | } |
710 | 717 | return rec_obj |
711 | 718 |
|
| 719 | + def has_recent_notificationguid_entry(self, mailtypes, since): |
| 720 | + if not mailtypes: |
| 721 | + return False |
| 722 | + return NotificationGUID.objects.filter(created_at__gte=since, email_type__in=mailtypes).exists() |
| 723 | + |
712 | 724 | def notify(self, records, rtype, stype, uid=None): |
713 | 725 | record_count = 0 |
714 | 726 | if records: |
@@ -781,6 +793,21 @@ def notify(self, records, rtype, stype, uid=None): |
781 | 793 | if self.is_daily_checkup_time(): |
782 | 794 | subject += " [daily followup]" |
783 | 795 |
|
| 796 | + mailtype_prefixes = [f"{RTYPE_NAMES[rtype]} notification"] |
| 797 | + if uid is None and rtype == RecordType.FIELD_REPORT: |
| 798 | + mailtype_prefixes = [ |
| 799 | + f"{RTYPE_NAMES[rtype]} notification (non_ifrc)", |
| 800 | + f"{RTYPE_NAMES[rtype]} notification (ifrc)", |
| 801 | + ] |
| 802 | + |
| 803 | + mailtype_variants = [f"{prefix} - {subject}" for prefix in mailtype_prefixes] |
| 804 | + if record_count == 1 and rtype != RecordType.WEEKLY_DIGEST: |
| 805 | + mailtype_variants.extend([f"{prefix} - {subject}: {record_entries[0]['title']}" for prefix in mailtype_prefixes]) |
| 806 | + |
| 807 | + if self.has_recent_notificationguid_entry(mailtype_variants, self.diff_9_minutes()): |
| 808 | + logger.info("Skipping notification – already sent recently.") |
| 809 | + return |
| 810 | + |
784 | 811 | template_path = self.get_template() |
785 | 812 | if rtype == RecordType.FIELD_REPORT or rtype == RecordType.APPEAL or rtype == RecordType.WEEKLY_DIGEST: |
786 | 813 | template_path = self.get_template(rtype) |
@@ -995,7 +1022,7 @@ def handle(self, *args, **options): |
995 | 1022 | if self.is_digest_mode(): |
996 | 1023 | time_diff = self.diff_1_week() # in digest mode (once a week, for new_entities only) we use a bigger interval |
997 | 1024 | else: |
998 | | - time_diff = self.diff_5_minutes() |
| 1025 | + time_diff = self.diff_9_minutes() |
999 | 1026 | time_diff_1_day = self.diff_1_day() |
1000 | 1027 |
|
1001 | 1028 | cond1 = Q(created_at__gte=time_diff) |
|
0 commit comments