fleet-platform/app/routers/views.py

45 lines
1.6 KiB
Python
Raw Normal View History

import json
from typing import Annotated, Any
from fastapi import APIRouter, Depends, HTTPException, Query, Request
from psycopg.types.json import Jsonb
from app.auth import AuthAccount, require_scope
from app.db import get_pool
from app.models.views import LiveViewResponse
from app.rate_limit import limiter
router = APIRouter(prefix="/api/views", tags=["views"])
_FILTERS_DESC = "JSON object: cost_centre, assigned_city, vehicle_numbers[]"
def _parse_filters(filters_q: str | None) -> dict[str, Any]:
if not filters_q:
return {}
try:
parsed = json.loads(filters_q)
except json.JSONDecodeError as exc:
raise HTTPException(status_code=400, detail=f"invalid filters json: {exc}") from exc
if not isinstance(parsed, dict):
raise HTTPException(status_code=400, detail="filters must be a JSON object")
return parsed
@router.get("/live", response_model=LiveViewResponse)
@limiter.limit("60/minute")
async def live_view(
request: Request,
_account: Annotated[AuthAccount, Depends(require_scope("read:fleet"))],
filters: Annotated[str | None, Query(description=_FILTERS_DESC)] = None,
) -> LiveViewResponse:
_ = request
filters_dict = _parse_filters(filters)
pool = await get_pool()
async with pool.connection() as conn, conn.cursor() as cur:
await cur.execute("SELECT serve.fn_live_view(%s)", (Jsonb(filters_dict),))
row = await cur.fetchone()
if row is None or row[0] is None:
raise HTTPException(status_code=500, detail="serve.fn_live_view returned NULL")
return LiveViewResponse.model_validate(row[0])