"""Users management router""" from fastapi import APIRouter, Depends, HTTPException, status, Query from typing import List, Optional from bson import ObjectId from app.models.user import User, UserUpdate, UserRole from app.routers.auth import get_current_user from app.utils.database import get_database from app.utils.security import hash_password from datetime import datetime router = APIRouter(prefix="/users", tags=["Users"]) def require_admin(current_user: User = Depends(get_current_user)) -> User: """Require admin role""" if current_user.role not in [UserRole.SYSTEM_ADMIN, UserRole.GROUP_ADMIN]: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not enough permissions" ) return current_user @router.get("/", response_model=List[User]) async def get_users( skip: int = Query(0, ge=0), limit: int = Query(10, ge=1, le=100), current_user: User = Depends(require_admin) ): """Get all users (admin only)""" db = get_database() users = await db.users.find().skip(skip).limit(limit).to_list(limit) return [User(**user) for user in users] @router.get("/{user_id}", response_model=User) async def get_user(user_id: str, current_user: User = Depends(get_current_user)): """Get user by ID""" # Users can only view their own profile unless they're admin if str(current_user.id) != user_id and current_user.role not in [UserRole.SYSTEM_ADMIN, UserRole.GROUP_ADMIN]: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not enough permissions" ) db = get_database() try: user = await db.users.find_one({"_id": ObjectId(user_id)}) if not user: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="User not found" ) return User(**user) except Exception as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid user ID" ) @router.put("/{user_id}", response_model=User) async def update_user( user_id: str, user_update: UserUpdate, current_user: User = Depends(get_current_user) ): """Update user""" # Users can only update their own profile unless they're admin if str(current_user.id) != user_id and current_user.role not in [UserRole.SYSTEM_ADMIN, UserRole.GROUP_ADMIN]: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not enough permissions" ) # Only system admin can change roles if user_update.role and current_user.role != UserRole.SYSTEM_ADMIN: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Only system admin can change user roles" ) db = get_database() try: # Prepare update data update_data = user_update.model_dump(exclude_unset=True) # Hash password if provided if "password" in update_data: update_data["hashed_password"] = hash_password(update_data.pop("password")) # Update timestamp update_data["updated_at"] = datetime.utcnow() # Update user result = await db.users.update_one( {"_id": ObjectId(user_id)}, {"$set": update_data} ) if result.modified_count == 0: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="User not found" ) # Return updated user user = await db.users.find_one({"_id": ObjectId(user_id)}) return User(**user) except Exception as e: if isinstance(e, HTTPException): raise raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=str(e) ) @router.delete("/{user_id}") async def delete_user( user_id: str, current_user: User = Depends(require_admin) ): """Delete user (admin only)""" # Prevent self-deletion if str(current_user.id) == user_id: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot delete your own account" ) db = get_database() try: result = await db.users.delete_one({"_id": ObjectId(user_id)}) if result.deleted_count == 0: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="User not found" ) return {"message": "User deleted successfully"} except Exception as e: if isinstance(e, HTTPException): raise raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid user ID" )