You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

3.8 KiB

用户服务完整实现

日期: 2026-01-29
类型: 功能实现
影响范围: 用户服务 API、Model 层、测试

概述

完成用户服务的完整实现,包括统一 API 响应格式、修复时区问题、更新测试代码。所有 11 个集成测试全部通过。

主要变更

1. 统一 API 响应格式

修改文件:

  • server/app/api/v1/auth.py
  • server/app/api/v1/users.py

变更内容:

  • 所有 API 端点使用 success_response() 包装返回数据
  • 移除 response_model 参数
  • 统一响应格式:{"code": 200, "message": "Success", "data": {...}}
  • 移除不存在的 service.close() 调用(Session 由 FastAPI 依赖注入自动管理)

影响的端点:

  • POST /api/v1/auth/sms/send - 发送短信验证码
  • POST /api/v1/auth/login/phone - 手机号登录
  • POST /api/v1/auth/refresh - 刷新 Token
  • POST /api/v1/auth/logout - 用户登出
  • GET /api/v1/users/me - 获取当前用户信息
  • PUT /api/v1/users/me - 更新用户信息
  • PUT /api/v1/users/me/username - 修改用户名
  • POST /api/v1/users/me/avatar - 上传头像
  • POST /api/v1/users/me/bind/phone - 绑定手机号
  • POST /api/v1/users/me/bind/wechat - 绑定微信
  • POST /api/v1/users/me/bind/email - 绑定邮箱
  • GET /api/v1/users/me/credits - 查询积分信息
  • DELETE /api/v1/users/me - 删除用户

2. 修复 User Model 时区问题

修改文件: server/app/models/user.py

问题: 时间字段使用了带时区的 datetime,但未在 SQLModel 中指定 DateTime(timezone=True),导致数据库操作时出现时区不匹配错误。

修复:

created_at: datetime = Field(
    default_factory=lambda: datetime.now(timezone.utc),
    sa_column=Column(DateTime(timezone=True), nullable=False),
    description="创建时间(UTC)"
)
updated_at: datetime = Field(
    default_factory=lambda: datetime.now(timezone.utc),
    sa_column=Column(DateTime(timezone=True), nullable=False),
    description="更新时间(UTC)"
)
deleted_at: Optional[datetime] = Field(
    default=None,
    sa_column=Column(DateTime(timezone=True), nullable=True),
    description="软删除时间(UTC)"
)

3. 更新集成测试

修改文件: server/tests/integration/test_user_api.py

变更内容:

  • 更新 login_and_get_token() 辅助函数以适配新的响应格式
  • 更新 test_phone_login() 测试以验证统一响应格式
  • 修复 test_update_user_info() 使用正确的 HTTP 方法(PUT 而非 PATCH)

测试结果: 11/11 测试通过

技术细节

响应格式示例

之前:

{
  "access_token": "...",
  "refresh_token": "...",
  "user": {...}
}

现在:

{
  "code": 200,
  "message": "Success",
  "data": {
    "access_token": "...",
    "refresh_token": "...",
    "user": {...}
  }
}

时区处理

  • 所有时间字段使用 datetime.now(timezone.utc) 生成 UTC 时间
  • 数据库列类型为 TIMESTAMPTZ(PostgreSQL)
  • SQLModel 使用 DateTime(timezone=True) 确保时区信息正确传递

测试覆盖

  • 健康检查
  • 发送短信验证码
  • 手机号登录
  • 获取当前用户信息
  • 更新用户信息
  • 查询积分信息
  • 绑定邮箱
  • 用户登出
  • 无效验证码登录(边界测试)
  • 无 Token 访问受保护路由(边界测试)
  • 无效 Token 访问受保护路由(边界测试)

相关文档

  • 用户服务设计文档: docs/requirements/backend/04-services/user/user-service.md
  • 统一 API 响应规范: docs/server/changelogs/2026-01-26-unified-api-response.md
  • 时区标准: docs/architecture/datetime-timezone-standards.md

后续优化

  1. 处理 Pydantic 序列化警告(Decimal 类型)
  2. 实现 Token 黑名单机制(logout 端点 TODO)
  3. 添加更多边界测试用例