""" Objekti Router — sportski objekti PGZ Created: 2026-05-09 v4.0-final pre-K3s Endpoints: GET /api/v2/objekti/list (paginated), /api/v2/objekti/{id} """ from fastapi import APIRouter, Depends, HTTPException, Query from typing import Optional, List import os, json from psycopg2.extras import RealDictCursor import psycopg2 router = APIRouter(prefix="/api/v2/objekti", tags=["objekti"]) def get_conn(): return psycopg2.connect( host=os.getenv("DB_HOST", "10.10.0.2"), port=int(os.getenv("DB_PORT", "6432")), dbname=os.getenv("DB_NAME", "rinet_v3"), user=os.getenv("DB_USER", "rinet"), password=os.environ["DB_PASSWORD"] ) @router.get("/list") def list_objekti( skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=200), grad: Optional[str] = None, tip: Optional[str] = None, region: Optional[str] = None, search: Optional[str] = None, ): """List sportski objekti sa filtriranjem""" where = ["aktivan = true"] params = [] if grad: where.append("grad ILIKE %s") params.append(f"%{grad}%") if tip: where.append("tip = %s") params.append(tip) if region: where.append("region ILIKE %s") params.append(f"%{region}%") if search: where.append("fts @@ plainto_tsquery(\'simple\', %s)") params.append(search) where_sql = " AND ".join(where) if where else "true" conn = get_conn() try: with conn.cursor(cursor_factory=RealDictCursor) as cur: # Count cur.execute(f"SELECT COUNT(*) FROM pgz_sport.objekti WHERE {where_sql}", params) total = cur.fetchone()["count"] # Data cur.execute(f""" SELECT id, naziv, tip, vlasnik, upravitelj, adresa, grad, region, kapacitet, godina_izgradnje, geo_lat, geo_lng, koristi_se_za, email, telefon, web, aktivan, pristupacan_invalidi FROM pgz_sport.objekti WHERE {where_sql} ORDER BY grad, naziv LIMIT %s OFFSET %s """, params + [limit, skip]) items = cur.fetchall() return { "items": items, "total": total, "skip": skip, "limit": limit } finally: conn.close() @router.get("/{objekt_id}") def get_objekt(objekt_id: int): """Detail jednog objekta""" conn = get_conn() try: with conn.cursor(cursor_factory=RealDictCursor) as cur: cur.execute("SELECT * FROM pgz_sport.objekti WHERE id = %s", (objekt_id,)) r = cur.fetchone() if not r: raise HTTPException(status_code=404, detail="Objekt not found") return r finally: conn.close() @router.get("/stats/by-tip") def stats_by_tip(): """Stats: count objekata po tip""" conn = get_conn() try: with conn.cursor(cursor_factory=RealDictCursor) as cur: cur.execute(""" SELECT tip, COUNT(*) as count FROM pgz_sport.objekti WHERE aktivan = true GROUP BY tip ORDER BY 2 DESC """) return {"items": cur.fetchall()} finally: conn.close() @router.get("/stats/by-region") def stats_by_region(): """Stats: count objekata po region""" conn = get_conn() try: with conn.cursor(cursor_factory=RealDictCursor) as cur: cur.execute(""" SELECT region, COUNT(*) as count FROM pgz_sport.objekti WHERE aktivan = true AND region IS NOT NULL GROUP BY region ORDER BY 2 DESC """) return {"items": cur.fetchall()} finally: conn.close()