diff --git a/VERSION b/VERSION index 41edc23..0948691 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1141 \ No newline at end of file +1155 \ No newline at end of file diff --git a/backend/main.py b/backend/main.py index df5124d..e954c83 100644 --- a/backend/main.py +++ b/backend/main.py @@ -511,11 +511,11 @@ async def sitemap(): urls = [ ("https://banyaro.app/", "weekly", "1.0"), ("https://banyaro.app/zuechter", "weekly", "0.9"), - ("https://banyaro.app/info", "monthly", "0.8"), - ("https://banyaro.app/presse", "monthly", "0.7"), - ("https://banyaro.app/wiki/rassen", "weekly", "0.8"), - ("https://banyaro.app/knigge", "monthly", "0.7"), ("https://banyaro.app/wurfboerse", "daily", "0.8"), + ("https://banyaro.app/wiki/rassen", "weekly", "0.8"), + ("https://banyaro.app/help", "monthly", "0.7"), + ("https://banyaro.app/knigge", "monthly", "0.7"), + ("https://banyaro.app/partner", "monthly", "0.6"), ] try: @@ -526,12 +526,6 @@ async def sitemap(): for r in rassen: urls.append((f"https://banyaro.app/wiki/rasse/{r['slug']}", "monthly", "0.7")) - events = conn.execute( - "SELECT id FROM events WHERE datum >= date('now') LIMIT 200" - ).fetchall() - for e in events: - urls.append((f"https://banyaro.app/api/events/{e['id']}", "weekly", "0.5")) - # Öffentliche Züchter-Profile breeders = conn.execute( "SELECT bp.zwingername FROM breeder_profiles bp " @@ -1348,12 +1342,47 @@ async def public_dog_page(dog_id: int): # ------------------------------------------------------------------ @app.get("/teilen/{token}") async def invite_page(token: str): - return FileResponse(f"{STATIC_DIR}/index.html", headers={"Cache-Control": "no-store, no-cache"}) + from fastapi.responses import HTMLResponse + with open(f"{STATIC_DIR}/index.html", encoding="utf-8") as _f: + _html = _f.read() + _html = _html.replace( + '', + '' + ) + return HTMLResponse(content=_html, headers={"Cache-Control": "no-store, no-cache"}) @app.get("/breeder/{zwingername}") async def breeder_profile_page(zwingername: str): - return FileResponse(f"{STATIC_DIR}/index.html", headers={"Cache-Control": "no-store, no-cache"}) + from fastapi.responses import HTMLResponse + from urllib.parse import unquote + from database import db as _db + import html as _html_mod + name = unquote(zwingername) + desc = f"Hundezüchter {_html_mod.escape(name)} auf Ban Yaro — Wurfbörse, Stammbaum und mehr." + try: + with _db() as conn: + bp = conn.execute( + "SELECT bp.rasse, bp.beschreibung FROM breeder_profiles bp " + "JOIN users u ON u.id = bp.user_id WHERE bp.zwingername=? AND u.rolle='breeder' LIMIT 1", + (name,) + ).fetchone() + if bp and bp["beschreibung"]: + desc = _html_mod.escape(bp["beschreibung"][:160]) + except Exception: + pass + with open(f"{STATIC_DIR}/index.html", encoding="utf-8") as _f: + _page = _f.read() + _page = _page.replace( + '', + f'' + ).replace( + '
Hundewelpen von geprüften Züchtern
+{count_text}
+ {litters_html or 'Aktuell keine Würfe eingetragen.
Schau bald wieder vorbei!
Keine Orte in der Nähe gefunden.
'; - } else { - sugEl.innerHTML = suggestions.map(s => ` - `).join(''); - sugEl.querySelectorAll('.diary-location-suggestion').forEach(el => { - el.addEventListener('click', () => _setName(el.dataset.name)); - }); - } - sugEl.style.display = ''; - } catch (err) { - UI.toast.error(err?.message?.includes('GPS') || lat == null - ? 'GPS nicht verfügbar.' : 'Ortssuche fehlgeschlagen.'); - } finally { - UI.setLoading(btn, false); - } - } - - document.getElementById('diary-location-btn')?.addEventListener('click', _showSuggestions); + if (_locLat != null) _diaryPicker.setValue(_locLat, _locLon, _locName); + }, 50); document.getElementById('diary-form-delete')?.addEventListener('click', async () => { const ok = await UI.modal.confirm({ diff --git a/backend/static/js/pages/forum.js b/backend/static/js/pages/forum.js index e2dfe19..512ed6d 100644 --- a/backend/static/js/pages/forum.js +++ b/backend/static/js/pages/forum.js @@ -640,6 +640,17 @@ function _fmtDate(iso) { } catch (err) { UI.toast.error(err.message); } }); + // Liker-Liste anzeigen (Klick auf die Zahl) + const _thLikeCount = document.getElementById('thread-like-count'); + if (_thLikeCount) { + _thLikeCount.style.cursor = 'pointer'; + _thLikeCount.title = 'Wer hat geliked?'; + _thLikeCount.addEventListener('click', e => { + e.stopPropagation(); + if ((thread.likes || 0) > 0) _showLikers('thread', thread.id); + }); + } + // Report thread document.getElementById('thread-report-btn')?.addEventListener('click', () => { _showReportForm('thread', thread.id); @@ -812,9 +823,9 @@ function _fmtDate(iso) { // Like container.querySelectorAll('.forum-post-like:not([data-bound])').forEach(btn => { btn.dataset.bound = '1'; + const postId = parseInt(btn.dataset.postId); btn.addEventListener('click', async () => { if (!uid) { UI.toast.info('Bitte erst anmelden.'); return; } - const postId = parseInt(btn.dataset.postId); try { const res = await API.forum.like('post', postId); btn.classList.toggle('active', res.liked); @@ -822,6 +833,16 @@ function _fmtDate(iso) { if (countEl) countEl.textContent = res.count; } catch (err) { UI.toast.error(err.message); } }); + // Klick auf die Zahl → Liker-Liste + const countEl = btn.querySelector('.forum-post-like-count'); + if (countEl) { + countEl.style.cursor = 'pointer'; + countEl.title = 'Wer hat geliked?'; + countEl.addEventListener('click', e => { + e.stopPropagation(); + if (parseInt(countEl.textContent) > 0) _showLikers('post', postId); + }); + } }); // Report @@ -874,6 +895,28 @@ function _fmtDate(iso) { }); } + // ---------------------------------------------------------- + // Liker-Liste — wer hat geliked? + // ---------------------------------------------------------- + async function _showLikers(targetType, targetId) { + try { + const likers = await API.forum.likers(targetType, targetId); + if (!likers.length) { UI.toast.info('Noch keine Likes.'); return; } + const rows = likers.map(l => ` +