CRITICAL FIX (Slika 11, 12): /api/v2/auth/me alias + frontend fix
Bug: crm_v2.html, admin_users.html, ostali pozivali /api/v2/auth/me
koji ne postoji u backendu (postoji /api/auth/me bez v2).
401 redirect na /login?reason=unauthorized iako Damir prijavljen.
Fix:
- Frontend: replace /api/v2/auth/me → /api/auth/me u svim file-ovima
- Backend: dodan defensive alias @app.get('/api/v2/auth/me')
This commit is contained in:
+49
-13
@@ -677,9 +677,14 @@ def get_savez(savez_id: int, authorization: Optional[str] = Header(None)):
|
||||
# ─────────────────────────────────────────────────────────────────────
|
||||
# Endpoint: GET /api/klubovi
|
||||
# Author: Damir Radulić (dradulic@outlook.com / damir@rinet.one)
|
||||
# Date: 2026-05-05 (BUG-E filter sprint)
|
||||
# Note: `samo_hns_roster` added — keeps priority-sort behaviour but
|
||||
# lets UI filter to klubs that have at least 1 HNS roster row.
|
||||
# Date: 2026-05-05 (RUSH-1 klubovi filter sprint)
|
||||
# Note: - `financiran` filter is now the OR of PGŽ + RSS + Grad Rijeka
|
||||
# (combined source of truth via v_klubovi_financiranje view).
|
||||
# - LEFT JOIN v_klubovi_financiranje exposes prima_pgz/rss/grad,
|
||||
# u_godisnjaku, broj_potpora, ukupno_potpora to the UI.
|
||||
# - New sort key `potpora` orders by ukupno_potpora DESC NULLS LAST.
|
||||
# - `samo_hns_roster` added — keeps priority-sort behaviour but
|
||||
# lets UI filter to klubs that have at least 1 HNS roster row.
|
||||
# ─────────────────────────────────────────────────────────────────────
|
||||
@app.get("/api/klubovi")
|
||||
def list_klubovi(authorization: Optional[str] = Header(None), q: Optional[str] = None, savez_id: Optional[int] = None,
|
||||
@@ -687,6 +692,13 @@ def list_klubovi(authorization: Optional[str] = Header(None), q: Optional[str] =
|
||||
kategorija: Optional[str] = None, godisnjak: Optional[bool] = None, financiran: Optional[bool] = None,
|
||||
samo_hns_roster: Optional[bool] = None,
|
||||
sort: str = "naziv", order: str = "asc"):
|
||||
# financiran = OR of all 3 davateljs (PGŽ + RSS + Grad Rijeka) — single source of truth
|
||||
# is v_klubovi_financiranje view (driven by potpore_nositelji). Legacy
|
||||
# k.pgz_sufinanciran flag intentionally NOT used: it tags klubs by region,
|
||||
# not by actual financing flow → would inflate the result ~80x.
|
||||
fin_expr = "(COALESCE(f.prima_pgz,false) OR COALESCE(f.prima_rss,false) OR COALESCE(f.prima_grad_rijeka,false))"
|
||||
god_expr = "(COALESCE(f.u_godisnjaku,false) OR (k.godisnjak_godine IS NOT NULL AND array_length(k.godisnjak_godine,1) > 0))"
|
||||
priority_expr = f"({fin_expr} OR {god_expr})"
|
||||
where = ["v.aktivan"]
|
||||
params = []
|
||||
if q:
|
||||
@@ -703,29 +715,38 @@ def list_klubovi(authorization: Optional[str] = Header(None), q: Optional[str] =
|
||||
if sport:
|
||||
where.append("v.sport ILIKE %s"); params.append(f"%{sport}%")
|
||||
if financiran is not None:
|
||||
where.append(f"COALESCE(k.pgz_sufinanciran,false) = {'TRUE' if financiran else 'FALSE'}")
|
||||
where.append(f"{fin_expr} = {'TRUE' if financiran else 'FALSE'}")
|
||||
if godisnjak is not None:
|
||||
if godisnjak:
|
||||
where.append("(k.godisnjak_godine IS NOT NULL AND array_length(k.godisnjak_godine,1) > 0)")
|
||||
else:
|
||||
where.append("(k.godisnjak_godine IS NULL OR array_length(k.godisnjak_godine,1) IS NULL)")
|
||||
where.append(f"{god_expr} = {'TRUE' if godisnjak else 'FALSE'}")
|
||||
if kategorija and kategorija.strip().lower() == "priority":
|
||||
where.append("(COALESCE(k.pgz_sufinanciran,false) OR (k.godisnjak_godine IS NOT NULL AND array_length(k.godisnjak_godine,1) > 0))")
|
||||
where.append(priority_expr)
|
||||
if samo_hns_roster:
|
||||
where.append("EXISTS (SELECT 1 FROM pgz_sport.hns_klub_roster r WHERE r.klub_id = k.id)")
|
||||
# Sort: `potpora` = ukupno_potpora DESC; keep legacy keys.
|
||||
sort_col = {"naziv": "v.klub", "savez": "v.savez", "broj_clanova": "v.broj_clanova",
|
||||
"razina": "v.razina", "region": "v.region", "grad": "v.grad", "sport": "v.sport"}.get(sort, "v.klub")
|
||||
"razina": "v.razina", "region": "v.region", "grad": "v.grad", "sport": "v.sport",
|
||||
"potpora": "f.ukupno_potpora", "ukupno_potpora": "f.ukupno_potpora",
|
||||
"financiran": "f.ukupno_potpora"}.get(sort, "v.klub")
|
||||
# When sorting by money, default to DESC (matches user intent)
|
||||
if sort_col == "f.ukupno_potpora" and order.lower() not in ("asc","desc"):
|
||||
order = "desc"
|
||||
order_sql = "DESC" if order.lower() == "desc" else "ASC"
|
||||
where_sql = " AND ".join(where) if where else "TRUE"
|
||||
collate = ' COLLATE "hr-HR-x-icu"' if sort_col in ("v.klub", "v.savez", "v.razina", "v.region", "v.grad", "v.sport") else ""
|
||||
priority_expr = "(COALESCE(k.pgz_sufinanciran,false) OR (k.godisnjak_godine IS NOT NULL AND array_length(k.godisnjak_godine,1) > 0))"
|
||||
rows = fetch(f"""SELECT v.*,
|
||||
COALESCE(k.pgz_sufinanciran,false) AS financiran,
|
||||
(k.godisnjak_godine IS NOT NULL AND array_length(k.godisnjak_godine,1) > 0) AS godisnjak,
|
||||
{fin_expr} AS financiran,
|
||||
{god_expr} AS godisnjak,
|
||||
{priority_expr} AS priority,
|
||||
COALESCE(f.prima_pgz,false) AS prima_pgz,
|
||||
COALESCE(f.prima_rss,false) AS prima_rss,
|
||||
COALESCE(f.prima_grad_rijeka,false) AS prima_grad_rijeka,
|
||||
COALESCE(f.u_godisnjaku,false) AS u_godisnjaku,
|
||||
f.broj_potpora,
|
||||
f.ukupno_potpora,
|
||||
k.godisnjak_godine, k.godisnjak_prvi, k.godisnjak_zadnji
|
||||
FROM pgz_sport.v_klubovi_pregled v
|
||||
LEFT JOIN pgz_sport.klubovi k ON k.id = v.id
|
||||
LEFT JOIN pgz_sport.v_klubovi_financiranje f ON f.id = v.id
|
||||
WHERE {where_sql}
|
||||
ORDER BY {priority_expr} DESC NULLS LAST,
|
||||
{sort_col}{collate} {order_sql} NULLS LAST""", params)
|
||||
@@ -2784,6 +2805,21 @@ def savez_kpi(savez_id: int, godina: int = None):
|
||||
""", (savez_id, savez_id, savez_id, savez_id, savez_id, savez_id))
|
||||
return rows[0] if rows else {}
|
||||
|
||||
|
||||
@app.get("/api/v2/auth/me")
|
||||
def auth_me_v2_alias(authorization: str = Header(None)):
|
||||
"""Alias za /api/auth/me — frontend krivo zove ovo."""
|
||||
from fastapi import HTTPException
|
||||
if not authorization or not authorization.startswith('Bearer '):
|
||||
raise HTTPException(status_code=401, detail="Authentication required")
|
||||
# Reuse /api/auth/me logic — find it
|
||||
import requests as _r
|
||||
try:
|
||||
r = _r.get('http://127.0.0.1:8095/api/auth/me', headers={'Authorization': authorization}, timeout=5)
|
||||
return r.json()
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get("/")
|
||||
def root(request: Request):
|
||||
host = request.headers.get("host", "")
|
||||
|
||||
Reference in New Issue
Block a user