"""Profile management routes. Admin can view, create, edit user profiles and switch the active profile. """ import structlog from fastapi import APIRouter, Depends, Request from fastapi.responses import HTMLResponse, RedirectResponse from sqlmodel import Session from app.database import get_db_session from app.models.user import User from app.services.user_service import UserService from app.utils.auth import get_current_admin_user, get_active_profile_id logger = structlog.get_logger(__name__) router = APIRouter(prefix="/profiles", tags=["profiles"]) @router.get("", response_class=HTMLResponse) async def list_profiles( request: Request, session: Session = Depends(get_db_session), admin: User = Depends(get_current_admin_user), ): """List all user profiles for the admin. Args: request: The incoming HTTP request. session: Database session. admin: The authenticated admin user. Returns: Rendered profile list page. """ user_service = UserService(session) profiles = user_service.list_users(exclude_admin=True) active_profile_id = get_active_profile_id(request) templates = request.app.state.templates return templates.TemplateResponse("pages/profiles.html", { "request": request, "profiles": profiles, "active_profile_id": active_profile_id, "admin": admin, }) @router.post("/switch") async def switch_profile( request: Request, session: Session = Depends(get_db_session), admin: User = Depends(get_current_admin_user), ): """Switch the active user profile. Sets a cookie with the selected profile ID. Args: request: The incoming HTTP request. session: Database session. admin: The authenticated admin user. Returns: Redirect to the referring page with profile cookie set. """ form = await request.form() profile_id = form.get("profile_id", "") # Validate profile exists and is not an admin user_service = UserService(session) profile = user_service.get_user_by_id(int(profile_id)) if profile_id.isdigit() else None referer = request.headers.get("referer", "/") response = RedirectResponse(url=referer, status_code=303) if profile and not profile.is_admin: response.set_cookie( key="active_profile_id", value=str(profile.id), httponly=True, samesite="lax", max_age=86400, ) logger.info("profile_switched", profile_id=profile.id, name=profile.display_name) else: logger.warning("profile_switch_failed", profile_id=profile_id) return response @router.get("/{profile_id}/edit", response_class=HTMLResponse) async def edit_profile_page( profile_id: int, request: Request, session: Session = Depends(get_db_session), admin: User = Depends(get_current_admin_user), ): """Render the profile edit form. Args: profile_id: The profile ID to edit. request: The incoming HTTP request. session: Database session. admin: The authenticated admin user. Returns: Rendered profile edit page. """ user_service = UserService(session) profile = user_service.get_user_by_id(profile_id) templates = request.app.state.templates return templates.TemplateResponse("pages/profile_edit.html", { "request": request, "profile": profile, "admin": admin, }) @router.post("/{profile_id}/edit") async def update_profile( profile_id: int, request: Request, session: Session = Depends(get_db_session), admin: User = Depends(get_current_admin_user), ): """Process profile edit form submission. Args: profile_id: The profile ID to update. request: The incoming HTTP request. session: Database session. admin: The authenticated admin user. Returns: Redirect to profiles page. """ form = await request.form() user_service = UserService(session) user_service.update_user( profile_id, display_name=form.get("display_name", ""), height=form.get("height", ""), weight=form.get("weight", ""), goals=form.get("goals", ""), ) return RedirectResponse(url="/profiles", status_code=303)