Refactor mock campaign send reporting
This commit is contained in:
@@ -299,6 +299,237 @@ def _mock_sent_folder(config: Any) -> str:
|
||||
return "Sent"
|
||||
|
||||
|
||||
def _mock_campaign_version(
|
||||
session: Session,
|
||||
*,
|
||||
tenant_id: str,
|
||||
campaign_id: str,
|
||||
version_id: str | None,
|
||||
) -> tuple[Campaign, CampaignVersion]:
|
||||
campaign = (
|
||||
session.query(Campaign)
|
||||
.filter(Campaign.id == campaign_id, Campaign.tenant_id == tenant_id)
|
||||
.one_or_none()
|
||||
)
|
||||
if not campaign:
|
||||
raise MockCampaignSendError("Campaign not found or not accessible")
|
||||
wanted_version_id = version_id or campaign.current_version_id
|
||||
if not wanted_version_id:
|
||||
raise MockCampaignSendError("Campaign has no current version")
|
||||
version = session.get(CampaignVersion, wanted_version_id)
|
||||
if not version or version.campaign_id != campaign.id:
|
||||
raise MockCampaignSendError(
|
||||
"Campaign version not found or not part of campaign"
|
||||
)
|
||||
return campaign, version
|
||||
|
||||
|
||||
def _mock_mailbox_for_run(*, send: bool, clear_mailbox: bool) -> Any | None:
|
||||
mailbox = _require_mock_mailbox() if send or clear_mailbox else _mock_mailbox()
|
||||
if clear_mailbox and mailbox is not None:
|
||||
mailbox.clear_records()
|
||||
return mailbox
|
||||
|
||||
|
||||
def _build_mock_campaign_run(
|
||||
session: Session,
|
||||
*,
|
||||
tenant_id: str,
|
||||
campaign: Campaign,
|
||||
version: CampaignVersion,
|
||||
mailbox: Any | None,
|
||||
send: bool,
|
||||
include_warnings: bool,
|
||||
include_needs_review: bool,
|
||||
append_sent: bool,
|
||||
check_files: bool,
|
||||
) -> tuple[Any, Any, _MockSendBatch]:
|
||||
files = files_integration()
|
||||
raw_json = version.raw_json if isinstance(version.raw_json, dict) else {}
|
||||
assert_server_safe_campaign_paths(
|
||||
raw_json,
|
||||
managed_files_available=files.available,
|
||||
)
|
||||
with files.prepared_campaign_snapshot(
|
||||
session,
|
||||
tenant_id=tenant_id,
|
||||
campaign_id=campaign.id,
|
||||
raw_json=raw_json,
|
||||
include_bytes=True,
|
||||
prefix="govoplan-mock-send-",
|
||||
) as prepared:
|
||||
prepared_raw = load_campaign_json(prepared.path)
|
||||
config = load_campaign_config_from_json(
|
||||
session,
|
||||
tenant_id=tenant_id,
|
||||
raw_json=prepared_raw,
|
||||
campaign_id=campaign.id,
|
||||
)
|
||||
validation_report = validate_campaign_config(
|
||||
config,
|
||||
campaign_file=prepared.path,
|
||||
check_files=check_files,
|
||||
)
|
||||
build_result = build_campaign_messages(
|
||||
config,
|
||||
campaign_file=prepared.path,
|
||||
write_eml=False,
|
||||
)
|
||||
files.annotate_built_messages_with_managed_files(
|
||||
build_result.built_messages,
|
||||
prepared.managed_files_by_local_path,
|
||||
)
|
||||
send_batch = _mock_send_batch(
|
||||
config=config,
|
||||
built_messages=build_result.built_messages,
|
||||
mailbox=mailbox,
|
||||
send=send,
|
||||
include_warnings=include_warnings,
|
||||
include_needs_review=include_needs_review,
|
||||
append_sent=append_sent,
|
||||
)
|
||||
return validation_report, build_result, send_batch
|
||||
|
||||
|
||||
def _mock_validation_payload(validation_report: Any) -> dict[str, Any]:
|
||||
payload = validation_report.model_dump(mode="json")
|
||||
payload.update(
|
||||
{
|
||||
"ok": validation_report.ok,
|
||||
"error_count": validation_report.error_count,
|
||||
"warning_count": validation_report.warning_count,
|
||||
}
|
||||
)
|
||||
return payload
|
||||
|
||||
|
||||
def _mock_build_payload(build_result: Any) -> dict[str, Any]:
|
||||
report = build_result.report
|
||||
payload = report.model_dump(mode="json")
|
||||
payload.update(
|
||||
{
|
||||
"built_count": report.built_count,
|
||||
"queueable_count": report.queueable_count,
|
||||
"needs_review_count": report.needs_review_count,
|
||||
"blocked_count": report.blocked_count,
|
||||
"warning_count": report.warning_count,
|
||||
"ready_count": report.ready_count,
|
||||
"messages": [_message_payload(message) for message in report.messages],
|
||||
}
|
||||
)
|
||||
return payload
|
||||
|
||||
|
||||
def _mock_send_steps(
|
||||
*,
|
||||
validation_report: Any,
|
||||
validation_payload: dict[str, Any],
|
||||
build_report: Any,
|
||||
send_batch: _MockSendBatch,
|
||||
send: bool,
|
||||
append_sent: bool,
|
||||
) -> list[dict[str, Any]]:
|
||||
return [
|
||||
{
|
||||
"key": "validate",
|
||||
"label": "Validate campaign JSON",
|
||||
"status": "ok" if validation_report.ok else "needs_review",
|
||||
"summary": validation_payload,
|
||||
},
|
||||
{
|
||||
"key": "build",
|
||||
"label": "Build messages",
|
||||
"status": "ok" if build_report.queueable_count else "needs_review",
|
||||
"summary": {
|
||||
"built": build_report.built_count,
|
||||
"queueable": build_report.queueable_count,
|
||||
"needs_review": build_report.needs_review_count,
|
||||
"blocked": build_report.blocked_count,
|
||||
},
|
||||
},
|
||||
{
|
||||
"key": "send",
|
||||
"label": "Mock SMTP delivery",
|
||||
"status": (
|
||||
"skipped"
|
||||
if not send
|
||||
else "ok"
|
||||
if send_batch.failed_count == 0
|
||||
else "needs_review"
|
||||
),
|
||||
"summary": {
|
||||
"attempted": send_batch.attempted_count,
|
||||
"sent": send_batch.sent_count,
|
||||
"failed": send_batch.failed_count,
|
||||
"skipped": send_batch.skipped_count,
|
||||
},
|
||||
},
|
||||
{
|
||||
"key": "imap",
|
||||
"label": "Mock IMAP Sent append",
|
||||
"status": (
|
||||
"skipped"
|
||||
if not send or not append_sent
|
||||
else "ok"
|
||||
if send_batch.imap_failed_count == 0
|
||||
else "needs_review"
|
||||
),
|
||||
"summary": {
|
||||
"appended": send_batch.imap_appended_count,
|
||||
"failed": send_batch.imap_failed_count,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def _mock_campaign_send_response(
|
||||
*,
|
||||
campaign: Campaign,
|
||||
version: CampaignVersion,
|
||||
mailbox: Any | None,
|
||||
validation_report: Any,
|
||||
validation_payload: dict[str, Any],
|
||||
build_result: Any,
|
||||
build_payload: dict[str, Any],
|
||||
send_batch: _MockSendBatch,
|
||||
send: bool,
|
||||
include_warnings: bool,
|
||||
include_needs_review: bool,
|
||||
append_sent: bool,
|
||||
) -> dict[str, Any]:
|
||||
return {
|
||||
"campaign_id": campaign.id,
|
||||
"version_id": version.id,
|
||||
"version_number": version.version_number,
|
||||
"send_requested": send,
|
||||
"include_warnings": include_warnings,
|
||||
"include_needs_review": include_needs_review,
|
||||
"append_sent": append_sent,
|
||||
"steps": _mock_send_steps(
|
||||
validation_report=validation_report,
|
||||
validation_payload=validation_payload,
|
||||
build_report=build_result.report,
|
||||
send_batch=send_batch,
|
||||
send=send,
|
||||
append_sent=append_sent,
|
||||
),
|
||||
"validation": validation_payload,
|
||||
"build": build_payload,
|
||||
"send": {
|
||||
"attempted_count": send_batch.attempted_count,
|
||||
"sent_count": send_batch.sent_count,
|
||||
"failed_count": send_batch.failed_count,
|
||||
"skipped_count": send_batch.skipped_count,
|
||||
"imap_appended_count": send_batch.imap_appended_count,
|
||||
"imap_failed_count": send_batch.imap_failed_count,
|
||||
"results": send_batch.results,
|
||||
},
|
||||
"mailbox": {
|
||||
"messages": mailbox.list_records(limit=200) if mailbox is not None else []
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def run_mock_campaign_send(
|
||||
session: Session,
|
||||
*,
|
||||
@@ -320,87 +551,38 @@ def run_mock_campaign_send(
|
||||
mailbox only when send=True.
|
||||
"""
|
||||
|
||||
campaign = session.query(Campaign).filter(Campaign.id == campaign_id, Campaign.tenant_id == tenant_id).one_or_none()
|
||||
if not campaign:
|
||||
raise MockCampaignSendError("Campaign not found or not accessible")
|
||||
wanted_version_id = version_id or campaign.current_version_id
|
||||
if not wanted_version_id:
|
||||
raise MockCampaignSendError("Campaign has no current version")
|
||||
version = session.get(CampaignVersion, wanted_version_id)
|
||||
if not version or version.campaign_id != campaign.id:
|
||||
raise MockCampaignSendError("Campaign version not found or not part of campaign")
|
||||
|
||||
mailbox = _require_mock_mailbox() if send or clear_mailbox else _mock_mailbox()
|
||||
if clear_mailbox and mailbox is not None:
|
||||
mailbox.clear_records()
|
||||
|
||||
files = files_integration()
|
||||
assert_server_safe_campaign_paths(
|
||||
version.raw_json if isinstance(version.raw_json, dict) else {},
|
||||
managed_files_available=files.available,
|
||||
)
|
||||
with files.prepared_campaign_snapshot(
|
||||
campaign, version = _mock_campaign_version(
|
||||
session,
|
||||
tenant_id=tenant_id,
|
||||
campaign_id=campaign.id,
|
||||
raw_json=version.raw_json if isinstance(version.raw_json, dict) else {},
|
||||
include_bytes=True,
|
||||
prefix="govoplan-mock-send-",
|
||||
) as prepared:
|
||||
prepared_raw = load_campaign_json(prepared.path)
|
||||
config = load_campaign_config_from_json(session, tenant_id=tenant_id, raw_json=prepared_raw, campaign_id=campaign.id)
|
||||
validation_report = validate_campaign_config(config, campaign_file=prepared.path, check_files=check_files)
|
||||
build_result = build_campaign_messages(config, campaign_file=prepared.path, write_eml=False)
|
||||
files.annotate_built_messages_with_managed_files(build_result.built_messages, prepared.managed_files_by_local_path)
|
||||
|
||||
send_batch = _mock_send_batch(
|
||||
config=config,
|
||||
built_messages=build_result.built_messages,
|
||||
mailbox=mailbox,
|
||||
send=send,
|
||||
include_warnings=include_warnings,
|
||||
include_needs_review=include_needs_review,
|
||||
append_sent=append_sent,
|
||||
)
|
||||
|
||||
validation_json = validation_report.model_dump(mode="json")
|
||||
validation_json.update({"ok": validation_report.ok, "error_count": validation_report.error_count, "warning_count": validation_report.warning_count})
|
||||
build_report = build_result.report
|
||||
build_json = build_report.model_dump(mode="json")
|
||||
build_json.update({
|
||||
"built_count": build_report.built_count,
|
||||
"queueable_count": build_report.queueable_count,
|
||||
"needs_review_count": build_report.needs_review_count,
|
||||
"blocked_count": build_report.blocked_count,
|
||||
"warning_count": build_report.warning_count,
|
||||
"ready_count": build_report.ready_count,
|
||||
"messages": [_message_payload(message) for message in build_report.messages],
|
||||
})
|
||||
|
||||
return {
|
||||
"campaign_id": campaign.id,
|
||||
"version_id": version.id,
|
||||
"version_number": version.version_number,
|
||||
"send_requested": send,
|
||||
"include_warnings": include_warnings,
|
||||
"include_needs_review": include_needs_review,
|
||||
"append_sent": append_sent,
|
||||
"steps": [
|
||||
{"key": "validate", "label": "Validate campaign JSON", "status": "ok" if validation_report.ok else "needs_review", "summary": validation_json},
|
||||
{"key": "build", "label": "Build messages", "status": "ok" if build_report.queueable_count else "needs_review", "summary": {"built": build_report.built_count, "queueable": build_report.queueable_count, "needs_review": build_report.needs_review_count, "blocked": build_report.blocked_count}},
|
||||
{"key": "send", "label": "Mock SMTP delivery", "status": "skipped" if not send else ("ok" if send_batch.failed_count == 0 else "needs_review"), "summary": {"attempted": send_batch.attempted_count, "sent": send_batch.sent_count, "failed": send_batch.failed_count, "skipped": send_batch.skipped_count}},
|
||||
{"key": "imap", "label": "Mock IMAP Sent append", "status": "skipped" if not send or not append_sent else ("ok" if send_batch.imap_failed_count == 0 else "needs_review"), "summary": {"appended": send_batch.imap_appended_count, "failed": send_batch.imap_failed_count}},
|
||||
],
|
||||
"validation": validation_json,
|
||||
"build": build_json,
|
||||
"send": {
|
||||
"attempted_count": send_batch.attempted_count,
|
||||
"sent_count": send_batch.sent_count,
|
||||
"failed_count": send_batch.failed_count,
|
||||
"skipped_count": send_batch.skipped_count,
|
||||
"imap_appended_count": send_batch.imap_appended_count,
|
||||
"imap_failed_count": send_batch.imap_failed_count,
|
||||
"results": send_batch.results,
|
||||
},
|
||||
"mailbox": {"messages": mailbox.list_records(limit=200) if mailbox is not None else []},
|
||||
}
|
||||
campaign_id=campaign_id,
|
||||
version_id=version_id,
|
||||
)
|
||||
mailbox = _mock_mailbox_for_run(send=send, clear_mailbox=clear_mailbox)
|
||||
validation_report, build_result, send_batch = _build_mock_campaign_run(
|
||||
session,
|
||||
tenant_id=tenant_id,
|
||||
campaign=campaign,
|
||||
version=version,
|
||||
mailbox=mailbox,
|
||||
send=send,
|
||||
include_warnings=include_warnings,
|
||||
include_needs_review=include_needs_review,
|
||||
append_sent=append_sent,
|
||||
check_files=check_files,
|
||||
)
|
||||
validation_payload = _mock_validation_payload(validation_report)
|
||||
build_payload = _mock_build_payload(build_result)
|
||||
return _mock_campaign_send_response(
|
||||
campaign=campaign,
|
||||
version=version,
|
||||
mailbox=mailbox,
|
||||
validation_report=validation_report,
|
||||
validation_payload=validation_payload,
|
||||
build_result=build_result,
|
||||
build_payload=build_payload,
|
||||
send_batch=send_batch,
|
||||
send=send,
|
||||
include_warnings=include_warnings,
|
||||
include_needs_review=include_needs_review,
|
||||
append_sent=append_sent,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user