Route dossier, geocode, and Wikimedia through the backend (#351, #352, #360)

Proxy region dossier, Sentinel search, Wikipedia, and Wikidata via self-hosted
APIs; remove LocateBar client-side Nominatim fallback; migrate legacy shadow-
operator handles to operator- prefix.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
BigBodyCobain
2026-06-02 15:20:44 -06:00
co-authored by Cursor
parent c3dd95f6a9
commit f08781bdc9
9 changed files with 250 additions and 622 deletions
+7 -2
View File
@@ -146,7 +146,12 @@ def get_operator_handle() -> str:
# 3. On-disk handle from a previous run.
persisted = _load_persisted_operator_handle()
if persisted:
_OPERATOR_HANDLE_CACHE = _normalize_handle(persisted)
normalized = _normalize_handle(persisted)
# Migrate legacy auto-generated handles (pre-Round-7a ``shadow-`` prefix).
if normalized.startswith("shadow-"):
normalized = f"operator-{normalized[len('shadow-'):]}"
_persist_operator_handle(normalized)
_OPERATOR_HANDLE_CACHE = normalized
return _OPERATOR_HANDLE_CACHE
# 4. Generate, persist, return.
@@ -178,7 +183,7 @@ def outbound_user_agent(purpose: str = "") -> str:
Returns something like::
Shadowbroker/0.9 (operator: shadow-7f3a92; purpose: wikipedia;
Shadowbroker/0.9 (operator: operator-7f3a92; purpose: wikipedia;
+https://github.com/BigBodyCobain/Shadowbroker/issues)
The ``purpose`` is optional but recommended — it tells the upstream
+33
View File
@@ -301,3 +301,36 @@ def get_region_dossier(lat: float, lng: float) -> dict:
dossier_cache[cache_key] = result
return result
def fetch_wikipedia_page_summary(title: str) -> dict | None:
"""Wikipedia REST summary for a page title (backend-proxied for #360)."""
trimmed = (title or "").strip()
if not trimmed:
return None
data = _fetch_local_wiki_summary(trimmed, "")
if not data.get("extract") and not data.get("description"):
return None
return {
"title": trimmed,
"description": data.get("description", ""),
"extract": data.get("extract", ""),
"thumbnail": data.get("thumbnail", ""),
"type": "standard",
}
def fetch_wikidata_sparql_bindings(sparql: str) -> list:
"""Run a Wikidata SPARQL query; returns bindings list (empty on failure)."""
trimmed = (sparql or "").strip()
if not trimmed:
return []
url = f"https://query.wikidata.org/sparql?query={quote(trimmed)}&format=json"
try:
res = fetch_with_curl(url, timeout=8, headers=_wikimedia_request_headers())
if res.status_code == 200:
bindings = res.json().get("results", {}).get("bindings", [])
return bindings if isinstance(bindings, list) else []
except (ConnectionError, TimeoutError, ValueError, KeyError, OSError) as e:
logger.warning("Wikidata SPARQL failed: %s", e)
return []