"""Blocker endpoints. `GET /api/blocker/policy` is the one the desktop app polls every few seconds; everything else is for the UI. """ from __future__ import annotations from datetime import date from fastapi import APIRouter, Query from app.api.deps import DbSession, Settings from app.api.schemas import BlockEventRequest from app.services import blocker_service from app.services.notify import notify router = APIRouter(prefix="/api/blocker", tags=["blocker"]) @router.get("/policy") def policy(session: DbSession, settings: Settings) -> dict: return blocker_service.policy(session, settings) @router.get("/events") def events( session: DbSession, settings: Settings, day: date | None = Query(default=None), ) -> dict: return blocker_service.events_for_day(session, settings, day) @router.post("/events") def record(body: BlockEventRequest, session: DbSession, settings: Settings) -> dict: """The desktop app reports every attempt it turned away. These are what make the daily report fun ("you reached for youtube 12 times"), so they are recorded even when the blocker only warned. """ event = blocker_service.record_event( session, settings, kind=body.kind, target=body.target, action=body.action, details=body.details, ) if settings.blocker.notify_on_block and body.action == "killed": notify(settings, f"🛑 Closed {body.target} — you are in a work interval.") return {"id": event.id, "recorded": True} @router.get("/defaults") def defaults() -> dict: """Starter lists, so the blocker page is not an empty text box.""" return {"domains": blocker_service.DEFAULT_DOMAINS, "apps": blocker_service.DEFAULT_APPS}