from typing import Optional from pydantic import BaseModel, EmailStr, Field, field_validator from datetime import datetime from typing import List # 中国大陆手机号(与 M2M 同步等接口一致) _CN_MOBILE_PATTERN = r"^1[3-9]\d{9}$" class UserBase(BaseModel): mobile: str name: Optional[str] = None english_name: Optional[str] = None status: str = "PENDING" role: Optional[str] = "ORDINARY_USER" is_deleted: int = 0 class UserCreate(UserBase): password: str admin_password: Optional[str] = None class UserRegister(BaseModel): mobile: str password: str sms_code: str # Added field name: str # Chinese Name class PromoteUserRequest(BaseModel): password: str captcha_id: str captcha_code: str class DeleteUserRequest(BaseModel): """删除普通用户(软删除)时校验操作者密码与短信验证码。""" password: str sms_code: str class BatchResetEnglishNameRequest(BaseModel): user_ids: List[int] admin_password: str class UserUpdate(BaseModel): password: Optional[str] = None mobile: Optional[str] = None name: Optional[str] = None english_name: Optional[str] = None status: Optional[str] = None role: Optional[str] = None is_deleted: Optional[int] = None admin_password: Optional[str] = None class UserSyncRequest(BaseModel): mobile: str = Field(..., pattern=_CN_MOBILE_PATTERN, description="用户手机号(平台唯一标识)") name: Optional[str] = Field( None, description="姓名;UPSERT 时必填。新建用户时英文名由平台根据姓名自动生成并去重", ) english_name: Optional[str] = Field( None, description="已废弃:M2M 同步不再使用此字段,英文名由平台根据姓名生成", ) password: Optional[str] = None status: Optional[str] = None mapped_key: str = Field(..., min_length=1, max_length=100, description="外部系统用户 ID(映射账号)") mapped_email: Optional[str] = None # External User Email is_active: Optional[bool] = None # True=Active, False=Disabled. None=No Change sync_action: Optional[str] = "UPSERT" @field_validator("mobile", "mapped_key", mode="before") @classmethod def strip_required_str(cls, v): if isinstance(v, str): return v.strip() return v class UserInDBBase(UserBase): id: int created_at: datetime updated_at: datetime class Config: from_attributes = True class User(UserInDBBase): pass class UserInDB(UserInDBBase): password_hash: str class UserList(BaseModel): total: int items: List[User] class UserSyncSimple(BaseModel): mobile: str name: Optional[str] = None english_name: Optional[str] = None class Config: from_attributes = True class UserSyncList(BaseModel): total: int items: List[UserSyncSimple]