"""Datenmodelle des Plugins „erinnerung“. Zwei eigene Tabellen (SQLite ↔ Postgres portabel), der Kern bleibt unberührt: - `erinnerung_ausgabe` — eine Magazin-Ausgabe mit Redaktionsschluss-Datum. Mehrere Ausgaben laufen parallel; der Name ist frei wählbar (z. B. „3/2025“). - `erinnerung_protokoll` — protokolliert jede versendete Erinnerung (Ausgabe + Benutzer). Die Eindeutigkeit von (ausgabe_id, user_id) stellt auf Datenbankebene sicher, dass niemand zweimal pro Ausgabe erinnert wird. Keine ORM-Indizes: Bei erneuter Ausführung des Moduls würde ein deklarativ definierter Index doppelt im Table-Objekt landen und die Migration würde ihn zweimal anlegen (gleiche Begründung wie im benachrichtigung-Plugin). """ from __future__ import annotations from datetime import date, datetime from sqlalchemy import Date, DateTime, ForeignKey, String, UniqueConstraint, func from sqlalchemy.orm import Mapped, mapped_column from redaktionskern.db import Base class Ausgabe(Base): """Eine Magazin-Ausgabe mit ihrem Redaktionsschluss-Datum.""" __tablename__ = "erinnerung_ausgabe" __table_args__ = {"extend_existing": True} id: Mapped[int] = mapped_column(primary_key=True) #: Name/Titel der Ausgabe, z. B. „3/2025“ oder „Sommer-Sonderheft“. name: Mapped[str] = mapped_column(String(200)) #: Redaktionsschluss (Datum, ohne Uhrzeit). redaktionsschluss: Mapped[date] = mapped_column(Date) erstellt_am: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) aktualisiert_am: Mapped[datetime] = mapped_column( DateTime, server_default=func.now(), onupdate=func.now() ) def __repr__(self) -> str: # pragma: no cover - Debug-Hilfe return f"" class ErinnerungsProtokoll(Base): """Eine versendete Erinnerung: wer wurde zu welcher Ausgabe wann erinnert.""" __tablename__ = "erinnerung_protokoll" __table_args__ = ( UniqueConstraint("ausgabe_id", "user_id", name="uq_erinnerung_ausgabe_user"), {"extend_existing": True}, ) id: Mapped[int] = mapped_column(primary_key=True) ausgabe_id: Mapped[int] = mapped_column(ForeignKey("erinnerung_ausgabe.id")) user_id: Mapped[int] = mapped_column(ForeignKey("users.id")) #: Zugestellte Kanäle (Komma-liste, z. B. „email,inapp“) — wie vom #: benachrichtigung-Plugin gemeldet; leer, falls kein Kanal zustellte. kanaele: Mapped[str] = mapped_column(String(200), default="") #: Wann wurde die Erinnerung ausgelöst. erstellt_am: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) def __repr__(self) -> str: # pragma: no cover - Debug-Hilfe return f""