123 lines
4.2 KiB
Python
123 lines
4.2 KiB
Python
from typing import Annotated
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.auth import get_current_admin, get_current_user, get_password_hash
|
|
from app.database import get_db
|
|
from app.models.user import User, UserRole
|
|
from app.schemas import AdminUserCreate, UserResponse, UserUpdate
|
|
from app.services.user_cleanup import cleanup_user_files
|
|
|
|
router = APIRouter(prefix="/api/users", tags=["users"])
|
|
|
|
|
|
def _count_admins(db: Session) -> int:
|
|
return db.query(User).filter(User.role == UserRole.admin, User.is_active == True).count()
|
|
|
|
|
|
@router.get("", response_model=list[UserResponse])
|
|
def list_users(
|
|
db: Annotated[Session, Depends(get_db)],
|
|
_: Annotated[User, Depends(get_current_admin)],
|
|
):
|
|
return db.query(User).order_by(User.created_at).all()
|
|
|
|
|
|
@router.post("", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
|
|
def create_user(
|
|
user_data: AdminUserCreate,
|
|
db: Annotated[Session, Depends(get_db)],
|
|
_: Annotated[User, Depends(get_current_admin)],
|
|
):
|
|
from app.auth import get_user_by_email, get_user_by_username
|
|
|
|
if get_user_by_email(db, user_data.email):
|
|
raise HTTPException(status_code=400, detail="Email already registered")
|
|
if get_user_by_username(db, user_data.username):
|
|
raise HTTPException(status_code=400, detail="Username already taken")
|
|
|
|
user = User(
|
|
email=user_data.email,
|
|
username=user_data.username,
|
|
hashed_password=get_password_hash(user_data.password),
|
|
role=user_data.role,
|
|
is_active=True,
|
|
)
|
|
db.add(user)
|
|
db.commit()
|
|
db.refresh(user)
|
|
return user
|
|
|
|
|
|
@router.patch("/{user_id}", response_model=UserResponse)
|
|
def update_user(
|
|
user_id: int,
|
|
update: UserUpdate,
|
|
db: Annotated[Session, Depends(get_db)],
|
|
current_user: Annotated[User, Depends(get_current_admin)],
|
|
):
|
|
from app.auth import get_user_by_email
|
|
|
|
user = db.query(User).filter(User.id == user_id).first()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
|
|
if user.id == current_user.id:
|
|
if update.role is not None and update.role != UserRole.admin:
|
|
raise HTTPException(status_code=400, detail="Cannot demote yourself")
|
|
if update.is_active is False:
|
|
raise HTTPException(status_code=400, detail="Cannot deactivate yourself")
|
|
|
|
if update.role is not None and update.role != UserRole.admin and user.role == UserRole.admin:
|
|
if _count_admins(db) <= 1:
|
|
raise HTTPException(status_code=400, detail="Cannot demote the last admin")
|
|
|
|
if update.is_active is False and user.role == UserRole.admin:
|
|
if _count_admins(db) <= 1:
|
|
raise HTTPException(status_code=400, detail="Cannot deactivate the last admin")
|
|
|
|
if update.email is not None and update.email != user.email:
|
|
if get_user_by_email(db, update.email):
|
|
raise HTTPException(status_code=400, detail="Email already registered")
|
|
user.email = update.email
|
|
|
|
if update.username is not None and update.username != user.username:
|
|
from app.auth import get_user_by_username
|
|
|
|
if get_user_by_username(db, update.username):
|
|
raise HTTPException(status_code=400, detail="Username already taken")
|
|
user.username = update.username
|
|
|
|
if update.role is not None:
|
|
user.role = update.role
|
|
if update.is_active is not None:
|
|
user.is_active = update.is_active
|
|
if update.password:
|
|
user.hashed_password = get_password_hash(update.password)
|
|
|
|
db.commit()
|
|
db.refresh(user)
|
|
return user
|
|
|
|
|
|
@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
def delete_user(
|
|
user_id: int,
|
|
db: Annotated[Session, Depends(get_db)],
|
|
current_user: Annotated[User, Depends(get_current_admin)],
|
|
):
|
|
user = db.query(User).filter(User.id == user_id).first()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
|
|
if user.id == current_user.id:
|
|
raise HTTPException(status_code=400, detail="Cannot delete yourself")
|
|
|
|
if user.role == UserRole.admin and _count_admins(db) <= 1:
|
|
raise HTTPException(status_code=400, detail="Cannot delete the last admin")
|
|
|
|
cleanup_user_files(db, user)
|
|
db.delete(user)
|
|
db.commit()
|