from datetime import datetime from typing import Annotated import asyncpg from dishka.integrations.fastapi import DishkaRoute, FromDishka from fastapi import APIRouter, Query from api.timezone import checked_tz from utils.read import presence, presence_stats from utils.read.models import ( DEFAULT_LIMIT, Page, PresenceHourly, PresenceSample, PresenceSession, PresenceStats, ) from utils.read.period import DEFAULT_TZ, MAX_DAYS router = APIRouter(prefix="/api/presence", tags=["presence"], route_class=DishkaRoute) AccountId = Annotated[int, Query()] PeerId = Annotated[int, Query()] DateFrom = Annotated[datetime | None, Query()] DateTo = Annotated[datetime | None, Query()] Days = Annotated[int, Query(ge=1, le=MAX_DAYS)] Tz = Annotated[str, Query()] @router.get("") async def presence_history( pool: FromDishka[asyncpg.Pool], account_id: AccountId, peer_id: PeerId, date_from: DateFrom = None, date_to: DateTo = None, limit: Annotated[int, Query()] = DEFAULT_LIMIT, offset: Annotated[int, Query()] = 0, ) -> list[PresenceSample]: return await presence.presence_history( pool, account_id, peer_id, Page(limit=limit, offset=offset), date_from=date_from, date_to=date_to, ) @router.get("/current") async def current_presence( pool: FromDishka[asyncpg.Pool], account_id: AccountId, peer_id: PeerId ) -> PresenceSample | None: return await presence.current_presence(pool, account_id, peer_id) @router.get("/hourly") async def presence_hourly( pool: FromDishka[asyncpg.Pool], account_id: AccountId, peer_id: PeerId, date_from: DateFrom = None, date_to: DateTo = None, ) -> list[PresenceHourly]: return await presence.presence_hourly( pool, account_id, peer_id, date_from=date_from, date_to=date_to ) @router.get("/stats") async def stats( pool: FromDishka[asyncpg.Pool], account_id: AccountId, peer_id: PeerId, days: Days = 30, tz: Tz = DEFAULT_TZ, limit: Annotated[int, Query()] = DEFAULT_LIMIT, offset: Annotated[int, Query()] = 0, ) -> PresenceStats: return await presence_stats.presence_stats( pool, account_id, peer_id, Page(limit=limit, offset=offset), days=days, tz=await checked_tz(pool, tz), ) @router.get("/sessions") async def sessions( pool: FromDishka[asyncpg.Pool], account_id: AccountId, peer_id: PeerId, days: Days = 30, tz: Tz = DEFAULT_TZ, limit: Annotated[int, Query()] = DEFAULT_LIMIT, offset: Annotated[int, Query()] = 0, ) -> list[PresenceSession]: return await presence_stats.presence_sessions( pool, account_id, peer_id, Page(limit=limit, offset=offset), days=days, tz=await checked_tz(pool, tz), )