from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.core.roles import ROLE_ADMIN from app.core.security import hash_password from app.models.user import User from app.schemas.admin_user import AdminUserCreate, AdminUserUpdate DEFAULT_PAGE_SIZE = 20 MAX_PAGE_SIZE = 100 class AdminUserError(Exception): def __init__(self, message: str) -> None: self.message = message super().__init__(message) async def list_users( db: AsyncSession, *, page: int = 1, page_size: int = DEFAULT_PAGE_SIZE, ) -> tuple[list[User], int]: page_size = min(max(page_size, 1), MAX_PAGE_SIZE) page = max(page, 1) offset = (page - 1) * page_size total = await db.scalar(select(func.count()).select_from(User)) or 0 result = await db.scalars( select(User).order_by(User.id.desc()).offset(offset).limit(page_size) ) return list(result.all()), total async def create_user(db: AsyncSession, body: AdminUserCreate) -> User: existing = await db.scalar(select(User).where(User.username == body.username)) if existing is not None: raise AdminUserError("用户名已存在") if body.phone: phone_taken = await db.scalar(select(User).where(User.phone == body.phone)) if phone_taken is not None: raise AdminUserError("手机号已被使用") user = User( username=body.username, password_hash=hash_password(body.password), phone=body.phone, role_id=body.role_id, vip_end_time=body.vip_end_time, ) db.add(user) await db.flush() await db.refresh(user) return user async def update_user( db: AsyncSession, user_id: int, body: AdminUserUpdate, *, actor_id: int, ) -> User: user = await db.get(User, user_id) if user is None: raise AdminUserError("用户不存在") if body.username is not None and body.username != user.username: taken = await db.scalar(select(User).where(User.username == body.username)) if taken is not None: raise AdminUserError("用户名已存在") user.username = body.username if body.phone is not None: if body.phone != user.phone: taken = await db.scalar(select(User).where(User.phone == body.phone)) if taken is not None: raise AdminUserError("手机号已被使用") user.phone = body.phone if body.role_id is not None: if user_id == actor_id and body.role_id != ROLE_ADMIN: raise AdminUserError("不能修改自己的管理员角色") user.role_id = body.role_id if body.password: user.password_hash = hash_password(body.password) if body.clear_vip_end_time: user.vip_end_time = None elif body.vip_end_time is not None: user.vip_end_time = body.vip_end_time await db.flush() await db.refresh(user) return user async def delete_user(db: AsyncSession, user_id: int, *, actor_id: int) -> None: if user_id == actor_id: raise AdminUserError("不能删除当前登录账号") user = await db.get(User, user_id) if user is None: raise AdminUserError("用户不存在") await db.delete(user)