from pydantic import BaseModel, ConfigDict, field_validator from datetime import datetime from typing import Literal, Optional AccentColor = Literal["cyan", "blue", "green", "purple", "red", "orange", "pink", "yellow"] def _validate_pin_length(v: str, label: str = "PIN") -> str: if len(v) < 4: raise ValueError(f'{label} must be at least 4 characters') if len(v) > 72: raise ValueError(f'{label} must be at most 72 characters') return v class SettingsCreate(BaseModel): pin: str @field_validator('pin') @classmethod def pin_length(cls, v: str) -> str: return _validate_pin_length(v) class SettingsUpdate(BaseModel): accent_color: Optional[AccentColor] = None upcoming_days: int | None = None preferred_name: str | None = None weather_city: str | None = None weather_lat: float | None = None weather_lon: float | None = None @field_validator('weather_lat') @classmethod def validate_lat(cls, v: float | None) -> float | None: if v is not None and (v < -90 or v > 90): raise ValueError('Latitude must be between -90 and 90') return v @field_validator('weather_lon') @classmethod def validate_lon(cls, v: float | None) -> float | None: if v is not None and (v < -180 or v > 180): raise ValueError('Longitude must be between -180 and 180') return v class SettingsResponse(BaseModel): id: int accent_color: str upcoming_days: int preferred_name: str | None = None weather_city: str | None = None weather_lat: float | None = None weather_lon: float | None = None created_at: datetime updated_at: datetime model_config = ConfigDict(from_attributes=True) class ChangePinRequest(BaseModel): old_pin: str new_pin: str @field_validator('new_pin') @classmethod def new_pin_length(cls, v: str) -> str: return _validate_pin_length(v, "New PIN")