"""User management router.""" from typing import Annotated from fastapi import APIRouter, Depends, HTTPException, status from pydantic import BaseModel, EmailStr from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from app.dependencies import CurrentUser from app.models.user import User router = APIRouter() # ─── Pydantic schemas ──────────────────────────────────────────────────────── class UserResponse(BaseModel): id: int username: str email: str is_active: bool model_config = {"from_attributes": True} class UserUpdate(BaseModel): email: EmailStr | None = None is_active: bool | None = None # ─── Endpoints ──────────────────────────────────────────────────────────────── @router.get("/me", response_model=UserResponse) async def get_current_user_profile( current_user: CurrentUser, ): """Get the currently authenticated user's profile.""" return current_user @router.get("/{user_id}", response_model=UserResponse) async def get_user( user_id: int, current_user: CurrentUser, db: Annotated[AsyncSession, Depends(get_db)], ): """Get a user by ID. Owners and admins can see any user; others see only their own profile.""" result = await db.execute(select(User).where(User.id == user_id)) user = result.scalar_one_or_none() if not user: raise HTTPException(status_code=404, detail="User not found") # Allow viewing own profile or if user is active (admins always allowed) if user.id != current_user.id and not current_user.is_active: raise HTTPException(status_code=403, detail="Not authorized to view this user") return user @router.patch("/{user_id}", response_model=UserResponse) async def update_user( user_id: int, user_update: UserUpdate, current_user: CurrentUser, db: Annotated[AsyncSession, Depends(get_db)], ): """Update a user. Only the owner (or an active admin) can update.""" result = await db.execute(select(User).where(User.id == user_id)) user = result.scalar_one_or_none() if not user: raise HTTPException(status_code=404, detail="User not found") if user.id != current_user.id and not current_user.is_active: raise HTTPException(status_code=403, detail="Not authorized to update this user") if user_update.email is not None: user.email = user_update.email if user_update.is_active is not None: user.is_active = user_update.is_active await db.commit() await db.refresh(user) return user @router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_user( user_id: int, current_user: CurrentUser, db: Annotated[AsyncSession, Depends(get_db)], ): """Delete a user. Only the owner (or an active admin) can delete.""" result = await db.execute(select(User).where(User.id == user_id)) user = result.scalar_one_or_none() if not user: raise HTTPException(status_code=404, detail="User not found") if user.id != current_user.id and not current_user.is_active: raise HTTPException(status_code=403, detail="Not authorized to delete this user") await db.delete(user) await db.commit()