100 lines
4.0 KiB
Python
100 lines
4.0 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from app.mailer.campaign.entries import EntryLoadError
|
|
from app.mailer.campaign.loader import CampaignLoadError, load_campaign_config
|
|
from app.mailer.messages.builder import build_campaign_messages
|
|
from app.mailer.messages.models import CampaignBuildReport
|
|
|
|
|
|
def _print_report(report: CampaignBuildReport, *, verbose: bool = False) -> None:
|
|
print(f"Campaign: {report.campaign_name} ({report.campaign_id})")
|
|
print(f"Campaign file: {report.campaign_file}")
|
|
print(f"Entries: {report.entries_count}")
|
|
print(
|
|
"Build: "
|
|
f"built={report.built_count}, "
|
|
f"failed={report.build_failed_count}, "
|
|
f"queueable={report.queueable_count}"
|
|
)
|
|
print(
|
|
"Validation: "
|
|
f"ready={report.ready_count}, "
|
|
f"warning={report.warning_count}, "
|
|
f"needs_review={report.needs_review_count}, "
|
|
f"blocked={report.blocked_count}, "
|
|
f"excluded={report.excluded_count}, "
|
|
f"inactive={report.inactive_count}"
|
|
)
|
|
|
|
for message in report.messages:
|
|
print("---")
|
|
label = message.entry_id or f"#{message.entry_index}"
|
|
eml = f", eml={message.eml_path}" if message.eml_path else ""
|
|
print(
|
|
f"Entry {label}: "
|
|
f"build={message.build_status.value}, "
|
|
f"validation={message.validation_status.value}, "
|
|
f"send={message.send_status.value}, "
|
|
f"imap={message.imap_status.value}, "
|
|
f"attachments={message.attachment_count}{eml}"
|
|
)
|
|
if message.subject:
|
|
print(f" Subject: {message.subject}")
|
|
if message.to:
|
|
print(" To: " + ", ".join(item.email for item in message.to))
|
|
for issue in message.issues:
|
|
behavior = f", behavior={issue.behavior}" if issue.behavior else ""
|
|
source = f", source={issue.source}" if issue.source else ""
|
|
print(f" [{issue.severity}] {issue.code}{behavior}{source}: {issue.message}")
|
|
if verbose:
|
|
for attachment in message.attachments:
|
|
print(
|
|
f" - attachment {attachment.attachment_id or ''}: "
|
|
f"{attachment.status}, matches={len(attachment.matches)}, "
|
|
f"zip={attachment.zip_enabled}, filter={attachment.directory}/{attachment.file_filter}"
|
|
)
|
|
for match in attachment.matches:
|
|
print(f" {match}")
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
parser = argparse.ArgumentParser(description="Build campaign message drafts and review statuses without sending.")
|
|
parser.add_argument("--campaign", required=True, help="Path to campaign.json")
|
|
parser.add_argument("--output-dir", default=None, help="Optional directory for generated .eml files")
|
|
parser.add_argument("--write-eml", action="store_true", help="Write generated messages as .eml files")
|
|
parser.add_argument("--json", action="store_true", help="Output machine-readable JSON report")
|
|
parser.add_argument("--verbose", "-v", action="store_true", help="Print attachment details")
|
|
args = parser.parse_args(argv)
|
|
|
|
campaign_path = Path(args.campaign).resolve()
|
|
output_dir = Path(args.output_dir).resolve() if args.output_dir else None
|
|
write_eml = args.write_eml or output_dir is not None
|
|
|
|
try:
|
|
config = load_campaign_config(campaign_path)
|
|
result = build_campaign_messages(
|
|
config,
|
|
campaign_file=campaign_path,
|
|
output_dir=output_dir,
|
|
write_eml=write_eml,
|
|
)
|
|
except (CampaignLoadError, EntryLoadError, ValueError, OSError) as exc:
|
|
print(f"Error: {exc}", file=sys.stderr)
|
|
return 2
|
|
|
|
if args.json:
|
|
print(json.dumps(result.report.model_dump(mode="json", by_alias=True), ensure_ascii=False, indent=2))
|
|
else:
|
|
_print_report(result.report, verbose=args.verbose)
|
|
|
|
return 0 if result.report.build_failed_count == 0 else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|