BakoAI / app /models /user.py
Okidi Norbert
Deployment fix: clean backend only
c6abe34
"""
Pydantic models for user-related schemas.
"""
from enum import Enum
from datetime import datetime
from typing import Optional
from uuid import UUID
from pydantic import BaseModel, EmailStr, Field, ConfigDict
from pydantic.alias_generators import to_camel
# AccountType Enum Refactor: Added robust validation for 'personal' type and safe fallbacks.
class AccountType(str, Enum):
"""User account type determining access level."""
TEAM = "team"
COACH = "coach"
PLAYER = "player"
PERSONAL = "personal"
@classmethod
def _missing_(cls, value):
if not isinstance(value, str):
return cls.PLAYER
val = value.lower()
# Explicit mapping to handle any weirdness on server
if val == "team": return cls.TEAM
if val == "coach": return cls.COACH
if val == "player": return cls.PLAYER
if val == "personal": return cls.PERSONAL
return cls.PLAYER # Fallback
class UserBase(BaseModel):
"""Base user fields."""
email: EmailStr
model_config = ConfigDict(
alias_generator=to_camel,
populate_by_name=True,
from_attributes=True
)
class UserCreate(UserBase):
"""Request schema for user registration."""
password: str = Field(..., min_length=8, description="Password must be at least 8 characters")
account_type: AccountType = Field(..., description="Account type: 'team', 'coach', 'player', or 'personal'")
full_name: Optional[str] = Field(None, max_length=100)
class UserLogin(BaseModel):
"""Request schema for user login."""
email: EmailStr
password: str
class UserUpdate(BaseModel):
"""Request schema for updating user profile."""
full_name: Optional[str] = Field(None, max_length=100)
avatar_url: Optional[str] = None
staff_role: Optional[str] = None
phone: Optional[str] = None
class User(UserBase):
"""Complete user model returned from API."""
id: UUID
account_type: AccountType
full_name: Optional[str] = None
avatar_url: Optional[str] = None
phone: Optional[str] = None
organization_id: Optional[UUID] = None
staff_role: Optional[str] = None
created_at: datetime
updated_at: Optional[datetime] = None
class UserInDB(User):
"""User model with hashed password for internal use."""
hashed_password: str
class TokenResponse(BaseModel):
"""Response schema for authentication tokens."""
access_token: str
refresh_token: str
token_type: str = "bearer"
expires_in: int = Field(..., description="Token expiration in seconds")
user: Optional[User] = None
model_config = ConfigDict(
alias_generator=to_camel,
populate_by_name=True
)
class RefreshTokenRequest(BaseModel):
"""Request schema for refreshing access tokens."""
refresh_token: str
model_config = ConfigDict(
alias_generator=to_camel,
populate_by_name=True
)
class TokenPayload(BaseModel):
"""JWT token payload schema."""
sub: str # User ID
email: str
account_type: AccountType
organization_id: Optional[str] = None
exp: datetime
model_config = ConfigDict(
alias_generator=to_camel,
populate_by_name=True
)