43 lines
1.8 KiB
Python
43 lines
1.8 KiB
Python
"""Archive location persistence (US06-01).
|
|
|
|
An archive location is a *medium*, not a path. External disks get mounted at
|
|
different mountpoints, and a different disk can be mounted at the same one, so a
|
|
recorded root alone can never prove "these bytes went to that volume". Each
|
|
location therefore owns a marker file written onto the medium itself; its
|
|
``media_id`` is the stable identity, and the root is only where it was last seen.
|
|
|
|
``capabilities`` and ``state`` are the last probe result, kept so the UI can list
|
|
locations without touching a sleeping disk. Preflight always re-probes — a stored
|
|
state is a hint, never evidence.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import DateTime, String, func
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from photo_pipeline.db import Base
|
|
|
|
|
|
class ArchiveLocation(Base):
|
|
__tablename__ = "archive_locations"
|
|
|
|
id: Mapped[str] = mapped_column(String, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String, nullable=False, unique=True)
|
|
root: Mapped[str] = mapped_column(String, nullable=False)
|
|
# Written into the marker file on the medium; proves the right volume is mounted.
|
|
media_id: Mapped[str] = mapped_column(String, nullable=False, unique=True)
|
|
capabilities: Mapped[str | None] = mapped_column(String) # JSON, last probe
|
|
# online | offline | wrong_volume | unwritable — the last probe's verdict.
|
|
state: Mapped[str] = mapped_column(String, nullable=False, default="offline")
|
|
last_seen_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), nullable=False, server_default=func.now()
|
|
)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now()
|
|
)
|