"""FlowDeck — Dashboard : account_api. Découpe A28 de l'ancien app/routers/dashboard.py (2 735 lignes, 63 routes) — un module par concern, contrat inchangé. """ from __future__ import annotations import logging from fastapi import APIRouter, Body, HTTPException, Request from app.db import get_conn from ._common import _require_user_id logger = logging.getLogger(__name__) router = APIRouter(tags=["dashboard"]) @router.put("/api/user/profile") def update_profile(request: Request, body: dict = Body(default={})): full_name = body.get("full_name", "").strip() uid = _require_user_id(request) with get_conn() as conn: conn.execute("UPDATE users SET full_name=? WHERE id=?", (full_name, uid)) conn.commit() return {"status": "ok"} @router.put("/api/user/password") def update_password(request: Request, body: dict = Body(default={})): from app.password_utils import hash_password, verify_password password = body.get("password", "").strip() if len(password) < 6: return {"error": "Password must be at least 6 characters"} uid = _require_user_id(request) # A3 : le mot de passe actuel est exigé (session volée ≠ droit de changer le mdp). current = body.get("current_password", "") with get_conn() as conn: row = conn.execute("SELECT password_hash FROM users WHERE id=?", (uid,)).fetchone() if not row or not verify_password(current, row["password_hash"]): raise HTTPException(403, "Current password is incorrect") conn.execute("UPDATE users SET password_hash=? WHERE id=?", (hash_password(password), uid)) conn.commit() return {"status": "ok"} @router.post("/api/user/token") def generate_token(request: Request): import secrets uid = _require_user_id(request) token = secrets.token_hex(32) with get_conn() as conn: conn.execute( "INSERT OR REPLACE INTO user_tokens (gitea_user_id, gitea_token, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP)", (uid, token), ) conn.commit() return {"token": f"fd_{token}"} @router.delete("/api/user/forge/{provider}") def disconnect_forge(request: Request, provider: str): uid = _require_user_id(request) with get_conn() as conn: conn.execute( "DELETE FROM user_oauth_tokens WHERE user_id=? AND provider=?", (uid, provider) ) conn.commit() return {"status": "ok"}