diff --git a/backend/static/js/app.js b/backend/static/js/app.js
index 1db5ad9..bdb4e29 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 = '588'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
+const APP_VER = '589'; // ← 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/admin.js b/backend/static/js/pages/admin.js
index fa8df59..6809ee0 100644
--- a/backend/static/js/pages/admin.js
+++ b/backend/static/js/pages/admin.js
@@ -1474,14 +1474,19 @@ window.Page_admin = (() => {
async function _loadModeration(el) {
el.innerHTML = `
Lade…
`;
- const [zuchter, fotos] = await Promise.all([
+ const [zuchter, fotos, reports, poiEdits] = await Promise.all([
API.get('/wiki/zuchter/pending').catch(() => []),
API.get('/wiki/foto-submissions').catch(() => []),
+ API.get('/moderation/reports').catch(() => []),
+ API.get('/moderation/poi-edits').catch(() => []),
]);
+ const poiPending = poiEdits.filter(e => e.status === 'pending');
const modItems = [
- { label: 'Züchter-Einreichungen', count: zuchter.length, icon: 'certificate' },
- { label: 'Foto-Einreichungen', count: fotos.length, icon: 'image' },
+ { label: 'Züchter-Einreichungen', count: zuchter.length, icon: 'certificate' },
+ { label: 'Foto-Einreichungen', count: fotos.length, icon: 'image' },
+ { label: 'Forum-Meldungen', count: reports.length, icon: 'warning' },
+ { label: 'POI-Korrekturen', count: poiPending.length, icon: 'map-pin' },
].filter(i => i.count > 0);
let html = `
@@ -1572,6 +1577,88 @@ window.Page_admin = (() => {
`;
}
+ // --- Forum-Meldungen ---
+ html += `
+ Forum-Meldungen
+
+ ${reports.length}
+
+
`;
+ if (!reports.length) {
+ html += `Keine offenen Meldungen.
`;
+ } else {
+ html += `
+ ${reports.map(r => `
+
+
+
+
+ ${_esc(r.target_type)} #${r.target_id} · Gemeldet von ${_esc(r.melder_name || '?')}
+
+
+ Grund: ${_esc(r.grund)}
+
+ ${r.content_preview ? `
+
${_esc(r.content_preview)}
` : ''}
+
+
+
+
`).join('')}
+
`;
+ }
+
+ // --- POI-Korrekturen ---
+ html += `
+ POI-Korrekturen
+
+ ${poiPending.length}
+
+
`;
+ if (!poiPending.length) {
+ html += `Keine ausstehenden POI-Korrekturen.
`;
+ } else {
+ html += ``;
+ }
+
el.innerHTML = html;
// Züchter freigeben
@@ -1610,6 +1697,41 @@ window.Page_admin = (() => {
await _loadModeration(el);
});
});
+
+ // Forum-Meldung erledigen
+ el.querySelectorAll('.adm-mod-resolve').forEach(btn => {
+ btn.addEventListener('click', async () => {
+ btn.disabled = true;
+ try {
+ await API.patch(`/moderation/reports/${btn.dataset.rid}`, {});
+ await _loadModeration(el);
+ } catch (e) { UI.toast.error(e.message); btn.disabled = false; }
+ });
+ });
+
+ // POI-Korrektur freigeben
+ el.querySelectorAll('.adm-poi-approve').forEach(btn => {
+ btn.addEventListener('click', async () => {
+ btn.disabled = true;
+ try {
+ await API.patch(`/moderation/poi-edits/${btn.dataset.id}`, { action: 'approve' });
+ UI.toast.success('Korrektur übernommen.');
+ await _loadModeration(el);
+ } catch (e) { UI.toast.error(e.message); btn.disabled = false; }
+ });
+ });
+
+ // POI-Korrektur ablehnen
+ el.querySelectorAll('.adm-poi-reject').forEach(btn => {
+ btn.addEventListener('click', async () => {
+ btn.disabled = true;
+ try {
+ await API.patch(`/moderation/poi-edits/${btn.dataset.id}`, { action: 'reject' });
+ UI.toast.success('Korrektur abgelehnt.');
+ await _loadModeration(el);
+ } catch (e) { UI.toast.error(e.message); btn.disabled = false; }
+ });
+ });
}
// ------------------------------------------------------------------
diff --git a/backend/static/sw.js b/backend/static/sw.js
index 57beb81..48d8c56 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-v588';
+const CACHE_VERSION = 'by-v589';
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