from typing import Optional from pydantic import BaseModel, EmailStr, Field, validator class UserBase(BaseModel): """ Base schema for user data """ email: Optional[EmailStr] = None username: Optional[str] = Field(None, min_length=3, max_length=20, pattern=r'^[a-zA-Z0-9_]+$') is_active: Optional[bool] = True is_superuser: bool = False @validator('username') def username_not_empty(cls, v): if v == "": raise ValueError('Username cannot be empty string') return v @validator('email', 'username') def check_one_field_present(cls, v, values): # If this is the second field (email or username) and both are None, raise error if 'email' in values and v is None and values['email'] is None: raise ValueError('Either email or username must be provided') if 'username' in values and v is None and values['username'] is None: raise ValueError('Either email or username must be provided') return v class UserCreate(UserBase): """ Schema for creating a new user """ password: str = Field(..., min_length=8) class UserUpdate(UserBase): """ Schema for updating a user """ password: Optional[str] = Field(None, min_length=8) class UserInDBBase(UserBase): """ Schema for user in DB """ id: int class Config: orm_mode = True class User(UserInDBBase): """ Schema for returning user information """ pass class UserInDB(UserInDBBase): """ Schema with password hash (for internal use) """ hashed_password: str class Token(BaseModel): """ Token schema """ access_token: str token_type: str class TokenPayload(BaseModel): """ Token payload schema """ sub: Optional[int] = None