# ============================================================================= # 企微IT智能服务台 — 管理员用户服务 # ============================================================================= # 说明:管理员用户的 CRUD 操作服务 # ============================================================================= import secrets import logging from datetime import datetime from typing import List, Optional, Tuple import bcrypt from sqlalchemy import select, func from sqlalchemy.ext.asyncio import AsyncSession from app.models.agent import Agent from app.utils.error_codes import ErrorCode from app.utils.response import AppException logger = logging.getLogger(__name__) class AdminUserService: """管理员用户服务。 提供管理员用户的增删改查、密码验证等功能。 """ def __init__(self, db: AsyncSession): """初始化服务。 Args: db: 数据库会话 """ self.db = db async def get_user_by_user_id(self, user_id: str) -> Optional[Agent]: """根据 user_id 查询管理员用户。 Args: user_id: 企微用户ID Returns: Optional[Agent]: 管理员用户,不存在返回 None """ stmt = select(Agent).where( Agent.user_id == user_id, Agent.role.in_(["admin", "super_admin"]), ) result = await self.db.execute(stmt) return result.scalars().first() async def get_user_by_id(self, id: str) -> Optional[Agent]: """根据 ID 查询管理员用户。 Args: id: 用户ID Returns: Optional[Agent]: 管理员用户,不存在返回 None """ stmt = select(Agent).where( Agent.id == id, Agent.role.in_(["admin", "super_admin"]), ) result = await self.db.execute(stmt) return result.scalars().first() async def list_admin_users( self, page: int = 1, page_size: int = 20, is_active: Optional[bool] = None, ) -> Tuple[List[Agent], int]: """查询管理员用户列表。 Args: page: 页码(从1开始) page_size: 每页数量 is_active: 按激活状态过滤 Returns: Tuple[List[Agent], int]: (用户列表, 总数) """ # 构建查询 stmt = select(Agent).where(Agent.role.in_(["admin", "super_admin"])) if is_active is not None: stmt = stmt.where(Agent.status == ("online" if is_active else "offline")) # 统计总数 count_stmt = select(func.count()).select_from(stmt.subquery()) total_result = await self.db.execute(count_stmt) total = total_result.scalar() or 0 # 分页查询 stmt = stmt.order_by(Agent.created_at.desc()) stmt = stmt.offset((page - 1) * page_size).limit(page_size) result = await self.db.execute(stmt) items = list(result.scalars().all()) return items, total async def create_admin_user( self, user_id: str, name: str, role: str = "admin", password: Optional[str] = None, ) -> Agent: """创建管理员用户。 Args: user_id: 企微用户ID name: 姓名 role: 角色(admin/super_admin) password: 初始密码(可选,不传则生成随机密码) Returns: Agent: 创建的用户 Raises: AppException: 用户已存在 """ # 检查是否已存在 existing = await self.get_user_by_user_id(user_id) if existing: raise AppException(ErrorCode.INVALID_PARAMETER, f"用户 {user_id} 已存在") # 生成密码 if not password: password = secrets.token_urlsafe(12) # 生成随机密码 # 密码哈希 password_hash = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()).decode("utf-8") # 创建用户 agent = Agent( user_id=user_id, name=name, role=role, status="offline", password_hash=password_hash, current_load=0, max_load=5, ) self.db.add(agent) await self.db.flush() logger.info(f"创建管理员用户: user_id={user_id}, role={role}") return agent async def update_admin_user( self, id: str, name: Optional[str] = None, role: Optional[str] = None, is_active: Optional[bool] = None, ) -> Agent: """更新管理员用户。 Args: id: 用户ID name: 姓名(可选) role: 角色(可选) is_active: 是否激活(可选) Returns: Agent: 更新后的用户 Raises: AppException: 用户不存在 """ agent = await self.get_user_by_id(id) if not agent: raise AppException(ErrorCode.NOT_FOUND, "用户不存在") if name is not None: agent.name = name if role is not None: agent.role = role if is_active is not None: agent.status = "online" if is_active else "offline" agent.updated_at = datetime.now() self.db.add(agent) await self.db.flush() logger.info(f"更新管理员用户: id={id}") return agent async def delete_admin_user(self, id: str) -> bool: """删除管理员用户。 Args: id: 用户ID Returns: bool: 是否删除成功 Raises: AppException: 用户不存在或无法删除超级管理员 """ agent = await self.get_user_by_id(id) if not agent: raise AppException(ErrorCode.NOT_FOUND, "用户不存在") # 不允许删除超级管理员 if agent.role == "super_admin": raise AppException(ErrorCode.FORBIDDEN, "无法删除超级管理员") await self.db.delete(agent) await self.db.flush() logger.info(f"删除管理员用户: id={id}") return True async def reset_password(self, id: str, new_password: str) -> Agent: """重置密码。 Args: id: 用户ID new_password: 新密码 Returns: Agent: 更新后的用户 Raises: AppException: 用户不存在 """ agent = await self.get_user_by_id(id) if not agent: raise AppException(ErrorCode.NOT_FOUND, "用户不存在") # 密码哈希 agent.password_hash = bcrypt.hashpw(new_password.encode("utf-8"), bcrypt.gensalt()).decode("utf-8") agent.updated_at = datetime.now() self.db.add(agent) await self.db.flush() logger.info(f"重置密码: id={id}") return agent async def verify_password(self, user_id: str, password: str) -> Optional[Agent]: """验证密码。 Args: user_id: 企微用户ID password: 密码 Returns: Optional[Agent]: 验证成功返回用户,否则返回 None """ agent = await self.get_user_by_user_id(user_id) if not agent: return None # 检查密码 if not agent.password_hash: return None if not bcrypt.checkpw(password.encode("utf-8"), agent.password_hash.encode("utf-8")): return None return agent async def init_super_admin(db: AsyncSession) -> Optional[Agent]: """初始化超级管理员。 从环境变量读取配置,创建超级管理员用户(如果不存在)。 环境变量: ADMIN_USERNAME: 超级管理员用户名(必填) ADMIN_PASSWORD: 超级管理员密码(必填) ADMIN_NAME: 超级管理员姓名(可选,默认"超级管理员") Args: db: 数据库会话 Returns: Optional[Agent]: 创建/已有的超级管理员用户 """ import os admin_username = os.getenv("ADMIN_USERNAME") admin_password = os.getenv("ADMIN_PASSWORD") admin_name = os.getenv("ADMIN_NAME", "超级管理员") if not admin_username or not admin_password: logger.info("未配置超级管理员,跳过初始化") return None service = AdminUserService(db) # 检查是否已存在 existing = await service.get_user_by_user_id(admin_username) if existing: logger.info(f"超级管理员已存在: user_id={admin_username}") return existing # 创建超级管理员 agent = await service.create_admin_user( user_id=admin_username, name=admin_name, role="super_admin", password=admin_password, ) await db.commit() logger.info(f"超级管理员初始化成功: user_id={admin_username}") return agent