Add personal monthly viewing reports and CSV exports
Magent CI/CD / verify (push) Successful in 10m58s
Magent CI/CD / deploy-prod (push) Skipped
Magent CI/CD / deploy-beta (push) Successful in 1m42s

This commit is contained in:
2026-09-09 16:25:35 +12:00
parent 437836243c
commit 333a799e21
13 changed files with 836 additions and 92 deletions
+35 -1
View File
@@ -1,17 +1,51 @@
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException, Query, Response
from pydantic import BaseModel, ConfigDict, field_validator
from pydantic import BaseModel, ConfigDict, Field, field_validator
from ..auth import get_current_user
from ..clients.jellystat import HistoryLimitError, JellystatError
from ..services.insights import get_insights
from ..services.insights_artwork import get_artwork
from ..services.monthly_reports import get_monthly_report, report_csv
from ..runtime import get_runtime_settings
router = APIRouter(prefix="/insights", tags=["insights"])
class MonthlyReportQuery(BaseModel):
model_config = ConfigDict(extra="forbid")
month: str | None = Field(default=None, max_length=7, pattern=r"^[0-9]{4}-[0-9]{2}$")
async def monthly_data(user: dict, month: str | None) -> dict:
try:
return await get_monthly_report(user, month)
except ValueError as exc:
raise HTTPException(422, "Choose the current month or one of the previous 23 months.") from exc
except HistoryLimitError as exc:
raise HTTPException(422, "This report exceeds Jellystat's history limit. No partial report has been generated.") from exc
except JellystatError as exc:
raise HTTPException(502, "Your monthly report is temporarily unavailable. Please try again shortly.") from exc
@router.get("/reports/monthly")
async def monthly_report(query: Annotated[MonthlyReportQuery, Query()], response: Response,
user: dict = Depends(get_current_user)) -> dict:
response.headers["Cache-Control"] = "no-store"
return await monthly_data(user, query.month)
@router.get("/reports/monthly.csv")
async def monthly_export(query: Annotated[MonthlyReportQuery, Query()], user: dict = Depends(get_current_user)):
report = await monthly_data(user, query.month)
if report["state"] != "ready":
raise HTTPException(409, "Connect Jellystat and link your viewing account before downloading a report.")
return Response(report_csv(report), media_type="text/csv; charset=utf-8", headers={
"Cache-Control": "no-store", "X-Content-Type-Options": "nosniff",
"Content-Disposition": f'attachment; filename="magent-monthly-report-{report["month"]}.csv"'})
@router.get("/artwork/{item_id}")
async def artwork(item_id: str, token: Annotated[str, Query(max_length=100)], user: dict = Depends(get_current_user)):
content, media_type = await get_artwork(user, get_runtime_settings(), item_id, token)