"""Authenticated read/download endpoints for the operational journal.""" from __future__ import annotations import asyncio from datetime import datetime from typing import Literal from fastapi import APIRouter, Depends, HTTPException, Query, Response from fastapi.responses import StreamingResponse from .auth_bridge import HockeyUser from .program_log import MOSCOW, ProgramLogStore def create_program_log_router(store: ProgramLogStore, auth_dependency): router = APIRouter(prefix="/api/hockey/program-logs", tags=["program-log"]) async def administrator(user: HockeyUser = Depends(auth_dependency)): if not user.is_admin: raise HTTPException(403, "Журнал программы доступен администратору") return user def filters(preset: Literal["today", "week", "month", "all"] = "week", date_from: str = Query("", max_length=10), date_to: str = Query("", max_length=10), level: str = Query("", max_length=10), category: str = Query("", max_length=120), actor: str = Query("", max_length=200), game_id: str = Query("", max_length=100), device_id: str = Query("", max_length=160), q: str = Query("", max_length=300), sort: Literal["asc", "desc"] = "desc"): result = dict(preset=preset, date_from=date_from, date_to=date_to, level=level, category=category, actor=actor, game_id=game_id, device_id=device_id, q=q, sort=sort) try: store._filters(result) except ValueError as error: raise HTTPException(422, str(error)) from error return result @router.get("/options") async def options(response: Response, user: HockeyUser = Depends(administrator)): response.headers["Cache-Control"] = "private, no-store" return await asyncio.to_thread(store.options) @router.get("/download") async def download(selected: dict = Depends(filters), format: Literal["txt", "jsonl"] = "txt", user: HockeyUser = Depends(administrator)): stamp = datetime.now(MOSCOW).strftime("%Y%m%d_%H%M%S") filename = f"hockey-log_{stamp}.{format}" return StreamingResponse(store.download(format=format, **selected), media_type="text/plain; charset=utf-8" if format == "txt" else "application/x-ndjson", headers={"Content-Disposition": f'attachment; filename="{filename}"', "Cache-Control": "private, no-store", "X-Content-Type-Options": "nosniff"}) @router.get("") async def records(response: Response, selected: dict = Depends(filters), limit: int = Query(100, ge=1, le=500), cursor: str = Query("", max_length=1024), user: HockeyUser = Depends(administrator)): response.headers["Cache-Control"] = "private, no-store" try: return await asyncio.to_thread(store.query, limit=limit, cursor=cursor, **selected) except ValueError as error: raise HTTPException(422, str(error)) from error return router