Files
p42.f-w/backend/app/links.py
T
guyg1474andClaude Opus 5.5 dd58b3d1f8 P42 Dashboard: erster Stand
FastAPI-Backend und React-Frontend mit Konten, Sendungsverfolgung,
Projekt-Artikeln, Vorrat & Einkauf mit Rezeptabgleich, Reise-Weltkarte,
Kanban-Projekten mit Priorität, Server-Monitoring und den Designs
Matrix und Blackwall. Betrieb per Docker hinter nginx (siehe DEPLOY.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:08:11 +02:00

65 lines
2.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Schnellzugriff-Links (Jellyfin, Audiobookshelf, Homer) – pro Konto."""
import re
from urllib.parse import urlparse
from fastapi import APIRouter, Body, Depends
from .auth import current_user
from .db import transaction
router = APIRouter()
KEYS = ("jellyfin", "audiobookshelf", "homer")
MAX_LEN = 500
HOSTNAME = re.compile(r"[A-Za-z0-9.-]+|\[[0-9A-Fa-f:.]+\]")
class ValidationError(ValueError):
pass
def normalize_url(value, field: str) -> str:
"""Prüft eine http(s)-Adresse; ergänzt fehlendes "http://". Leer bleibt leer."""
v = value.strip() if isinstance(value, str) else ""
if not v:
return ""
if "://" not in v:
v = f"http://{v}" # "jellyfin.local:8096" -> "http://jellyfin.local:8096"
try:
parsed = urlparse(v)
host = parsed.netloc.rsplit("@", 1)[-1]
host = host[: host.find("]") + 1] if host.startswith("[") else host.split(":")[0]
parsed.port # wirft bei ungültigem Port
except ValueError:
host, parsed = "", None
if (
not parsed
or parsed.scheme not in ("http", "https")
or not HOSTNAME.fullmatch(host)
or re.search(r"\s", v)
or len(v) > MAX_LEN
):
raise ValidationError(f"Ungültige Adresse für {field}.")
return v
def _get(conn, user_id: int) -> dict:
rows = conn.execute("SELECT key, url FROM user_links WHERE user_id = ?", (user_id,)).fetchall()
stored = {r["key"]: r["url"] for r in rows}
return {key: stored.get(key, "") for key in KEYS}
@router.get("/api/links")
def get_links(user: dict = Depends(current_user)):
with transaction() as conn:
return _get(conn, user["id"])
@router.put("/api/links")
def update_links(data: dict = Body(...), user: dict = Depends(current_user)):
values = {key: normalize_url(data[key], key) for key in KEYS if key in data}
with transaction() as conn:
for key, url in values.items():
conn.execute("INSERT OR REPLACE INTO user_links VALUES (?, ?, ?)", (user["id"], key, url))
return _get(conn, user["id"])