Files
kadence/backend/app/api/routes_reports.py
T
2026-10-18 18:02:05 +03:00

101 lines
3.7 KiB
Python

"""Report and statistics endpoints."""
from __future__ import annotations
from datetime import date, timedelta
from fastapi import APIRouter, Query
from app.api.deps import DbSession, Settings
from app.api.schemas import SendReportRequest, TestNotificationRequest
from app.services import notify as notify_service
from app.services import report, scheduler, stats
from app.timeutil import ensure_utc, local_date
router = APIRouter(prefix="/api", tags=["reports"])
@router.get("/reports/daily")
def daily(
session: DbSession,
settings: Settings,
day: date | None = Query(default=None),
rebuild: bool = Query(default=True),
) -> dict:
target = day or local_date(settings.timezone)
row, payload = report.get_or_build_daily(session, settings, target, rebuild=rebuild)
return {
"report": payload,
"sent_at": ensure_utc(row.sent_at).isoformat() if row.sent_at else None,
"telegram_preview": report.render_daily_telegram(payload, settings),
}
@router.post("/reports/daily/send")
def send_daily(body: SendReportRequest, session: DbSession, settings: Settings) -> dict:
target = body.report_date or local_date(settings.timezone)
return report.send_daily(session, settings, target, force=body.force)
@router.get("/reports/weekly")
def weekly(
session: DbSession,
settings: Settings,
end: date | None = Query(default=None),
) -> dict:
target = end or local_date(settings.timezone)
payload = report.build_weekly(session, settings, target)
return {"report": payload, "telegram_preview": report.render_weekly_telegram(payload, settings)}
@router.post("/reports/weekly/send")
def send_weekly(session: DbSession, settings: Settings) -> dict:
payload = report.build_weekly(session, settings, local_date(settings.timezone))
text = report.render_weekly_telegram(payload, settings)
deliveries = notify_service.notify(settings, text, urgent=True)
return {"sent": any(d.ok for d in deliveries), "deliveries": [d.as_dict() for d in deliveries]}
@router.post("/reports/briefing/send")
def send_briefing(session: DbSession, settings: Settings) -> dict:
text = report.render_morning_briefing(session, settings)
deliveries = notify_service.notify(settings, text, urgent=True)
return {
"sent": any(d.ok for d in deliveries),
"deliveries": [d.as_dict() for d in deliveries],
"text": text,
}
@router.get("/stats/summary")
def summary(session: DbSession, settings: Settings, days: int = Query(default=30, ge=1, le=365)) -> dict:
today = local_date(settings.timezone)
return {
"today": stats.day_metrics(session, settings, today),
"streak": stats.streak(session, settings),
"lifetime": stats.lifetime(session, settings),
"average_7d": stats.averages(session, settings, 7, until=today),
"range": stats.range_metrics(session, settings, today - timedelta(days=days - 1), today),
"heatmap": stats.heatmap(session, settings, weeks=12),
}
@router.get("/stats/day")
def day_stats(session: DbSession, settings: Settings, day: date | None = Query(default=None)) -> dict:
return stats.day_metrics(session, settings, day or local_date(settings.timezone))
@router.post("/notifications/test")
def test_notification(body: TestNotificationRequest, settings: Settings) -> dict:
text = body.text or (
"🍅 <b>Kadence</b>\nNotifications are wired up correctly."
)
deliveries = notify_service.notify(settings, text, urgent=True)
return {"deliveries": [d.as_dict() for d in deliveries]}
@router.get("/scheduler/jobs")
def scheduler_jobs() -> dict:
"""What the background jobs are, and when they next fire."""
return {"jobs": scheduler.describe()}