Backend: gemeinsame Helfer in common.py

- Eine ValidationError-Klasse statt zwei (links.py, projects.py), ein
  Fehler-Handler in main.py
- clean_text() ersetzt vier fast gleiche Text-Prüfungen (Kanban, Haushalt,
  Reisen, Artikel); Fehlermeldungen nennen jetzt überall die Höchstlänge
- Zeitstempel (now_iso, iso_ago, iso_after) und Kontenliste (user_list)
  an einer Stelle; ungenutzte Importe entfernt
- Tests für die Helfer und für einheitliche 400-Fehler aus allen Bereichen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
guyg1474andClaude Opus 5.5 committed 2026-10-15 18:10:43 +02:00
1 parent d28e6b2e4b
commit 4aba48ce51
14 files changed
+117 -86

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
"""Gemeinsame Helfer fürs Backend: Eingabefehler, Texte prüfen, Zeitstempel, Kontenliste."""
import re
from datetime import datetime, timedelta, timezone
class ValidationError(ValueError):
"""Ungültige Eingabe; main.py macht daraus HTTP 400 mit {"error": Meldung}."""
def clean_text(value, field: str, max_len: int, *, required: bool = True, collapse: bool = True) -> str:
"""Text säubern und prüfen. collapse: Leerraum (auch Zeilenumbrüche) zu einem Leerzeichen zusammenfassen."""
if not isinstance(value, str):
value = ""
v = re.sub(r"\s+", " ", value).strip() if collapse else value.strip()
if required and not v:
raise ValidationError(f"{field} fehlt.")
if len(v) > max_len:
raise ValidationError(f"{field} ist zu lang (max. {max_len} Zeichen).")
return v
# ---------- Zeitstempel: ISO 8601 in UTC mit Millisekunden, z. B. 2026-10-15T08:57:47.533Z ----------
# Einheitliches Format, damit Vergleiche als Text in SQLite stimmen (done_at <= ? usw.).
def iso(moment: datetime) -> str:
return moment.astimezone(timezone.utc).isoformat(timespec="milliseconds").replace("+00:00", "Z")
def now_iso() -> str:
return iso(datetime.now(timezone.utc))
def iso_ago(delta: timedelta) -> str:
return iso(datetime.now(timezone.utc) - delta)
def iso_after(value: str, delta: timedelta) -> str:
return iso(datetime.fromisoformat(value.replace("Z", "+00:00")) + delta)
# ---------- Konten ----------
def user_list(conn) -> list:
"""Alle Konten für Auswahlfelder (Bearbeiter, Freigaben), alphabetisch."""
rows = conn.execute("SELECT id, display_name FROM users ORDER BY display_name COLLATE NOCASE").fetchall()
return [{"id": u["id"], "name": u["display_name"]} for u in rows]