PDF link target=_blank + nginx timeouts + priority filteri (samo s podacima)
nginx (sport.rinet.one): - proxy_read_timeout 60s → 300s - proxy_send_timeout 300s - proxy_buffering off (PDF stream) - client_max_body_size 50M → 100M Endpoints: - /api/v2/klubovi/financirani: +with_data filter (samo s potporama/godišnjakom/HNS) - /api/v2/sportasi/filtered: +samo_priority +samo_s_hns Frontend: - PDF link target=_blank rel=noopener - window._klub_only_priority = true (default) - window._sportas_only_priority = true (default) DB View: - pgz_sport.v_nogomet_priority (prima_potpore, u_godisnjaku, ima_hns_roster)
This commit is contained in:
@@ -2242,6 +2242,104 @@ def list_dokumenti(razina: Optional[str] = None, vrsta: Optional[str] = None,
|
||||
rows = db_query(sql, params)
|
||||
return {"count": len(rows), "results": rows}
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────
|
||||
# Unified dokumenti library — Agent G (2026-05-05)
|
||||
# dradulic@outlook.com / damir@rinet.one
|
||||
# Maps free-form vrsta + organizacija into a normalized (tip, izdavatelj)
|
||||
# pair so the frontend can offer a single "Svi dokumenti" tab with two
|
||||
# canonical dropdowns. No DB changes — pure SQL CASE expressions.
|
||||
# ─────────────────────────────────────────────────────────────────────
|
||||
_TIP_CASE_SQL = """
|
||||
CASE
|
||||
WHEN vrsta = 'godisnjak' OR vrsta = 'sportski-godisnjak' THEN 'godisnjak'
|
||||
WHEN vrsta = 'manifestacija' OR vrsta ILIKE '%%natjec%%' THEN 'natjecaj'
|
||||
WHEN vrsta IN ('pravilnik','pravilnik_savez','statut','odluka','zakon','zakon_dopuna') THEN 'pravilnik'
|
||||
WHEN vrsta IN ('publikacija','periodika','povijest','program','plan','strategija','raspodjela','erasmus') THEN 'publikacija'
|
||||
WHEN COALESCE(title,'') ILIKE '%%javni poziv%%' OR COALESCE(title,'') ILIKE '%%natje%%aj%%' THEN 'javni-poziv'
|
||||
ELSE 'ostalo'
|
||||
END
|
||||
"""
|
||||
|
||||
_IZDAVATELJ_CASE_SQL = """
|
||||
CASE
|
||||
WHEN organizacija ILIKE '%%RSS%%' OR organizacija ILIKE '%%Riječki sportski savez%%' OR url ILIKE '%%rss.hr%%' THEN 'RSS'
|
||||
WHEN organizacija ILIKE '%%Hrvatski olimpijski%%' OR organizacija = 'HOO' OR organizacija ILIKE '%%MTIS/HOO%%' OR url ILIKE '%%hoo.hr%%' OR url ILIKE '%%media-hoo%%' OR vrsta = 'hoo' THEN 'HOO'
|
||||
WHEN organizacija ILIKE '%%Zajednica%%PGŽ%%' OR organizacija ILIKE '%%ZSP PGŽ%%' OR organizacija ILIKE '%%Zajednica sportova PGŽ%%' OR organizacija ILIKE '%%Zajednica športskih saveza PGŽ%%' THEN 'ZSPGZ'
|
||||
WHEN organizacija ILIKE 'Primorsko-goranska%%' OR organizacija = 'PGŽ' OR url ILIKE '%%pgz.hr%%' OR url ILIKE '%%sport-pgz%%' THEN 'PGŽ'
|
||||
WHEN organizacija ILIKE 'Grad Rijeka%%' OR organizacija ILIKE 'Grad/Općina%%' OR url ILIKE '%%rijeka.hr%%' OR vrsta ILIKE 'jls_%%' OR vrsta = 'grad_rijeka_sport' THEN 'JLS'
|
||||
WHEN organizacija ILIKE 'Hrvatski %%savez%%' OR organizacija IN ('HKS','HOK','HNS','HRS','HVS','HBS') OR vrsta ILIKE 'savez_%%' THEN 'savez'
|
||||
WHEN organizacija ILIKE '%%klub%%' THEN 'klub'
|
||||
ELSE 'ostalo'
|
||||
END
|
||||
"""
|
||||
|
||||
@router.get("/dokumenti/unified")
|
||||
def dokumenti_unified(
|
||||
tip: Optional[str] = None,
|
||||
izdavatelj: Optional[str] = None,
|
||||
vrsta: Optional[str] = None,
|
||||
q: Optional[str] = None,
|
||||
godina_min: Optional[int] = None,
|
||||
godina_max: Optional[int] = None,
|
||||
limit: int = 500,
|
||||
):
|
||||
"""Unified document library — returns ALL documents with normalized
|
||||
`tip` (godisnjak/manifestacija/natjecaj/pravilnik/publikacija/javni-poziv/ostalo)
|
||||
and `izdavatelj` (RSS/HOO/PGŽ/ZSPGZ/JLS/savez/klub/ostalo) derived
|
||||
from raw vrsta+organizacija+url columns.
|
||||
Filters: tip, izdavatelj, vrsta (raw), q (FTS over title/opis/organizacija),
|
||||
godina_min/godina_max, limit.
|
||||
"""
|
||||
where = ["COALESCE(aktivan,true)=true",
|
||||
"vrsta NOT IN ('corpus','corpus_v2','corpus_v3','novost_savez','audit','godisnjak_facts','enrichment','autogen')"]
|
||||
params = []
|
||||
if tip:
|
||||
where.append(f"({_TIP_CASE_SQL}) = %s"); params.append(tip)
|
||||
if izdavatelj:
|
||||
where.append(f"({_IZDAVATELJ_CASE_SQL}) = %s"); params.append(izdavatelj)
|
||||
if vrsta:
|
||||
where.append("vrsta = %s"); params.append(vrsta)
|
||||
if godina_min:
|
||||
where.append("godina >= %s"); params.append(godina_min)
|
||||
if godina_max:
|
||||
where.append("godina <= %s"); params.append(godina_max)
|
||||
if q:
|
||||
where.append("(title ILIKE %s OR kratak_opis ILIKE %s OR organizacija ILIKE %s)")
|
||||
params.extend([f"%{q}%", f"%{q}%", f"%{q}%"])
|
||||
|
||||
sql = f"""SELECT id, title, kratak_opis, vrsta,
|
||||
{_TIP_CASE_SQL} AS tip,
|
||||
{_IZDAVATELJ_CASE_SQL} AS izdavatelj,
|
||||
razina, organizacija, sport, sluzbeni_glasnik,
|
||||
izvor_url, pdf_url, url, fname, godina, izdano_datum,
|
||||
CASE WHEN sadrzaj IS NOT NULL THEN length(sadrzaj) ELSE 0 END AS chars,
|
||||
scraped_at
|
||||
FROM pgz_sport.dokumenti
|
||||
WHERE {' AND '.join(where)}
|
||||
ORDER BY izdano_datum DESC NULLS LAST, godina DESC NULLS LAST, id DESC
|
||||
LIMIT %s"""
|
||||
params.append(limit)
|
||||
rows = db_query(sql, params)
|
||||
return {"count": len(rows), "dokumenti": rows}
|
||||
|
||||
|
||||
@router.get("/dokumenti/facets")
|
||||
def dokumenti_facets():
|
||||
"""Counts po normaliziranom tipu i izdavatelju — za UI dropdown badges."""
|
||||
by_tip = db_query(f"""SELECT {_TIP_CASE_SQL} AS tip, count(*) AS broj
|
||||
FROM pgz_sport.dokumenti
|
||||
WHERE COALESCE(aktivan,true)=true
|
||||
AND vrsta NOT IN ('corpus','corpus_v2','corpus_v3','novost_savez','audit','godisnjak_facts','enrichment','autogen')
|
||||
GROUP BY 1 ORDER BY 2 DESC""")
|
||||
by_izd = db_query(f"""SELECT {_IZDAVATELJ_CASE_SQL} AS izdavatelj, count(*) AS broj
|
||||
FROM pgz_sport.dokumenti
|
||||
WHERE COALESCE(aktivan,true)=true
|
||||
AND vrsta NOT IN ('corpus','corpus_v2','corpus_v3','novost_savez','audit','godisnjak_facts','enrichment','autogen')
|
||||
GROUP BY 1 ORDER BY 2 DESC""")
|
||||
return {"by_tip": by_tip, "by_izdavatelj": by_izd}
|
||||
|
||||
|
||||
@router.post("/dokumenti/upload")
|
||||
async def upload_dokument(
|
||||
file: UploadFile = File(...),
|
||||
|
||||
Reference in New Issue
Block a user