"""User model definitions""" from typing import Optional, List from pydantic import BaseModel, EmailStr, Field, ConfigDict from datetime import datetime from enum import Enum from bson import ObjectId class UserRole(str, Enum): """User role enumeration""" SYSTEM_ADMIN = "system_admin" GROUP_ADMIN = "group_admin" USER = "user" class PyObjectId(ObjectId): """Custom ObjectId type for Pydantic""" @classmethod def __get_validators__(cls): yield cls.validate @classmethod def validate(cls, v): if not ObjectId.is_valid(v): raise ValueError("Invalid ObjectId") return ObjectId(v) @classmethod def __get_pydantic_json_schema__(cls, field_schema): field_schema.update(type="string") class UserBase(BaseModel): """Base user model""" email: EmailStr username: str = Field(..., min_length=3, max_length=50) full_name: Optional[str] = None role: UserRole = UserRole.USER profile_picture: Optional[str] = None phone_number: Optional[str] = None gender: Optional[str] = None birth_date: Optional[str] = None is_active: bool = True model_config = ConfigDict(use_enum_values=True) class UserCreate(UserBase): """User creation model""" password: str = Field(..., min_length=8) class UserUpdate(BaseModel): """User update model""" email: Optional[EmailStr] = None username: Optional[str] = Field(None, min_length=3, max_length=50) full_name: Optional[str] = None role: Optional[UserRole] = None profile_picture: Optional[str] = None phone_number: Optional[str] = None gender: Optional[str] = None birth_date: Optional[str] = None is_active: Optional[bool] = None password: Optional[str] = Field(None, min_length=8) class User(UserBase): """User response model""" id: str = Field(alias="_id") created_at: datetime updated_at: datetime model_config = ConfigDict( populate_by_name=True, arbitrary_types_allowed=True, json_encoders={ObjectId: str} ) class UserInDB(User): """User model in database""" hashed_password: str class UserLogin(BaseModel): """User login model""" username: str password: str class TokenData(BaseModel): """Token data model""" user_id: Optional[str] = None username: Optional[str] = None role: Optional[str] = None class Token(BaseModel): """Token response model""" access_token: str refresh_token: str token_type: str = "bearer" class TokenRefresh(BaseModel): """Token refresh request model""" refresh_token: str