Files
chat/services/user_service/schemas.py
Andrew K. Choi 537e7b363f
All checks were successful
continuous-integration/drone/push Build is passing
main commit
2025-10-16 16:30:25 +09:00

133 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from datetime import date
from typing import Optional
from uuid import UUID
from pydantic import BaseModel, EmailStr, Field, field_validator
class UserBase(BaseModel):
email: EmailStr
username: Optional[str] = None
phone: Optional[str] = None
phone_number: Optional[str] = None # Альтернативное поле для phone
first_name: Optional[str] = ""
last_name: Optional[str] = ""
full_name: Optional[str] = None # Будет разделено на first_name и last_name
date_of_birth: Optional[date] = None
bio: Optional[str] = Field(None, max_length=500)
@field_validator("full_name")
@classmethod
def split_full_name(cls, v, info):
"""Разделяет полное имя на first_name и last_name."""
if v:
values = info.data
parts = v.split(" ", 1)
if "first_name" in values and not values["first_name"]:
info.data["first_name"] = parts[0]
if "last_name" in values and not values["last_name"]:
info.data["last_name"] = parts[1] if len(parts) > 1 else ""
return v
@field_validator("phone_number")
@classmethod
def map_phone_number(cls, v, info):
"""Копирует phone_number в phone если phone не указан."""
if v:
values = info.data
if "phone" in values and not values["phone"]:
info.data["phone"] = v
return v
class UserCreate(UserBase):
password: str = Field(..., min_length=8, description="Password for user registration")
@field_validator("password")
@classmethod
def validate_password_bytes(cls, v):
"""Basic validation for password."""
# Только проверка минимальной длины
if not v or len(v.strip()) < 8:
raise ValueError("Password must be at least 8 characters")
return v
class UserUpdate(BaseModel):
first_name: Optional[str] = Field(None, min_length=1, max_length=50)
last_name: Optional[str] = Field(None, min_length=1, max_length=50)
phone: Optional[str] = None
date_of_birth: Optional[date] = None
bio: Optional[str] = Field(None, max_length=500)
avatar_url: Optional[str] = None
# Emergency contacts
emergency_contact_1_name: Optional[str] = Field(None, max_length=100)
emergency_contact_1_phone: Optional[str] = Field(None, max_length=20)
emergency_contact_2_name: Optional[str] = Field(None, max_length=100)
emergency_contact_2_phone: Optional[str] = Field(None, max_length=20)
# Settings
location_sharing_enabled: Optional[bool] = None
emergency_notifications_enabled: Optional[bool] = None
push_notifications_enabled: Optional[bool] = None
class UserResponse(UserBase):
id: int
uuid: str
avatar_url: Optional[str] = None
emergency_contact_1_name: Optional[str] = None
emergency_contact_1_phone: Optional[str] = None
emergency_contact_2_name: Optional[str] = None
emergency_contact_2_phone: Optional[str] = None
location_sharing_enabled: bool
emergency_notifications_enabled: bool
push_notifications_enabled: bool
email_verified: bool
phone_verified: bool
is_active: bool
@field_validator("uuid", mode="before")
@classmethod
def convert_uuid_to_str(cls, v):
if isinstance(v, UUID):
return str(v)
return v
class Config:
from_attributes = True
class UserLogin(BaseModel):
email: Optional[EmailStr] = None
username: Optional[str] = None
password: str = Field(..., min_length=1, description="Password for authentication")
@field_validator("password")
@classmethod
def validate_password_bytes(cls, v):
"""Basic password validation."""
if not v or len(v.strip()) == 0:
raise ValueError("Password cannot be empty")
# Не делаем проверку на максимальную длину - passlib/bcrypt сам справится с ограничениями
return v
@field_validator("username")
@classmethod
def validate_login_fields(cls, v, info):
"""Ensure at least email or username is provided."""
email = info.data.get('email')
if not email and not v:
raise ValueError("Either email or username must be provided")
return v
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
email: Optional[str] = None