fix: literal_error

This commit is contained in:
tao.chen
2026-08-26 09:50:56 +08:00
parent 6fe2d0b42e
commit b3066d6940
2 changed files with 25 additions and 3 deletions
+16 -1
View File
@@ -79,7 +79,22 @@ async def _is_system_admin(session: AsyncSession, user: Users) -> bool:
async def _load_role_by_code(session: AsyncSession, role_code: str) -> Roles:
role = await session.scalar(select(Roles).where(Roles.role_code == role_code))
"""Load a live platform-scoped role by code; 422 if missing.
之所以把 ``is_deleted == 0`` 和 ``role_scope == "platform"`` 写进 helper,
是因为本 helper 的所有调用方(``employees`` create/update / 两个 count
helper)都需要的是 platform 角色。Workspace 角色不应被赋值到
``users.platform_role_id``,软删除的 role 也不应被新引用 —— 在 helper
层兜底一次,后续 schema 放宽 ``role_code`` 为 ``str`` 时不必每个端点
再补守卫。
"""
role = await session.scalar(
select(Roles).where(
Roles.role_code == role_code,
Roles.is_deleted == 0,
Roles.role_scope == "platform",
)
)
if role is None:
raise HTTPException(
status.HTTP_422_UNPROCESSABLE_ENTITY,
@@ -26,6 +26,13 @@ from backend.api.platform._deps import (
system_admin_context,
)
# 平台角色 code 的字符串约束:与 RoleCreate.role_code 一致。
# 之所以从 Literal["admin","developer"] 放宽为 str,是因为 ``listPlatformRoles``
# 现已返回用户自建的 platform 角色(``role_scope=="platform"`` 且 ``is_builtin==0``),
# 前端 dialog 用 ``listPlatformRoles()`` 渲染选项,提交非内置 code 时会被 Pydantic
# Literal 校验直接 422 拒掉。schema 不应枚举运行时数据;改用 ``_load_role_by_code``
# 做存在性 + 平台作用域校验(并隐式排除 is_deleted=1)。
router = APIRouter(prefix="/api/v1/platform", tags=["platform"])
@@ -42,7 +49,7 @@ class PlatformEmployeeCreate(BaseModel):
display_name: str = Field(min_length=1, max_length=100)
email: str | None = Field(default=None, max_length=255)
password: str = Field(min_length=8, max_length=72)
role_code: Literal["admin", "developer"] | None = None
role_code: str | None = Field(default=None, min_length=2, max_length=64)
# 修改平台用户资料、状态或平台角色的请求体。
@@ -52,7 +59,7 @@ class PlatformEmployeeUpdate(BaseModel):
display_name: str | None = Field(default=None, min_length=1, max_length=100)
email: str | None = Field(default=None, max_length=255)
status: Literal["active", "disabled", "locked"] | None = None
role_code: Literal["admin", "developer"] | None = None
role_code: str | None = Field(default=None, min_length=2, max_length=64)
# ---------------------------------------------------------------------------