feat: harden campaign delivery and editing
This commit is contained in:
@@ -10,12 +10,15 @@ from typing import Any, Iterator
|
||||
from govoplan_core.core.postbox import (
|
||||
CAPABILITY_POSTBOX_DIRECTORY,
|
||||
CAPABILITY_POSTBOX_DELIVERY,
|
||||
CAPABILITY_POSTBOX_EVIDENCE,
|
||||
PostboxDeliveryCatalogRef,
|
||||
PostboxDeliveryProvider,
|
||||
PostboxDeliveryReceiptSummaryRef,
|
||||
PostboxDeliveryRequest,
|
||||
PostboxDeliveryResult,
|
||||
PostboxDirectoryEntryRef,
|
||||
PostboxDirectoryProvider,
|
||||
PostboxEvidenceProvider,
|
||||
PostboxTargetRef,
|
||||
)
|
||||
from govoplan_campaign.backend.runtime import capability
|
||||
@@ -25,6 +28,7 @@ FILES_CAPABILITY = "files.campaign_attachments"
|
||||
MAIL_CAPABILITY = "mail.campaign_delivery"
|
||||
POSTBOX_CAPABILITY = CAPABILITY_POSTBOX_DELIVERY
|
||||
POSTBOX_DIRECTORY_CAPABILITY = CAPABILITY_POSTBOX_DIRECTORY
|
||||
POSTBOX_EVIDENCE_CAPABILITY = CAPABILITY_POSTBOX_EVIDENCE
|
||||
|
||||
|
||||
class OptionalModuleUnavailable(RuntimeError):
|
||||
@@ -63,6 +67,10 @@ class MailProfileError(OptionalModuleUnavailable):
|
||||
pass
|
||||
|
||||
|
||||
class MailDeliveryCommandError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class PostboxDeliveryUnavailable(OptionalModuleUnavailable):
|
||||
pass
|
||||
|
||||
@@ -158,6 +166,12 @@ class MailCampaignIntegration:
|
||||
def available(self) -> bool:
|
||||
return self._delegate is not None
|
||||
|
||||
@property
|
||||
def durable_delivery_available(self) -> bool:
|
||||
return self._delegate is not None and callable(
|
||||
getattr(self._delegate, "submit_delivery_command", None)
|
||||
)
|
||||
|
||||
def _require(self) -> Any:
|
||||
if self._delegate is None:
|
||||
raise MailProfileError("Mail module is not available")
|
||||
@@ -220,6 +234,42 @@ class MailCampaignIntegration:
|
||||
except getattr(delegate, "MailProfileError", MailProfileError) as exc:
|
||||
raise MailProfileError(str(exc)) from exc
|
||||
|
||||
def submit_delivery_command(self, session: Any, **kwargs: Any) -> dict[str, Any]:
|
||||
delegate = self._require()
|
||||
method = getattr(delegate, "submit_delivery_command", None)
|
||||
if not callable(method):
|
||||
raise MailDeliveryCommandError(
|
||||
"The installed Mail module does not provide durable delivery commands"
|
||||
)
|
||||
try:
|
||||
return dict(method(session, **kwargs))
|
||||
except Exception as exc:
|
||||
raise MailDeliveryCommandError(str(exc)) from exc
|
||||
|
||||
def delivery_command_summary(
|
||||
self,
|
||||
session: Any,
|
||||
*,
|
||||
tenant_id: str,
|
||||
command_id: str,
|
||||
) -> dict[str, Any]:
|
||||
delegate = self._require()
|
||||
method = getattr(delegate, "delivery_command_summary", None)
|
||||
if not callable(method):
|
||||
raise MailDeliveryCommandError(
|
||||
"The installed Mail module does not provide durable delivery status"
|
||||
)
|
||||
try:
|
||||
return dict(
|
||||
method(
|
||||
session,
|
||||
tenant_id=tenant_id,
|
||||
command_id=command_id,
|
||||
)
|
||||
)
|
||||
except Exception as exc:
|
||||
raise MailDeliveryCommandError(str(exc)) from exc
|
||||
|
||||
def mock_mailbox(self) -> Any | None:
|
||||
if self._delegate is None or not hasattr(self._delegate, "mock_mailbox"):
|
||||
return None
|
||||
@@ -231,6 +281,7 @@ class PostboxCampaignIntegration:
|
||||
self,
|
||||
delivery_delegate: object | None = None,
|
||||
directory_delegate: object | None = None,
|
||||
evidence_delegate: object | None = None,
|
||||
) -> None:
|
||||
self._delivery_delegate = (
|
||||
delivery_delegate
|
||||
@@ -242,6 +293,11 @@ class PostboxCampaignIntegration:
|
||||
if isinstance(directory_delegate, PostboxDirectoryProvider)
|
||||
else None
|
||||
)
|
||||
self._evidence_delegate = (
|
||||
evidence_delegate
|
||||
if isinstance(evidence_delegate, PostboxEvidenceProvider)
|
||||
else None
|
||||
)
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
@@ -250,6 +306,10 @@ class PostboxCampaignIntegration:
|
||||
and self._directory_delegate is not None
|
||||
)
|
||||
|
||||
@property
|
||||
def receipt_evidence_available(self) -> bool:
|
||||
return self._evidence_delegate is not None
|
||||
|
||||
def delivery_catalog(
|
||||
self,
|
||||
session: object,
|
||||
@@ -298,6 +358,28 @@ class PostboxCampaignIntegration:
|
||||
)
|
||||
return self._delivery_delegate.deliver(session, request)
|
||||
|
||||
def delivery_receipt_summaries(
|
||||
self,
|
||||
session: object,
|
||||
*,
|
||||
tenant_id: str,
|
||||
delivery_ids: list[str] | tuple[str, ...],
|
||||
) -> dict[str, PostboxDeliveryReceiptSummaryRef]:
|
||||
if self._evidence_delegate is None:
|
||||
return {}
|
||||
unique_ids = tuple(dict.fromkeys(delivery_ids))
|
||||
summaries: dict[str, PostboxDeliveryReceiptSummaryRef] = {}
|
||||
for offset in range(0, len(unique_ids), 500):
|
||||
summaries.update(
|
||||
self._evidence_delegate.delivery_receipt_summaries(
|
||||
session,
|
||||
tenant_id=tenant_id,
|
||||
producer_module="campaigns",
|
||||
delivery_ids=unique_ids[offset : offset + 500],
|
||||
)
|
||||
)
|
||||
return summaries
|
||||
|
||||
|
||||
def files_integration() -> FilesCampaignIntegration:
|
||||
return FilesCampaignIntegration(capability(FILES_CAPABILITY))
|
||||
@@ -311,4 +393,5 @@ def postbox_integration() -> PostboxCampaignIntegration:
|
||||
return PostboxCampaignIntegration(
|
||||
capability(POSTBOX_CAPABILITY),
|
||||
capability(POSTBOX_DIRECTORY_CAPABILITY),
|
||||
capability(POSTBOX_EVIDENCE_CAPABILITY),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user