From 4332b1195e0b8fefb747965f1658f8cf3ea3f473 Mon Sep 17 00:00:00 2001 From: rene Date: Thu, 14 May 2026 11:17:49 +0200 Subject: [PATCH] =?UTF-8?q?Refactor:=20Z=C3=BCchter-Antrag=20in=20Upgrade-?= =?UTF-8?q?Flow=20integriert=20(SW=20by-v925)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /breeder/apply: Dokument jetzt optional (File(None)), kann per Mail nachgereicht werden - _showUpgradeModal('breeder'): enthält jetzt Zwinger-Formular (Zwingername*, Rasse*, Verein, Stadt, VDH-Checkbox, optionales Dokument) → sendet /breeder/apply + /auth/upgrade-request in einem Schritt - Züchter-Profil-Karte in Settings: 'Züchter werden'-Button entfernt → für neue User ohne Antrag wird die Card vollständig ausgeblendet → 'Neu beantragen' bei Ablehnung öffnet jetzt _showUpgradeModal('breeder') - Verifizierte Züchter: Card unverändert (Profil, Edit, KI-Settings) --- backend/main.py | 2 +- backend/routes/breeder.py | 42 +++++------ backend/static/js/app.js | 2 +- backend/static/js/pages/settings.js | 108 ++++++++++++++++++++++++---- backend/static/sw.js | 2 +- 5 files changed, 118 insertions(+), 38 deletions(-) diff --git a/backend/main.py b/backend/main.py index 60eca50..835da3e 100644 --- a/backend/main.py +++ b/backend/main.py @@ -406,7 +406,7 @@ async def serve_media(path: str, request: _Request): raise _HE(404, "Nicht gefunden.") return _media_response(filepath) -APP_VER = "924" # muss mit APP_VER in app.js übereinstimmen +APP_VER = "925" # muss mit APP_VER in app.js übereinstimmen @app.get("/.well-known/assetlinks.json") async def assetlinks(): diff --git a/backend/routes/breeder.py b/backend/routes/breeder.py index 700fabf..fe4028b 100644 --- a/backend/routes/breeder.py +++ b/backend/routes/breeder.py @@ -87,7 +87,7 @@ async def breeder_apply( stadt: str = Form(...), website: str = Form(""), beschreibung: str = Form(""), - dokument: UploadFile = File(...), + dokument: UploadFile = File(None), user=Depends(get_current_user), ): with db() as conn: @@ -103,28 +103,27 @@ async def breeder_apply( if row["breeder_status"] == "pending": raise HTTPException(400, "Du hast bereits einen offenen Antrag.") - # Dokument validieren und speichern - data = await dokument.read() - if len(data) > 10 * 1024 * 1024: - raise HTTPException(400, "Dokument zu groß (max. 10 MB).") - ext = os.path.splitext(dokument.filename or "")[1].lower() - if ext not in (".pdf", ".jpg", ".jpeg", ".png", ".webp"): - raise HTTPException(400, "Nur PDF, JPG, PNG oder WebP erlaubt.") - - user_doc_dir = os.path.join(BREEDER_DOCS_DIR, str(user["id"])) - os.makedirs(user_doc_dir, exist_ok=True) - - filename = f"antrag_{datetime.now(_TZ).strftime('%Y%m%d_%H%M%S')}{ext}" - filepath = os.path.join(user_doc_dir, filename) - with open(filepath, "wb") as f: - f.write(data) + # Dokument optional speichern + filepath = None + if dokument and dokument.filename: + data = await dokument.read() + if len(data) > 10 * 1024 * 1024: + raise HTTPException(400, "Dokument zu groß (max. 10 MB).") + ext = os.path.splitext(dokument.filename)[1].lower() + if ext not in (".pdf", ".jpg", ".jpeg", ".png", ".webp"): + raise HTTPException(400, "Nur PDF, JPG, PNG oder WebP erlaubt.") + user_doc_dir = os.path.join(BREEDER_DOCS_DIR, str(user["id"])) + os.makedirs(user_doc_dir, exist_ok=True) + filename = f"antrag_{datetime.now(_TZ).strftime('%Y%m%d_%H%M%S')}{ext}" + filepath = os.path.join(user_doc_dir, filename) + with open(filepath, "wb") as f: + f.write(data) with db() as conn: conn.execute( "UPDATE users SET breeder_status='pending' WHERE id=?", (user["id"],) ) - # Profil-Entwurf anlegen (oder überschreiben wenn rejected) conn.execute( "INSERT INTO breeder_profiles (user_id, zwingername, rasse_text, verein, vdh_mitglied, stadt, website, beschreibung) " "VALUES (?,?,?,?,?,?,?,?) " @@ -135,10 +134,11 @@ async def breeder_apply( "verified_at=NULL", (user["id"], zwingername, rasse_text, verein, vdh_mitglied, stadt, website, beschreibung) ) - conn.execute( - "INSERT INTO breeder_documents (user_id, dokument_typ, file_path) VALUES (?,?,?)", - (user["id"], "antrag", filepath) - ) + if filepath: + conn.execute( + "INSERT INTO breeder_documents (user_id, dokument_typ, file_path) VALUES (?,?,?)", + (user["id"], "antrag", filepath) + ) # Admin benachrichtigen admin_body = f""" diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 047fb78..505ea98 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 = '924'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '925'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const APP_VERSION = '1.5.1'; // ← semantische Version, wird bei make release gesetzt const IS_STAGING = location.hostname === 'staging.banyaro.app'; // Cache-Bust-Parameter nach Update-Reload sofort entfernen diff --git a/backend/static/js/pages/settings.js b/backend/static/js/pages/settings.js index 96ee9f7..180069a 100644 --- a/backend/static/js/pages/settings.js +++ b/backend/static/js/pages/settings.js @@ -152,6 +152,61 @@ window.Page_settings = (() => { `
  • ✓ ${f}
  • ` ).join(''); + const inputStyle = `width:100%;box-sizing:border-box;padding:var(--space-2) var(--space-3); + border:1.5px solid var(--c-border);border-radius:var(--radius-md); + font-size:var(--text-sm);font-family:inherit;background:var(--c-surface);color:var(--c-text)`; + + const breederForm = isPro ? '' : ` +
    +
    + Dein Zwinger +
    +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    + + +
    + Zuchtbuch, Vereinsausweis o.ä. — kann auch per E-Mail nachgereicht werden +
    +
    +
    +
    `; + UI.modal.open({ title: `${label} freischalten`, body: ` @@ -162,7 +217,7 @@ window.Page_settings = (() => { Einmaliger Jahresbeitrag
    Kündigung jederzeit möglich -