130 lines
3.9 KiB
Python
130 lines
3.9 KiB
Python
from dotenv import load_dotenv
|
|
load_dotenv('/opt/rinet-gpu/.env.master')
|
|
# auto-added by patch_scrapers_with_dotenv.sh
|
|
"""
|
|
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()
|