# -*- coding: utf-8 -*- """运营方管理端点(证明 RBAC 角色/权限/审计)。""" from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException, Request from pydantic import BaseModel from ..dependencies import get_db from ..schemas.admin import SetUserRoleRequest, SetUserStatusRequest, UserClassificationRequest from ..schemas.admin import UserCreateRequest, RolePermissionRequest, UpdateUserRequest from ...rbac import require_permission, require_roles, write_audit from ...infrastructure.repositories import Database from ...services import compute_client router = APIRouter(prefix="/admin", tags=["admin"]) async def _sync_compute(coro) -> None: """算力引擎用户同步为附加能力:失败不阻断平台用户操作(引擎未配置/不可达时静默)。""" try: await coro except Exception: # noqa: BLE001 pass @router.post("/users", summary="新增账号(按类型/角色)") async def create_user( req: UserCreateRequest, request: Request, db: Database = Depends(get_db), actor: dict = Depends(require_permission("action:user.assign_role")), ): from ...services.user_admin_service import UserAdminService user = await UserAdminService(db).create_user(req, actor) # 平台用户创建 → 引擎同步建号 + 签发 PAT(算力引擎用户与平台一致) await _sync_compute(compute_client.create_user(user["username"])) await _sync_compute(compute_client.issue_pat(user["username"])) await write_audit(db, action="user.create", resource="user", resource_id=user["id"], detail=f"role={req.role}", user=actor, request=request) return await db.users.to_profile(user) def _port_for_role(role: str) -> str: return { "opc_member": "opc", "carrier": "carrier", "enterprise": "enterprise", "provider": "provider", "government": "government", "operator": "operator", "investor": "investor", "developer": "developer", }.get(role, "opc") @router.get("/users", summary="用户列表(运营方)") async def list_users( request: Request, db: Database = Depends(get_db), _role: dict = Depends(require_roles("operator")), _perm: dict = Depends(require_permission("menu:admin_user_mgmt")), ): return await db.users.list() @router.post("/users/{user_id}/role", summary="分配角色") async def set_user_role( user_id: str, req: SetUserRoleRequest, request: Request, db: Database = Depends(get_db), actor: dict = Depends(require_permission("action:user.assign_role")), ): from ...services.user_admin_service import UserAdminService if await db.users.get_by_id(user_id) is None: raise HTTPException(status_code=404, detail="User not found") updated = await UserAdminService(db).set_user_role( actor, user_id, req.role, req.sub_role, req.org_id, req.region_id, ) await write_audit( db, action="role.assign", resource="user", resource_id=user_id, detail=f"{actor['username']} -> role={req.role} sub={req.sub_role}", user=actor, request=request, ) return {"ok": True, "user": await db.users.to_profile(updated)} @router.post("/users/{user_id}/classification", summary="设置用户认证状态/所属/账号类型") async def set_user_classification( user_id: str, req: UserClassificationRequest, request: Request, db: Database = Depends(get_db), actor: dict = Depends(require_permission("action:user.manage")), ): fields = req.model_dump(exclude_none=True) updated = await db.users.set_classification(user_id, **fields) if updated is None: raise HTTPException(status_code=404, detail="User not found") await write_audit(db, action="user.classification", resource="user", resource_id=user_id, detail=str(fields), user=actor, request=request) return {"ok": True, "user": updated} @router.post("/users/{user_id}/status", summary="禁用/启用用户") async def set_user_status( user_id: str, req: SetUserStatusRequest, request: Request, db: Database = Depends(get_db), actor: dict = Depends(require_permission("action:user.disable")), ): user = await db.users.get_by_id(user_id) if user is None: raise HTTPException(status_code=404, detail="User not found") updated = await db.users.set_status(user_id, req.status) # 平台用户启用/禁用 → 引擎镜像同步 await _sync_compute(compute_client.sync_user_enabled( user.get("username"), req.status == "active", )) await write_audit( db, action="user.disable", resource="user", resource_id=user_id, detail=f"{actor['username']} -> status={req.status}", user=actor, request=request, ) return {"ok": True, "user": await db.users.to_profile(updated)} @router.put("/users/{user_id}", summary="修改用户(资料/角色)") async def update_user( user_id: str, req: UpdateUserRequest, request: Request, db: Database = Depends(get_db), actor: dict = Depends(require_permission("action:user.manage")), ): user = await db.users.get_by_id(user_id) if user is None: raise HTTPException(status_code=404, detail="User not found") profile_fields = {k: v for k, v in req.model_dump(exclude_none=True).items() if k in ("nickname",)} if profile_fields: user = await db.users.update_profile(user_id, profile_fields) or user if req.role or req.sub_role is not None: user = await db.users.set_role(user_id, req.role or user.get("role"), req.sub_role, req.org_id or user.get("org_id"), req.region_id or user.get("region_id")) await write_audit(db, action="user.update", resource="user", resource_id=user_id, detail=str(req.model_dump(exclude_none=True)), user=actor, request=request) return {"ok": True, "user": await db.users.to_profile(user)} @router.delete("/users/{user_id}", summary="删除用户") async def delete_user( user_id: str, request: Request, db: Database = Depends(get_db), actor: dict = Depends(require_permission("action:user.manage")), ): user = await db.users.get_by_id(user_id) ok = await db.users.delete(user_id) if not ok: raise HTTPException(status_code=404, detail="User not found") # 平台用户删除 → 引擎镜像同步删除 if user: await _sync_compute(compute_client.sync_delete_user(user.get("username"))) await write_audit(db, action="user.delete", resource="user", resource_id=user_id, detail="deleted", user=actor, request=request) return {"ok": True, "user_id": user_id} @router.get("/roles", summary="角色列表") async def list_roles( db: Database = Depends(get_db), _user: dict = Depends(require_permission("menu:admin_role_mgmt")), ): return await db.roles.list_roles() @router.get("/permissions", summary="权限列表") async def list_permissions( db: Database = Depends(get_db), _user: dict = Depends(require_permission("menu:admin_role_mgmt")), ): return await db.roles.list_permissions() @router.post("/roles/{role_id}/permissions", summary="配置角色权限") async def set_role_permissions( role_id: str, req: RolePermissionRequest, request: Request, db: Database = Depends(get_db), actor: dict = Depends(require_permission("action:role.grant_perm")), ): if not await db.roles.role_exists(role_id): raise HTTPException(status_code=404, detail="Role not found") perms = await db.roles.set_role_permissions(role_id, req.permissions) await write_audit(db, action="role.grant_perm", resource="role", resource_id=role_id, detail=f"permissions={len(req.permissions)}", user=actor, request=request) return {"ok": True, "role_id": role_id, "permissions": perms} @router.get("/audit-logs", summary="审计日志") async def list_audit_logs( limit: int = 100, offset: int = 0, db: Database = Depends(get_db), _user: dict = Depends(require_permission("action:audit.view")), ): return await db.audit.list(limit=min(limit, 500), offset=offset)