Spaces:
Runtime error
Runtime error
| from fastapi import APIRouter, Depends, HTTPException, Request, status | |
| from pydantic import ValidationError | |
| from sqlalchemy import select | |
| from sqlalchemy.ext.asyncio import AsyncSession | |
| from api.deps import get_admin_user | |
| from core.database import get_db | |
| from core.models import User | |
| from core.schemas import MessageResponse, UserCreateRequest, UserOut, UserUpdateRequest | |
| from core.security import hash_password | |
| router = APIRouter(tags=["admin"]) | |
| async def list_users( | |
| _: User = Depends(get_admin_user), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| stmt = select(User).order_by(User.created_at.asc()) | |
| rows = (await db.scalars(stmt)).all() | |
| users: list[UserOut] = [] | |
| for row in rows: | |
| try: | |
| users.append( | |
| UserOut( | |
| id=row.id, | |
| email=row.email, | |
| role=row.role, | |
| is_active=row.is_active, | |
| created_at=row.created_at, | |
| ) | |
| ) | |
| except ValidationError: | |
| # Skip malformed legacy rows so admin endpoints remain available. | |
| continue | |
| return users | |
| async def create_user( | |
| payload: UserCreateRequest, | |
| _: User = Depends(get_admin_user), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| existing = await db.scalar(select(User).where(User.email == payload.email.lower())) | |
| if existing: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail="User already exists", | |
| ) | |
| user = User( | |
| email=payload.email.lower(), | |
| password_hash=hash_password(payload.password), | |
| role="user", | |
| is_active=True, | |
| ) | |
| db.add(user) | |
| await db.commit() | |
| return MessageResponse(message=f"User {user.email} created") | |
| async def update_user( | |
| user_id: str, | |
| payload: UserUpdateRequest, | |
| _: User = Depends(get_admin_user), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| user = await db.get(User, user_id) | |
| if not user: | |
| raise HTTPException(status_code=404, detail="User not found") | |
| if payload.email: | |
| conflict = await db.scalar( | |
| select(User).where(User.email == payload.email.lower(), User.id != user.id) | |
| ) | |
| if conflict: | |
| raise HTTPException(status_code=400, detail="Email already in use") | |
| user.email = payload.email.lower() | |
| if payload.password: | |
| user.password_hash = hash_password(payload.password) | |
| if not payload.email and not payload.password: | |
| raise HTTPException(status_code=400, detail="No changes provided") | |
| await db.commit() | |
| return MessageResponse(message="User updated") | |
| async def delete_user( | |
| user_id: str, | |
| current_admin: User = Depends(get_admin_user), | |
| db: AsyncSession = Depends(get_db), | |
| ): | |
| if str(current_admin.id) == user_id: | |
| raise HTTPException(status_code=400, detail="Cannot delete your own account") | |
| user = await db.get(User, user_id) | |
| if not user: | |
| raise HTTPException(status_code=404, detail="User not found") | |
| await db.delete(user) | |
| await db.commit() | |
| return MessageResponse(message="User deleted") | |