"""FlowDeck — Board : import_. 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, HTTPException, Request from app.services.automations import fire_event from ._common import _create_page_from_markdown logger = logging.getLogger(__name__) router = APIRouter(tags=["board"], prefix="/board") @router.post("/api/pages/import") async def import_page(request: Request): """v5.4.0: import markdown text as a new page (blocks) in the workspace.""" try: body = await request.json() except Exception: raise HTTPException(400, "Invalid JSON body") from None markdown = body.get("markdown", "") title = body.get("title", "") if not markdown and not body.get("csv"): raise HTTPException(400, "markdown field required") if not markdown.strip(): raise HTTPException(400, "markdown is empty") page_id = await _create_page_from_markdown(request, markdown, title) await fire_event("page.created", {"page_id": page_id, "title": title or "Import", "workspace": ""}) return {"status": "ok", "id": page_id} @router.post("/api/pages/import/file") async def import_file(request: Request): """v5.4.0: import an uploaded .md file (or a Notion export .zip containing markdown pages) into the workspace. Returns the created page ids.""" import io as _io import zipfile form = await request.form() upload = form.get("file") if upload is None or not hasattr(upload, "filename"): raise HTTPException(400, "file field required") filename = (upload.filename or "import.md").replace("\\", "/").rsplit("/", 1)[-1] data = await upload.read() created_ids = [] if filename.lower().endswith(".zip"): try: zf = zipfile.ZipFile(_io.BytesIO(data)) except zipfile.BadZipFile: raise HTTPException(400, "Invalid zip archive") from None md_entries = sorted( (n for n in zf.namelist() if n.lower().endswith((".md", ".markdown"))), key=lambda n: (n.count("/"), n.lower()), ) if not md_entries: raise HTTPException(400, "No .md files found in archive") for name in md_entries: raw = zf.read(name).decode("utf-8", errors="replace") title = name.replace("\\", "/").rsplit("/", 1)[-1][:-3] try: created_ids.append(await _create_page_from_markdown(request, raw, title)) except Exception as exc: # noqa: BLE001 - keep importing the rest logger.warning("import failed for %s: %s", name, exc) else: try: raw = data.decode("utf-8") except UnicodeDecodeError: raise HTTPException(400, "Only text/markdown files are supported") from None title = filename.replace(".md", "").replace(".markdown", "").replace(".txt", "") created_ids.append(await _create_page_from_markdown(request, raw, title)) if not created_ids: raise HTTPException(422, "No pages could be imported") return {"status": "ok", "ids": created_ids, "count": len(created_ids)}