Files
hockey_new/hockey_data/program_log_router.py

63 lines
3.1 KiB
Python

"""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