368 lines
11 KiB
Python
368 lines
11 KiB
Python
# =============================================================================
|
|
# 企微IT智能服务台 — 管理员用户管理 API
|
|
# =============================================================================
|
|
# 说明:管理员用户的 CRUD API
|
|
# 端点:
|
|
# GET /api/admin/users — 获取管理员列表
|
|
# POST /api/admin/users — 创建管理员
|
|
# GET /api/admin/users/{id} — 获取管理员详情
|
|
# PUT /api/admin/users/{id} — 更新管理员
|
|
# DELETE /api/admin/users/{id} — 删除管理员
|
|
# POST /api/admin/users/{id}/reset-password — 重置密码
|
|
# =============================================================================
|
|
|
|
import logging
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.database import get_db
|
|
from app.dependencies import UserInfo, get_current_user, require_role
|
|
from app.schemas.admin_user import (
|
|
AdminUserCreateRequest,
|
|
AdminUserListResponse,
|
|
AdminUserResetPasswordRequest,
|
|
AdminUserResponse,
|
|
AdminUserUpdateRequest,
|
|
)
|
|
from app.services.admin_user_service import AdminUserService
|
|
from app.utils.response import AppException, success_response
|
|
from app.utils.error_codes import ErrorCode
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# 创建路由器
|
|
router = APIRouter(prefix="/admin/users", tags=["管理员用户管理"])
|
|
|
|
|
|
# =============================================================================
|
|
# 0. GET /api/admin/users/me — 获取当前登录用户信息
|
|
# =============================================================================
|
|
@router.get("/me", response_model=None)
|
|
async def get_current_admin_user(
|
|
current_user: UserInfo = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""获取当前登录的管理员用户信息。
|
|
|
|
无需额外权限,任何已登录用户都可以访问。
|
|
|
|
Args:
|
|
current_user: 当前用户
|
|
db: 数据库会话
|
|
|
|
Returns:
|
|
当前用户信息
|
|
"""
|
|
service = AdminUserService(db)
|
|
agent = await service.get_user_by_user_id(current_user.employee_id)
|
|
|
|
if not agent:
|
|
raise AppException(ErrorCode.NOT_FOUND, "用户不存在")
|
|
|
|
return success_response(data=AdminUserResponse(
|
|
id=agent.id,
|
|
user_id=agent.user_id,
|
|
name=agent.name,
|
|
role=agent.role,
|
|
is_active=agent.status == "online",
|
|
mfa_enabled=agent.mfa_enabled,
|
|
mfa_bound_at=agent.mfa_bound_at,
|
|
created_at=agent.created_at,
|
|
updated_at=agent.updated_at,
|
|
).model_dump())
|
|
|
|
|
|
# =============================================================================
|
|
# 1. GET /api/admin/users — 获取管理员列表
|
|
# =============================================================================
|
|
@router.get("", response_model=None)
|
|
async def list_admin_users(
|
|
page: int = Query(1, ge=1, description="页码"),
|
|
page_size: int = Query(20, ge=1, le=100, description="每页数量"),
|
|
is_active: Optional[bool] = Query(None, description="是否激活(true=在线,false=离线)"),
|
|
current_user: UserInfo = Depends(require_role("admin")),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""获取管理员用户列表。
|
|
|
|
需要 admin 或 super_admin 角色。
|
|
|
|
Args:
|
|
page: 页码
|
|
page_size: 每页数量
|
|
is_active: 按激活状态过滤
|
|
current_user: 当前用户
|
|
db: 数据库会话
|
|
|
|
Returns:
|
|
管理员列表
|
|
"""
|
|
service = AdminUserService(db)
|
|
items, total = await service.list_admin_users(
|
|
page=page,
|
|
page_size=page_size,
|
|
is_active=is_active,
|
|
)
|
|
|
|
# 转换为响应格式
|
|
user_responses = []
|
|
for agent in items:
|
|
user_responses.append(AdminUserResponse(
|
|
id=agent.id,
|
|
user_id=agent.user_id,
|
|
name=agent.name,
|
|
role=agent.role,
|
|
is_active=agent.status == "online",
|
|
mfa_enabled=agent.mfa_enabled,
|
|
mfa_bound_at=agent.mfa_bound_at,
|
|
created_at=agent.created_at,
|
|
updated_at=agent.updated_at,
|
|
))
|
|
|
|
return success_response(data=AdminUserListResponse(
|
|
items=user_responses,
|
|
total=total,
|
|
).model_dump())
|
|
|
|
|
|
# =============================================================================
|
|
# 2. POST /api/admin/users — 创建管理员
|
|
# =============================================================================
|
|
@router.post("", response_model=None)
|
|
async def create_admin_user(
|
|
body: AdminUserCreateRequest,
|
|
current_user: UserInfo = Depends(require_role("super_admin")),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""创建管理员用户。
|
|
|
|
需要 super_admin 角色。
|
|
|
|
Args:
|
|
body: 创建请求
|
|
current_user: 当前用户
|
|
db: 数据库会话
|
|
|
|
Returns:
|
|
创建的用户信息
|
|
"""
|
|
service = AdminUserService(db)
|
|
|
|
try:
|
|
agent = await service.create_admin_user(
|
|
user_id=body.user_id,
|
|
name=body.name,
|
|
role=body.role,
|
|
password=body.password,
|
|
)
|
|
await db.commit()
|
|
|
|
return success_response(data=AdminUserResponse(
|
|
id=agent.id,
|
|
user_id=agent.user_id,
|
|
name=agent.name,
|
|
role=agent.role,
|
|
is_active=agent.status == "online",
|
|
mfa_enabled=agent.mfa_enabled,
|
|
mfa_bound_at=agent.mfa_bound_at,
|
|
created_at=agent.created_at,
|
|
updated_at=agent.updated_at,
|
|
).model_dump())
|
|
|
|
except AppException:
|
|
await db.rollback()
|
|
raise
|
|
except Exception as e:
|
|
await db.rollback()
|
|
logger.error(f"创建管理员失败: {e}")
|
|
raise AppException(ErrorCode.INTERNAL_ERROR, "创建管理员失败")
|
|
|
|
|
|
# =============================================================================
|
|
# 3. GET /api/admin/users/{id} — 获取管理员详情
|
|
# =============================================================================
|
|
@router.get("/{id}", response_model=None)
|
|
async def get_admin_user(
|
|
id: str,
|
|
current_user: UserInfo = Depends(require_role("admin")),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""获取管理员用户详情。
|
|
|
|
需要 admin 或 super_admin 角色。
|
|
|
|
Args:
|
|
id: 用户ID
|
|
current_user: 当前用户
|
|
db: 数据库会话
|
|
|
|
Returns:
|
|
用户详情
|
|
"""
|
|
service = AdminUserService(db)
|
|
agent = await service.get_user_by_id(id)
|
|
|
|
if not agent:
|
|
raise AppException(ErrorCode.NOT_FOUND, "用户不存在")
|
|
|
|
return success_response(data=AdminUserResponse(
|
|
id=agent.id,
|
|
user_id=agent.user_id,
|
|
name=agent.name,
|
|
role=agent.role,
|
|
is_active=agent.status == "online",
|
|
mfa_enabled=agent.mfa_enabled,
|
|
mfa_bound_at=agent.mfa_bound_at,
|
|
created_at=agent.created_at,
|
|
updated_at=agent.updated_at,
|
|
).model_dump())
|
|
|
|
|
|
# =============================================================================
|
|
# 4. PUT /api/admin/users/{id} — 更新管理员
|
|
# =============================================================================
|
|
@router.put("/{id}", response_model=None)
|
|
async def update_admin_user(
|
|
id: str,
|
|
body: AdminUserUpdateRequest,
|
|
current_user: UserInfo = Depends(require_role("admin")),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""更新管理员用户。
|
|
|
|
需要 admin 或 super_admin 角色。
|
|
- admin 角色只能更新普通 admin
|
|
- super_admin 角色可以更新所有用户
|
|
|
|
Args:
|
|
id: 用户ID
|
|
body: 更新请求
|
|
current_user: 当前用户
|
|
db: 数据库会话
|
|
|
|
Returns:
|
|
更新后的用户信息
|
|
"""
|
|
# 权限检查:非 super_admin 不能修改 super_admin
|
|
if "super_admin" not in current_user.roles:
|
|
target = await AdminUserService(db).get_user_by_id(id)
|
|
if target and target.role == "super_admin":
|
|
raise AppException(ErrorCode.FORBIDDEN, "无法修改超级管理员")
|
|
|
|
service = AdminUserService(db)
|
|
|
|
try:
|
|
agent = await service.update_admin_user(
|
|
id=id,
|
|
name=body.name,
|
|
role=body.role,
|
|
is_active=body.is_active,
|
|
)
|
|
await db.commit()
|
|
|
|
return success_response(data=AdminUserResponse(
|
|
id=agent.id,
|
|
user_id=agent.user_id,
|
|
name=agent.name,
|
|
role=agent.role,
|
|
is_active=agent.status == "online",
|
|
mfa_enabled=agent.mfa_enabled,
|
|
mfa_bound_at=agent.mfa_bound_at,
|
|
created_at=agent.created_at,
|
|
updated_at=agent.updated_at,
|
|
).model_dump())
|
|
|
|
except AppException:
|
|
await db.rollback()
|
|
raise
|
|
except Exception as e:
|
|
await db.rollback()
|
|
logger.error(f"更新管理员失败: {e}")
|
|
raise AppException(ErrorCode.INTERNAL_ERROR, "更新管理员失败")
|
|
|
|
|
|
# =============================================================================
|
|
# 5. DELETE /api/admin/users/{id} — 删除管理员
|
|
# =============================================================================
|
|
@router.delete("/{id}", response_model=None)
|
|
async def delete_admin_user(
|
|
id: str,
|
|
current_user: UserInfo = Depends(require_role("super_admin")),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""删除管理员用户。
|
|
|
|
需要 super_admin 角色。
|
|
|
|
Args:
|
|
id: 用户ID
|
|
current_user: 当前用户
|
|
db: 数据库会话
|
|
|
|
Returns:
|
|
删除结果
|
|
"""
|
|
service = AdminUserService(db)
|
|
|
|
try:
|
|
await service.delete_admin_user(id)
|
|
await db.commit()
|
|
|
|
return success_response(data={"message": "删除成功"})
|
|
|
|
except AppException:
|
|
await db.rollback()
|
|
raise
|
|
except Exception as e:
|
|
await db.rollback()
|
|
logger.error(f"删除管理员失败: {e}")
|
|
raise AppException(ErrorCode.INTERNAL_ERROR, "删除管理员失败")
|
|
|
|
|
|
# =============================================================================
|
|
# 6. POST /api/admin/users/{id}/reset-password — 重置密码
|
|
# =============================================================================
|
|
@router.post("/{id}/reset-password", response_model=None)
|
|
async def reset_password(
|
|
id: str,
|
|
body: AdminUserResetPasswordRequest,
|
|
current_user: UserInfo = Depends(require_role("admin")),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""重置管理员密码。
|
|
|
|
需要 admin 或 super_admin 角色。
|
|
|
|
Args:
|
|
id: 用户ID
|
|
body: 重置请求
|
|
current_user: 当前用户
|
|
db: 数据库会话
|
|
|
|
Returns:
|
|
重置结果
|
|
"""
|
|
# 权限检查:非 super_admin 不能重置 super_admin 的密码
|
|
if "super_admin" not in current_user.roles:
|
|
target = await AdminUserService(db).get_user_by_id(id)
|
|
if target and target.role == "super_admin":
|
|
raise AppException(ErrorCode.FORBIDDEN, "无法重置超级管理员密码")
|
|
|
|
service = AdminUserService(db)
|
|
|
|
try:
|
|
await service.reset_password(id, body.new_password)
|
|
await db.commit()
|
|
|
|
return success_response(data={"message": "密码重置成功"})
|
|
|
|
except AppException:
|
|
await db.rollback()
|
|
raise
|
|
except Exception as e:
|
|
await db.rollback()
|
|
logger.error(f"重置密码失败: {e}")
|
|
raise AppException(ErrorCode.INTERNAL_ERROR, "重置密码失败")
|