""" 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"" 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""