Start robuster: Problembilder verhindern die Umstellung nicht

- Migration Schritt 2: Lese-/Schreibfehler (z. B. Dateirechte) und kaputte
  Bilder werden protokolliert und übersprungen, statt den Serverstart
  abzubrechen
- bilder.py: alle Pillow-Fehler werden zu einer Eingabe-Fehlermeldung bzw.
  "keine Metadaten" statt zu Fehler 500
- Test mit schreibgeschütztem und kaputtem Bild

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
guyg1474andClaude Opus 5.5 committed 2026-10-15 18:51:42 +02:00
1 parent bb20135876
commit a1a1998d1e
3 files changed
+25 -8

No files matched your search

+2 -2
View File
@@ -23,7 +23,7 @@ def hat_metadaten(data: bytes) -> bool:
with Image.open(io.BytesIO(data)) as img:
return bool(img.getexif()) or any(k in img.info for k in ("xmp", "XML:com.adobe.xmp", "comment", "exif")) \
or bool(getattr(img, "text", None))
except (OSError, ValueError, Image.DecompressionBombError):
except Exception: # kaputte oder exotische Datei: als "ohne Metadaten" behandeln
return False
@@ -50,5 +50,5 @@ def ohne_metadaten(data: bytes, ext: str) -> bytes:
else:
img.save(out, "WEBP", quality=90, icc_profile=icc)
return out.getvalue()
except (OSError, ValueError, Image.DecompressionBombError):
except Exception: # Pillow wirft je nach Format verschiedene Fehler
raise ValidationError("Das Bild konnte nicht gelesen werden oder ist zu groß.")
+7 -6
View File
@@ -205,18 +205,19 @@ def _v2_datenschutz(conn) -> None:
cleaned = sanitize(row["content"] or "")
if cleaned != (row["content"] or ""):
conn.execute("UPDATE projects SET content = ? WHERE id = ?", (cleaned, row["id"]))
# Hochgeladene Bilder: nur solche mit Metadaten neu schreiben (die anderen bleiben unverändert)
# Hochgeladene Bilder: nur solche mit Metadaten neu schreiben (die anderen bleiben unverändert).
# Ein einzelnes Problembild (Rechte, kaputte Datei) darf den Serverstart nie verhindern.
uploads = DATA_DIR / "uploads"
if uploads.is_dir():
for f in uploads.iterdir():
if not re.fullmatch(r"[a-f0-9]{24}\.(jpg|png|webp)", f.name):
continue
data = f.read_bytes()
if hat_metadaten(data):
try:
try:
data = f.read_bytes()
if hat_metadaten(data):
f.write_bytes(ohne_metadaten(data, f.suffix[1:]))
except ValidationError:
log.warning("Bild %s konnte nicht bereinigt werden", f.name)
except (OSError, ValidationError) as e:
log.warning("Bild %s konnte nicht bereinigt werden: %s", f.name, e)
# Reihenfolge = Versionsnummer (Index + 1). Nur anhängen, nie umsortieren oder entfernen.