Files
Vorrania/backend/tests/test_product_images.py
Scarriffle c155116b4e Artikelbilder lokal speichern und auf der Artikelseite anzeigen
Open Food Facts liefert nur eine Bildadresse. Direkt dorthin zu verlinken hiesse:
Das Bild verschwindet, wenn OFF es austauscht, die Installation braucht Internet,
und jeder Seitenaufruf verraet OFF, welche Artikel jemand ansieht.

Das Bild wird daher einmal geholt und in einer eigenen Tabelle product_images
abgelegt - eigene Tabelle, damit Artikellisten die Blobs nicht mitziehen.
Geholt wird beim Anlegen, bei geaenderter Bildadresse und beim ersten Abruf
(so bekommen auch bestehende Artikel ihre Kopie, ohne Wanderung ueber alle
Datensaetze).

GET /products/{id}/image verlangt eine Anmeldung - aus den Bildern liesse sich
sonst ohne Konto ablesen, was im Vorrat liegt. Da ein <img src> keinen
Authorization-Header schickt, laedt die Oberflaeche das Bild ueber fetch und
zeigt es als Objekt-URL.

Angezeigt wird es rechts neben Barcode, Name und Marke. Fehlt ein Bild, rendert
die Komponente nichts und die Felder nehmen die volle Breite ein.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 13:35:10 +02:00

54 lines
1.8 KiB
Python

from app.models import BaseUnit, Product, ProductImage
from app.services import images
EIN_PIXEL = b"\x89PNG\r\n\x1a\n-nicht-echt-aber-egal"
def _artikel(db, url=None):
p = Product(name="Pesto", base_unit=BaseUnit.gram, package_size=195, image_url=url)
db.add(p)
db.commit()
db.refresh(p)
return p
def test_ohne_bildadresse_gibt_es_nichts_zu_holen(db, monkeypatch):
monkeypatch.setattr(images, "fetch", lambda url: (_ for _ in ()).throw(AssertionError))
assert images.ensure(db, _artikel(db)) is None
def test_bild_wird_einmal_geholt_und_danach_lokal_geliefert(db, monkeypatch):
aufrufe = []
def gefaelscht(url):
aufrufe.append(url)
return EIN_PIXEL, "image/png"
monkeypatch.setattr(images, "fetch", gefaelscht)
artikel = _artikel(db, "https://example.org/pesto.png")
erstes = images.ensure(db, artikel)
assert erstes is not None
assert erstes.data == EIN_PIXEL
assert erstes.content_type == "image/png"
# Zweiter Aufruf darf nicht erneut ins Netz gehen - genau das ist der Zweck.
images.ensure(db, artikel)
assert aufrufe == ["https://example.org/pesto.png"]
def test_ein_nicht_erreichbares_bild_bleibt_folgenlos(db, monkeypatch):
monkeypatch.setattr(images, "fetch", lambda url: None)
artikel = _artikel(db, "https://example.org/weg.png")
assert images.ensure(db, artikel) is None
assert db.get(ProductImage, artikel.id) is None
def test_fetch_geht_nur_an_http_adressen(monkeypatch):
"""Ohne diese Schranke waere eine 'file://'-Adresse ein Weg ins Dateisystem."""
monkeypatch.setattr(
images.httpx, "get", lambda *a, **k: (_ for _ in ()).throw(AssertionError)
)
assert images.fetch("file:///etc/passwd") is None
assert images.fetch("") is None