From b47a54db39c3693f567668e3d977760d35a2793e Mon Sep 17 00:00:00 2001 From: rene Date: Sat, 2 May 2026 10:09:06 +0200 Subject: [PATCH] Fix: Media-Symlinks beim Start, Sitter-Datenschutztext, Recalls Dark-Mode, Ausweis neuer Tab, SW by-v600 --- backend/main.py | 33 +++++++++++++------------- backend/static/css/components.css | 23 ++++++++++++++++++ backend/static/js/app.js | 2 +- backend/static/js/pages/dog-profile.js | 3 ++- backend/static/js/pages/recalls.js | 8 +++---- backend/static/sw.js | 2 +- 6 files changed, 47 insertions(+), 24 deletions(-) diff --git a/backend/main.py b/backend/main.py index 15136bb..5cf7e95 100644 --- a/backend/main.py +++ b/backend/main.py @@ -48,6 +48,7 @@ async def lifespan(app: FastAPI): init_db() from routes.movies import seed_movies seed_movies() + _link_prod_media() logger.info(f"KI-Modus: {ki.KI_MODE}") sched.start() yield @@ -280,25 +281,25 @@ app.mount("/img", StaticFiles(directory=f"{STATIC_DIR}/img"), name="img") # User-generierte Medien (Fotos aus Tagebuch, Giftköder-Alarm, etc.) MEDIA_DIR = os.getenv("MEDIA_DIR", "/data/media") -PROD_MEDIA_DIR = os.getenv("PROD_MEDIA_DIR", "") # Staging-only: Fallback auf Prod-Media +PROD_MEDIA_DIR = os.getenv("PROD_MEDIA_DIR", "") # Staging-only: Production-Media einlinken os.makedirs(MEDIA_DIR, exist_ok=True) +app.mount("/media", StaticFiles(directory=MEDIA_DIR), name="media") -if PROD_MEDIA_DIR: - # Staging: erst eigenes media-Verzeichnis, dann Prod-Fallback - from pathlib import Path as _Path - from starlette.responses import FileResponse as _FileResponse - @app.get("/media/{path:path}") - async def serve_media(path: str): - p = _Path(MEDIA_DIR) / path - if p.is_file(): - return _FileResponse(str(p)) - pp = _Path(PROD_MEDIA_DIR) / path - if pp.is_file(): - return _FileResponse(str(pp)) - raise HTTPException(404, "Media not found") -else: - app.mount("/media", StaticFiles(directory=MEDIA_DIR), name="media") +def _link_prod_media(): + """Staging: symlinkt Production-Media-Verzeichnisse in das Staging-Media-Verzeichnis.""" + if not PROD_MEDIA_DIR or not os.path.isdir(PROD_MEDIA_DIR): + return + import pathlib + staging = pathlib.Path(MEDIA_DIR) + for item in pathlib.Path(PROD_MEDIA_DIR).iterdir(): + link = staging / item.name + if not link.exists() and not link.is_symlink(): + try: + link.symlink_to(item) + logger.info(f"Prod-Media verlinkt: {link} → {item}") + except OSError as e: + logger.warning(f"Symlink fehlgeschlagen {link}: {e}") @app.get("/robots.txt") async def robots(): diff --git a/backend/static/css/components.css b/backend/static/css/components.css index ddaa344..0acff7a 100644 --- a/backend/static/css/components.css +++ b/backend/static/css/components.css @@ -6924,3 +6924,26 @@ svg.empty-state-icon { margin-top: var(--space-1); line-height: 1.4; } + +/* Rückrufe — Warnbanner (Dark-Mode-sicher) */ +.recalls-warning-banner { + background: var(--c-danger-subtle); + border: 1px solid var(--c-danger); + border-radius: var(--radius-md); + padding: var(--space-3) var(--space-4); + margin-bottom: var(--space-4); + display: flex; + align-items: flex-start; + gap: var(--space-2); +} +.recalls-warning-icon { + color: var(--c-danger); + flex-shrink: 0; + margin-top: 2px; +} +.recalls-warning-text { + margin: 0; + font-size: var(--text-sm); + color: var(--c-text); + line-height: 1.5; +} diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 8f56651..3cd9d67 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -3,7 +3,7 @@ Router, State-Management, Navigation, Initialisierung. ============================================================ */ -const APP_VER = '599'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '600'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const APP_VERSION = '1.2.1'; // ← semantische Version, wird bei make release gesetzt const IS_STAGING = location.hostname === 'staging.banyaro.app'; diff --git a/backend/static/js/pages/dog-profile.js b/backend/static/js/pages/dog-profile.js index a36fbaa..9f60609 100644 --- a/backend/static/js/pages/dog-profile.js +++ b/backend/static/js/pages/dog-profile.js @@ -213,7 +213,8 @@ window.Page_dog_profile = (() => {
Sitter-Zugang
- Gib einem Freund temporären Schreibzugang für diesen Hund + Gib einem Freund temporären Schreibzugang für diesen Hund. + Deine bestehenden Daten und Medien bleiben unsichtbar und privat — der Sitter kann nur neue Einträge anlegen.
Lade…
diff --git a/backend/static/js/pages/recalls.js b/backend/static/js/pages/recalls.js index 86ac5d5..fd45d64 100644 --- a/backend/static/js/pages/recalls.js +++ b/backend/static/js/pages/recalls.js @@ -38,13 +38,11 @@ window.Page_recalls = (() => { async function _render() { _container.innerHTML = ` -
-
+ -

+

Hinweis: Prüfe immer das Mindesthaltbarkeitsdatum und die Chargen-Nummer bevor du ein gemeldetes Produkt entsorgst oder zurückgibst.

diff --git a/backend/static/sw.js b/backend/static/sw.js index 5444477..abcaaed 100644 --- a/backend/static/sw.js +++ b/backend/static/sw.js @@ -3,7 +3,7 @@ Offline-Cache + Push Notifications + Tile-Cache ============================================================ */ -const CACHE_VERSION = 'by-v599'; +const CACHE_VERSION = 'by-v600'; const CACHE_STATIC = `${CACHE_VERSION}-static`; const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten const CACHE_API = 'ban-yaro-api-v1'; // API-Response-Cache