feat(release): publish minimal self-contained Magent source
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
from ..feature_guards import require_stats
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Response
|
||||
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"], dependencies=[Depends(require_stats)])
|
||||
|
||||
|
||||
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)
|
||||
return Response(content=content, media_type=media_type,
|
||||
headers={"Cache-Control": "private, max-age=600", "Vary": "Cookie, Authorization", "X-Content-Type-Options": "nosniff"})
|
||||
|
||||
|
||||
class InsightsQuery(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
days: int = 30
|
||||
|
||||
@field_validator("days")
|
||||
@classmethod
|
||||
def supported_period(cls, value: int) -> int:
|
||||
if value not in {7, 30, 90, 365}:
|
||||
raise ValueError("Choose 7, 30, 90 or 365 days")
|
||||
return value
|
||||
|
||||
|
||||
@router.get("")
|
||||
async def dashboard(query: Annotated[InsightsQuery, Query()], response: Response,
|
||||
user: dict = Depends(get_current_user)) -> dict:
|
||||
response.headers["Cache-Control"] = "no-store"
|
||||
try:
|
||||
return await get_insights(user, query.days)
|
||||
except HistoryLimitError as exc:
|
||||
raise HTTPException(status_code=422, detail="There is too much history for this period. Choose a shorter period.") from exc
|
||||
except JellystatError as exc:
|
||||
raise HTTPException(status_code=502, detail="Your viewing stats are temporarily unavailable. Please try again shortly.") from exc
|
||||
Reference in New Issue
Block a user