fix: A21 phase 2c — 190 routes hors loop, 86 % total (v7.26.0)
FlowDeck CI / lint (push) Successful in 1m55s
FlowDeck CI / test (push) Successful in 15m23s
FlowDeck CI / docker (push) Canceled after 0s

4 passes (283 → 93 routes async sur 667 = 86 % hors loop, avant 61 %) :

A. RACINE AUTH — `get_current_user` (auth/session.py) était `async def`
   SANS aucun await (cookie decode = synchrone) ; idem ses clones :
   `agent._current_user_id/_workspace_id/_current_admin` (34 sites) et
   `sso._require_admin` (corps 0 await, 6 sites) → `def` +
   47 `await` supprimés. Piège : 3 call sites passaient par l'alias `gcu`
   (grep littéral aveugle) — 8 tests en échec → corrigés.

B. Re-scan : 19 routes devenues SANS await → `def` (agent 8, sso 5,
   web_clipper 3, projects 2, auth 1…).

C/D. 155 routes dont les seuls awaits = `request.json()` / événements :
   - try/except `body = {}` → `Body(default={})` (même tolérance)
   - try/except `raise HTTPException(400)` → `Body(...)` REQUIS
     (422 FastAPI — aucun test ne couvrait le 400)
   - forme conditionnelle `request.json() if content-type else {}`
     (54 sites) → défaut `{}` (sans corps = `{}` dans les 2 cas)
   - `await fire_*` → `run_event_sync(...)` ; imports `Body` /
     `run_event_sync` ajoutés aux routers convertis

Reste async (93, justifié) : form/upload/file (22), réseau gitea/llm/oidc,
`_json_body` (9), 2 JSON inline en argument, 1 fallback logique
(capture_frontend_error), 1 lecture conditionnelle (web_clipper), mixtes.

suite **1089/1089** · ruff OK · docs à jour
This commit is contained in:
2026-10-01 22:17:48 -04:00
parent 8d0d69e7b8
commit 45e59009c3
34 changed files with 2479 additions and 680 deletions
+5 -21
View File
@@ -19,7 +19,7 @@ import time
import unicodedata
from datetime import UTC, datetime
from fastapi import APIRouter, HTTPException, Request
from fastapi import APIRouter, Body, HTTPException, Request
from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse
from app.auth.session import SessionManager
@@ -256,12 +256,8 @@ def _check_form_rate(ip: str) -> None:
# ── Sites CRUD (session or Bearer) ─────────────────────────────────────────
@router.post("/api/v2/sites")
async def create_site(request: Request):
def create_site(request: Request, body: dict = Body(default={})):
user = _auth_user(request, require_write=True)
try:
body = await request.json()
except Exception:
body = {}
root_page_id = body.get("root_page_id")
if not root_page_id:
raise HTTPException(400, "root_page_id is required")
@@ -349,12 +345,8 @@ def get_site(site_id: int, request: Request):
@router.patch("/api/v2/sites/{site_id}")
async def update_site(site_id: int, request: Request):
def update_site(site_id: int, request: Request, body: dict = Body(default={})):
user = _auth_user(request, require_write=True)
try:
body = await request.json()
except Exception:
body = {}
with get_conn() as conn:
row = conn.execute("SELECT * FROM sites WHERE id=?", (site_id,)).fetchone()
if not row:
@@ -432,12 +424,8 @@ def list_site_pages(site_id: int, request: Request):
@router.post("/api/v2/sites/{site_id}/pages")
async def add_site_page(site_id: int, request: Request):
def add_site_page(site_id: int, request: Request, body: dict = Body(default={})):
user = _auth_user(request, require_write=True)
try:
body = await request.json()
except Exception:
body = {}
page_id = body.get("page_id")
if not page_id:
raise HTTPException(400, "page_id is required")
@@ -622,12 +610,8 @@ def get_form_config(collection_id: int, request: Request):
@router.put("/api/v2/collections/{collection_id}/form")
async def put_form_config(collection_id: int, request: Request):
def put_form_config(collection_id: int, request: Request, body: dict = Body(default={})):
user = _auth_user(request, require_write=True)
try:
body = await request.json()
except Exception:
body = {}
with get_conn() as conn:
info = _form_config(conn, collection_id)
cfg = info["config"] if isinstance(info["config"], dict) else {}