101 lines
3.7 KiB
Python
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()}
|