101 lines
3.6 KiB
Python
101 lines
3.6 KiB
Python
|
|
"""角色管理接口(自主完善模块:需求 2.5.1 仅定义 admin / user 两个角色)。
|
|||
|
|
|
|||
|
|
保护规则(admin 禁删禁停、有绑定的角色禁删、role_code 不可改)见
|
|||
|
|
`role_service` 模块 docstring。前端会禁用相应按钮,但**后端校验是唯一防线**。
|
|||
|
|
|
|||
|
|
全部要求管理员权限;写操作经 `RequestMetaDep` 带入请求元信息由 service
|
|||
|
|
层写入操作日志。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from typing import Annotated
|
|||
|
|
|
|||
|
|
from fastapi import APIRouter, Path, Query
|
|||
|
|
|
|||
|
|
from app.api.deps import AdminUser, DbSession, RequestMetaDep
|
|||
|
|
from app.core.response import ApiResponse, PageResult, ok
|
|||
|
|
from app.schemas.role import RoleCreateIn, RoleManageOut, RoleQuery, RoleStatusIn, RoleUpdateIn
|
|||
|
|
from app.services import role_service
|
|||
|
|
|
|||
|
|
router = APIRouter(prefix="/roles", tags=["系统管理 · 角色"])
|
|||
|
|
|
|||
|
|
|
|||
|
|
@router.get("", response_model=ApiResponse[PageResult[RoleManageOut]], summary="角色列表")
|
|||
|
|
def list_roles(
|
|||
|
|
session: DbSession,
|
|||
|
|
_: AdminUser,
|
|||
|
|
query: Annotated[RoleQuery, Query()],
|
|||
|
|
) -> ApiResponse[PageResult[RoleManageOut]]:
|
|||
|
|
"""分页查询角色。
|
|||
|
|
|
|||
|
|
与用户表单的角色下拉口径不同:**本列表含停用角色**(下拉只给启用项)。
|
|||
|
|
每行附带 `user_count`(绑定用户数),供前端提示删除保护。
|
|||
|
|
"""
|
|||
|
|
return ok(role_service.list_roles(session, query))
|
|||
|
|
|
|||
|
|
|
|||
|
|
@router.post("", response_model=ApiResponse[RoleManageOut], summary="新增角色")
|
|||
|
|
def create_role(
|
|||
|
|
session: DbSession,
|
|||
|
|
current_user: AdminUser,
|
|||
|
|
payload: RoleCreateIn,
|
|||
|
|
meta: RequestMetaDep,
|
|||
|
|
) -> ApiResponse[RoleManageOut]:
|
|||
|
|
"""新增角色。编码全局唯一、创建后不可修改;新角色默认启用。"""
|
|||
|
|
return ok(
|
|||
|
|
role_service.create_role(session, payload, operator=current_user, meta=meta),
|
|||
|
|
message="角色已创建",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
@router.put("/{role_id}", response_model=ApiResponse[RoleManageOut], summary="编辑角色")
|
|||
|
|
def update_role(
|
|||
|
|
session: DbSession,
|
|||
|
|
current_user: AdminUser,
|
|||
|
|
role_id: Annotated[int, Path(ge=1)],
|
|||
|
|
payload: RoleUpdateIn,
|
|||
|
|
meta: RequestMetaDep,
|
|||
|
|
) -> ApiResponse[RoleManageOut]:
|
|||
|
|
"""编辑角色名称/说明/排序。
|
|||
|
|
|
|||
|
|
**不含 role_code** —— 编码是授权判定(`ROLE_ADMIN` 常量)的锚点。
|
|||
|
|
"""
|
|||
|
|
return ok(
|
|||
|
|
role_service.update_role(session, role_id, payload, operator=current_user, meta=meta),
|
|||
|
|
message="已保存",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
@router.put("/{role_id}/status", response_model=ApiResponse[RoleManageOut], summary="启用/禁用角色")
|
|||
|
|
def set_status(
|
|||
|
|
session: DbSession,
|
|||
|
|
current_user: AdminUser,
|
|||
|
|
role_id: Annotated[int, Path(ge=1)],
|
|||
|
|
payload: RoleStatusIn,
|
|||
|
|
meta: RequestMetaDep,
|
|||
|
|
) -> ApiResponse[RoleManageOut]:
|
|||
|
|
"""启用或禁用角色。
|
|||
|
|
|
|||
|
|
停用**不解除**用户绑定、也不影响既有授权(授权判定只看编码、不看状态);
|
|||
|
|
内置管理员角色不可停用。
|
|||
|
|
"""
|
|||
|
|
result = role_service.set_status(
|
|||
|
|
session, role_id, payload.status, operator=current_user, meta=meta
|
|||
|
|
)
|
|||
|
|
return ok(result, message="已启用" if payload.status == 1 else "已禁用")
|
|||
|
|
|
|||
|
|
|
|||
|
|
@router.delete("/{role_id}", response_model=ApiResponse[None], summary="删除角色")
|
|||
|
|
def delete_role(
|
|||
|
|
session: DbSession,
|
|||
|
|
current_user: AdminUser,
|
|||
|
|
role_id: Annotated[int, Path(ge=1)],
|
|||
|
|
meta: RequestMetaDep,
|
|||
|
|
) -> ApiResponse[None]:
|
|||
|
|
"""删除角色。
|
|||
|
|
|
|||
|
|
内置管理员角色不可删除;仍有关联用户的角色不可删除(提示先解除绑定)——
|
|||
|
|
`user_roles` 外键是 CASCADE,后端拦截是防止静默剥离权限的唯一防线。
|
|||
|
|
"""
|
|||
|
|
role_service.delete_role(session, role_id, operator=current_user, meta=meta)
|
|||
|
|
return ok(message="角色已删除")
|