from __future__ import annotations from datetime import datetime, timezone from typing import Optional from sqlmodel import Field, SQLModel def _now() -> datetime: return datetime.now(timezone.utc) FREQUENCIES = ["hourly", "daily", "weekly"] class BackupSchedule(SQLModel, table=True): """An automatic, recurring backup of a local stack to a destination.""" id: Optional[int] = Field(default=None, primary_key=True) stack_id: str destination_id: int frequency: str = "daily" # one of FREQUENCIES hour: int = 3 # UTC, used for daily/weekly minute: int = 0 weekday: int = 0 # 0=Mon .. 6=Sun, used for weekly include_volumes: bool = True stop_first: bool = True keep: int = 7 # retention: keep newest N for this stack on the dest (0 = all) enabled: bool = True last_run: Optional[datetime] = None last_status: Optional[str] = None # "ok" | "error: ..." next_run: Optional[datetime] = None created_at: datetime = Field(default_factory=_now) # --- API schemas --- class ScheduleCreate(SQLModel): stack_id: str destination_id: int frequency: str = "daily" hour: int = 3 minute: int = 0 weekday: int = 0 include_volumes: bool = True stop_first: bool = True keep: int = 7 enabled: bool = True class ScheduleUpdate(SQLModel): destination_id: Optional[int] = None frequency: Optional[str] = None hour: Optional[int] = None minute: Optional[int] = None weekday: Optional[int] = None include_volumes: Optional[bool] = None stop_first: Optional[bool] = None keep: Optional[int] = None enabled: Optional[bool] = None class ScheduleRead(SQLModel): id: int stack_id: str destination_id: int destination_name: Optional[str] frequency: str hour: int minute: int weekday: int include_volumes: bool stop_first: bool keep: int enabled: bool last_run: Optional[datetime] last_status: Optional[str] next_run: Optional[datetime] created_at: datetime