perf(campaign): share linear collision-safe attachment naming
Release v0.1.29. Coordinated integrity review: GovOPlaN/govoplan-core#298.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from govoplan_campaign.backend.services.filenames import FilenameAllocator
|
||||
|
||||
import mimetypes
|
||||
import re
|
||||
import tempfile
|
||||
@@ -303,15 +305,8 @@ def _archive_filename(archive: ZipArchiveConfig, values: dict[str, Any], entry_i
|
||||
return filename if filename.lower().endswith(".zip") else f"{filename}.zip"
|
||||
|
||||
|
||||
def _unique_attachment_filename(filename: str, used: set[str]) -> str:
|
||||
candidate = filename
|
||||
path = Path(filename)
|
||||
counter = 2
|
||||
while candidate.casefold() in used:
|
||||
candidate = f"{path.stem} ({counter}){path.suffix}"
|
||||
counter += 1
|
||||
used.add(candidate.casefold())
|
||||
return candidate
|
||||
def _unique_attachment_filename(filename: str, used: FilenameAllocator) -> str:
|
||||
return used.allocate(filename)
|
||||
|
||||
|
||||
def _deduplicated_archive_members(members: list[tuple[Path, str]]) -> list[tuple[Path, str]]:
|
||||
@@ -381,8 +376,8 @@ def _attach_files(
|
||||
evidence: list[dict[str, object]] = []
|
||||
archive_members: dict[str, list[tuple[Path, str]]] = {}
|
||||
archive_attachments: dict[str, list[ResolvedAttachment]] = {}
|
||||
used_message_filenames: set[str] = set()
|
||||
used_zip_member_filenames: dict[str, set[str]] = {}
|
||||
used_message_filenames = FilenameAllocator()
|
||||
used_zip_member_filenames: dict[str, FilenameAllocator] = {}
|
||||
|
||||
for attachment in resolution.attachments:
|
||||
attachment.message_filenames = []
|
||||
@@ -394,7 +389,7 @@ def _attach_files(
|
||||
continue
|
||||
match_paths = [Path(match) for match in attachment.matches]
|
||||
if attachment.zip_enabled and attachment.zip_archive_id:
|
||||
used_archive_names = used_zip_member_filenames.setdefault(attachment.zip_archive_id, set())
|
||||
used_archive_names = used_zip_member_filenames.setdefault(attachment.zip_archive_id, FilenameAllocator())
|
||||
for position, path in enumerate(match_paths, start=1):
|
||||
requested = _render_attachment_filename(
|
||||
template=attachment.zip_entry_name_template,
|
||||
|
||||
Reference in New Issue
Block a user