2025-05-30 17:39:08 +00:00

97 lines
2.4 KiB
Python

"""
User schemas for API request and response validation
"""
import re
from typing import Optional
from pydantic import BaseModel, EmailStr, Field, validator
class UserBase(BaseModel):
"""
Base user schema with common attributes
"""
email: EmailStr
username: str = Field(..., min_length=3, max_length=50)
is_active: Optional[bool] = True
class UserCreate(UserBase):
"""
Schema for user creation with password
"""
password: str = Field(..., min_length=8)
@validator('password')
def password_strength(cls, v):
"""
Validate password strength
"""
if not re.search(r'[A-Z]', v):
raise ValueError('Password must contain at least one uppercase letter')
if not re.search(r'[a-z]', v):
raise ValueError('Password must contain at least one lowercase letter')
if not re.search(r'[0-9]', v):
raise ValueError('Password must contain at least one digit')
return v
class UserUpdate(BaseModel):
"""
Schema for user update
"""
email: Optional[EmailStr] = None
username: Optional[str] = Field(None, min_length=3, max_length=50)
password: Optional[str] = Field(None, min_length=8)
is_active: Optional[bool] = None
@validator('password')
def password_strength(cls, v):
"""
Validate password strength if provided
"""
if v is None:
return v
if not re.search(r'[A-Z]', v):
raise ValueError('Password must contain at least one uppercase letter')
if not re.search(r'[a-z]', v):
raise ValueError('Password must contain at least one lowercase letter')
if not re.search(r'[0-9]', v):
raise ValueError('Password must contain at least one digit')
return v
class UserInDBBase(UserBase):
"""
Base schema for user in database
"""
id: int
is_superuser: Optional[bool] = False
class Config:
"""
Pydantic config
"""
orm_mode = True
class User(UserInDBBase):
"""
Schema for user response
"""
pass
class UserInDB(UserInDBBase):
"""
Schema for user in database with password
"""
hashed_password: str
class Token(BaseModel):
"""
Schema for access token
"""
access_token: str
token_type: str
class TokenPayload(BaseModel):
"""
Schema for token payload
"""
sub: Optional[int] = None