import re from typing import Literal, Optional, Annotated from fastapi import HTTPException from pydantic import BaseModel, Field, field_validator default_portrait_url = '#' ChinaPhone = Annotated[str, Field(pattern=r"^1[3-9]\d{9}$")] EmailField = Annotated[str, Field(pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$")] class UserIn(BaseModel): username: str password: str email: str phone: Optional[str] = None lang_pref: Literal['jp', 'fr', 'private'] = "private" portrait: str = default_portrait_url code: str @field_validator('email') @classmethod def validate_email(cls, v): if not re.match(pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$", string=v): raise HTTPException(status_code=400, detail="邮箱格式错误") return v @field_validator('phone') @classmethod def validate_phone(cls, v): if not re.match(pattern=r"^1[3-9]\d{9}$", string=v): raise HTTPException(status_code=400, detail="手机号格式错误") return v # @field_validator('username') # @classmethod # def validate_username(cls, v): # if not (3 <= len(v) <= 20): # raise ValueError("用户名长度必须在3到20个字符之间") # if not re.fullmatch(r'[a-zA-Z_][a-zA-Z0-9_]*', v): # raise ValueError("用户名只能包含字母、数字和下划线,且不能以数字开头") # return v # 校验密码 # @field_validator("password") # @classmethod # def verify_password(cls, password: str): # if len(password) < 6 or len(password) > 20: # raise ValueError("Password must be between 6 and 20 characters") # # 检查是否包含至少一个数字 # if not re.search(r'\d', password): # raise ValueError('密码必须包含至少一个数字') # # 检查是否包含非法特殊字符(只允许字母和数字) # if re.search(r'[^a-zA-Z0-9]', password): # raise ValueError('密码不能包含特殊字符') # return password # @field_validator('lang_pref') # @classmethod # def validate_lang_pref(cls, v): # assert v in ('jp', 'en') # return v class UserOut(BaseModel): name: str potrait: str = '#' class UpdateUserRequest(BaseModel): current_password: Optional[str] = None new_username: Optional[str] = None new_password: Optional[str] = None new_language: Literal["jp", "fr", "private"] = "private" # lang_pref: str = "jp" class UserLoginRequest(BaseModel): name: str password: str class UserSchema(BaseModel): id: int name: str class UserResetPhoneRequest(BaseModel): phone_number: ChinaPhone class VerifyPhoneCodeRequest(BaseModel): code: str phone: ChinaPhone class UserResetEmailRequest(BaseModel): email: EmailField class VerifyEmailRequest(BaseModel): email: EmailField code: str class UserResetPasswordRequest(BaseModel): password: str