"""Attribution for quote_events.actor — the VERIFIED user, not the raw token. Historically this stored the bearer token string verbatim (unverifiable and a token leak into the database). All routes that use it now sit behind the global JWT dependency, so the token is resolved to the authenticated user and the display name is recorded instead. """ from fastapi import Request from app.auth import get_optional_user async def get_actor(request: Request) -> str | None: """Resolve the caller's display name from the Casdoor Bearer token. Uses its own session (get_optional_user default) — same reason as get_current_user: quote routers open explicit db.begin() blocks. """ ctx = await get_optional_user(request) if ctx is not None: return ctx.display_name # Dev-mode header fallback (only active when DEV_LOGIN_ENABLED) carries # the name in X-User-Name / X-User-Name-B64 — keep attribution useful. name = request.headers.get("x-user-name") import base64 b64 = request.headers.get("x-user-name-b64") if b64: try: name = base64.b64decode(b64.encode()).decode("utf-8") except Exception: pass return name