From 01ef3c96371ac07a748e5474ea90b54f400512cf Mon Sep 17 00:00:00 2001 From: PineHomePC Date: Mon, 24 Aug 2026 09:51:52 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20schemas=20=E6=8A=BD=E5=8F=96?= =?UTF-8?q?=EF=BC=88DTO=20=E4=BB=8E=20models.py=20=E4=B8=8E=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E5=86=85=E8=81=94=E8=BF=81=E8=87=B3=20api/schemas/?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新建 api/schemas/:auth/agents/admin/ecosystem/investor/opc/operator/org/portals - models.py 移除 15 个 Pydantic DTO(保留 ORM 数据模型层) - 13 个路由内联 DTO 全部迁出,路由瘦身仅剩处理逻辑 - 全量 66 测试通过 --- app/api/routers/agents.py | 2 +- app/api/routers/auth.py | 2 +- app/api/routers/rbac_admin.py | 33 +----- app/api/routers/rbac_ecosystem.py | 15 +-- app/api/routers/rbac_investor.py | 29 +----- app/api/routers/rbac_opc.py | 22 +--- app/api/routers/rbac_operator.py | 49 +-------- app/api/routers/rbac_org.py | 8 +- app/api/routers/rbac_portals.py | 25 +---- app/api/schemas/__init__.py | 0 app/api/schemas/admin.py | 43 ++++++++ app/api/schemas/agents.py | 39 +++++++ app/api/schemas/auth.py | 103 +++++++++++++++++++ app/api/schemas/ecosystem.py | 19 ++++ app/api/schemas/investor.py | 33 ++++++ app/api/schemas/opc.py | 26 +++++ app/api/schemas/operator.py | 57 +++++++++++ app/api/schemas/org.py | 10 ++ app/api/schemas/portals.py | 29 ++++++ app/infrastructure/models.py | 165 ------------------------------ 20 files changed, 369 insertions(+), 340 deletions(-) create mode 100644 app/api/schemas/__init__.py create mode 100644 app/api/schemas/admin.py create mode 100644 app/api/schemas/agents.py create mode 100644 app/api/schemas/auth.py create mode 100644 app/api/schemas/ecosystem.py create mode 100644 app/api/schemas/investor.py create mode 100644 app/api/schemas/opc.py create mode 100644 app/api/schemas/operator.py create mode 100644 app/api/schemas/org.py create mode 100644 app/api/schemas/portals.py diff --git a/app/api/routers/agents.py b/app/api/routers/agents.py index bcb354f..5ac47e1 100644 --- a/app/api/routers/agents.py +++ b/app/api/routers/agents.py @@ -9,7 +9,7 @@ from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException from ..dependencies import get_db, require_port -from ...infrastructure.models import AgentCreate, AgentInfo, AgentUpdate +from ..schemas.agents import AgentCreate, AgentInfo, AgentUpdate from ...infrastructure.repositories import Database router = APIRouter(prefix="/agents", tags=["agents"]) diff --git a/app/api/routers/auth.py b/app/api/routers/auth.py index be25619..ae1c6c2 100644 --- a/app/api/routers/auth.py +++ b/app/api/routers/auth.py @@ -13,7 +13,7 @@ from fastapi import APIRouter, Depends, HTTPException, Request from ... import config from ..dependencies import get_current_user, get_db, extract_bearer_token -from ...infrastructure.models import ( +from ..schemas.auth import ( AuthStatusResponse, IdentityInfo, LoginRequest, diff --git a/app/api/routers/rbac_admin.py b/app/api/routers/rbac_admin.py index a7ac3f8..0cc5a21 100644 --- a/app/api/routers/rbac_admin.py +++ b/app/api/routers/rbac_admin.py @@ -6,43 +6,14 @@ from fastapi import APIRouter, Depends, HTTPException, Request from pydantic import BaseModel from ..dependencies import get_db -from ...infrastructure.models import SetUserRoleRequest, SetUserStatusRequest +from ..schemas.admin import SetUserRoleRequest, SetUserStatusRequest +from ..schemas.admin import UserCreateRequest, RolePermissionRequest from ...rbac import require_permission, require_roles, write_audit from ...infrastructure.repositories import Database router = APIRouter(prefix="/admin", tags=["admin"]) -class UserCreateRequest(BaseModel): - username: str # 手机号 - password: str - nickname: str = "" - role: str = "opc_member" - sub_role: str | None = None - org_id: str | None = None - region_id: str | None = None - - -class RolePermissionRequest(BaseModel): - permissions: list[str] = [] - - -async def _validate_role_assignment(db: Database, actor: dict, role: str, sub_role: str | None) -> None: - """白名单 + 提权防护:拒绝非法角色组合,及无权者创建/提升特权角色。""" - key = role if not sub_role else f"{role}|{sub_role}" - if not await db.roles.role_exists(role): - raise HTTPException(status_code=400, detail=f"无效角色: {role}") - if sub_role and not await db.roles.role_exists(f"{role}|{sub_role}"): - raise HTTPException(status_code=400, detail=f"无效角色组合: {key}") - # 目标角色若授予「配置角色权限」,仅持该权限者(超管)可创建/分配 - if "action:role.grant_perm" in await db.roles.permissions_for(role, sub_role) and \ - "action:role.grant_perm" not in actor.get("permissions", []): - raise HTTPException( - status_code=403, - detail="无权创建/分配特权角色(仅超级管理员)", - ) - - @router.post("/users", summary="新增账号(按类型/角色)") async def create_user( req: UserCreateRequest, diff --git a/app/api/routers/rbac_ecosystem.py b/app/api/routers/rbac_ecosystem.py index 808d6c4..fb9713f 100644 --- a/app/api/routers/rbac_ecosystem.py +++ b/app/api/routers/rbac_ecosystem.py @@ -7,6 +7,7 @@ from fastapi import APIRouter, Depends, HTTPException, Request from pydantic import BaseModel from ..dependencies import get_db +from ..schemas.ecosystem import RatingRequest, SignRequest, DisputeRequest from ...rbac import require_permission, require_roles, write_audit from ...infrastructure.repositories import Database @@ -44,12 +45,6 @@ async def my_credit( "rating_count": len(await db.ratings.list_for(user["id"])) if hasattr(db.ratings, "list_for") else 0} -class RatingRequest(BaseModel): - score: int = 5 - comment: str = "" - to_id: str = "" - - @router.post("/tasks/{task_id}/rate", summary="任务互评") async def rate_task( task_id: str, @@ -79,10 +74,6 @@ async def get_contract( return contract -class SignRequest(BaseModel): - opc_id: str = "" - - @router.post("/tasks/{task_id}/sign", summary="签订电子合同") async def sign_contract( task_id: str, @@ -125,10 +116,6 @@ async def operator_settlements( # ── 争议 ────────────────────────────────────────────────────────────────── -class DisputeRequest(BaseModel): - reason: str = "" - - @router.post("/tasks/{task_id}/dispute", summary="发起争议") async def create_dispute( task_id: str, diff --git a/app/api/routers/rbac_investor.py b/app/api/routers/rbac_investor.py index 3a079d2..bf9857a 100644 --- a/app/api/routers/rbac_investor.py +++ b/app/api/routers/rbac_investor.py @@ -12,6 +12,7 @@ from fastapi import APIRouter, Depends, HTTPException, Request from pydantic import BaseModel from ..dependencies import get_db +from ..schemas.investor import PreferenceRequest, IntentRequest, RoadshowCreate from ...rbac import require_roles, write_audit from ...infrastructure.repositories import Database @@ -21,34 +22,6 @@ router = APIRouter(prefix="/investor", tags=["investor"]) _ROADSHOW_ROLES = ("investor", "government", "operator", "carrier", "enterprise") -class PreferenceRequest(BaseModel): - industries: list[str] = [] - stage: str = "" - amount_min: int = 0 - amount_max: int = 0 - region_id: str | None = None - - -class IntentRequest(BaseModel): - project_id: str - project_name: str = "" - message: str = "" - - -class RoadshowCreate(BaseModel): - title: str - summary: str = "" - activity_type: str = "online" # online/offline/hybrid - scope_type: str = "all" # all/region/org - region_id: str | None = None - start_at: str = "" - end_at: str = "" - register_deadline: str = "" - quota: int = 0 - venue: str = "" - live_url: str = "" - - def _need_review(user: dict, req: RoadshowCreate, db: Database) -> bool: """按发布主体与范围判断是否需要审核。""" role = user.get("role") diff --git a/app/api/routers/rbac_opc.py b/app/api/routers/rbac_opc.py index 0497fd5..408f88f 100644 --- a/app/api/routers/rbac_opc.py +++ b/app/api/routers/rbac_opc.py @@ -10,6 +10,7 @@ from fastapi import APIRouter, Depends, HTTPException, Request from pydantic import BaseModel from ..dependencies import get_db +from ..schemas.opc import BidRequest, ProfileUpdate, FinanceRecordCreate from ...rbac import require_roles, write_audit from ...infrastructure.repositories import Database, new_id, utcnow_iso from ...infrastructure.models import FinanceRecord @@ -114,11 +115,6 @@ async def opc_profile( return profile -class BidRequest(BaseModel): - quote: int = 0 - plan: str = "" - - @router.post("/tasks/{task_id}/grab", summary="OPC 抢单") async def opc_grab( task_id: str, @@ -165,15 +161,6 @@ async def opc_deliver( return updated -class ProfileUpdate(BaseModel): - nickname: str | None = None - account: str | None = None - company: str | None = None - room: str | None = None - skills: list[str] = [] - credit_score: int | None = None - - @router.put("/profile", summary="OPC 基础资料编辑") async def opc_update_profile( req: ProfileUpdate, @@ -193,13 +180,6 @@ async def opc_update_profile( return await opc_profile(db, fresh_user) -class FinanceRecordCreate(BaseModel): - category: str = "income" # income | expense - amount: int - date: str = "" - note: str = "" - - @router.post("/finance/record", summary="OPC 记一笔收支") async def opc_add_finance( req: FinanceRecordCreate, diff --git a/app/api/routers/rbac_operator.py b/app/api/routers/rbac_operator.py index 8444cc4..21052b9 100644 --- a/app/api/routers/rbac_operator.py +++ b/app/api/routers/rbac_operator.py @@ -9,60 +9,13 @@ from fastapi import APIRouter, Depends, HTTPException, Request from pydantic import BaseModel from ..dependencies import get_db +from ..schemas.operator import TaskCreateRequest, TaskStatusRequest, ProviderCreateRequest, ProviderUpdateRequest, ContentCreateRequest, ContentStatusRequest, ConfigUpdateRequest from ...rbac import require_permission, require_roles, write_audit from ...infrastructure.repositories import Database router = APIRouter(prefix="/admin", tags=["admin-op"]) -class TaskCreateRequest(BaseModel): - title: str - category: str = "" - sub_category: str = "" - description: str = "" - mode: str = "grab" - budget_min: int = 0 - budget_max: int = 0 - deadline: str = "" - publisher_name: str = "" - - -class TaskStatusRequest(BaseModel): - status: str # review/published/completed/cancelled - - -class ProviderCreateRequest(BaseModel): - name: str - category: str = "" - level: str = "certified" - status: str = "pending" - contact: str = "" - - -class ProviderUpdateRequest(BaseModel): - level: str | None = None - status: str | None = None - contact: str | None = None - - -class ContentCreateRequest(BaseModel): - type: str = "news" - title: str - summary: str = "" - body: str = "" - status: str = "draft" - - -class ContentStatusRequest(BaseModel): - status: str # published/offline/draft - - -class ConfigUpdateRequest(BaseModel): - value: str - description: str = "" - - -# ── 任务管理 ────────────────────────────────────────────────────────────── @router.get("/tasks", summary="任务列表") async def list_tasks( status: str | None = None, diff --git a/app/api/routers/rbac_org.py b/app/api/routers/rbac_org.py index aef05c7..c8f8165 100644 --- a/app/api/routers/rbac_org.py +++ b/app/api/routers/rbac_org.py @@ -6,6 +6,7 @@ from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel from ..dependencies import get_db +from ..schemas.org import OrgMemberAdd from ...rbac import require_roles from ...infrastructure.repositories import Database @@ -74,13 +75,6 @@ async def org_members( return {"items": await db.org_members.list_for_org(org_id)} -class OrgMemberAdd(BaseModel): - user_id: str | None = None - username: str | None = None # 支持按用户名添加(解析为 user_id) - role: str = "member" - is_admin: bool = False - - @router.post("/org/{org_id}/members", summary="添加机构成员(子账号)") async def org_add_member( org_id: str, diff --git a/app/api/routers/rbac_portals.py b/app/api/routers/rbac_portals.py index a2087c4..6d0ca2e 100644 --- a/app/api/routers/rbac_portals.py +++ b/app/api/routers/rbac_portals.py @@ -10,6 +10,7 @@ from fastapi import APIRouter, Depends, HTTPException, Request from pydantic import BaseModel from ..dependencies import get_db +from ..schemas.portals import EnterpriseTaskCreate, TaskReviewRequest, ReferralCreate from ...rbac import require_roles, write_audit from ...infrastructure.repositories import Database @@ -75,18 +76,6 @@ router.get("/government/policies", summary="政务·政策管理")(_page("govern # ── 企业·任务(发布任务/我的任务)───────────────────────────────────────── -class EnterpriseTaskCreate(BaseModel): - title: str - category: str = "" - sub_category: str = "" - description: str = "" - mode: str = "grab" - budget_min: int = 0 - budget_max: int = 0 - deadline: str = "" - publisher_name: str = "" - - @router.get("/enterprise/tasks", summary="企业·我的任务列表") async def enterprise_tasks( db: Database = Depends(get_db), @@ -148,11 +137,6 @@ async def enterprise_win_bid( return bid -class TaskReviewRequest(BaseModel): - action: str # accept | reject - comment: str = "" - - @router.post("/enterprise/tasks/{task_id}/review", summary="企业·验收任务") async def enterprise_review_task( task_id: str, @@ -172,13 +156,6 @@ async def enterprise_review_task( # ── 载体·服务商引荐(三方绑定:载体引荐服务商→服务园区内 OPC)───────────── -class ReferralCreate(BaseModel): - provider_id: str = "" - provider_name: str = "" - opc_id: str = "" - opc_name: str = "" - - @router.get("/carrier/referrals", summary="载体·引荐记录") async def carrier_referrals( db: Database = Depends(get_db), diff --git a/app/api/schemas/__init__.py b/app/api/schemas/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/api/schemas/admin.py b/app/api/schemas/admin.py new file mode 100644 index 0000000..53ceb93 --- /dev/null +++ b/app/api/schemas/admin.py @@ -0,0 +1,43 @@ +from pydantic import BaseModel, Field + +class SetUserRoleRequest(BaseModel): + role: str + sub_role: str | None = None + org_id: str | None = None + region_id: str | None = None + +class SetUserStatusRequest(BaseModel): + status: str = "active" # active | disabled + +class UserCreateRequest(BaseModel): + username: str # 手机号 + password: str + nickname: str = "" + role: str = "opc_member" + sub_role: str | None = None + org_id: str | None = None + region_id: str | None = None + + + +class RolePermissionRequest(BaseModel): + permissions: list[str] = [] + + +async def _validate_role_assignment(db: Database, actor: dict, role: str, sub_role: str | None) -> None: + """白名单 + 提权防护:拒绝非法角色组合,及无权者创建/提升特权角色。""" + key = role if not sub_role else f"{role}|{sub_role}" + if not await db.roles.role_exists(role): + raise HTTPException(status_code=400, detail=f"无效角色: {role}") + if sub_role and not await db.roles.role_exists(f"{role}|{sub_role}"): + raise HTTPException(status_code=400, detail=f"无效角色组合: {key}") + # 目标角色若授予「配置角色权限」,仅持该权限者(超管)可创建/分配 + if "action:role.grant_perm" in await db.roles.permissions_for(role, sub_role) and \ + "action:role.grant_perm" not in actor.get("permissions", []): + raise HTTPException( + status_code=403, + detail="无权创建/分配特权角色(仅超级管理员)", + ) + + + diff --git a/app/api/schemas/agents.py b/app/api/schemas/agents.py new file mode 100644 index 0000000..105a3ea --- /dev/null +++ b/app/api/schemas/agents.py @@ -0,0 +1,39 @@ +from pydantic import BaseModel, Field + +class AgentCreate(BaseModel): + """创建智能体身份。""" + + name: str + description: str = "" + language: str = "zh" + model_name: str = "" + +class AgentUpdate(BaseModel): + """更新智能体身份字段(可空字段,仅提交需要变更的项)。""" + + name: str | None = None + description: str | None = None + language: str | None = None + model_name: str | None = None + use_fixed_soul: bool | None = None + +class AgentInfo(BaseModel): + """智能体身份记录(按用户隔离)。 + + - ``deletable``:是否允许删除(默认智能体由服务端保护为不可删)。 + - ``use_fixed_soul``:该智能体是否**必须**使用服务端托管、最高优先级的 + ``fixed_soul`` 不可变段(否则忽略)。 + """ + + id: str + user_id: str + port: str = "opc" + name: str + description: str = "" + language: str = "zh" + model_name: str = "" + created_at: str = "" + updated_at: str = "" + deletable: bool = True + use_fixed_soul: bool = False + diff --git a/app/api/schemas/auth.py b/app/api/schemas/auth.py new file mode 100644 index 0000000..3b76c65 --- /dev/null +++ b/app/api/schemas/auth.py @@ -0,0 +1,103 @@ +from pydantic import BaseModel, Field + +class IdentityInfo(BaseModel): + """账号绑定的一端口身份摘要(登录/选择身份时返回)。""" + + id: str + port: str = "opc" + role: str = "opc_member" + sub_role: str | None = None + name: str = "" + org_id: str | None = None + region_id: str | None = None + org_name: str | None = None + region_name: str | None = None + status: str = "active" + +class LoginRequest(BaseModel): + username: str + password: str + expires_in: int | None = Field( + default=None, + description="令牌有效期(秒),-1/0 表示永久,省略为 7 天", + ) + +class RegisterRequest(BaseModel): + username: str + password: str + expires_in: int | None = Field( + default=None, + description="令牌有效期(秒),-1/0 表示永久,省略为 7 天", + ) + +class UpdateProfileRequest(BaseModel): + """更新资料/凭据。``current_password`` 仅在修改用户名/密码时校验。""" + + current_password: str = "" + new_username: str | None = None + new_password: str | None = None + expires_in: int | None = None + # 演示用户资料字段(账户管理页可编辑) + nickname: str | None = None + account: str | None = None + company: str | None = None + room: str | None = None + avatar: str | None = None + company_avatar: str | None = None + +class RevokeTokenRequest(BaseModel): + token: str | None = Field( + default=None, + description="要吊销的令牌;省略则吊销当前令牌", + ) + +class AuthStatusResponse(BaseModel): + enabled: bool + has_users: bool + +class VerifyResponse(BaseModel): + valid: bool + username: str = "" + +class UserProfile(BaseModel): + """用户资料(登录/me/update-profile 均返回该结构)。""" + + username: str = "" + nickname: str = "" + account: str = "" + company: str = "" + room: str = "" + avatar: str = "" + company_avatar: str = "" + # RBAC(登录/me 返回;update-profile 不重签时不返回权限明细) + role: str = "opc_member" + sub_role: str | None = None + org_id: str | None = None + region_id: str | None = None + permissions: list[str] = Field(default_factory=list) + scope_region_ids: list[str] = Field(default_factory=list) + # 当前生效的端口身份(多身份绑定) + identity_id: str | None = None + port: str | None = None + identity_name: str = "" + +class LoginResponse(UserProfile): + """登录/注册成功后的响应:资料 + 新令牌。""" + + token: str = "" + identities: list[IdentityInfo] = Field(default_factory=list) + +class ProfileResponse(UserProfile): + """update-profile 成功后的响应;修改凭据时附带新令牌。""" + + token: str = "" + identities: list[IdentityInfo] = Field(default_factory=list) + +class SelectIdentityRequest(BaseModel): + """切换到指定端口身份:为新身份签发令牌。""" + + identity_id: str + + +# RBAC 管理请求/响应 + diff --git a/app/api/schemas/ecosystem.py b/app/api/schemas/ecosystem.py new file mode 100644 index 0000000..7baad49 --- /dev/null +++ b/app/api/schemas/ecosystem.py @@ -0,0 +1,19 @@ +from pydantic import BaseModel + +class RatingRequest(BaseModel): + score: int = 5 + comment: str = "" + to_id: str = "" + + + +class SignRequest(BaseModel): + opc_id: str = "" + + + +class DisputeRequest(BaseModel): + reason: str = "" + + + diff --git a/app/api/schemas/investor.py b/app/api/schemas/investor.py new file mode 100644 index 0000000..aee2e28 --- /dev/null +++ b/app/api/schemas/investor.py @@ -0,0 +1,33 @@ +from pydantic import BaseModel + +class PreferenceRequest(BaseModel): + industries: list[str] = [] + stage: str = "" + amount_min: int = 0 + amount_max: int = 0 + region_id: str | None = None + + + +class IntentRequest(BaseModel): + project_id: str + project_name: str = "" + message: str = "" + + + +class RoadshowCreate(BaseModel): + title: str + summary: str = "" + activity_type: str = "online" # online/offline/hybrid + scope_type: str = "all" # all/region/org + region_id: str | None = None + start_at: str = "" + end_at: str = "" + register_deadline: str = "" + quota: int = 0 + venue: str = "" + live_url: str = "" + + + diff --git a/app/api/schemas/opc.py b/app/api/schemas/opc.py new file mode 100644 index 0000000..a4663d0 --- /dev/null +++ b/app/api/schemas/opc.py @@ -0,0 +1,26 @@ +from pydantic import BaseModel + +class BidRequest(BaseModel): + quote: int = 0 + plan: str = "" + + + +class ProfileUpdate(BaseModel): + nickname: str | None = None + account: str | None = None + company: str | None = None + room: str | None = None + skills: list[str] = [] + credit_score: int | None = None + + + +class FinanceRecordCreate(BaseModel): + category: str = "income" # income | expense + amount: int + date: str = "" + note: str = "" + + + diff --git a/app/api/schemas/operator.py b/app/api/schemas/operator.py new file mode 100644 index 0000000..47ef5c7 --- /dev/null +++ b/app/api/schemas/operator.py @@ -0,0 +1,57 @@ +from pydantic import BaseModel + +class TaskCreateRequest(BaseModel): + title: str + category: str = "" + sub_category: str = "" + description: str = "" + mode: str = "grab" + budget_min: int = 0 + budget_max: int = 0 + deadline: str = "" + publisher_name: str = "" + + + +class TaskStatusRequest(BaseModel): + status: str # review/published/completed/cancelled + + + +class ProviderCreateRequest(BaseModel): + name: str + category: str = "" + level: str = "certified" + status: str = "pending" + contact: str = "" + + + +class ProviderUpdateRequest(BaseModel): + level: str | None = None + status: str | None = None + contact: str | None = None + + + +class ContentCreateRequest(BaseModel): + type: str = "news" + title: str + summary: str = "" + body: str = "" + status: str = "draft" + + + +class ContentStatusRequest(BaseModel): + status: str # published/offline/draft + + + +class ConfigUpdateRequest(BaseModel): + value: str + description: str = "" + + +# ── 任务管理 ────────────────────────────────────────────────────────────── + diff --git a/app/api/schemas/org.py b/app/api/schemas/org.py new file mode 100644 index 0000000..1566579 --- /dev/null +++ b/app/api/schemas/org.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel + +class OrgMemberAdd(BaseModel): + user_id: str | None = None + username: str | None = None # 支持按用户名添加(解析为 user_id) + role: str = "member" + is_admin: bool = False + + + diff --git a/app/api/schemas/portals.py b/app/api/schemas/portals.py new file mode 100644 index 0000000..845fdd8 --- /dev/null +++ b/app/api/schemas/portals.py @@ -0,0 +1,29 @@ +from pydantic import BaseModel + +class EnterpriseTaskCreate(BaseModel): + title: str + category: str = "" + sub_category: str = "" + description: str = "" + mode: str = "grab" + budget_min: int = 0 + budget_max: int = 0 + deadline: str = "" + publisher_name: str = "" + + + +class TaskReviewRequest(BaseModel): + action: str # accept | reject + comment: str = "" + + + +class ReferralCreate(BaseModel): + provider_id: str = "" + provider_name: str = "" + opc_id: str = "" + opc_name: str = "" + + + diff --git a/app/infrastructure/models.py b/app/infrastructure/models.py index 4e2c87c..cb121d7 100644 --- a/app/infrastructure/models.py +++ b/app/infrastructure/models.py @@ -576,168 +576,3 @@ class UserIdentity(Base): status: Mapped[str] = mapped_column(String, default="active") # active | disabled created_at: Mapped[str] = mapped_column(String, default="") updated_at: Mapped[str] = mapped_column(String, default="") - - -# =========================================================================== -# Pydantic 请求/响应模型 -# =========================================================================== - -class LoginRequest(BaseModel): - username: str - password: str - expires_in: int | None = Field( - default=None, - description="令牌有效期(秒),-1/0 表示永久,省略为 7 天", - ) - - -class RegisterRequest(BaseModel): - username: str - password: str - expires_in: int | None = Field( - default=None, - description="令牌有效期(秒),-1/0 表示永久,省略为 7 天", - ) - - -class UpdateProfileRequest(BaseModel): - """更新资料/凭据。``current_password`` 仅在修改用户名/密码时校验。""" - - current_password: str = "" - new_username: str | None = None - new_password: str | None = None - expires_in: int | None = None - # 演示用户资料字段(账户管理页可编辑) - nickname: str | None = None - account: str | None = None - company: str | None = None - room: str | None = None - avatar: str | None = None - company_avatar: str | None = None - - -class RevokeTokenRequest(BaseModel): - token: str | None = Field( - default=None, - description="要吊销的令牌;省略则吊销当前令牌", - ) - - -class AgentCreate(BaseModel): - """创建智能体身份。""" - - name: str - description: str = "" - language: str = "zh" - model_name: str = "" - - -class AgentUpdate(BaseModel): - """更新智能体身份字段(可空字段,仅提交需要变更的项)。""" - - name: str | None = None - description: str | None = None - language: str | None = None - model_name: str | None = None - use_fixed_soul: bool | None = None - - -class AgentInfo(BaseModel): - """智能体身份记录(按用户隔离)。 - - - ``deletable``:是否允许删除(默认智能体由服务端保护为不可删)。 - - ``use_fixed_soul``:该智能体是否**必须**使用服务端托管、最高优先级的 - ``fixed_soul`` 不可变段(否则忽略)。 - """ - - id: str - user_id: str - port: str = "opc" - name: str - description: str = "" - language: str = "zh" - model_name: str = "" - created_at: str = "" - updated_at: str = "" - deletable: bool = True - use_fixed_soul: bool = False - - -class AuthStatusResponse(BaseModel): - enabled: bool - has_users: bool - - -class VerifyResponse(BaseModel): - valid: bool - username: str = "" - - -class UserProfile(BaseModel): - """用户资料(登录/me/update-profile 均返回该结构)。""" - - username: str = "" - nickname: str = "" - account: str = "" - company: str = "" - room: str = "" - avatar: str = "" - company_avatar: str = "" - # RBAC(登录/me 返回;update-profile 不重签时不返回权限明细) - role: str = "opc_member" - sub_role: str | None = None - org_id: str | None = None - region_id: str | None = None - permissions: list[str] = Field(default_factory=list) - scope_region_ids: list[str] = Field(default_factory=list) - # 当前生效的端口身份(多身份绑定) - identity_id: str | None = None - port: str | None = None - identity_name: str = "" - - -class LoginResponse(UserProfile): - """登录/注册成功后的响应:资料 + 新令牌。""" - - token: str = "" - identities: list[IdentityInfo] = Field(default_factory=list) - - -class ProfileResponse(UserProfile): - """update-profile 成功后的响应;修改凭据时附带新令牌。""" - - token: str = "" - identities: list[IdentityInfo] = Field(default_factory=list) - - -class IdentityInfo(BaseModel): - """账号绑定的一端口身份摘要(登录/选择身份时返回)。""" - - id: str - port: str = "opc" - role: str = "opc_member" - sub_role: str | None = None - name: str = "" - org_id: str | None = None - region_id: str | None = None - org_name: str | None = None - region_name: str | None = None - status: str = "active" - - -class SelectIdentityRequest(BaseModel): - """切换到指定端口身份:为新身份签发令牌。""" - - identity_id: str - - -# RBAC 管理请求/响应 -class SetUserRoleRequest(BaseModel): - role: str - sub_role: str | None = None - org_id: str | None = None - region_id: str | None = None - - -class SetUserStatusRequest(BaseModel): - status: str = "active" # active | disabled