108 lines
3.7 KiB
Python
108 lines
3.7 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
from fastapi import APIRouter, Depends, Request
|
|
from fastapi.responses import JSONResponse
|
|
|
|
from app_dependencies import get_runtime
|
|
from card_store import (
|
|
delete_card,
|
|
load_card,
|
|
load_cards,
|
|
normalize_card_id,
|
|
parse_iso_datetime,
|
|
write_card,
|
|
)
|
|
from route_helpers import read_json_request
|
|
from session_store import normalize_session_chat_id
|
|
from web_runtime import WebAppRuntime
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/cards")
|
|
async def get_cards(request: Request) -> JSONResponse:
|
|
chat_id = normalize_session_chat_id(str(request.query_params.get("chat_id", "web") or "web"))
|
|
if not chat_id:
|
|
return JSONResponse({"error": "invalid chat id"}, status_code=400)
|
|
return JSONResponse(load_cards(chat_id))
|
|
|
|
|
|
@router.delete("/cards/{card_id}")
|
|
async def delete_card_route(
|
|
card_id: str,
|
|
runtime: WebAppRuntime = Depends(get_runtime),
|
|
) -> JSONResponse:
|
|
if not normalize_card_id(card_id):
|
|
return JSONResponse({"error": "invalid card id"}, status_code=400)
|
|
card = load_card(card_id)
|
|
delete_card(card_id)
|
|
await runtime.publish_cards_changed(card.get("chat_id") if isinstance(card, dict) else None)
|
|
return JSONResponse({"status": "ok"})
|
|
|
|
|
|
@router.post("/cards/{card_id}/snooze")
|
|
async def snooze_card(
|
|
card_id: str,
|
|
request: Request,
|
|
runtime: WebAppRuntime = Depends(get_runtime),
|
|
) -> JSONResponse:
|
|
if not normalize_card_id(card_id):
|
|
return JSONResponse({"error": "invalid card id"}, status_code=400)
|
|
|
|
try:
|
|
payload = await read_json_request(request)
|
|
except ValueError as exc:
|
|
return JSONResponse({"error": str(exc)}, status_code=400)
|
|
|
|
until_raw = str(payload.get("until", "")).strip()
|
|
until_dt = parse_iso_datetime(until_raw)
|
|
if until_dt is None:
|
|
return JSONResponse({"error": "until must be a valid ISO datetime"}, status_code=400)
|
|
|
|
card = load_card(card_id)
|
|
if card is None:
|
|
return JSONResponse({"error": "card not found"}, status_code=404)
|
|
|
|
card["snooze_until"] = until_dt.isoformat()
|
|
card["updated_at"] = datetime.now(timezone.utc).isoformat()
|
|
persisted = write_card(card)
|
|
if persisted is None:
|
|
return JSONResponse({"error": "failed to snooze card"}, status_code=500)
|
|
await runtime.publish_cards_changed(persisted.get("chat_id"))
|
|
return JSONResponse({"status": "ok", "card": persisted})
|
|
|
|
|
|
@router.post("/cards/{card_id}/state")
|
|
async def update_card_state(
|
|
card_id: str,
|
|
request: Request,
|
|
runtime: WebAppRuntime = Depends(get_runtime),
|
|
) -> JSONResponse:
|
|
if not normalize_card_id(card_id):
|
|
return JSONResponse({"error": "invalid card id"}, status_code=400)
|
|
|
|
try:
|
|
payload = await read_json_request(request)
|
|
except ValueError as exc:
|
|
return JSONResponse({"error": str(exc)}, status_code=400)
|
|
|
|
template_state = payload.get("template_state")
|
|
if not isinstance(template_state, dict):
|
|
return JSONResponse({"error": "template_state must be an object"}, status_code=400)
|
|
|
|
card = load_card(card_id)
|
|
if card is None:
|
|
return JSONResponse({"error": "card not found"}, status_code=404)
|
|
|
|
if str(card.get("kind", "")) != "text":
|
|
return JSONResponse({"error": "only text cards support template_state"}, status_code=400)
|
|
|
|
card["template_state"] = template_state
|
|
card["updated_at"] = datetime.now(timezone.utc).isoformat()
|
|
persisted = write_card(card)
|
|
if persisted is None:
|
|
return JSONResponse({"error": "failed to update card state"}, status_code=500)
|
|
await runtime.publish_cards_changed(persisted.get("chat_id"))
|
|
return JSONResponse({"status": "ok", "card": persisted})
|