"""SQLModel database table definitions.""" from __future__ import annotations from datetime import datetime, timezone from typing import Any from sqlmodel import JSON, Column, Field, SQLModel def _utcnow() -> datetime: return datetime.now(timezone.utc) class User(SQLModel, table=True): """Application user.""" id: int | None = Field(default=None, primary_key=True) username: str = Field(index=True, unique=True) hashed_password: str role: str = Field(default="user") # "admin" or "user" created_at: datetime = Field(default_factory=_utcnow) class ImmichServer(SQLModel, table=True): """Immich server connection.""" __tablename__ = "immich_server" id: int | None = Field(default=None, primary_key=True) user_id: int = Field(foreign_key="user.id") name: str = Field(default="Immich") url: str api_key: str external_domain: str | None = None created_at: datetime = Field(default_factory=_utcnow) class NotificationTarget(SQLModel, table=True): """Notification destination (Telegram chat, webhook URL).""" __tablename__ = "notification_target" id: int | None = Field(default=None, primary_key=True) user_id: int = Field(foreign_key="user.id") type: str # "telegram" or "webhook" name: str config: dict[str, Any] = Field(default_factory=dict, sa_column=Column(JSON)) created_at: datetime = Field(default_factory=_utcnow) class MessageTemplate(SQLModel, table=True): """Jinja2 message template.""" __tablename__ = "message_template" id: int | None = Field(default=None, primary_key=True) user_id: int = Field(foreign_key="user.id") name: str body: str = Field(default="") body_ru: str = Field(default="") # Russian locale variant (empty = use body) event_type: str = Field(default="") # "" = all events, or specific type is_default: bool = Field(default=False) created_at: datetime = Field(default_factory=_utcnow) class AlbumTracker(SQLModel, table=True): """Album change tracker configuration.""" __tablename__ = "album_tracker" id: int | None = Field(default=None, primary_key=True) user_id: int = Field(foreign_key="user.id") server_id: int = Field(foreign_key="immich_server.id") name: str album_ids: list[str] = Field(default_factory=list, sa_column=Column(JSON)) event_types: list[str] = Field( default_factory=lambda: ["assets_added"], sa_column=Column(JSON), ) target_ids: list[int] = Field(default_factory=list, sa_column=Column(JSON)) template_id: int | None = Field(default=None, foreign_key="message_template.id") scan_interval: int = Field(default=60) # seconds enabled: bool = Field(default=True) quiet_hours_start: str | None = None # "HH:MM" quiet_hours_end: str | None = None # "HH:MM" # Enhanced filtering (matching HAOS blueprint) track_images: bool = Field(default=True) track_videos: bool = Field(default=True) notify_favorites_only: bool = Field(default=False) include_people: bool = Field(default=True) include_asset_details: bool = Field(default=False) max_assets_to_show: int = Field(default=5) assets_order_by: str = Field(default="none") # none/date/rating/name/random assets_order: str = Field(default="descending") created_at: datetime = Field(default_factory=_utcnow) class ScheduledJob(SQLModel, table=True): """Scheduled notification job (periodic summary, scheduled assets, memory mode).""" __tablename__ = "scheduled_job" id: int | None = Field(default=None, primary_key=True) tracker_id: int = Field(foreign_key="album_tracker.id") job_type: str # "periodic_summary", "scheduled_assets", "memory" enabled: bool = Field(default=True) # Timing times: str = Field(default="09:00") # "HH:MM, HH:MM" interval_days: int = Field(default=1) # For periodic: 1=daily, 7=weekly start_date: str = Field(default="2025-01-01") # For periodic interval anchor # Asset fetching config (scheduled_assets + memory modes) album_mode: str = Field(default="per_album") # per_album/combined/random limit: int = Field(default=10) favorite_only: bool = Field(default=False) asset_type: str = Field(default="all") # all/photo/video min_rating: int = Field(default=0) # 0=no filter, 1-5 order_by: str = Field(default="random") order: str = Field(default="descending") min_date: str | None = None max_date: str | None = None # Template message_template: str = Field(default="") # Custom Jinja2 template for this job created_at: datetime = Field(default_factory=_utcnow) class AlbumState(SQLModel, table=True): """Persisted album state for change detection across restarts.""" __tablename__ = "album_state" id: int | None = Field(default=None, primary_key=True) tracker_id: int = Field(foreign_key="album_tracker.id") album_id: str asset_ids: list[str] = Field(default_factory=list, sa_column=Column(JSON)) pending_asset_ids: list[str] = Field(default_factory=list, sa_column=Column(JSON)) last_updated: datetime = Field(default_factory=_utcnow) class EventLog(SQLModel, table=True): """Log of detected album change events.""" __tablename__ = "event_log" id: int | None = Field(default=None, primary_key=True) tracker_id: int | None = Field(default=None, foreign_key="album_tracker.id") event_type: str album_id: str album_name: str details: dict[str, Any] = Field(default_factory=dict, sa_column=Column(JSON)) created_at: datetime = Field(default_factory=_utcnow)