142 lines
4.2 KiB
Python
142 lines
4.2 KiB
Python
from __future__ import annotations
|
|
|
|
from enum import StrEnum
|
|
from typing import Literal
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
from app.mailer.campaign.models import BuildStatus, SendStatus
|
|
|
|
|
|
class MessageValidationStatus(StrEnum):
|
|
READY = "ready"
|
|
WARNING = "warning"
|
|
NEEDS_REVIEW = "needs_review"
|
|
BLOCKED = "blocked"
|
|
EXCLUDED = "excluded"
|
|
INACTIVE = "inactive"
|
|
|
|
|
|
class ImapStatus(StrEnum):
|
|
NOT_REQUESTED = "not_requested"
|
|
PENDING = "pending"
|
|
APPENDED = "appended"
|
|
FAILED = "failed"
|
|
SKIPPED = "skipped"
|
|
|
|
|
|
class MessageIssue(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
severity: Literal["info", "warning", "error"]
|
|
code: str
|
|
message: str
|
|
behavior: str | None = None
|
|
source: str | None = None
|
|
|
|
|
|
class MessageAddress(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
email: str
|
|
name: str | None = None
|
|
|
|
|
|
class MessageAttachmentSummary(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
attachment_id: str | None = None
|
|
label: str | None = None
|
|
status: str
|
|
behavior: str | None = None
|
|
required: bool
|
|
allow_multiple: bool
|
|
zip_enabled: bool
|
|
base_path_name: str | None = None
|
|
base_path: str | None = None
|
|
file_filter: str
|
|
directory: str
|
|
matches: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class MessageDraft(BaseModel):
|
|
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
|
|
entry_index: int
|
|
entry_id: str | None = None
|
|
active: bool
|
|
|
|
build_status: BuildStatus
|
|
validation_status: MessageValidationStatus
|
|
send_status: SendStatus
|
|
imap_status: ImapStatus
|
|
|
|
subject: str | None = None
|
|
from_: MessageAddress | None = Field(default=None, alias="from")
|
|
to: list[MessageAddress] = Field(default_factory=list)
|
|
cc: list[MessageAddress] = Field(default_factory=list)
|
|
bcc: list[MessageAddress] = Field(default_factory=list)
|
|
reply_to: list[MessageAddress] = Field(default_factory=list)
|
|
bounce_to: list[MessageAddress] = Field(default_factory=list)
|
|
disposition_notification_to: list[MessageAddress] = Field(default_factory=list)
|
|
|
|
attachment_count: int = 0
|
|
attachments: list[MessageAttachmentSummary] = Field(default_factory=list)
|
|
issues: list[MessageIssue] = Field(default_factory=list)
|
|
|
|
eml_path: str | None = None
|
|
eml_size_bytes: int | None = None
|
|
|
|
@property
|
|
def is_queueable(self) -> bool:
|
|
return self.active and self.build_status == BuildStatus.BUILT and self.validation_status in {
|
|
MessageValidationStatus.READY,
|
|
MessageValidationStatus.WARNING,
|
|
}
|
|
|
|
|
|
class CampaignBuildReport(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
campaign_id: str
|
|
campaign_name: str
|
|
campaign_file: str
|
|
entries_count: int
|
|
messages: list[MessageDraft] = Field(default_factory=list)
|
|
|
|
@property
|
|
def built_count(self) -> int:
|
|
return sum(1 for message in self.messages if message.build_status == BuildStatus.BUILT)
|
|
|
|
@property
|
|
def build_failed_count(self) -> int:
|
|
return sum(1 for message in self.messages if message.build_status == BuildStatus.BUILD_FAILED)
|
|
|
|
@property
|
|
def ready_count(self) -> int:
|
|
return sum(1 for message in self.messages if message.validation_status == MessageValidationStatus.READY)
|
|
|
|
@property
|
|
def warning_count(self) -> int:
|
|
return sum(1 for message in self.messages if message.validation_status == MessageValidationStatus.WARNING)
|
|
|
|
@property
|
|
def needs_review_count(self) -> int:
|
|
return sum(1 for message in self.messages if message.validation_status == MessageValidationStatus.NEEDS_REVIEW)
|
|
|
|
@property
|
|
def blocked_count(self) -> int:
|
|
return sum(1 for message in self.messages if message.validation_status == MessageValidationStatus.BLOCKED)
|
|
|
|
@property
|
|
def excluded_count(self) -> int:
|
|
return sum(1 for message in self.messages if message.validation_status == MessageValidationStatus.EXCLUDED)
|
|
|
|
@property
|
|
def inactive_count(self) -> int:
|
|
return sum(1 for message in self.messages if message.validation_status == MessageValidationStatus.INACTIVE)
|
|
|
|
@property
|
|
def queueable_count(self) -> int:
|
|
return sum(1 for message in self.messages if message.is_queueable)
|