Files
wecom_it_smart_desk/backend/app/schemas/qrcode.py
T

127 lines
4.8 KiB
Python
Raw Normal View History

# =============================================================================
# 企微IT智能服务台 — 扫码登录 Pydantic Schema
# =============================================================================
# 说明:定义扫码登录的请求/响应数据结构
# 涵盖 4 个端点的入参/出参:
# 1. POST /api/auth_qrcode/create — 创建扫码登录票据
# 2. GET /api/auth_qrcode/poll/{ticket} — 前端轮询扫码状态
# 3. POST /api/auth_qrcode/scan — 企微用户扫码后 OAuth code 回调
# 4. POST /api/auth_qrcode/confirm — 当前已登录用户确认授权
# =============================================================================
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel, Field
# --------------------------------------------------------------------------
# POST /api/auth_qrcode/create — 创建扫码登录票据
# --------------------------------------------------------------------------
class QrcodeCreateResponse(BaseModel):
"""扫码登录票据创建响应。
Attributes:
ticket: 票据 UUID,前端用此票据轮询状态
qrcode_url: 企微 OAuth2 授权 URL(前端渲染二维码)
expires_in: 票据有效期(秒),默认 120
expires_at: 票据过期时间(ISO 8601 字符串)
"""
ticket: str = Field(..., description="票据 UUID")
qrcode_url: str = Field(..., description="企微 OAuth2 授权 URL")
expires_in: int = Field(120, description="有效期(秒)")
expires_at: datetime = Field(..., description="过期时间(ISO 8601)")
# --------------------------------------------------------------------------
# GET /api/auth_qrcode/poll/{ticket} — 轮询扫码状态
# --------------------------------------------------------------------------
class QrcodePollResponse(BaseModel):
"""扫码登录票据轮询响应。
status 取值:
- waiting: 票据有效,等待扫码
- scanned: 已扫码,等待确认
- confirmed: 已确认登录成功,附带 token
- expired: 票据过期/不存在
Attributes:
status: 扫码状态
employee_id: 企微用户 ID(scanned/confirmed 时返回)
name: 企微用户姓名(scanned/confirmed 时返回)
token: 登录 Token(confirmed 时返回,前端存 localStorage)
"""
status: str = Field(..., description="等待/已扫码/已确认/已过期")
employee_id: Optional[str] = Field(None, description="企微用户 ID")
name: Optional[str] = Field(None, description="企微用户姓名")
token: Optional[str] = Field(None, description="登录 Token")
# --------------------------------------------------------------------------
# POST /api/auth_qrcode/scan — 企微 OAuth code 回调
# --------------------------------------------------------------------------
class QrcodeScanRequest(BaseModel):
"""扫码登录扫码请求体。
Attributes:
ticket: 扫码登录票据(UUID)
code: 企微 OAuth2 授权回调 code
"""
ticket: str = Field(..., min_length=1, description="扫码登录票据")
code: str = Field(..., min_length=1, description="企微 OAuth2 授权 code")
class QrcodeScanResponse(BaseModel):
"""扫码登录扫码响应。
Attributes:
success: 是否成功
message: 提示消息
"""
success: bool = Field(..., description="是否成功")
message: str = Field(..., description="提示消息")
# --------------------------------------------------------------------------
# POST /api/auth_qrcode/confirm — 当前已登录用户确认授权
# --------------------------------------------------------------------------
class QrcodeConfirmRequest(BaseModel):
"""扫码登录确认请求体。
Attributes:
ticket: 扫码登录票据(UUID)
otp_code: OTP 动态码(管理员场景下可选,普通坐席可空)
"""
ticket: str = Field(..., min_length=1, description="扫码登录票据")
otp_code: Optional[str] = Field(
None,
min_length=6,
max_length=6,
description="OTP 动态码(管理员可选,普通坐席留空)",
)
class QrcodeConfirmResponse(BaseModel):
"""扫码登录确认响应。
Attributes:
token: 登录 Token(scanned 用户换发的新 token)
employee_id: 企微用户 ID
name: 用户姓名
roles: 用户角色列表
require_otp: 是否需要 OTP 二次验证(预留,本任务不强制)
"""
token: str = Field(..., description="登录 Token")
employee_id: str = Field(..., description="企微用户 ID")
name: str = Field(..., description="用户姓名")
roles: List[str] = Field(default_factory=list, description="用户角色列表")
require_otp: Optional[bool] = Field(
None,
description="是否需要 OTP 二次验证(预留字段,Phase 2.1 实现)",
)