"""Wersjonowanie zmian regulaminów i terminów (Warstwa 1).""" from __future__ import annotations import os from datetime import datetime, timezone from typing import Any, Dict, List, Optional from sqlalchemy.orm import Session from core.grants.models import GrantVersion, HumanVerificationItem TRACKED_FIELDS = ("deadline", "regulation_url", "precise_regulation_url", "status", "url", "official_page_url") VERIFICATION_FIELDS = frozenset({"deadline", "regulation_url", "precise_regulation_url", "status"}) def _norm(val: Any) -> str: if val is None: return "" return str(val).strip() def detect_field_changes( source_id: str, old_item: Dict[str, Any], new_item: Dict[str, Any], ) -> List[Dict[str, Any]]: changes: List[Dict[str, Any]] = [] for field in TRACKED_FIELDS: old_v = _norm(old_item.get(field)) new_v = _norm(new_item.get(field)) if old_v == new_v: continue if not old_v and not new_v: continue summary = _summarize_change(field, old_v, new_v) changes.append( { "grant_source_id": source_id, "field_name": field, "old_value": old_v, "new_value": new_v, "change_summary": summary, "requires_verification": field in VERIFICATION_FIELDS, } ) return changes def _summarize_change(field: str, old_v: str, new_v: str) -> str: labels = { "deadline": "Termin naboru", "regulation_url": "Regulamin", "precise_regulation_url": "Regulamin (precyzyjny)", "status": "Status", "url": "Strona programu", "official_page_url": "Oficjalna strona", } label = labels.get(field, field) if not old_v: return f"{label}: ustawiono → {new_v[:120]}" if not new_v: return f"{label}: usunięto (było: {old_v[:80]})" return f"{label}: {old_v[:60]} → {new_v[:60]}" def record_changes( db: Session, changes: List[Dict[str, Any]], *, source: str = "import", ) -> Dict[str, int]: """Zapisuje GrantVersion + opcjonalnie HumanVerificationQueue.""" if os.environ.get("HUMAN_VERIF_QUEUE", "true").lower() == "false": enqueue_hvq = False else: enqueue_hvq = True versions = 0 queued = 0 for ch in changes: db.add( GrantVersion( grant_source_id=ch["grant_source_id"], field_name=ch["field_name"], old_value=ch.get("old_value"), new_value=ch.get("new_value"), change_summary=ch.get("change_summary"), source=source, requires_verification=ch.get("requires_verification", False), ) ) versions += 1 if enqueue_hvq and ch.get("requires_verification"): db.add( HumanVerificationItem( grant_source_id=ch["grant_source_id"], change_type="field_update", field_name=ch["field_name"], old_value=ch.get("old_value"), new_value=ch.get("new_value"), summary=ch.get("change_summary"), priority=8 if ch["field_name"] == "deadline" else 6, ) ) queued += 1 return {"versions_recorded": versions, "verification_queued": queued} def get_recent_versions( db: Session, *, grant_source_id: Optional[str] = None, limit: int = 50, ) -> List[Dict[str, Any]]: q = db.query(GrantVersion).order_by(GrantVersion.detected_at.desc()) if grant_source_id: q = q.filter(GrantVersion.grant_source_id == grant_source_id) rows = q.limit(limit).all() return [ { "id": r.id, "grant_source_id": r.grant_source_id, "field_name": r.field_name, "old_value": r.old_value, "new_value": r.new_value, "change_summary": r.change_summary, "detected_at": r.detected_at.isoformat() if r.detected_at else None, "source": r.source, "requires_verification": r.requires_verification, } for r in rows ]