from __future__ import annotations import time import uuid from fastapi import APIRouter, Depends, Request, Response from sqlalchemy import select from sqlalchemy.orm import Session from app.api.deps import get_current_user, get_db, require_operations_manager from app.core.config import get_settings from app.core.security import SessionPayload, create_session_token, read_session_token from app.models.user import User from app.schemas import CurrentUser, DemoLoginRequest from app.seed_loader import reset_and_seed from app.services.audit import record_audit_event router = APIRouter(prefix="/api/v1/demo", tags=["demo"]) settings = get_settings() @router.post("/login", response_model=CurrentUser) def demo_login( body: DemoLoginRequest, response: Response, db: Session = Depends(get_db) ) -> CurrentUser: public_ref = "USR-OPS" if body.role == "operations_manager" else "USR-EMP" user = db.scalar(select(User).where(User.public_ref == public_ref)) if user is None: raise LookupError("Demo users are missing; run the seed loader first.") token = create_session_token( SessionPayload( user_id=str(user.id), public_ref=user.public_ref, role=user.role, display_name=user.display_name, issued_at=int(time.time()), ) ) response.set_cookie( settings.session_cookie_name, token, httponly=True, samesite="lax", secure=settings.session_cookie_secure, max_age=settings.session_ttl_seconds, ) record_audit_event( db, actor_type="user", actor_id=user.id, actor_label=user.display_name, action="demo_login", entity_type="user", entity_id=user.id, ) db.commit() return CurrentUser(public_ref=user.public_ref, display_name=user.display_name, role=body.role) @router.get("/session", response_model=CurrentUser) def get_session( response: Response, user: CurrentUser = Depends(get_current_user) ) -> CurrentUser: # Never let the browser (or an intermediary) cache an authentication check — a stale # cached 200 here would keep showing a logged-out browser as authenticated. response.headers["Cache-Control"] = "no-store" return user @router.post("/logout") def demo_logout(request: Request, response: Response, db: Session = Depends(get_db)) -> dict: token = request.cookies.get(settings.session_cookie_name) payload = read_session_token(token) if token else None if payload is not None: record_audit_event( db, actor_type="user", actor_id=uuid.UUID(payload.user_id), actor_label=payload.display_name, action="demo_logout", entity_type="user", ) db.commit() response.delete_cookie(settings.session_cookie_name) return {"status": "logged_out"} @router.post("/reset") def demo_reset( response: Response, db: Session = Depends(get_db), user: CurrentUser = Depends(require_operations_manager), ) -> dict: result = reset_and_seed(db) record_audit_event( db, actor_type="user", actor_label=user.display_name, action="demo_reset", entity_type="system", metadata={"counts": result.counts}, ) db.commit() response.delete_cookie(settings.session_cookie_name) return {"status": "reset", "counts": result.counts}