feat: add api and mcp

This commit is contained in:
hh committed 2026-05-30 01:32:35 +02:00
1 parent 6a5cde6ae4
commit c40e720163
30 files changed
+2354 -31

No files matched your search

+82
View File
@@ -0,0 +1,82 @@
from typing import Annotated, Any
import asyncpg
from dishka.integrations.fastapi import DishkaRoute, FromDishka
from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel
from utils.read import watches
from utils.read.models import DEFAULT_LIMIT, AlertView, Page, WatchView
router = APIRouter(prefix="/api", tags=["watches"], route_class=DishkaRoute)
class WatchCreate(BaseModel):
account_id: int
kind: str
params: dict[str, Any] = {}
enabled: bool = True
class WatchUpdate(BaseModel):
params: dict[str, Any] = {}
enabled: bool = True
@router.get("/watches")
async def list_watches(
pool: FromDishka[asyncpg.Pool], account_id: Annotated[int, Query()]
) -> list[WatchView]:
return await watches.list_watches(pool, account_id)
@router.post("/watches", status_code=201)
async def create_watch(pool: FromDishka[asyncpg.Pool], body: WatchCreate) -> WatchView:
return await watches.create_watch(
pool, body.account_id, body.kind, body.params, enabled=body.enabled
)
@router.get("/watches/{watch_id}")
async def get_watch(pool: FromDishka[asyncpg.Pool], watch_id: int) -> WatchView:
watch = await watches.get_watch(pool, watch_id)
if watch is None:
raise HTTPException(status_code=404, detail="watch not found")
return watch
@router.put("/watches/{watch_id}")
async def update_watch(
pool: FromDishka[asyncpg.Pool], watch_id: int, body: WatchUpdate
) -> WatchView:
watch = await watches.update_watch(
pool, watch_id, body.params, enabled=body.enabled
)
if watch is None:
raise HTTPException(status_code=404, detail="watch not found")
return watch
@router.delete("/watches/{watch_id}", status_code=204)
async def delete_watch(pool: FromDishka[asyncpg.Pool], watch_id: int) -> None:
if not await watches.delete_watch(pool, watch_id):
raise HTTPException(status_code=404, detail="watch not found")
@router.get("/alerts")
async def list_alerts(
pool: FromDishka[asyncpg.Pool],
account_id: Annotated[int, Query()],
seen: Annotated[bool | None, Query()] = None,
limit: Annotated[int, Query()] = DEFAULT_LIMIT,
offset: Annotated[int, Query()] = 0,
) -> list[AlertView]:
return await watches.list_alerts(
pool, account_id, Page(limit=limit, offset=offset), seen=seen
)
@router.post("/alerts/{alert_id}/seen", status_code=204)
async def mark_alert_seen(pool: FromDishka[asyncpg.Pool], alert_id: int) -> None:
if not await watches.mark_alert_seen(pool, alert_id):
raise HTTPException(status_code=404, detail="alert not found")