68 lines
2.0 KiB
Python
68 lines
2.0 KiB
Python
from datetime import datetime
|
|
from typing import Annotated, Literal
|
|
|
|
from pydantic import BaseModel, ConfigDict, EmailStr, Field, SecretStr, field_validator
|
|
|
|
Password = Annotated[SecretStr, Field(min_length=15, max_length=128)]
|
|
|
|
|
|
class AuthInput(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class ProfileInput(AuthInput):
|
|
nickname: str | None = Field(None, min_length=1, max_length=80)
|
|
email: EmailStr | None = Field(None, max_length=254)
|
|
|
|
@field_validator("nickname", "email", mode="before")
|
|
@classmethod
|
|
def optional_text(cls, value):
|
|
return (value.strip() or None) if isinstance(value, str) else value
|
|
|
|
@field_validator("nickname")
|
|
@classmethod
|
|
def no_control_characters(cls, value):
|
|
if value and any(ord(char) < 32 or ord(char) == 127 for char in value):
|
|
raise ValueError("昵称不能包含控制字符")
|
|
return value
|
|
|
|
|
|
class RegisterInput(ProfileInput):
|
|
username: str = Field(min_length=3, max_length=32, pattern=r"^[a-z][a-z0-9_]{2,31}$")
|
|
password: Password
|
|
|
|
@field_validator("username", mode="before")
|
|
@classmethod
|
|
def canonical_username(cls, value):
|
|
return value.strip().lower() if isinstance(value, str) else value
|
|
|
|
|
|
class LoginInput(AuthInput):
|
|
username: str = Field(min_length=3, max_length=32, pattern=r"^[a-z][a-z0-9_]{2,31}$")
|
|
password: SecretStr = Field(min_length=1, max_length=128)
|
|
|
|
@field_validator("username", mode="before")
|
|
@classmethod
|
|
def canonical_username(cls, value):
|
|
return value.strip().lower() if isinstance(value, str) else value
|
|
|
|
|
|
class PasswordChangeInput(AuthInput):
|
|
current_password: SecretStr = Field(min_length=1, max_length=128)
|
|
new_password: Password
|
|
|
|
|
|
class UserRead(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
id: int
|
|
username: str
|
|
nickname: str | None
|
|
email: str | None
|
|
role: Literal["user", "admin"]
|
|
created_at: datetime
|
|
|
|
|
|
class SessionRead(UserRead):
|
|
csrf_token: str
|