Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions dashboard/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -817,11 +817,11 @@ function openDrawer(id) { const i = STATE.digest.incidents.find((x) => x.incide
<h4 class="drawer__subhead">Original source records (${i.source_links.length})</h4>
<ul class="src-links">
${i.source_links.map((L) => `
<li><a class="src-link" href="${esc(L.url)}" target="_blank" rel="noopener">
<li>${L.url ? `<a class="src-link" href="${esc(L.url)}" target="_blank" rel="noopener">` : `<span class="src-link src-link--no-url" aria-disabled="true">`}
<span class="src-link__type src-link__type--${L.type}">${L.type}</span>
<span class="src-link__label">${esc(L.label)}${L.meta ? ` <em>${esc(L.meta)}</em>` : ""}</span>
<span class="src-link__arrow" aria-hidden="true"></span>
</a></li>`).join("")}
<span class="src-link__arrow" aria-hidden="true">${L.url ? "↗" : "⊘"}</span>
${L.url ? `</a>` : `</span>`}</li>`).join("")}
</ul>` : `<p class="muted">No deep links available for this incident.</p>`}
</div>
${(i.logs && i.logs.length) ? `<div class="drawer__section"><h3>Timeline · ${i.logs.length} log(s)</h3>
Expand Down
37 changes: 36 additions & 1 deletion scripts/generate_dashboard_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,41 @@ def _resolve_region(name: str, latest_summary: str | None, is_disease: bool) ->
return "Global" if is_disease else "Unknown"


_GDACS_EVENTTYPE_CODES = {
"Tropical Cyclone": "TC",
"Earthquake": "EQ",
"Flood": "FL",
"Forest Fire": "WF",
"Drought": "DR",
"Tsunami": "TS",
"Volcano": "VO",
}


def _resolve_gdacs_link(
raw_fields: dict[str, object],
source_id: str,
incident_type: str,
) -> str:
link = raw_fields.get("link", "")
if link:
return str(link)
url = raw_fields.get("url")
if isinstance(url, dict):
report = url.get("report", "")
if report:
return str(report)
eventid = str(raw_fields.get("eventid") or source_id or "")
episodeid = str(raw_fields.get("episodeid") or "")
eventtype = _GDACS_EVENTTYPE_CODES.get(incident_type, "")
if eventid and episodeid and eventtype:
return (
f"https://www.gdacs.org/report.aspx?eventid={eventid}"
f"&episodeid={episodeid}&eventtype={eventtype}"
)
return ""


def build_incident_object(store: ContentStore, inc: dict, as_of_date: datetime) -> dict | None:
incident_id = inc["incident_id"]
reports = load_reports_for_incident(store, incident_id)
Expand Down Expand Up @@ -491,7 +526,7 @@ def build_incident_object(store: ContentStore, inc: dict, as_of_date: datetime)
source_links.append({
"type": "GDACS",
"label": f"{alert_label} · {rf.get('severitytext', r['name'])}" if alert_label else r["name"],
"url": rf.get("link", ""),
"url": _resolve_gdacs_link(rf, r["source_id"], r["incident_type"]),
"meta": " · ".join(meta_parts) if meta_parts else "",
})
elif r["source"] == "WHO":
Expand Down
27 changes: 26 additions & 1 deletion tests/integration/generate_dashboard_data_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from datetime import datetime, timezone

from scripts.generate_dashboard_data import _resolve_region, generate_md_report
from scripts.generate_dashboard_data import _resolve_gdacs_link, _resolve_region, generate_md_report


class TestResolveRegion:
Expand All @@ -24,6 +24,31 @@ def test_disease_with_country_in_summary_returns_that_region(self) -> None:
assert _resolve_region("Disease Japan 2025-01-01", summary, True) == "Asia"


class TestResolveGdacsLink:
def test_link_field_used_directly_when_present(self) -> None:
rf: dict[str, object] = {"link": "https://www.gdacs.org/report.aspx?eventid=1&episodeid=2&eventtype=EQ"}
assert _resolve_gdacs_link(rf, "1", "Earthquake") == rf["link"]

def test_url_dict_report_subkey_used_when_no_link(self) -> None:
rf: dict[str, object] = {"url": {"report": "https://www.gdacs.org/report.aspx?eventid=2&episodeid=3&eventtype=WF"}}
assert _resolve_gdacs_link(rf, "2", "Forest Fire") == "https://www.gdacs.org/report.aspx?eventid=2&episodeid=3&eventtype=WF"

def test_constructed_from_source_id_and_episodeid_for_degenerate_drought(self) -> None:
rf: dict[str, object] = {"alertlevel": "Green", "severity": "Minor", "population": 0, "episodeid": "14"}
url = _resolve_gdacs_link(rf, "1018332", "Drought")
assert url == "https://www.gdacs.org/report.aspx?eventid=1018332&episodeid=14&eventtype=DR"

def test_eventid_in_raw_fields_preferred_over_source_id(self) -> None:
rf: dict[str, object] = {"eventid": "999", "episodeid": "5", "eventtype": "FL"}
url = _resolve_gdacs_link(rf, "ignored", "Flood")
assert "eventid=999" in url
assert "episodeid=5" in url

def test_returns_empty_when_nothing_reconstructable(self) -> None:
rf: dict[str, object] = {}
assert _resolve_gdacs_link(rf, "", "Drought") == ""


def _make_incident(
incident_id: str = "x",
name: str = "Earthquake M7.5 Yumare, Venezuela 2026-06-24",
Expand Down
8 changes: 8 additions & 0 deletions tests/integration/generate_dashboard_data_test.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ class TestResolveRegion:
def test_disease_with_country_in_summary_returns_that_region(self) -> None: ...


class TestResolveGdacsLink:
def test_link_field_used_directly_when_present(self) -> None: ...
def test_url_dict_report_subkey_used_when_no_link(self) -> None: ...
def test_constructed_from_source_id_and_episodeid_for_degenerate_drought(self) -> None: ...
def test_eventid_in_raw_fields_preferred_over_source_id(self) -> None: ...
def test_returns_empty_when_nothing_reconstructable(self) -> None: ...


class TestGenerateMdReportDayPrimary:
def test_day_primary_shows_3_most_recent_days(self) -> None: ...
def test_each_incident_shows_only_that_day_log(self) -> None: ...
Expand Down
Loading