feat: harden campaign delivery and editing
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from collections.abc import Sequence
|
||||
from collections.abc import Mapping, Sequence
|
||||
from typing import Literal
|
||||
|
||||
from fastapi import HTTPException, Query, status
|
||||
@@ -13,6 +13,7 @@ from govoplan_campaign.backend.schemas import (
|
||||
CampaignJobDiagnosticsResponse,
|
||||
)
|
||||
from govoplan_core.auth import ApiPrincipal
|
||||
from govoplan_core.core.postbox import PostboxDeliveryReceiptSummaryRef
|
||||
from govoplan_core.core.change_sequence import (
|
||||
encode_sequence_watermark,
|
||||
max_sequence_id,
|
||||
@@ -30,6 +31,8 @@ from govoplan_campaign.backend.change_tracking import (
|
||||
from govoplan_campaign.backend.db.models import (
|
||||
Campaign,
|
||||
CampaignJob,
|
||||
CampaignMessageAction,
|
||||
CampaignMessageActionAttempt,
|
||||
CampaignVersion,
|
||||
ImapAppendAttempt,
|
||||
JobImapStatus,
|
||||
@@ -128,7 +131,12 @@ def _job_attempts_payload(
|
||||
send_attempts: list[SendAttempt],
|
||||
imap_attempts: list[ImapAppendAttempt],
|
||||
postbox_attempts: Sequence[PostboxDeliveryAttempt] = (),
|
||||
message_actions: Sequence[CampaignMessageAction] = (),
|
||||
message_action_attempts: Sequence[CampaignMessageActionAttempt] = (),
|
||||
*,
|
||||
postbox_receipts: (
|
||||
Mapping[str, PostboxDeliveryReceiptSummaryRef] | None
|
||||
) = None,
|
||||
include_diagnostics: bool = False,
|
||||
) -> dict[str, list[dict[str, object]]]:
|
||||
smtp_payloads: list[dict[str, object]] = []
|
||||
@@ -186,11 +194,109 @@ def _job_attempts_payload(
|
||||
payload["evidence"] = attempt.evidence or {}
|
||||
payload["error_type"] = attempt.error_type
|
||||
payload["error_message"] = attempt.error_message
|
||||
if attempt.provider_delivery_id:
|
||||
receipt_summary = (
|
||||
postbox_receipts.get(attempt.provider_delivery_id)
|
||||
if postbox_receipts is not None
|
||||
else None
|
||||
)
|
||||
payload["receipt_summary_status"] = (
|
||||
"available"
|
||||
if receipt_summary is not None
|
||||
else "not_found"
|
||||
if postbox_receipts is not None
|
||||
else "unavailable"
|
||||
)
|
||||
if receipt_summary is not None:
|
||||
payload["receipt_summary"] = _postbox_receipt_summary_payload(
|
||||
receipt_summary
|
||||
)
|
||||
postbox_payloads.append(payload)
|
||||
action_attempts_by_action = {
|
||||
attempt.action_id: attempt
|
||||
for attempt in message_action_attempts
|
||||
}
|
||||
message_action_payloads: list[dict[str, object]] = []
|
||||
for action in message_actions:
|
||||
action_attempt = action_attempts_by_action.get(action.id)
|
||||
payload = {
|
||||
"id": action.id,
|
||||
"kind": action.kind,
|
||||
"status": action.status,
|
||||
"reason": action.reason,
|
||||
"actor_user_id": action.actor_user_id,
|
||||
"actor_api_key_id": action.actor_api_key_id,
|
||||
"campaign_version_id": action.campaign_version_id,
|
||||
"message_sha256": action.message_sha256,
|
||||
"recipient_manifest_sha256": action.recipient_manifest_sha256,
|
||||
"recipient_count": action.recipient_count,
|
||||
"prior_send_status": action.prior_send_status,
|
||||
"final_send_status": action.final_send_status,
|
||||
"accepted_count": action.accepted_count,
|
||||
"refused_count": action.refused_count,
|
||||
"refusal_summary": action.refusal_summary or {},
|
||||
"linked_send_attempt_id": action.linked_send_attempt_id,
|
||||
"created_at": action.created_at,
|
||||
"effect_started_at": action.effect_started_at,
|
||||
"completed_at": action.completed_at,
|
||||
"attempt": (
|
||||
{
|
||||
"id": action_attempt.id,
|
||||
"status": action_attempt.status,
|
||||
"started_at": action_attempt.started_at,
|
||||
"effect_started_at": action_attempt.effect_started_at,
|
||||
"completed_at": action_attempt.completed_at,
|
||||
"accepted_count": action_attempt.accepted_count,
|
||||
"refused_count": action_attempt.refused_count,
|
||||
}
|
||||
if action_attempt is not None
|
||||
else None
|
||||
),
|
||||
}
|
||||
if include_diagnostics:
|
||||
payload["idempotency_key"] = action.idempotency_key
|
||||
payload["canonical_request_hash"] = action.canonical_request_hash
|
||||
payload["context"] = action.context or {}
|
||||
payload["error_type"] = action.error_type
|
||||
payload["error_message"] = action.error_message
|
||||
if action_attempt is not None:
|
||||
payload["attempt"] = {
|
||||
**dict(payload["attempt"] or {}),
|
||||
"outcome_code": action_attempt.outcome_code,
|
||||
"diagnostic_summary": action_attempt.diagnostic_summary,
|
||||
}
|
||||
message_action_payloads.append(payload)
|
||||
return {
|
||||
"smtp": smtp_payloads,
|
||||
"imap": imap_payloads,
|
||||
"postbox": postbox_payloads,
|
||||
"message_actions": message_action_payloads,
|
||||
}
|
||||
|
||||
|
||||
def _postbox_receipt_summary_payload(
|
||||
summary: PostboxDeliveryReceiptSummaryRef,
|
||||
) -> dict[str, object]:
|
||||
return {
|
||||
"delivery_id": summary.delivery_id,
|
||||
"message_id": summary.message_id,
|
||||
"postbox_id": summary.postbox_id,
|
||||
"delivery_status": summary.delivery_status,
|
||||
"accepted_at": summary.accepted_at,
|
||||
"current_holder_count": summary.current_holder_count,
|
||||
"currently_readable": summary.currently_readable,
|
||||
"message_count": summary.message_count,
|
||||
"routed_message_count": summary.routed_message_count,
|
||||
"readable_message_count": summary.readable_message_count,
|
||||
"read_receipt_count": summary.read_receipt_count,
|
||||
"acknowledged_receipt_count": summary.acknowledged_receipt_count,
|
||||
"withdrawn_message_count": summary.withdrawn_message_count,
|
||||
"expired_message_count": summary.expired_message_count,
|
||||
"first_read_at": summary.first_read_at,
|
||||
"last_read_at": summary.last_read_at,
|
||||
"first_acknowledged_at": summary.first_acknowledged_at,
|
||||
"last_acknowledged_at": summary.last_acknowledged_at,
|
||||
"route_status_counts": dict(summary.route_status_counts),
|
||||
}
|
||||
|
||||
|
||||
@@ -199,6 +305,12 @@ def _job_diagnostics_payload(
|
||||
send_attempts: list[SendAttempt],
|
||||
imap_attempts: list[ImapAppendAttempt],
|
||||
postbox_attempts: Sequence[PostboxDeliveryAttempt] = (),
|
||||
message_actions: Sequence[CampaignMessageAction] = (),
|
||||
message_action_attempts: Sequence[CampaignMessageActionAttempt] = (),
|
||||
*,
|
||||
postbox_receipts: (
|
||||
Mapping[str, PostboxDeliveryReceiptSummaryRef] | None
|
||||
) = None,
|
||||
) -> CampaignJobDiagnosticsResponse:
|
||||
return CampaignJobDiagnosticsResponse(
|
||||
job_id=job.id,
|
||||
@@ -221,6 +333,9 @@ def _job_diagnostics_payload(
|
||||
send_attempts,
|
||||
imap_attempts,
|
||||
postbox_attempts,
|
||||
message_actions,
|
||||
message_action_attempts,
|
||||
postbox_receipts=postbox_receipts,
|
||||
include_diagnostics=True,
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user