mirror of
https://github.com/idrainformatica/PecFlow.git
synced 2026-06-16 12:45:42 +02:00
183 lines
5.9 KiB
Python
183 lines
5.9 KiB
Python
"""
|
||
Modelli Virtual Box – filtri nominati assegnabili agli utenti.
|
||
|
||
Struttura:
|
||
VirtualBox → definisce il filtro (nome, label, mailbox scope)
|
||
VirtualBoxRule → singola regola (field + pattern) dentro una VBox
|
||
VirtualBoxAssignment → assegnazione VBox → User
|
||
|
||
Logica:
|
||
- Le regole nella stessa VBox si combinano in AND.
|
||
- Più VBox assegnate allo stesso utente si uniscono in OR.
|
||
- Il filtro si applica automaticamente a inbox e ricerca.
|
||
"""
|
||
|
||
import uuid
|
||
from datetime import datetime
|
||
|
||
from sqlalchemy import (
|
||
Boolean,
|
||
Column,
|
||
DateTime,
|
||
ForeignKey,
|
||
Index,
|
||
String,
|
||
Table,
|
||
Text,
|
||
UniqueConstraint,
|
||
func,
|
||
)
|
||
from sqlalchemy.dialects.postgresql import UUID
|
||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||
|
||
from app.database import Base
|
||
|
||
# ─── Tabella di associazione VirtualBox ↔ Mailbox ─────────────────────────────
|
||
virtual_box_mailboxes = Table(
|
||
"virtual_box_mailboxes",
|
||
Base.metadata,
|
||
Column(
|
||
"virtual_box_id",
|
||
UUID(as_uuid=True),
|
||
ForeignKey("virtual_boxes.id", ondelete="CASCADE"),
|
||
primary_key=True,
|
||
),
|
||
Column(
|
||
"mailbox_id",
|
||
UUID(as_uuid=True),
|
||
ForeignKey("mailboxes.id", ondelete="CASCADE"),
|
||
primary_key=True,
|
||
),
|
||
)
|
||
|
||
|
||
class VirtualBox(Base):
|
||
"""Casella virtuale: contenitore di regole + etichetta opzionale."""
|
||
|
||
__tablename__ = "virtual_boxes"
|
||
|
||
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)
|
||
label: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
||
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||
|
||
created_by: Mapped[uuid.UUID | None] = mapped_column(
|
||
UUID(as_uuid=True), ForeignKey("users.id"), 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()
|
||
)
|
||
|
||
# Relazioni
|
||
rules: Mapped[list["VirtualBoxRule"]] = relationship(
|
||
"VirtualBoxRule", back_populates="virtual_box", cascade="all, delete-orphan",
|
||
order_by="VirtualBoxRule.created_at"
|
||
)
|
||
assignments: Mapped[list["VirtualBoxAssignment"]] = relationship(
|
||
"VirtualBoxAssignment", back_populates="virtual_box", cascade="all, delete-orphan"
|
||
)
|
||
mailboxes: Mapped[list["Mailbox"]] = relationship( # noqa: F821
|
||
"Mailbox",
|
||
secondary=virtual_box_mailboxes,
|
||
lazy="selectin",
|
||
)
|
||
|
||
__table_args__ = (
|
||
UniqueConstraint("tenant_id", "name", name="uq_vbox_name_tenant"),
|
||
Index("idx_vbox_tenant", "tenant_id"),
|
||
)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<VirtualBox {self.name!r}>"
|
||
|
||
|
||
class VirtualBoxRule(Base):
|
||
"""
|
||
Singola regola di filtro all'interno di una VBox.
|
||
|
||
field : mailbox_id | imap_folder | subject | from_address | to_address
|
||
operator : contains | equals | starts_with | ends_with | regex
|
||
value : valore da confrontare
|
||
|
||
Può anche specificare un date_from / date_to per filtrare per periodo.
|
||
"""
|
||
|
||
__tablename__ = "virtual_box_rules"
|
||
|
||
id: Mapped[uuid.UUID] = mapped_column(
|
||
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
||
)
|
||
virtual_box_id: Mapped[uuid.UUID] = mapped_column(
|
||
UUID(as_uuid=True),
|
||
ForeignKey("virtual_boxes.id", ondelete="CASCADE"),
|
||
nullable=False,
|
||
)
|
||
field: Mapped[str] = mapped_column(String(50), nullable=False)
|
||
operator: Mapped[str] = mapped_column(String(20), nullable=False, default="contains")
|
||
value: Mapped[str] = mapped_column(Text, nullable=False)
|
||
date_from: Mapped[str | None] = mapped_column(String(20), nullable=True) # ISO date
|
||
date_to: Mapped[str | None] = mapped_column(String(20), nullable=True) # ISO date
|
||
|
||
created_at: Mapped[datetime] = mapped_column(
|
||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||
)
|
||
|
||
# Relazioni
|
||
virtual_box: Mapped["VirtualBox"] = relationship(
|
||
"VirtualBox", back_populates="rules"
|
||
)
|
||
|
||
__table_args__ = (
|
||
Index("idx_vbox_rule_vbox", "virtual_box_id"),
|
||
)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<VirtualBoxRule {self.field!r} {self.operator!r} {self.value!r}>"
|
||
|
||
|
||
class VirtualBoxAssignment(Base):
|
||
"""Assegnazione di una VBox a un utente."""
|
||
|
||
__tablename__ = "virtual_box_assignments"
|
||
|
||
id: Mapped[uuid.UUID] = mapped_column(
|
||
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
||
)
|
||
virtual_box_id: Mapped[uuid.UUID] = mapped_column(
|
||
UUID(as_uuid=True),
|
||
ForeignKey("virtual_boxes.id", ondelete="CASCADE"),
|
||
nullable=False,
|
||
)
|
||
user_id: Mapped[uuid.UUID] = mapped_column(
|
||
UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
|
||
)
|
||
assigned_by: Mapped[uuid.UUID | None] = mapped_column(
|
||
UUID(as_uuid=True), ForeignKey("users.id"), nullable=True
|
||
)
|
||
assigned_at: Mapped[datetime] = mapped_column(
|
||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||
)
|
||
|
||
# Relazioni
|
||
virtual_box: Mapped["VirtualBox"] = relationship(
|
||
"VirtualBox", back_populates="assignments"
|
||
)
|
||
|
||
__table_args__ = (
|
||
UniqueConstraint("virtual_box_id", "user_id", name="uq_vbox_assignment"),
|
||
Index("idx_vbox_assign_user", "user_id"),
|
||
Index("idx_vbox_assign_vbox", "virtual_box_id"),
|
||
)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<VirtualBoxAssignment vbox={self.virtual_box_id} user={self.user_id}>"
|