From 370b6009164bfa857f2d003189fd489822f9c800 Mon Sep 17 00:00:00 2001 From: jessikitty Date: Mon, 26 Jan 2026 21:56:52 +1100 Subject: [PATCH] Add user management endpoints --- backend/app/api/v1/users.py | 114 ++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 backend/app/api/v1/users.py diff --git a/backend/app/api/v1/users.py b/backend/app/api/v1/users.py new file mode 100644 index 0000000..6d3b0f4 --- /dev/null +++ b/backend/app/api/v1/users.py @@ -0,0 +1,114 @@ +"""User management endpoints.""" +from fastapi import APIRouter, Depends, HTTPException, status +from sqlalchemy.orm import Session +from typing import List + +from app.core.database import get_db +from app.models.user import User +from app.schemas.user import UserResponse, UserUpdate +from app.api.v1.auth import get_current_user + +router = APIRouter() + +@router.get("/", response_model=List[UserResponse]) +async def list_users( + skip: int = 0, + limit: int = 100, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """List all users (admin only).""" + if not current_user.is_admin: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Not enough permissions" + ) + + users = db.query(User).offset(skip).limit(limit).all() + return users + +@router.get("/{user_id}", response_model=UserResponse) +async def get_user( + user_id: int, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """Get user by ID.""" + # Users can view their own profile, admins can view any profile + if user_id != current_user.id and not current_user.is_admin: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Not enough permissions" + ) + + user = db.query(User).filter(User.id == user_id).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="User not found" + ) + + return user + +@router.put("/{user_id}", response_model=UserResponse) +async def update_user( + user_id: int, + user_update: UserUpdate, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """Update user information.""" + # Users can update their own profile, admins can update any profile + if user_id != current_user.id and not current_user.is_admin: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Not enough permissions" + ) + + user = db.query(User).filter(User.id == user_id).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="User not found" + ) + + # Update fields if provided + if user_update.email is not None: + user.email = user_update.email + if user_update.full_name is not None: + user.full_name = user_update.full_name + if user_update.password is not None: + from app.core.security import get_password_hash + user.hashed_password = get_password_hash(user_update.password) + if user_update.is_active is not None and current_user.is_admin: + user.is_active = user_update.is_active + + db.commit() + db.refresh(user) + + return user + +@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT) +async def delete_user( + user_id: int, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """Delete user (admin only).""" + if not current_user.is_admin: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Not enough permissions" + ) + + user = db.query(User).filter(User.id == user_id).first() + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="User not found" + ) + + db.delete(user) + db.commit() + + return None