66 lines
2.8 KiB
Python
66 lines
2.8 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from app.core.db import get_db
|
|
from app.core.deps import require_roles
|
|
from app.core.security import hash_password
|
|
from app.models.models import User
|
|
from app.schemas.user import UserCreate, UserOut, UserUpdate
|
|
from app.services.audit import write_audit_log
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("", response_model=list[UserOut])
|
|
async def list_users(admin: User = Depends(require_roles("admin")), db: AsyncSession = Depends(get_db)) -> list[UserOut]:
|
|
users = (await db.scalars(select(User).order_by(User.id.asc()))).all()
|
|
_ = admin
|
|
return [UserOut.model_validate(user) for user in users]
|
|
|
|
|
|
@router.post("", response_model=UserOut, status_code=status.HTTP_201_CREATED)
|
|
async def create_user(payload: UserCreate, admin: User = Depends(require_roles("admin")), db: AsyncSession = Depends(get_db)) -> UserOut:
|
|
exists = await db.scalar(select(User).where(User.email == payload.email))
|
|
if exists:
|
|
raise HTTPException(status_code=409, detail="Email already exists")
|
|
user = User(email=payload.email, password_hash=hash_password(payload.password), role=payload.role)
|
|
db.add(user)
|
|
await db.commit()
|
|
await db.refresh(user)
|
|
await write_audit_log(db, "admin.user.create", admin.id, {"created_user_id": user.id})
|
|
return UserOut.model_validate(user)
|
|
|
|
|
|
@router.put("/{user_id}", response_model=UserOut)
|
|
async def update_user(
|
|
user_id: int,
|
|
payload: UserUpdate,
|
|
admin: User = Depends(require_roles("admin")),
|
|
db: AsyncSession = Depends(get_db),
|
|
) -> UserOut:
|
|
user = await db.scalar(select(User).where(User.id == user_id))
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
update_data = payload.model_dump(exclude_unset=True)
|
|
if "password" in update_data and update_data["password"]:
|
|
user.password_hash = hash_password(update_data.pop("password"))
|
|
for key, value in update_data.items():
|
|
setattr(user, key, value)
|
|
await db.commit()
|
|
await db.refresh(user)
|
|
await write_audit_log(db, "admin.user.update", admin.id, {"updated_user_id": user.id})
|
|
return UserOut.model_validate(user)
|
|
|
|
|
|
@router.delete("/{user_id}")
|
|
async def delete_user(user_id: int, admin: User = Depends(require_roles("admin")), db: AsyncSession = Depends(get_db)) -> dict:
|
|
if user_id == admin.id:
|
|
raise HTTPException(status_code=400, detail="Cannot delete yourself")
|
|
user = await db.scalar(select(User).where(User.id == user_id))
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
await db.delete(user)
|
|
await db.commit()
|
|
await write_audit_log(db, "admin.user.delete", admin.id, {"deleted_user_id": user_id})
|
|
return {"status": "deleted"}
|