Files
PecHub/backend/app/models/signature.py
T
2026-06-04 20:54:49 +02:00

119 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Modelli Signature firme automatiche per caselle PEC e Virtual Box.
Struttura:
Signature → definisce il testo della firma (con editor rich text)
SignatureAssignment → collega una firma a una casella o virtual box per un contesto
(risposta, nuova composizione, o entrambi)
"""
import uuid
from datetime import datetime
from sqlalchemy import (
CheckConstraint,
DateTime,
ForeignKey,
Index,
String,
Text,
UniqueConstraint,
func,
)
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column
from app.database import Base
class Signature(Base):
"""Firma riutilizzabile di un tenant."""
__tablename__ = "signatures"
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
)
tenant_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False
)
name: Mapped[str] = mapped_column(String(255), nullable=False)
description: Mapped[str | None] = mapped_column(Text, nullable=True)
body_html: Mapped[str | None] = mapped_column(Text, nullable=True)
body_text: Mapped[str | None] = mapped_column(Text, nullable=True)
created_by: Mapped[uuid.UUID | None] = mapped_column(
UUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=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()
)
__table_args__ = (
UniqueConstraint("tenant_id", "name", name="uq_signature_name_tenant"),
Index("idx_signatures_tenant", "tenant_id"),
)
def __repr__(self) -> str:
return f"<Signature {self.name!r}>"
class SignatureAssignment(Base):
"""
Assegna una firma a una casella PEC o a una Virtual Box per un determinato contesto.
context:
reply firma inserita automaticamente nelle risposte
compose firma inserita automaticamente nelle nuove composizioni
both firma inserita in entrambi i contesti
Vincolo: esattamente uno tra mailbox_id e virtual_box_id deve essere valorizzato.
Vincolo unique: non puo' esistere piu' di un'assegnazione per la stessa
(casella/vbox, contesto) coppia.
"""
__tablename__ = "signature_assignments"
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
)
tenant_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False
)
signature_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("signatures.id", ondelete="CASCADE"), nullable=False
)
mailbox_id: Mapped[uuid.UUID | None] = mapped_column(
UUID(as_uuid=True), ForeignKey("mailboxes.id", ondelete="CASCADE"), nullable=True
)
virtual_box_id: Mapped[uuid.UUID | None] = mapped_column(
UUID(as_uuid=True), ForeignKey("virtual_boxes.id", ondelete="CASCADE"), nullable=True
)
# "reply" | "compose" | "both"
context: Mapped[str] = mapped_column(String(20), nullable=False, default="both")
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), nullable=False, server_default=func.now()
)
__table_args__ = (
# Almeno uno tra mailbox_id e virtual_box_id deve essere valorizzato
CheckConstraint(
"(mailbox_id IS NOT NULL)::int + (virtual_box_id IS NOT NULL)::int = 1",
name="ck_sig_assignment_target",
),
# Non puo' esserci piu' di un'assegnazione per la stessa casella+contesto
UniqueConstraint("mailbox_id", "context", name="uq_sig_mailbox_context"),
# Non puo' esserci piu' di un'assegnazione per la stessa vbox+contesto
UniqueConstraint("virtual_box_id", "context", name="uq_sig_vbox_context"),
Index("idx_sig_assign_tenant", "tenant_id"),
Index("idx_sig_assign_mailbox", "mailbox_id"),
Index("idx_sig_assign_vbox", "virtual_box_id"),
)
def __repr__(self) -> str:
target = f"mailbox={self.mailbox_id}" if self.mailbox_id else f"vbox={self.virtual_box_id}"
return f"<SignatureAssignment sig={self.signature_id} {target} ctx={self.context!r}>"