mock server, file and folder management

This commit is contained in:
2026-06-12 02:18:30 +02:00
parent b67c8abdc5
commit f3db5fc5cf
28 changed files with 3049 additions and 6 deletions

View File

@@ -129,9 +129,14 @@ def _recipient_values(entry: EntryConfig) -> dict[str, str]:
def _template_values(config: CampaignConfig, entry: EntryConfig) -> dict[str, Any]:
values: dict[str, Any] = {}
for field in config.fields:
values.setdefault(field.name, "")
values.setdefault(f"global::{field.name}", "")
values.setdefault(f"local::{field.name}", "")
for key, value in config.global_values.items():
values[f"global::{key}"] = value
for key, value in effective_entry_field_values(config, entry).items():
values[key] = value
values[f"local::{key}"] = value
if entry.id:
values["local::id"] = entry.id
@@ -552,6 +557,62 @@ def build_entry_message(
return BuiltMessage(draft=draft, mime=message)
def _unsent_attachment_issues(
*,
config: CampaignConfig,
campaign_file: str | Path,
built_messages: list[BuiltMessage],
) -> list[MessageIssue]:
behavior = config.validation_policy.unsent_attachment_files.value
if behavior == Behavior.CONTINUE.value:
return []
matched_files = {
Path(match).resolve()
for built in built_messages
for attachment in built.draft.attachments
for match in attachment.matches
}
issues: list[MessageIssue] = []
for base_path in config.attachments.base_paths:
if not base_path.unsent_warning:
continue
directory = _resolve(campaign_file, base_path.path)
if not directory.exists() or not directory.is_dir():
continue
all_files = sorted(path.resolve() for path in directory.rglob("*") if path.is_file())
unsent = [path for path in all_files if path not in matched_files]
if not unsent:
continue
shown = ", ".join(str(path.relative_to(directory)) for path in unsent[:10])
if len(unsent) > 10:
shown += f", … (+{len(unsent) - 10} more)"
issues.append(
_issue_from_behavior(
code="unsent_attachment_files",
message=f"{len(unsent)} file(s) in attachment source {base_path.name!r} are not used by any message: {shown}",
behavior=behavior,
source=f"attachments:{base_path.name}",
)
)
return issues
def _apply_campaign_level_issues(built_messages: list[BuiltMessage], issues: list[MessageIssue]) -> None:
if not issues:
return
for built in built_messages:
if not built.draft.active:
continue
built.draft.issues.extend(issues)
status = built.draft.validation_status
for issue in issues:
if issue.behavior:
status = _apply_behavior(status, issue.behavior)
built.draft.validation_status = status
def build_campaign_messages(
config: CampaignConfig,
*,
@@ -577,6 +638,10 @@ def build_campaign_messages(
)
for index, entry in enumerate(entries, start=1)
]
_apply_campaign_level_issues(
built_messages,
_unsent_attachment_issues(config=config, campaign_file=campaign_path, built_messages=built_messages),
)
report = CampaignBuildReport(
campaign_id=config.campaign.id,