Files
2026-03-27 20:59:06 +01:00

115 lines
4.3 KiB
Python

"""
Modelli RoutingRule, RoutingRuleCondition, RoutingRuleAction.
Le regole di smistamento automatico vengono valutate a ogni messaggio in arrivo:
1. Si caricano tutte le regole attive del tenant, ordinate per priority ASC
2. Per ogni regola si valutano le condizioni (AND tra le condizioni della stessa regola)
3. Se tutte le condizioni sono soddisfatte, si eseguono le azioni
4. Se stop_processing=True, si ferma l'elaborazione (non vengono valutate regole successive)
"""
import uuid
from datetime import datetime
from sqlalchemy import Boolean, DateTime, ForeignKey, Index, Integer, String, Text, func
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.database import Base
class RoutingRule(Base):
__tablename__ = "routing_rules"
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)
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
priority: Mapped[int] = mapped_column(Integer, nullable=False, default=100)
# Se True, le regole successive non vengono valutate una volta che questa fa match
stop_processing: Mapped[bool] = mapped_column(Boolean, nullable=False, default=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()
)
# Relazioni
conditions: Mapped[list["RoutingRuleCondition"]] = relationship(
"RoutingRuleCondition", back_populates="rule", cascade="all, delete-orphan"
)
actions: Mapped[list["RoutingRuleAction"]] = relationship(
"RoutingRuleAction", back_populates="rule", cascade="all, delete-orphan"
)
__table_args__ = (
Index("idx_routing_rules_tenant", "tenant_id"),
Index("idx_routing_rules_active", "tenant_id", "priority"),
)
def __repr__(self) -> str:
return f"<RoutingRule {self.name!r} priority={self.priority}>"
class RoutingRuleCondition(Base):
"""
Singola condizione di una regola.
field : from_address | to_address | subject | mailbox_id | pec_type
operator : contains | equals | starts_with | ends_with | regex | not_contains
value : valore da confrontare (stringa)
"""
__tablename__ = "routing_rule_conditions"
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
)
rule_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("routing_rules.id", ondelete="CASCADE"), nullable=False
)
field: Mapped[str] = mapped_column(String(50), nullable=False)
operator: Mapped[str] = mapped_column(String(30), nullable=False, default="contains")
value: Mapped[str] = mapped_column(Text, nullable=False)
rule: Mapped["RoutingRule"] = relationship("RoutingRule", back_populates="conditions")
__table_args__ = (
Index("idx_routing_conditions_rule", "rule_id"),
)
class RoutingRuleAction(Base):
"""
Singola azione di una regola.
action_type : apply_label | assign_vbox | mark_read | mark_starred | notify_webhook
action_value : UUID della label/vbox, o URL del webhook
"""
__tablename__ = "routing_rule_actions"
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
)
rule_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("routing_rules.id", ondelete="CASCADE"), nullable=False
)
action_type: Mapped[str] = mapped_column(String(50), nullable=False)
action_value: Mapped[str | None] = mapped_column(Text, nullable=True)
rule: Mapped["RoutingRule"] = relationship("RoutingRule", back_populates="actions")
__table_args__ = (
Index("idx_routing_actions_rule", "rule_id"),
)