"""User management router (admin only).""" import uuid from fastapi import APIRouter, Depends, status from sqlalchemy.orm import Session from app.database import get_db from app.dependencies.auth import require_role from app.domain.unit_of_work import UnitOfWork from app.models.user import User from app.dependencies.auth import get_current_user from app.schemas.user import UserCreate, UserUpdate, UserOut, UserPreferencesUpdate from app.services.audit_service import log_action from app.services.user_service import ( create_user, get_user_or_raise, list_users, update_user, ) router = APIRouter(prefix="/users", tags=["users"]) # --------------------------------------------------------------------------- # PATCH /users/me/preferences — update current user preferences # --------------------------------------------------------------------------- @router.patch("/me/preferences", response_model=UserOut) def update_my_preferences( payload: UserPreferencesUpdate, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """Update the current user's notification preferences, Jira account ID and Jira API token. Send ``jira_api_token: ""`` to clear a previously stored token. The token is never returned in any response. """ update_data = payload.model_dump(exclude_unset=True) for field, value in update_data.items(): if field in ("jira_api_token", "jira_email"): # Empty string means "clear the value" setattr(current_user, field, value if value else None) else: setattr(current_user, field, value) db.commit() db.refresh(current_user) return current_user # --------------------------------------------------------------------------- # GET /users/me — get current user's own profile # --------------------------------------------------------------------------- @router.get("/me", response_model=UserOut) def get_me( current_user: User = Depends(get_current_user), ): """Return the currently authenticated user's profile.""" return current_user # --------------------------------------------------------------------------- # GET /users — list all users # --------------------------------------------------------------------------- @router.get("", response_model=list[UserOut]) def list_users_route( db: Session = Depends(get_db), current_user: User = Depends(require_role("admin")), ): """Return a list of all users. **Requires admin role.**""" return list_users(db) # --------------------------------------------------------------------------- # POST /users — create a new user # --------------------------------------------------------------------------- @router.post("", response_model=UserOut, status_code=status.HTTP_201_CREATED) def create_user_route( payload: UserCreate, db: Session = Depends(get_db), current_user: User = Depends(require_role("admin")), ): """Create a new user. **Requires admin role.**""" with UnitOfWork(db) as uow: user = create_user( db, username=payload.username, email=payload.email, password=payload.password, role=payload.role, ) log_action( db, user_id=current_user.id, action="create_user", entity_type="user", entity_id=user.id, details={"username": user.username, "role": user.role}, ) uow.commit() db.refresh(user) return user # --------------------------------------------------------------------------- # GET /users/{id} — get a single user # --------------------------------------------------------------------------- @router.get("/{user_id}", response_model=UserOut) def get_user( user_id: uuid.UUID, db: Session = Depends(get_db), current_user: User = Depends(require_role("admin")), ): """Return a single user by ID. **Requires admin role.**""" return get_user_or_raise(db, user_id) # --------------------------------------------------------------------------- # PATCH /users/{id} — update a user # --------------------------------------------------------------------------- @router.patch("/{user_id}", response_model=UserOut) def update_user_route( user_id: uuid.UUID, payload: UserUpdate, db: Session = Depends(get_db), current_user: User = Depends(require_role("admin")), ): """Update one or more fields of an existing user. **Requires admin role.**""" update_data = payload.model_dump(exclude_unset=True) with UnitOfWork(db) as uow: user = update_user(db, user_id, **update_data) log_action( db, user_id=current_user.id, action="update_user", entity_type="user", entity_id=user.id, details={"updated_fields": list(update_data.keys())}, ) uow.commit() db.refresh(user) return user