Some checks failed
Validate / Hassfest (push) Has been cancelled
Backend changes for full blueprint feature parity: Database models: - MessageTemplate: add body_ru (locale variant), event_type field - AlbumTracker: add track_images, track_videos, notify_favorites_only, include_people, include_asset_details, max_assets_to_show, assets_order_by, assets_order fields - New ScheduledJob model: supports periodic_summary, scheduled_assets, and memory (On This Day) notification modes with full config (times, interval, album_mode, limit, filters, sorting) API: - New /api/scheduled/* CRUD endpoints for scheduled jobs - Tracker create/update accept all new filtering fields - Tracker response includes new fields Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
152 lines
5.5 KiB
Python
152 lines
5.5 KiB
Python
"""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)
|