feat: add governed postbox delivery and report hardening

This commit is contained in:
2026-07-29 14:16:28 +02:00
parent f11c56e890
commit 5240749ae1
47 changed files with 5538 additions and 288 deletions

View File

@@ -21,6 +21,7 @@ from govoplan_campaign.backend.db.models import (
CampaignShare,
CampaignVersion,
ImapAppendAttempt,
PostboxDeliveryAttempt,
SendAttempt,
new_uuid,
)
@@ -55,7 +56,10 @@ def _record_campaign_changes(session: OrmSession, _flush_context: object, _insta
_record_job_change(session, obj)
elif isinstance(obj, CampaignIssue):
_record_issue_change(session, obj)
elif isinstance(obj, (SendAttempt, ImapAppendAttempt)):
elif isinstance(
obj,
(SendAttempt, ImapAppendAttempt, PostboxDeliveryAttempt),
):
_record_attempt_change(session, obj)
@@ -182,8 +186,11 @@ def _record_job_change(session: OrmSession, job: CampaignJob) -> None:
"validation_status",
"queue_status",
"send_status",
"delivery_channel_policy",
"postbox_status",
"imap_status",
"attempt_count",
"postbox_attempt_count",
"last_error",
"queued_at",
"claimed_at",
@@ -191,6 +198,7 @@ def _record_job_change(session: OrmSession, job: CampaignJob) -> None:
"outcome_unknown_at",
"sent_at",
"resolved_recipients",
"resolved_postbox_targets",
"resolved_attachments",
"issues_snapshot",
),
@@ -217,6 +225,8 @@ def _record_job_change(session: OrmSession, job: CampaignJob) -> None:
"validation_status": job.validation_status,
"queue_status": job.queue_status,
"send_status": job.send_status,
"delivery_channel_policy": job.delivery_channel_policy,
"postbox_status": job.postbox_status,
"imap_status": job.imap_status,
},
)
@@ -247,10 +257,25 @@ def _record_issue_change(session: OrmSession, issue: CampaignIssue) -> None:
)
def _record_attempt_change(session: OrmSession, attempt: SendAttempt | ImapAppendAttempt) -> None:
def _record_attempt_change(
session: OrmSession,
attempt: SendAttempt | ImapAppendAttempt | PostboxDeliveryAttempt,
) -> None:
operation = _operation_for_object(
attempt,
changed_attrs=("status", "claim_token", "smtp_status_code", "smtp_response", "error_type", "error_message", "folder"),
changed_attrs=(
"status",
"claim_token",
"smtp_status_code",
"smtp_response",
"error_type",
"error_message",
"folder",
"provider_delivery_id",
"provider_message_id",
"postbox_id",
"evidence",
),
)
if operation is None:
return
@@ -270,7 +295,13 @@ def _record_attempt_change(session: OrmSession, attempt: SendAttempt | ImapAppen
payload={
**(_campaign_payload(campaign) if campaign is not None else {"campaign_id": job.campaign_id}),
"attempt_id": attempt_id,
"attempt_kind": "imap" if isinstance(attempt, ImapAppendAttempt) else "smtp",
"attempt_kind": (
"postbox"
if isinstance(attempt, PostboxDeliveryAttempt)
else "imap"
if isinstance(attempt, ImapAppendAttempt)
else "smtp"
),
"job_id": job.id,
"version_id": job.campaign_version_id,
},