From 628a4f1435c59f2b2527ab8b05b98a4334658c2b Mon Sep 17 00:00:00 2001 From: Codex Agent Date: Fri, 24 Oct 2025 09:05:21 +0800 Subject: [PATCH] Revert "Revert "feat: surface permit metadata in v2 results"" This reverts commit 33bbbb7d8c58194d16a916d6a9cb3a18fbf4b2e9. --- licensing_repo.py | 91 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 9 deletions(-) diff --git a/licensing_repo.py b/licensing_repo.py index ff2a6d5..aab3a01 100644 --- a/licensing_repo.py +++ b/licensing_repo.py @@ -1,7 +1,7 @@ from __future__ import annotations import os -from typing import Dict, List +from typing import Dict, List, Optional, Set import pg8000.dbapi as pg @@ -104,6 +104,13 @@ def _load_permit_scopes_for_region( return scope_map +def _clean_text(value: Optional[str]) -> Optional[str]: + if value is None: + return None + txt = str(value).strip() + return txt or None + + def load_permits_and_risks(region_id: str, theme_id: str) -> List[Dict[str, object]]: """Return permits with attached risk entries for a region-theme pair.""" sql = """ @@ -114,9 +121,21 @@ def load_permits_and_risks(region_id: str, theme_id: str) -> List[Dict[str, obje rk.risk_content, rk.legal_basis, rk.document_no, - rk.summary + rk.summary, + rpd.permit_status, + rpd.subitem_summary, + rpd.responsible_contact, + rpd.jurisdiction_scope, + psi.description AS subitem_desc FROM region_theme_permits rtp JOIN permits p ON p.id = rtp.permit_id + LEFT JOIN region_permit_details rpd + ON rpd.region_id = rtp.region_id + AND rpd.permit_id = rtp.permit_id + LEFT JOIN region_permit_subitems rpsi + ON rpsi.region_id = rtp.region_id + AND rpsi.permit_id = rtp.permit_id + LEFT JOIN permit_subitems psi ON psi.id = rpsi.subitem_id LEFT JOIN region_permit_risks rpr ON rpr.region_id = rtp.region_id AND rpr.permit_id = rtp.permit_id @@ -129,7 +148,20 @@ def load_permits_and_risks(region_id: str, theme_id: str) -> List[Dict[str, obje cur = conn.cursor() cur.execute(sql, (region_id, theme_id)) for row in cur.fetchall(): - permit_id, permit_name, risk_id, risk_content, legal_basis, document_no, summary = row + ( + permit_id, + permit_name, + risk_id, + risk_content, + legal_basis, + document_no, + summary, + permit_status, + subitem_summary, + responsible_contact, + jurisdiction_scope, + subitem_desc, + ) = row pid = str(permit_id) entry = permits.setdefault( pid, @@ -138,23 +170,64 @@ def load_permits_and_risks(region_id: str, theme_id: str) -> List[Dict[str, obje "name": str(permit_name), "business_scopes": [], "risks": [], + "scopes": [], + "risk_count": 0, + "permit_status": None, + "subitem_summary": None, + "subitems": [], + "responsible_contact": None, + "jurisdiction_scope": None, + "_risk_ids": set(), + "_subitems": set(), }, ) + if permit_status is not None: + entry["permit_status"] = _clean_text(permit_status) + if subitem_summary is not None: + entry["subitem_summary"] = _clean_text(subitem_summary) + if responsible_contact is not None: + entry["responsible_contact"] = _clean_text(responsible_contact) + if jurisdiction_scope is not None: + entry["jurisdiction_scope"] = _clean_text(jurisdiction_scope) + if subitem_desc: + cleaned = _clean_text(subitem_desc) + if cleaned: + entry["_subitems"].add(cleaned) if risk_id is not None: + rid = str(risk_id) + risk_ids: Set[str] = entry["_risk_ids"] + if rid in risk_ids: + continue + risk_ids.add(rid) entry["risks"].append( { - "id": str(risk_id), - "risk_content": risk_content or "", - "legal_basis": legal_basis or "", - "document_no": document_no or "", - "summary": summary or "", + "id": rid, + "risk_content": _clean_text(risk_content) or "", + "legal_basis": _clean_text(legal_basis) or "", + "document_no": _clean_text(document_no) or "", + "summary": _clean_text(summary) or "", } ) permit_ids = list(permits.keys()) scope_map = _load_permit_scopes_for_region(conn, region_id, permit_ids) for pid in permit_ids: - permits[pid]["business_scopes"] = scope_map.get(pid, []) + entry = permits[pid] + entry["business_scopes"] = scope_map.get(pid, []) + entry["scopes"] = [ + scope.get("description", "") + for scope in entry["business_scopes"] + if scope.get("description") + ] + subitems_set: Set[str] = entry.pop("_subitems", set()) + entry["subitems"] = sorted(subitems_set) + risk_ids: Set[str] = entry.pop("_risk_ids", set()) + entry["risk_count"] = len(risk_ids) + # Ensure optional text fields default to None if empty strings slipped through + entry["permit_status"] = _clean_text(entry.get("permit_status")) + entry["subitem_summary"] = _clean_text(entry.get("subitem_summary")) + entry["responsible_contact"] = _clean_text(entry.get("responsible_contact")) + entry["jurisdiction_scope"] = _clean_text(entry.get("jurisdiction_scope")) return list(permits.values())