Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
40a3fe4
chore(index_and_notify): use exc_info and logger_context with logger.…
thenav56 Oct 8, 2025
cab1469
cached excluded doc and converted the serializer to one pass to reduc…
TKartist Jan 28, 2026
84d279b
cached excluded doc and converted the serializer to one pass to reduc…
TKartist Jan 28, 2026
cd09b2a
caching excluded codes to view object, one passing serializer instead…
TKartist Jan 29, 2026
f69da01
Reversing datatype to None when the sector is false
TKartist Feb 6, 2026
e6aa7d8
reversing datatype to NOne when the sector is false and adding back c…
TKartist Feb 6, 2026
4f396d1
chore(deps): bump cryptography from 44.0.1 to 46.0.5
dependabot[bot] Feb 11, 2026
bade208
Merge pull request #2655 from IFRCGo/dependabot/uv/cryptography-46.0.5
szabozoltan69 Feb 11, 2026
8971fe0
chore(deps): bump pyasn1 from 0.6.1 to 0.6.2
dependabot[bot] Feb 11, 2026
ca7d126
chore(deps): bump django from 4.2.26 to 4.2.28
dependabot[bot] Feb 11, 2026
d8b76d9
chore(deps): bump protobuf from 5.29.3 to 5.29.6
dependabot[bot] Feb 11, 2026
b07a4a6
chore(deps): bump pypdf from 5.3.0 to 6.6.2
dependabot[bot] Feb 11, 2026
1c79f44
chore(deps): bump azure-core from 1.32.0 to 1.38.0
dependabot[bot] Feb 11, 2026
204fc21
Crisis categorization history to appear on event Admin
szabozoltan69 Jan 24, 2026
2fd3f9f
CrisisCategorisationByCountry v1.0
szabozoltan69 Feb 11, 2026
abf2310
Merge pull request #2640 from IFRCGo/feature/crisis-categorization-on…
szabozoltan69 Feb 11, 2026
1224257
Merge pull request #2657 from IFRCGo/dependabot/uv/django-4.2.28
szabozoltan69 Feb 11, 2026
eed82cf
Merge pull request #2656 from IFRCGo/dependabot/uv/pyasn1-0.6.2
szabozoltan69 Feb 11, 2026
c15282a
Merge pull request #2658 from IFRCGo/dependabot/uv/protobuf-5.29.6
szabozoltan69 Feb 11, 2026
eaf4fe1
Merge pull request #2659 from IFRCGo/dependabot/uv/pypdf-6.6.2
szabozoltan69 Feb 11, 2026
9a55503
Merge pull request #2660 from IFRCGo/dependabot/uv/azure-core-1.38.0
szabozoltan69 Feb 11, 2026
e77fd25
chore(deps): bump h11 from 0.14.0 to 0.16.0
dependabot[bot] Feb 11, 2026
92327ac
chore(deps): bump setuptools from 75.8.0 to 78.1.1
dependabot[bot] Feb 11, 2026
aa20de5
chore(deps): bump jinja2 from 3.1.5 to 3.1.6
dependabot[bot] Feb 11, 2026
c022835
Merge pull request #2661 from IFRCGo/dependabot/uv/h11-0.16.0
szabozoltan69 Feb 11, 2026
41e54e3
Merge pull request #2663 from IFRCGo/dependabot/uv/jinja2-3.1.6
szabozoltan69 Feb 11, 2026
bc9ded8
Merge pull request #2662 from IFRCGo/dependabot/uv/setuptools-78.1.1
szabozoltan69 Feb 11, 2026
4eeedd3
Use admin1_pco instead of ADMIN01COD for admin1 data
szabozoltan69 Feb 11, 2026
0b9906a
Avoid error 500 when deleting a district
szabozoltan69 Feb 13, 2026
9646f11
refactor: setup tilesets manager
thenav56 Feb 10, 2026
d734356
chore: cleanup static mapbox recipe files
thenav56 Feb 12, 2026
79d3ffd
Merge pull request #2654 from IFRCGo/refac/update-mapbox-tileset
szabozoltan69 Feb 13, 2026
9e79340
Fix missing frontend_url in notifications
szabozoltan69 Feb 13, 2026
d533ac0
CrisisCategorisationByCountry v1.1
szabozoltan69 Feb 11, 2026
6298cf8
CrisisCategorisationByCountry v1.2
szabozoltan69 Feb 13, 2026
da9e5fb
Merge pull request #2664 from IFRCGo/feature/crisis-categorization-on…
szabozoltan69 Feb 13, 2026
cd3eace
chore(deps): bump sqlparse from 0.5.3 to 0.5.4
dependabot[bot] Feb 13, 2026
1df2a7d
Merge pull request #2667 from IFRCGo/dependabot/uv/sqlparse-0.5.4
szabozoltan69 Feb 14, 2026
ce44d7d
Security upgrades of some packages, e.g. celery and pillow
szabozoltan69 Feb 17, 2026
9fc1d4c
Chromatic redirection, only for Staging
szabozoltan69 Feb 18, 2026
8f96f6d
Ordering fix in Emergencies, missing PER api endpoint value fix
szabozoltan69 Feb 18, 2026
7b1556b
A fix to PerMapDataView
szabozoltan69 Feb 18, 2026
5cf53f1
Fix2 to PerMapDataView
szabozoltan69 Feb 19, 2026
bbfccae
Change an ssh pub key
szabozoltan69 Feb 19, 2026
bd4f570
Merge pull request #2644 from IFRCGo/feature/dref3-optimization
szabozoltan69 Feb 19, 2026
cda57b1
Fix urban_considerations and migration_considerations in PerMapDataView
szabozoltan69 Feb 19, 2026
525a093
chore(deps): bump pypdf from 6.6.2 to 6.7.1
dependabot[bot] Feb 19, 2026
4d47447
Merge pull request #2669 from IFRCGo/dependabot/uv/pypdf-6.7.1
szabozoltan69 Feb 20, 2026
833b3f5
Extend DREF3 permissions
szabozoltan69 Feb 20, 2026
102aaef
Send notification to Crisis Categorization Validator when needed in CC
szabozoltan69 Feb 24, 2026
f6cdddc
chore(translation): register new fields of dref for translation
susilnem Feb 18, 2026
fc99de2
chore(schema): generate schema for dref translation
susilnem Feb 18, 2026
ccbad6b
chore(deps): bump pypdf from 6.7.1 to 6.7.2
dependabot[bot] Feb 25, 2026
3d970ce
Merge pull request #2671 from IFRCGo/dependabot/uv/pypdf-6.7.2
szabozoltan69 Feb 25, 2026
e53c5df
fix(dref): remove title from triggering translation
susilnem Feb 26, 2026
32dffbe
Merge pull request #2668 from IFRCGo/project/dref-missing-translation
szabozoltan69 Feb 26, 2026
1260f44
Set temporary URL for appeal-related jobs
szabozoltan69 Feb 27, 2026
05cf629
Set new URL for appeal-related jobs
szabozoltan69 Feb 27, 2026
3ffba0d
Add a severity level tooltip
szabozoltan69 Feb 27, 2026
505d99f
CrisisCategorisationByCountry v1.3
szabozoltan69 Feb 27, 2026
39509b5
Apply sync_appealdocs to AppGW
szabozoltan69 Mar 2, 2026
e4573a1
Apply ingest_ns_contact, directory, document, country_plan_file to AppGW
szabozoltan69 Mar 3, 2026
9004c4f
fix(dref): add SourceInformation for trigger Translation
susilnem Mar 3, 2026
21e0655
chore(deps): bump pypdf from 6.7.2 to 6.7.5
dependabot[bot] Mar 3, 2026
65b7203
Merge pull request #2675 from IFRCGo/project/dref-translation-feedback
szabozoltan69 Mar 3, 2026
0127a48
Merge pull request #2676 from IFRCGo/dependabot/uv/pypdf-6.7.5
szabozoltan69 Mar 3, 2026
afeccde
Fix ingest_climate and ingest_hdr error handling
szabozoltan69 Mar 4, 2026
54eed1a
chore(deps): bump django from 4.2.28 to 4.2.29
dependabot[bot] Mar 4, 2026
164997f
Merge pull request #2678 from IFRCGo/dependabot/uv/django-4.2.29
szabozoltan69 Mar 5, 2026
6028d9e
Detect IP addresses of requests
szabozoltan69 Mar 5, 2026
311eb6e
Merge pull request #2679 from IFRCGo/feature/log-ips
szabozoltan69 Mar 5, 2026
f4383fd
Remove configuration-snippet rows from ingress.yaml
szabozoltan69 Mar 5, 2026
2df222d
feat: include client ip in gunicorn logs
thenav56 Mar 6, 2026
4c7431b
Revert "Detect IP addresses of requests"
thenav56 Mar 6, 2026
dd2d13a
Merge pull request #2680 from IFRCGo/feat/gunicorn-logging-include-ip
szabozoltan69 Mar 6, 2026
bf85d80
Apply ingest_appeals to AppGW
szabozoltan69 Mar 6, 2026
8f48db0
pref: fix N+1 issues for dref3 endpoint
thenav56 Mar 6, 2026
33c1a46
fix(dref3): update existing filter logics
thenav56 Mar 6, 2026
2849b7d
Merge pull request #2681 from IFRCGo/pref/dref3
szabozoltan69 Mar 6, 2026
482817a
Add created_at and updated_at to EventAdmin details
szabozoltan69 Mar 6, 2026
a960344
Search for GUID in Notification guids Admin
szabozoltan69 Mar 6, 2026
344b420
Fix ingest_appeals: date interval narrowing
szabozoltan69 Mar 6, 2026
197d328
Use select_related also for DREF3 optimisation
szabozoltan69 Mar 9, 2026
78647bf
Merge pull request #2683 from IFRCGo/performance/dref3
szabozoltan69 Mar 9, 2026
5d07b03
Avoid skipping notification-sending for new entities created in gap-time
szabozoltan69 Mar 10, 2026
ccc129a
chore(deps): bump pypdf from 6.7.5 to 6.8.0
dependabot[bot] Mar 11, 2026
cc7ce21
Fix sentry issue ifrc-go/issues/5159
szabozoltan69 Mar 11, 2026
6e6384e
Merge pull request #2686 from IFRCGo/dependabot/uv/pypdf-6.8.0
szabozoltan69 Mar 11, 2026
37890e1
Merge pull request #2566 from IFRCGo/fix/sentry-errors
szabozoltan69 Mar 11, 2026
a5419e0
chore(deps): bump pyjwt from 2.10.1 to 2.12.0
dependabot[bot] Mar 14, 2026
0e1e9e9
Merge pull request #2688 from IFRCGo/dependabot/uv/pyjwt-2.12.0
szabozoltan69 Mar 14, 2026
0c34a29
Add a new action to EventAdmin: create FR from Event
szabozoltan69 Feb 27, 2026
f6e3a2c
fix(export): add OLD_FINAL_REPORT in export type list
sudip-khanal Mar 11, 2026
83abf90
feat(dref): add validation to prevent updates for approved dref resou…
sudip-khanal Mar 13, 2026
6998d58
Merge pull request #2687 from IFRCGo/fix/old-dref-final-report-transl…
susilnem Mar 16, 2026
523ffc4
Use more form-specific css definitions for CrisisCategorisationByCountry
szabozoltan69 Mar 17, 2026
f607868
chore(deps): bump pyasn1 from 0.6.2 to 0.6.3
dependabot[bot] Mar 17, 2026
bd9d795
Merge pull request #2690 from IFRCGo/dependabot/uv/pyasn1-0.6.3
szabozoltan69 Mar 17, 2026
54bf79c
chore(deps): bump pypdf from 6.8.0 to 6.9.1
dependabot[bot] Mar 18, 2026
ae55ba9
fix(lang): translation duplicate creationg issue
susilnem Mar 19, 2026
487fccc
Merge pull request #2694 from IFRCGo/fix/dref-activities-translation
szabozoltan69 Mar 19, 2026
6ddad0f
feat(dref): make proposed actions activities partially required
frozenhelium Mar 23, 2026
2d21f7e
Merge pull request #2695 from IFRCGo/feat/update-dref-proposed-actions
szabozoltan69 Mar 23, 2026
43fbce9
Merge pull request #2693 from IFRCGo/dependabot/uv/pypdf-6.9.1
szabozoltan69 Mar 23, 2026
4e4e741
Merge pull request #2672 from IFRCGo/feature/event-to-fr-action
szabozoltan69 Mar 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
768 changes: 763 additions & 5 deletions api/admin.py

Large diffs are not rendered by default.

1,637 changes: 953 additions & 684 deletions api/locale/ar/LC_MESSAGES/django.po

Large diffs are not rendered by default.

1,629 changes: 949 additions & 680 deletions api/locale/en/LC_MESSAGES/django.po

Large diffs are not rendered by default.

1,629 changes: 949 additions & 680 deletions api/locale/es/LC_MESSAGES/django.po

Large diffs are not rendered by default.

1,629 changes: 949 additions & 680 deletions api/locale/fr/LC_MESSAGES/django.po

Large diffs are not rendered by default.

554 changes: 554 additions & 0 deletions api/management/commands/acc.py

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions api/management/commands/import-admin1-data.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def handle(self, *args, **options):

# loop through each feature in the shapefile
for feature in data[0]:
code = feature.get("ADMIN01COD")
code = feature.get("admin1_pco")
name = feature.get("ADMIN01NAM")

geom_wkt = feature.geom.wkt
Expand Down Expand Up @@ -142,7 +142,7 @@ def handle(self, *args, **options):
print("done!")

def add_district(self, options, import_missing, feature, geom, centroid, bbox):
code = feature.get("ADMIN01COD") or "N.A"
code = feature.get("admin1_pco") or "N.A"
name = feature.get("ADMIN01NAM")
district = District()
district.code = code
Expand Down
91 changes: 63 additions & 28 deletions api/management/commands/index_and_notify.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,20 @@
)
from deployments.models import ERU, Personnel, PersonnelDeployment
from main.sentry import SentryMonitor
from main.utils import logger_context
from notifications.hello import get_hello
from notifications.models import RecordType, Subscription, SubscriptionType, SurgeAlert
from notifications.models import (
NotificationGUID,
RecordType,
Subscription,
SubscriptionType,
SurgeAlert,
)
from notifications.notification import send_notification
from utils.elasticsearch import construct_es_data

time_5_minutes = timedelta(minutes=5)
# avoid skipping new entities that were created during 2 consecutive runs, scheduled to every 5 minutes:
time_9_minutes = timedelta(minutes=9)
time_1_day = timedelta(days=1)
time_1_week = timedelta(days=7) # for digest mode
digest_time = int(10314) # weekday - hour - min for digest timing (5 minutes once a week, Monday dawn)
Expand Down Expand Up @@ -72,23 +80,23 @@ class Command(BaseCommand):

# Digest mode duration is 5 minutes once a week
def is_digest_mode(self):
today = datetime.utcnow().replace(tzinfo=timezone.utc)
today = datetime.now(timezone.utc)
weekdayhourmin = int(today.strftime("%w%H%M"))
return digest_time <= weekdayhourmin and weekdayhourmin < digest_time + 5

def is_daily_checkup_time(self):
today = datetime.utcnow().replace(tzinfo=timezone.utc)
today = datetime.now(timezone.utc)
hourmin = int(today.strftime("%H%M"))
return daily_retro <= hourmin and hourmin < daily_retro + 5

def diff_5_minutes(self):
return datetime.utcnow().replace(tzinfo=timezone.utc) - time_5_minutes
def diff_9_minutes(self):
return datetime.now(timezone.utc) - time_9_minutes

def diff_1_day(self):
return datetime.utcnow().replace(tzinfo=timezone.utc) - time_1_day
return datetime.now(timezone.utc) - time_1_day

def diff_1_week(self):
return datetime.utcnow().replace(tzinfo=timezone.utc) - time_1_week
return datetime.now(timezone.utc) - time_1_week

def gather_country_and_region(self, records):
# Appeals only, since these have a single country/region
Expand Down Expand Up @@ -121,7 +129,7 @@ def gather_event_countries_and_regions(self, records):
# many-to-many relationship to countries and regions through event table
countries = []
for record in records:
if record.event.countries is not None:
if record.event is not None and record.event.countries is not None:
countries += [country.id for country in record.event.countries.all()]
countries = list(set(countries))
qs = Country.objects.filter(pk__in=countries)
Expand Down Expand Up @@ -231,24 +239,24 @@ def get_template(self, rtype=99):
# Get the front-end url of the resource
def get_resource_uri(self, record, rtype):
# Determine the front-end URL
resource_uri = settings.FRONTEND_URL
resource_uri = settings.GO_WEB_URL
if (
rtype == RecordType.SURGE_ALERT or rtype == RecordType.FIELD_REPORT
): # Pointing to event instead of field report %s/%s/%s - Munu asked - ¤
belonging_event = (
record.event.id if record.event is not None else 57
) # Very rare – giving a non-existent | manually created surge – no event
resource_uri = "%s/emergencies/%s" % (settings.FRONTEND_URL, belonging_event)
resource_uri = "%s/emergencies/%s" % (settings.GO_WEB_URL, belonging_event)
elif rtype == RecordType.SURGE_DEPLOYMENT_MESSAGES:
resource_uri = "%s/%s" % (settings.FRONTEND_URL, "surge/overview") # could be further sophisticated:
resource_uri = "%s/%s" % (settings.GO_WEB_URL, "surge/overview") # could be further sophisticated:
# e.g. emergencies/6700/surge, where 6700 is the related emergency ID
elif rtype == RecordType.APPEAL and (record.event is not None and not record.needs_confirmation):
# Appeals with confirmed emergencies link to that emergency
resource_uri = "%s/emergencies/%s" % (settings.FRONTEND_URL, record.event.id)
resource_uri = "%s/emergencies/%s" % (settings.GO_WEB_URL, record.event.id)
elif rtype != RecordType.APPEAL:
# One-by-one followed or globally subscribed emergencies
resource_uri = "%s/%s/%s" % (
settings.FRONTEND_URL,
settings.GO_WEB_URL,
# this else never occurs, see ¤
"emergencies" if rtype == RecordType.EVENT or rtype == RecordType.FOLLOWED_EVENT else "field-reports",
record.id,
Expand Down Expand Up @@ -337,7 +345,7 @@ def get_record_display(self, rtype, count):
return display

def get_weekly_digest_data(self, field):
today = datetime.utcnow().replace(tzinfo=timezone.utc)
today = datetime.now(timezone.utc)
if field == "dref":
return Appeal.objects.filter(end_date__gt=today, atype=0).count()
elif field == "ea":
Expand Down Expand Up @@ -394,8 +402,8 @@ def get_weekly_digest_latest_deployments(self):
# 'type': 'Alert',
# 'operation': alert.operation,
# 'event_url': (
# '{}/emergencies/{}'.format(settings.FRONTEND_URL, event.id) if event else
# settings.FRONTEND_URL,
# '{}/emergencies/{}'.format(settings.GO_WEB_URL, event.id) if event else
# settings.GO_WEB_URL,
# ),
# 'society_from': '',
# 'deployed_to': '',
Expand All @@ -413,7 +421,7 @@ def get_weekly_digest_latest_deployments(self):
country_from = Country.objects.get(id=pers.country_from_id) if pers.country_from_id is not None else None
dep_to_add = {
"operation": event.name if event else "",
"event_url": ("{}/emergencies/{}".format(settings.FRONTEND_URL, event.id) if event else settings.FRONTEND_URL),
"event_url": ("{}/emergencies/{}".format(settings.GO_WEB_URL, event.id) if event else settings.GO_WEB_URL),
"society_from": country_from.society_name if country_from else "",
"name": pers.name,
"role": pers.role,
Expand Down Expand Up @@ -655,10 +663,10 @@ def construct_template_record(self, rtype, record):
volunteers += int(f.num_volunteers or 0)
delegates += int(f.num_expats_delegates or 0)
resource_uri, follow_url = self.get_resource_uri(record, rtype), None
if resource_uri != settings.FRONTEND_URL:
if resource_uri != settings.GO_WEB_URL:
follow_url = resource_uri + "/follow"
rec_obj = {
"frontend_url": settings.FRONTEND_URL,
"frontend_url": settings.GO_WEB_URL,
"resource_uri": resource_uri,
"follow_url": follow_url,
"admin_uri": self.get_admin_uri(record, rtype),
Expand All @@ -682,7 +690,7 @@ def construct_template_record(self, rtype, record):
}
elif rtype == RecordType.WEEKLY_DIGEST:
rec_obj = {
"resource_uri": settings.FRONTEND_URL,
"resource_uri": settings.GO_WEB_URL,
"active_dref": self.get_weekly_digest_data("dref"),
"active_ea": self.get_weekly_digest_data("ea"),
"funding_coverage": self.get_weekly_digest_data("fund"),
Expand All @@ -709,6 +717,11 @@ def construct_template_record(self, rtype, record):
}
return rec_obj

def has_recent_notificationguid_entry(self, mailtypes, since):
if not mailtypes:
return False
return NotificationGUID.objects.filter(created_at__gte=since, email_type__in=mailtypes).exists()

def notify(self, records, rtype, stype, uid=None):
record_count = 0
if records:
Expand Down Expand Up @@ -781,6 +794,21 @@ def notify(self, records, rtype, stype, uid=None):
if self.is_daily_checkup_time():
subject += " [daily followup]"

mailtype_prefixes = [f"{RTYPE_NAMES[rtype]} notification"]
if uid is None and rtype == RecordType.FIELD_REPORT:
mailtype_prefixes = [
f"{RTYPE_NAMES[rtype]} notification (non_ifrc)",
f"{RTYPE_NAMES[rtype]} notification (ifrc)",
]

mailtype_variants = [f"{prefix} - {subject}" for prefix in mailtype_prefixes]
if record_count == 1 and rtype != RecordType.WEEKLY_DIGEST:
mailtype_variants.extend([f"{prefix} - {subject}: {record_entries[0]['title']}" for prefix in mailtype_prefixes])

if self.has_recent_notificationguid_entry(mailtype_variants, self.diff_9_minutes()):
logger.info("Skipping notification – already sent recently.")
return

template_path = self.get_template()
if rtype == RecordType.FIELD_REPORT or rtype == RecordType.APPEAL or rtype == RecordType.WEEKLY_DIGEST:
template_path = self.get_template(rtype)
Expand All @@ -794,6 +822,7 @@ def notify(self, records, rtype, stype, uid=None):
"is_staff": True if uid is None else is_staff, # TODO: fork the sending to "is_staff / not ~" groups
"subject": subject,
"hide_preferences": False,
"frontend_url": settings.GO_WEB_URL,
},
)
recipients = emails
Expand Down Expand Up @@ -830,6 +859,7 @@ def notify(self, records, rtype, stype, uid=None):
"is_staff": True if uid is None else is_staff,
"subject": subject,
"hide_preferences": False,
"frontend_url": settings.GO_WEB_URL,
},
)
send_notification(
Expand Down Expand Up @@ -864,6 +894,7 @@ def notify(self, records, rtype, stype, uid=None):
"is_staff": True if uid is None else is_staff,
"subject": subject,
"hide_preferences": False,
"frontend_url": settings.GO_WEB_URL,
},
)

Expand Down Expand Up @@ -933,12 +964,16 @@ def index_records(self, records, to_create=True):
def bulk(self, actions):
try:
created, errors = bulk(client=ES_CLIENT, actions=actions)
if len(errors):
logger.error("Produced the following errors:")
logger.error("[%s]" % ", ".join(map(str, errors)))
except Exception as e:
logger.error("Could not index records")
logger.error("%s..." % str(e)[:512])
if errors:
logger.error(
"(index_and_notify:bulk): produced errors:",
extra=logger_context(dict(errors=errors)),
)
except Exception:
logger.error(
"(index_and_notify:bulk): could not index records",
exc_info=True,
)

# Remove items in a queryset where updated_at == created_at.
# This leaves us with only ones that have been modified.
Expand Down Expand Up @@ -992,7 +1027,7 @@ def handle(self, *args, **options):
if self.is_digest_mode():
time_diff = self.diff_1_week() # in digest mode (once a week, for new_entities only) we use a bigger interval
else:
time_diff = self.diff_5_minutes()
time_diff = self.diff_9_minutes()
time_diff_1_day = self.diff_1_day()

cond1 = Q(created_at__gte=time_diff)
Expand Down
24 changes: 15 additions & 9 deletions api/management/commands/ingest_appeals.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,26 +99,28 @@ def get_new_or_modified_appeals(self):
else:
# get latest BILATERALS
logger.info("Querying appeals API for new appeals data (bilateral)")
url = "http://go-api.ifrc.org/api/appealbilaterals"
url = "https://go-api.ifrc.org/api/appealbilaterals"
auth = (settings.APPEALS_USER, settings.APPEALS_PASS)

adapter = HTTPAdapter(max_retries=settings.RETRY_STRATEGY)
sess = Session()
sess.mount("http://", adapter)
sess.mount("https://", adapter)
# IFRC App Gateway doesn't like python-requests/2... as User-Agent.
headers = {"User-Agent": "go-requests/2.32.4"}

# try 3 times to reach the API
try:
response = sess.get(url, auth=auth)
response = sess.get(url, auth=auth, headers=headers) # Bilaterals API doesn't need narrowing by date
except reqexc.HTTPError as ex:
log_text = f"Error querying AppealBilaterals API: {ex}"
logger.error(log_text)
create_cron_record(CRON_NAME, log_text, CronJobStatus.ERRONEOUS)
return
return None, None, None
except Exception as ex:
log_text = f"Error querying AppealBilaterals API at {url}: {str(ex)}"
logger.error(log_text)
create_cron_record(CRON_NAME, log_text, CronJobStatus.ERRONEOUS)
return
return None, None, None
records = response.json()
bilaterals = self.create_bilaterals_dict(records)

Expand All @@ -128,20 +130,21 @@ def get_new_or_modified_appeals(self):

# get latest APPEALS
logger.info("Querying appeals API for new appeals data")
url = "http://go-api.ifrc.org/api/appeals" # DEBUG: can append filter ?app_code=MDRDJ003
url = "https://go-api.ifrc.org/api/appeals" # DEBUG: can append filter &app_code=MDRDJ003
params = {"App_startDate": "2020-01-01|2100-01-01"}
# try 3 times to reach the API
try:
response = sess.get(url, auth=auth)
response = sess.get(url, auth=auth, headers=headers, params=params)
except reqexc.HTTPError as ex:
log_text = f"Error querying Appeals API: {ex}"
logger.error(log_text)
create_cron_record(CRON_NAME, log_text, CronJobStatus.ERRONEOUS)
return
return None, None, None
except Exception as ex:
log_text = f"Error querying Appeals API at {url}: {str(ex)}"
logger.error(log_text)
create_cron_record(CRON_NAME, log_text, CronJobStatus.ERRONEOUS)
return
return None, None, None

records = response.json()

Expand Down Expand Up @@ -300,6 +303,9 @@ def handle(self, *args, **options):
except Exception as ex:
logger.error(f"Getting Appeals and AppealBilaterals failed: {str(ex)}")
return
if new is None or modified is None or bilaterals is None:
logger.error("Appeals ingest aborted due to upstream API errors.")
return
logger.info(f"{start_appeals_count} current appeals")
logger.info(f"Creating {len(new)} new appeals")
logger.info(f"Updating {len(modified)} existing appeals that MIGHT have been modified")
Expand Down
3 changes: 2 additions & 1 deletion api/management/commands/ingest_ns_contact.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class Command(BaseCommand):
def handle(self, *args, **kwargs):
logger.info("Starting NS Contacts")
url = "https://go-api.ifrc.org/"
headers = {"accept": "application/xml;q=0.9, */*;q=0.8"}
# IFRC App Gateway doesn't like python-requests/2... as User-Agent, so let's fix it via the first one:
headers = {"User-Agent": "go-requests/2.32.4", "accept": "application/xml;q=0.9, */*;q=0.8"}
response = requests.get(
"https://go-api.ifrc.org/api/NationalSocieties",
auth=HTTPBasicAuth(settings.NS_CONTACT_USERNAME, settings.NS_CONTACT_PASSWORD),
Expand Down
3 changes: 2 additions & 1 deletion api/management/commands/ingest_ns_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def postprocessor(path, key, value):

logger.info("Starting NS Contacts")
url = "https://go-api.ifrc.org/"
headers = {"accept": "application/xml;q=0.9, */*;q=0.8"}
# IFRC App Gateway doesn't like python-requests/2... as User-Agent, so let's fix it via the first one:
headers = {"User-Agent": "go-requests/2.32.4", "accept": "application/xml;q=0.9, */*;q=0.8"}
response = requests.get(
"https://go-api.ifrc.org/api/NationalSocietiesContacts/",
auth=HTTPBasicAuth(settings.NS_CONTACT_USERNAME, settings.NS_CONTACT_PASSWORD),
Expand Down
3 changes: 2 additions & 1 deletion api/management/commands/ingest_ns_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ def handle(self, *args, **kwargs):

# Fetch country codes
country_code_url = "https://go-api.ifrc.org/api/NationalSocietiesContacts/"
headers = {"Authorization": f"Basic {settings.NS_INITIATIVES_API_TOKEN}"}
# IFRC App Gateway doesn't like python-requests/2... as User-Agent, so let's fix it via the first one:
headers = {"User-Agent": "go-requests/2.32.4", "Authorization": f"Basic {settings.NS_INITIATIVES_API_TOKEN}"}
country_code_response = requests.get(url=country_code_url, headers=headers)

if country_code_response.status_code != 200:
Expand Down
5 changes: 3 additions & 2 deletions api/management/commands/sync_appealdocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def handle(self, *args, **options):
print("Doing a full scan of all Appeals")
qset = Appeal.objects.all()
else:
# By default, only check appeals for the past 3 months where Appeal Documents is 0
# By default, only check appeals for the past 6 months where Appeal Documents is 0
now = datetime.now().replace(tzinfo=timezone.utc)
six_months_ago = now - relativedelta(months=6)
# This was the original qset, but it wouldn't get newer docs for the same Appeals
Expand All @@ -59,7 +59,8 @@ def handle(self, *args, **options):
# First get all Appeal Codes
appeal_codes = [a.code for a in qset]
auth = (settings.APPEALS_USER, settings.APPEALS_PASS)
headers = {"Accept": "application/json"}
# IFRC App Gateway doesn't like python-requests/2... as User-Agent, so let's fix it via the first one:
headers = {"User-Agent": "go-requests/2.32.4", "Accept": "application/json"}
existing = []
created = []

Expand Down
Loading
Loading