Files
DadaoTask/backend/app/api/schemas.py
T
Steven 2b493bd9f8
CI / backend (push) Canceled after 0s
fix(m0): 迁移可执行 + 测试全绿(33 条)
跑通迁移与测试后修掉的真问题:

- alembic 0001:asyncpg 走预备语句,一次 execute 只能一条 SQL。
  CREATE FUNCTION / CREATE POLICY / GRANT 全部拆成单语句逐条执行,
  否则报 "cannot insert multiple commands into a prepared statement"。
- 创建工作区:ORM flush 只按 relationship 排序,裸外键不算数,
  member 可能先于 workspace 落地撞 FK。改为先 flush workspace 再插 member。
- datetime.UTC 是 3.11+ 才有的,本机 3.10 直接 ImportError。改用 timezone.utc。
- 幂等中间件:原来会缓存 4xx。校验失败被缓存后,用户改对参数仍拿到同一个 422。
  改为只缓存 <400。
- 发码节流窗口改为可配置 SMS_THROTTLE_SECONDS(测试置 0),
  节流用例自己显式打开,避免"整库关掉节流"导致节流从未被验证。
- 租户隔离用例:pytest.raises(Exception) 改为精确的 ProgrammingError,
  否则任何异常都会让"应用角色不能建表"这条断言假通过。

验收:pytest 33 passed;ruff check / format 通过;真机跑 uvicorn,
/health、/version、登录、建工作区、列表、/auth/me 全通。
2026-10-28 03:22:59 +08:00

68 lines
1.3 KiB
Python

"""对外输出模型。字段命名一次定死,客户端按契约生成。"""
from __future__ import annotations
import uuid
from datetime import datetime
from pydantic import BaseModel, ConfigDict, Field
class UserOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
phone: str = Field(description="已打码的手机号,如 138****8000")
nickname: str
created_at: datetime
class TokenOut(BaseModel):
access_token: str
refresh_token: str
token_type: str = "bearer" # noqa: S105 - 不是密码,是 OAuth2 的固定字段值
expires_in: int
class LoginOut(BaseModel):
user: UserOut
tokens: TokenOut
class WorkspaceOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
name: str
slug: str
plan: str
role: str = ""
created_at: datetime
class MemberOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
user_id: uuid.UUID
role: str
status: str
nickname: str = ""
phone: str = ""
joined_at: datetime
class InvitationOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
code: str
role: str
expires_at: datetime
accepted_at: datetime | None = None
class MeOut(BaseModel):
user: UserOut
workspaces: list[WorkspaceOut]