mirror of
https://github.com/turnstonelabs/turnstone.git
synced 2026-08-23 12:24:46 -06:00
4332997d59
- core/thumbnails.py + GET .../attachments/{id}/thumbnail: server-rendered PNG
thumbnails (image downscale; pdf first page via pypdfium2). Extracted a shared
ownership-gated blob resolver used by both get_content and the thumbnail route
- buildAttachmentPreview (composer_attachments.js): image/pdf -> thumbnail,
audio -> <audio> player, text -> lazy snippet; reused by the composer chips and
the sent-message pills (interactive.js). Cookie auth, so direct media src works
- chip kind icons now cover pdf/audio; the upload swap adopts the server's
authoritative kind for styling + icon + preview
- chat.css preview styling; tests for make_thumbnail
52 lines
1.9 KiB
Python
52 lines
1.9 KiB
Python
"""Tests for attachment thumbnail generation (image downscale + pdf first page)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from turnstone.core.thumbnails import make_thumbnail
|
|
|
|
PNG_1x1 = (
|
|
b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01"
|
|
b"\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\rIDATx\x9cc\xfc\xcf"
|
|
b"\xc0\xc0\xc0\x00\x00\x00\x05\x00\x01\xa5\xf6E@\x00\x00\x00\x00IEND\xaeB`\x82"
|
|
)
|
|
_PNG_MAGIC = b"\x89PNG\r\n\x1a\n"
|
|
|
|
|
|
def _minimal_pdf(text: str = "Hi") -> bytes:
|
|
stream = b"BT /F1 24 Tf 20 60 Td (" + text.encode("latin-1") + b") Tj ET"
|
|
objs = [
|
|
b"<</Type/Catalog/Pages 2 0 R>>",
|
|
b"<</Type/Pages/Kids[3 0 R]/Count 1>>",
|
|
b"<</Type/Page/Parent 2 0 R/MediaBox[0 0 300 144]"
|
|
b"/Contents 4 0 R/Resources<</Font<</F1 5 0 R>>>>>>",
|
|
b"<</Length %d>>\nstream\n%s\nendstream" % (len(stream), stream),
|
|
b"<</Type/Font/Subtype/Type1/BaseFont/Helvetica>>",
|
|
]
|
|
pdf = b"%PDF-1.4\n"
|
|
offsets = []
|
|
for i, obj in enumerate(objs, 1):
|
|
offsets.append(len(pdf))
|
|
pdf += b"%d 0 obj\n%s\nendobj\n" % (i, obj)
|
|
xref = len(pdf)
|
|
pdf += b"xref\n0 %d\n0000000000 65535 f \n" % (len(objs) + 1)
|
|
for off in offsets:
|
|
pdf += b"%010d 00000 n \n" % off
|
|
pdf += b"trailer\n<</Size %d/Root 1 0 R>>\nstartxref\n%d\n%%%%EOF" % (len(objs) + 1, xref)
|
|
return pdf
|
|
|
|
|
|
class TestMakeThumbnail:
|
|
def test_image_thumbnail_is_png(self) -> None:
|
|
out = make_thumbnail(PNG_1x1, "image")
|
|
assert out is not None and out[:8] == _PNG_MAGIC
|
|
|
|
def test_pdf_thumbnail_is_png(self) -> None:
|
|
out = make_thumbnail(_minimal_pdf(), "pdf")
|
|
assert out is not None and out[:8] == _PNG_MAGIC
|
|
|
|
def test_audio_has_no_thumbnail(self) -> None:
|
|
assert make_thumbnail(b"RIFFfake", "audio") is None
|
|
|
|
def test_garbage_image_returns_none(self) -> None:
|
|
assert make_thumbnail(b"not an image", "image") is None
|