Files
beavergram/backend/src/api/routers/policy.py
T

94 lines
2.8 KiB
Python

from typing import Annotated
import asyncpg
from dishka.integrations.fastapi import DishkaRoute, FromDishka
from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel
from utils.policy import repository
from utils.policy.models import (
CaptureToggles,
ChatKind,
ChatMeta,
PolicyCreate,
PolicyRecord,
)
from utils.policy.resolver import resolve
router = APIRouter(prefix="/api/policy", tags=["policy"], route_class=DishkaRoute)
POLICY_CHANGED_CHANNEL = "policy_changed"
class EffectiveQuery(BaseModel):
account_id: int
chat_id: int
kind: ChatKind
is_bot: bool = False
is_contact: bool | None = None
@router.get("")
async def list_policies(
pool: FromDishka[asyncpg.Pool], account_id: Annotated[int, Query()]
) -> list[PolicyRecord]:
return await repository.list_policies(pool, account_id)
@router.get("/effective")
async def effective_policy(
pool: FromDishka[asyncpg.Pool], query: Annotated[EffectiveQuery, Query()]
) -> CaptureToggles:
folders = await repository.list_folders(pool, query.account_id)
policies = await repository.load_policy_set(pool, query.account_id)
chat = ChatMeta(
chat_id=query.chat_id,
kind=query.kind,
is_bot=query.is_bot,
is_contact=query.is_contact,
)
return resolve(chat, folders, policies)
@router.post("", status_code=201)
async def create_policy(
pool: FromDishka[asyncpg.Pool], body: PolicyCreate
) -> PolicyRecord:
record = await repository.create_policy(
pool, body.account_id, body.scope_type, body.scope_id, body
)
await pool.execute(f"NOTIFY {POLICY_CHANGED_CHANNEL}")
return record
@router.get("/{policy_id}")
async def get_policy(pool: FromDishka[asyncpg.Pool], policy_id: int) -> PolicyRecord:
record = await repository.get_policy(pool, policy_id)
if record is None:
raise HTTPException(status_code=404, detail="policy not found")
return record
@router.put("/{policy_id}")
async def update_policy(
pool: FromDishka[asyncpg.Pool],
policy_id: int,
body: CaptureToggles,
account_id: Annotated[int | None, Query()] = None,
) -> PolicyRecord:
if account_id is None:
record = await repository.update_policy(pool, policy_id, body)
else:
record = await repository.override_policy(pool, policy_id, account_id, body)
if record is None:
raise HTTPException(status_code=404, detail="policy not found")
await pool.execute(f"NOTIFY {POLICY_CHANGED_CHANNEL}")
return record
@router.delete("/{policy_id}", status_code=204)
async def delete_policy(pool: FromDishka[asyncpg.Pool], policy_id: int) -> None:
if not await repository.delete_policy(pool, policy_id):
raise HTTPException(status_code=404, detail="policy not found")
await pool.execute(f"NOTIFY {POLICY_CHANGED_CHANNEL}")