From 1475bad48bfd3792841ae83510225f3396338cf0 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 19 May 2026 11:11:07 -0400 Subject: [PATCH] feat(attachments): sha-addressed AttachmentStore Co-Authored-By: Claude Opus 4.7 (1M context) --- backend/app/services/attachment_store.py | 27 +++++++++++++++++++++++ tests/test_attachment_store.py | 28 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 backend/app/services/attachment_store.py create mode 100644 tests/test_attachment_store.py diff --git a/backend/app/services/attachment_store.py b/backend/app/services/attachment_store.py new file mode 100644 index 0000000..6b29c24 --- /dev/null +++ b/backend/app/services/attachment_store.py @@ -0,0 +1,27 @@ +"""sha-addressed store for preserved non-art post files. + +Arbitrary binaries — never opened or validated as images. Parallels the +thumbnail store layout (/images/attachments//). +""" + +import shutil +from pathlib import Path + + +class AttachmentStore: + def __init__(self, images_root: Path): + self.root = Path(images_root) / "attachments" + + def store(self, src: Path, sha256: str) -> str: + """Copy src into the sha-addressed store; idempotent on sha. + Returns the stored absolute path as a string.""" + ext = Path(src).suffix.lower() + dest_dir = self.root / sha256[:3] + dest_dir.mkdir(parents=True, exist_ok=True) + dest = dest_dir / f"{sha256}{ext}" + if dest.exists(): + return str(dest) + partial = dest.with_suffix(dest.suffix + ".partial") + shutil.copy2(src, partial) + partial.rename(dest) + return str(dest) diff --git a/tests/test_attachment_store.py b/tests/test_attachment_store.py new file mode 100644 index 0000000..f10ad3a --- /dev/null +++ b/tests/test_attachment_store.py @@ -0,0 +1,28 @@ +from pathlib import Path + +from backend.app.services.attachment_store import AttachmentStore + + +def test_store_layout_and_dedup(tmp_path): + src = tmp_path / "pack.zip" + src.write_bytes(b"\x00\x01binary\xff") + store = AttachmentStore(images_root=tmp_path / "images") + sha = "ab" + "c" * 62 + + p1 = store.store(src, sha) + assert p1.endswith(f"attachments/{sha[:3]}/{sha}.zip") + assert Path(p1).read_bytes() == b"\x00\x01binary\xff" + + # second store of same sha: returns same path, no rewrite + before = Path(p1).stat().st_mtime_ns + p2 = store.store(src, sha) + assert p2 == p1 + assert Path(p1).stat().st_mtime_ns == before + + +def test_store_preserves_extension_case_insensitive(tmp_path): + src = tmp_path / "Doc.PDF" + src.write_bytes(b"%PDF-1.4") + store = AttachmentStore(images_root=tmp_path / "images") + p = store.store(src, "f" * 64) + assert p.endswith(".pdf")