alpha-engine / api /admin.py
Dharambir Agrawal
HF Space server-only
fd48bc8
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"])
@router.get("/admin/users", response_model=list[UserOut])
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
@router.post("/admin/users", response_model=MessageResponse)
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")
@router.patch("/admin/users/{user_id}", response_model=MessageResponse)
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")
@router.delete("/admin/users/{user_id}", response_model=MessageResponse)
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")