"""FlowDeck — Board : synced. Découpe A28 de l'ancien app/routers/board.py (2 101 lignes, 53 routes) — un module par concern, contrat inchangé. """ from __future__ import annotations import logging from fastapi import APIRouter, Body, HTTPException, Query, Request from app.auth.session import SessionManager logger = logging.getLogger(__name__) router = APIRouter(tags=["board"], prefix="/board") # ═══════════════ v5.14.0: Synced Blocks ─═══════════════════ # These routes MUST be registered before the catch-all /{owner}/{repo} below. @router.get("/api/synced-blocks") def list_synced_blocks_api(request: Request, workspace: str = Query(default="")): """List synced blocks for a workspace.""" user = SessionManager.decode_session(request.cookies.get("flowdeck_session", "")) from app.services.synced_blocks import list_synced_blocks return {"synced_blocks": list_synced_blocks(workspace or user.get("login", ""))} @router.post("/api/synced-blocks") def create_synced_block_api(request: Request, body: dict = Body(...)): """Create a new synced block.""" user = SessionManager.decode_session(request.cookies.get("flowdeck_session", "")) from app.services.synced_blocks import create_synced_block sid = create_synced_block( workspace=body.get("workspace", ""), title=body.get("title", "Synced block"), content=body.get("content", []), created_by=user.get("id"), ) return {"status": "ok", "synced_block_id": sid} @router.put("/api/synced-blocks/{sid}") async def update_synced_block_api(request: Request, sid: int): """Update a synced block's content (propagates to all pages).""" try: body = await request.json() except Exception: raise HTTPException(400, "Invalid JSON body") from None from app.services.synced_blocks import ( get_synced_block, page_ids_for_synced, sync_synced_blocks_in_page, update_synced_block, ) sb = get_synced_block(sid) if not sb: raise HTTPException(404, "Synced block not found") update_synced_block(sid, body.get("title", sb["title"]), body.get("content", [])) # v6.5.0: rewrite every referencing page's stored content first (DB row # content pages included), THEN push the realtime update so open rooms # reload the fresh content from the DB. for pid in page_ids_for_synced(sid): sync_synced_blocks_in_page(pid) from app.services.realtime_server import manager await manager._propagate_synced(sid) return {"status": "ok"} @router.delete("/api/synced-blocks/{sid}") async def delete_synced_block_api(request: Request, sid: int): """Delete a synced block.""" from app.services.synced_blocks import ( delete_synced_block, get_synced_block, mark_synced_block_deleted, page_ids_for_synced, ) sb = get_synced_block(sid) if not sb: raise HTTPException(404, "Synced block not found") # v6.5.0: collect referencing pages BEFORE the FK cascade wipes the # refs, rewrite their stored content (deleted state), then broadcast. pids = page_ids_for_synced(sid) delete_synced_block(sid) mark_synced_block_deleted(sid, pids) from app.services.realtime_server import manager await manager._broadcast_synced_to(pids, sid) return {"status": "ok"} @router.get("/api/synced-blocks/{sid}") def get_synced_block_api(sid: int): """Get a synced block by id.""" from app.services.synced_blocks import get_synced_block sb = get_synced_block(sid) if not sb: raise HTTPException(404, "Synced block not found") return dict(sb) @router.post("/api/pages/{page_id}/synced") def add_synced_to_page(request: Request, page_id: int, body: dict = Body(...)): """Add a synced block reference to a page.""" from app.services.synced_blocks import add_page_synced, get_synced_block sid = body.get("synced_block_id") sb = get_synced_block(sid) if not sb: raise HTTPException(404, "Synced block not found") add_page_synced(page_id, sid, body.get("block_index", 0)) return {"status": "ok", "synced_block_id": sid} @router.delete("/api/pages/{page_id}/synced/{sid}") def remove_synced_from_page(request: Request, page_id: int, sid: int): """Remove a synced block reference from a page (unsync).""" from app.services.synced_blocks import remove_page_synced remove_page_synced(page_id, sid) return {"status": "ok"} @router.get("/api/pages/{page_id}/synced") def get_page_synced_refs(request: Request, page_id: int): """Get all synced block references for a page.""" from app.services.synced_blocks import get_page_synced return {"synced_blocks": get_page_synced(page_id)} # ═══════════ Board page ═══════════