# ============================================================================= # 角色 Pydantic Schema # ============================================================================= # 说明:定义角色相关的请求/响应数据结构 # 包含:角色响应、角色分配、角色映射规则等 Schema # ============================================================================= from datetime import datetime from typing import List, Optional from pydantic import BaseModel, Field, field_validator # -------------------------------------------------------------------------- # 角色响应 Schema # -------------------------------------------------------------------------- class RoleResponse(BaseModel): """角色响应 Schema。 Attributes: id: 角色ID name: 角色标识(user/agent/admin) display_name: 显示名称(用户/坐席/管理员) description: 角色描述 permissions: 权限列表 is_default: 是否默认角色 user_count: 拥有该角色的用户数(可选) created_at: 创建时间 updated_at: 更新时间 """ id: str name: str display_name: str description: Optional[str] = None permissions: List[str] = [] is_default: bool = False user_count: Optional[int] = None created_at: datetime updated_at: datetime model_config = {"from_attributes": True} # -------------------------------------------------------------------------- # 用户角色响应 Schema # -------------------------------------------------------------------------- class UserRoleResponse(BaseModel): """用户角色响应 Schema。 Attributes: id: 记录ID employee_id: 企微 UserID role_id: 角色 ID role_name: 角色标识 role_display_name: 角色显示名称 source: 角色来源(auto/tag/ehr/manual) assigned_by: 分配者 assigned_at: 分配时间 expires_at: 过期时间 """ id: str employee_id: str role_id: str role_name: str role_display_name: str source: str assigned_by: Optional[str] = None assigned_at: datetime expires_at: Optional[datetime] = None model_config = {"from_attributes": True} # -------------------------------------------------------------------------- # 角色分配请求 Schema # -------------------------------------------------------------------------- class RoleAssignRequest(BaseModel): """角色分配请求 Schema。 Attributes: employee_id: 企微 UserID role_name: 角色标识(user/agent/admin) reason: 分配原因(可选) """ employee_id: str = Field(..., min_length=1, max_length=100, description="企微 UserID") role_name: str = Field(..., min_length=1, max_length=50, description="角色标识") reason: Optional[str] = Field(None, max_length=500, description="分配原因") # -------------------------------------------------------------------------- # 角色撤销请求 Schema # -------------------------------------------------------------------------- class RoleRevokeRequest(BaseModel): """角色撤销请求 Schema。 Attributes: employee_id: 企微 UserID role_name: 角色标识(user/agent/admin) reason: 撤销原因(可选) """ employee_id: str = Field(..., min_length=1, max_length=100, description="企微 UserID") role_name: str = Field(..., min_length=1, max_length=50, description="角色标识") reason: Optional[str] = Field(None, max_length=500, description="撤销原因") # -------------------------------------------------------------------------- # 角色映射规则响应 Schema # -------------------------------------------------------------------------- class RoleMappingRuleResponse(BaseModel): """角色映射规则响应 Schema。 Attributes: id: 规则ID role_id: 目标角色 ID role_name: 目标角色标识 source_type: 来源类型(wecom_tag/ehr_position) source_value: 来源值(标签名/岗位关键词) priority: 优先级 is_active: 是否启用 created_at: 创建时间 """ id: str role_id: str role_name: str source_type: str source_value: str priority: int = 0 is_active: bool = True created_at: datetime model_config = {"from_attributes": True} # -------------------------------------------------------------------------- # 角色映射规则创建/更新请求 Schema # -------------------------------------------------------------------------- class RoleMappingRuleRequest(BaseModel): """角色映射规则创建/更新请求 Schema。 Attributes: role_name: 目标角色标识(user/agent/admin) source_type: 来源类型(wecom_tag/ehr_position) source_value: 来源值(标签名/岗位关键词) priority: 优先级(数值越大优先级越高) is_active: 是否启用 """ role_name: str = Field(..., min_length=1, max_length=50, description="目标角色标识") source_type: str = Field(..., min_length=1, max_length=50, description="来源类型") source_value: str = Field(..., min_length=1, max_length=200, description="来源值") priority: int = Field(0, ge=0, le=100, description="优先级(0-100)") is_active: bool = Field(True, description="是否启用") @field_validator("source_type") @classmethod def validate_source_type(cls, v: str) -> str: """校验来源类型是否合法。""" allowed_types = {"wecom_tag", "ehr_position"} if v not in allowed_types: raise ValueError(f"无效的来源类型: {v},合法值为: {allowed_types}") return v @field_validator("role_name") @classmethod def validate_role_name(cls, v: str) -> str: """校验角色标识是否合法。""" allowed_roles = {"user", "agent", "admin"} if v not in allowed_roles: raise ValueError(f"无效的角色标识: {v},合法值为: {allowed_roles}") return v @field_validator("source_value") @classmethod def validate_source_value(cls, v: str) -> str: """校验来源值是否包含恶意内容。""" # 过滤特殊字符 forbidden_chars = {"<", ">", ";", "'", '"', "\\", "/", "(", ")"} for char in v: if char in forbidden_chars: raise ValueError(f"来源值包含非法字符: {char}") return v # -------------------------------------------------------------------------- # Portal 用户信息响应 Schema # -------------------------------------------------------------------------- class PortalUserInfo(BaseModel): """Portal 用户信息响应 Schema。 用于路由选择页展示用户信息和角色列表。 Attributes: employee_id: 企微 UserID name: 姓名 department: 部门 avatar: 头像URL roles: 角色列表 current_role: 当前选择的角色 """ employee_id: str name: str department: Optional[str] = None avatar: Optional[str] = None roles: List[RoleResponse] = [] current_role: str = "user" # -------------------------------------------------------------------------- # 角色切换请求 Schema # -------------------------------------------------------------------------- class SwitchRoleRequest(BaseModel): """角色切换请求 Schema。 Attributes: new_role: 目标角色标识 """ new_role: str = Field(..., min_length=1, max_length=50, description="目标角色标识") # -------------------------------------------------------------------------- # 角色切换响应 Schema # -------------------------------------------------------------------------- class SwitchRoleResponse(BaseModel): """角色切换响应 Schema。 Attributes: current_role: 切换后的角色标识 redirect_url: 重定向URL """ current_role: str redirect_url: str