- Add first_day_of_week column to settings (0=Sunday, 1=Monday) - Add Calendar section in Settings with toggle button - Pass firstDay to FullCalendar from settings - Align calendar toolbar and sidebar header to h-16 (matches UMBRA header) - Remove border/padding wrapper from calendar grid for full-width layout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
79 lines
2.3 KiB
Python
79 lines
2.3 KiB
Python
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
|
|
first_day_of_week: int | None = None
|
|
|
|
@field_validator('first_day_of_week')
|
|
@classmethod
|
|
def validate_first_day(cls, v: int | None) -> int | None:
|
|
if v is not None and v not in (0, 1):
|
|
raise ValueError('first_day_of_week must be 0 (Sunday) or 1 (Monday)')
|
|
return v
|
|
|
|
@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
|
|
first_day_of_week: int = 0
|
|
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")
|