mirror of
https://github.com/turnstonelabs/turnstone.git
synced 2026-08-12 23:12:23 -06:00
fix(attachments): preserve pdf/audio kind when reloading attachments from the DB
_reconstruct_attachment_refs collapsed every non-image attachment to the 'document' placeholder kind, so a reloaded session's pdf/audio placeholder type ({type:document}) mismatched the live-injection type ({type:pdf}/{type:audio}). Harmless today (resolution keys on attachment_id + blob kind) but a latent footgun for any consumer branching on the pre-resolution placeholder type. Preserve image/pdf/audio verbatim; only a stored 'text' blob collapses to 'document'.
This commit is contained in:
@@ -75,6 +75,45 @@ class TestSniffAudio:
|
||||
assert sniff_audio_mime(b"") is None
|
||||
|
||||
|
||||
class TestReconstructAttachmentRefs:
|
||||
def test_preserves_pdf_audio_kind_on_reload(self) -> None:
|
||||
from turnstone.core.storage._utils import _reconstruct_attachment_refs
|
||||
|
||||
atts = {
|
||||
1: [
|
||||
{
|
||||
"attachment_id": "a1",
|
||||
"kind": "pdf",
|
||||
"filename": "r.pdf",
|
||||
"mime_type": "application/pdf",
|
||||
},
|
||||
{
|
||||
"attachment_id": "a2",
|
||||
"kind": "audio",
|
||||
"filename": "a.wav",
|
||||
"mime_type": "audio/wav",
|
||||
},
|
||||
{
|
||||
"attachment_id": "a3",
|
||||
"kind": "image",
|
||||
"filename": "i.png",
|
||||
"mime_type": "image/png",
|
||||
},
|
||||
{
|
||||
"attachment_id": "a4",
|
||||
"kind": "text",
|
||||
"filename": "t.txt",
|
||||
"mime_type": "text/plain",
|
||||
},
|
||||
]
|
||||
}
|
||||
refs, meta = _reconstruct_attachment_refs(atts, 1)
|
||||
# pdf/audio/image kept verbatim; only 'text' collapses to 'document'
|
||||
# (so the placeholder type can't collide with a real text content part).
|
||||
assert [r.kind for r in refs] == ["pdf", "audio", "image", "document"]
|
||||
assert [m["kind"] for m in meta] == ["pdf", "audio", "image", "text"]
|
||||
|
||||
|
||||
class TestSafeAttachmentLabel:
|
||||
def test_strips_frame_breakers(self) -> None:
|
||||
from turnstone.core.attachments import safe_attachment_label
|
||||
|
||||
@@ -410,11 +410,15 @@ def _reconstruct_attachment_refs(
|
||||
if not attachments_by_msg or row_id is None:
|
||||
return refs, meta
|
||||
for att in attachments_by_msg.get(row_id, []):
|
||||
# AttachmentRef.kind is the by-reference content kind ('image' |
|
||||
# 'document'); the stored blob kind ('image' | 'text') drives the actual
|
||||
# resolution. 'document' (not 'text') keeps the placeholder type from
|
||||
# colliding with a real text content part on the dict round-trip.
|
||||
ref_kind = "image" if str(att.get("kind") or "") == "image" else "document"
|
||||
# AttachmentRef.kind is the by-reference placeholder kind: the stored
|
||||
# blob kind verbatim for image / pdf / audio, else 'document' for a
|
||||
# stored 'text' blob (so the placeholder type can't collide with a real
|
||||
# text content part on the dict round-trip). The blob kind drives the
|
||||
# actual resolution; preserving pdf / audio here keeps the reloaded
|
||||
# placeholder type ({type:pdf} / {type:audio}) consistent with the live
|
||||
# injection path, which already emits those.
|
||||
kind_str = str(att.get("kind") or "")
|
||||
ref_kind = kind_str if kind_str in ("image", "pdf", "audio") else "document"
|
||||
refs.append(
|
||||
AttachmentRef(
|
||||
attachment_id=str(att.get("attachment_id") or ""),
|
||||
|
||||
Reference in New Issue
Block a user