diff --git a/Makefile b/Makefile index 2427674..8bc1dc6 100644 --- a/Makefile +++ b/Makefile @@ -138,8 +138,7 @@ release: check-ssh @git checkout main @git merge develop --no-ff -m "Release v$(VERSION)" @sed -i '' 's/"version": "[^"]*"/"version": "$(VERSION)"/' backend/static/manifest.json - @sed -i '' "s/const APP_VERSION = '[^']*'/const APP_VERSION = '$(VERSION)'/" backend/static/js/app.js - @git add backend/static/manifest.json backend/static/js/app.js + @git add backend/static/manifest.json @git commit --amend --no-edit @git tag "v$(VERSION)" @git push $(GIT_REMOTE) main --tags diff --git a/backend/auth.py b/backend/auth.py index 942a3f1..d923c70 100644 --- a/backend/auth.py +++ b/backend/auth.py @@ -87,7 +87,7 @@ def get_current_user( user_id = int(payload["sub"]) with db() as conn: row = conn.execute( - "SELECT id, email, name, rolle, is_premium, is_moderator, is_banned, ban_reason, is_social_media, notes_ki_enabled, breeder_status, is_founder, is_partner, founder_number FROM users WHERE id=?", + "SELECT id, email, name, rolle, is_premium, is_moderator, is_banned, ban_reason, is_social_media, notes_ki_enabled, breeder_status, is_founder, is_partner FROM users WHERE id=?", (user_id,) ).fetchone() diff --git a/backend/routes/admin.py b/backend/routes/admin.py index 09a4127..8be436c 100644 --- a/backend/routes/admin.py +++ b/backend/routes/admin.py @@ -296,7 +296,6 @@ async def list_users( rows = conn.execute(f""" SELECT u.id, u.name, {_email_col}, u.rolle, u.is_premium, u.is_moderator, u.is_banned, u.ban_reason, - u.is_founder, u.is_partner, u.founder_number, u.created_at, u.last_login, (SELECT COUNT(*) FROM dogs d WHERE d.user_id=u.id) AS dog_count, (SELECT COUNT(*) FROM forum_threads t WHERE t.user_id=u.id AND t.is_deleted=0) AS thread_count, diff --git a/backend/routes/friends.py b/backend/routes/friends.py index cac5f4b..df7c96a 100644 --- a/backend/routes/friends.py +++ b/backend/routes/friends.py @@ -32,7 +32,6 @@ async def list_friends(user=Depends(get_current_user)): u.name AS friend_name, u.bio, u.wohnort, u.erfahrung, u.social_link, u.profil_sichtbarkeit, u.avatar_url, - u.is_founder, u.is_partner, u.founder_number, {dogs_sq} AS dogs_json FROM friendships f JOIN users u ON u.id = CASE WHEN f.requester_id=? THEN f.addressee_id ELSE f.requester_id END @@ -93,7 +92,6 @@ async def search_users(q: str = "", user=Depends(get_current_user)): SELECT u.id, u.name, u.bio, u.wohnort, u.erfahrung, u.social_link, u.profil_sichtbarkeit, u.avatar_url, - u.is_founder, u.is_partner, u.founder_number, (SELECT json_group_array(json_object('name', d.name, 'rasse', d.rasse)) FROM dogs d WHERE d.user_id=u.id AND d.is_public=1) AS dogs_json FROM users u diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 9d526bd..c05a7a5 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -3,8 +3,8 @@ Router, State-Management, Navigation, Initialisierung. ============================================================ */ -const APP_VER = '533'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen -const APP_VERSION = '1.1.2'; // ← semantische Version, wird bei make release gesetzt +const APP_VER = '522'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VERSION = '1.0.0'; // ← semantische Version, wird bei make release gesetzt const IS_STAGING = location.hostname === 'staging.banyaro.app'; const App = (() => { diff --git a/backend/static/js/pages/admin.js b/backend/static/js/pages/admin.js index 69ed773..4706cee 100644 --- a/backend/static/js/pages/admin.js +++ b/backend/static/js/pages/admin.js @@ -19,7 +19,7 @@ window.Page_admin = (() => { { id: 'analytics', label: 'Analytics', icon: 'target' }, { id: 'system', label: 'System', icon: 'gear' }, { id: 'jobs', label: 'Jobs', icon: 'clock' }, - { id: 'partner', label: 'Partner', icon: 'handshake' }, + { id: 'partner', label: 'Partner & Codes', icon: 'handshake' }, { id: 'audit', label: 'Audit-Log', icon: 'clipboard-text' }, ]; @@ -1792,23 +1792,13 @@ window.Page_admin = (() => { // TAB: AUDIT-LOG // ------------------------------------------------------------------ async function _renderPartner(el) { - const codes = (await API.get('/admin/partner/codes')) || []; + const [codes] = await Promise.all([ + API.get('/api/admin/partner/codes'), + ]); el.innerHTML = `
1. Partner-Code erstellen — Erstelle einen Code (z. B. HUNDEBLOG) für einen Influencer oder Partner. Der Code wird an die Person weitergegeben.
2. Registrierung mit Code — Wenn sich ein neuer User mit diesem Code registriert, wird er automatisch als Gründer markiert (Platz #1–100, lebenslang kostenlos). Du siehst in der Tabelle wie viele Einlösungen jeder Code hat.
-3. Partner-Status vergeben — Den Influencer selbst suchst du unten bei «Nutzer-Status» und setzt Partner-Badge (blaues Badge im Profil) und Gründer-Lizenz. So ist auch er als Gründer #X sichtbar.
-Max. 100 Gründer — Ist die Zahl bei einem Code leer, ist sie unbegrenzt. Die globale Grenze über alle Codes hinweg sind 100 Gründer-Plätze.
-Freunde werben — Jeder eingeloggte User hat einen persönlichen Einladungslink (Einstellungen → Freunde werben). Bei 10 geworbenen Usern gibt es 20 % Rabatt, bei 20 → 30 %, bei 50 → 50 % — lebenslang, sobald Bezahlfunktionen aktiv sind.
-Kein User gefunden.
`; return; } grantResult.innerHTML = users.map(u => `✓ ${div.dataset.name} ausgewählt${div.dataset.founder==='1' ? ' · ⭐ Gründer' : ''}${div.dataset.partner==='1' ? ' · 🤝 Partner' : ''}
`; + grantResult.innerHTML = `✓ ${div.dataset.name} ausgewählt
`; }); }); - } catch(e) { - grantResult.innerHTML = `${e.message || 'Suchfehler'}
`; - } + } catch { grantResult.innerHTML = ''; } }, 400); }); @@ -2005,14 +1985,13 @@ window.Page_admin = (() => { const isFounder = e.target.querySelector('[name="is_founder"]').checked ? 1 : 0; const isPartner = e.target.querySelector('[name="is_partner"]').checked ? 1 : 0; await UI.asyncButton(btn, async () => { - const result = await API.post(`/admin/partner/users/${_grantUserId}/grant`, { + const result = await API.post(`/api/admin/partner/users/${_grantUserId}/grant`, { is_founder: isFounder, is_partner: isPartner, }); - if (!result) throw new Error('Keine Antwort vom Server.'); UI.toast.success(`Status für ${result.name} gesetzt.`); grantResult.innerHTML = `✓ Gründer: ${result.is_founder ? 'Ja' : 'Nein'} | Partner: ${result.is_partner ? 'Ja' : 'Nein'}
`; - }).catch(e => UI.toast.error(e.message || 'Fehler beim Speichern.')); + }); }); } diff --git a/backend/static/js/pages/friends.js b/backend/static/js/pages/friends.js index 3f2e690..837474c 100644 --- a/backend/static/js/pages/friends.js +++ b/backend/static/js/pages/friends.js @@ -610,23 +610,10 @@ window.Page_friends = (() => { margin-bottom:var(--space-4)">${parts.join('')}