From d603b7bae17983cdfbecd370a85665dddd552e03 Mon Sep 17 00:00:00 2001 From: rene Date: Sat, 25 Apr 2026 09:35:06 +0200 Subject: [PATCH] =?UTF-8?q?Wiki:=20Bildrechte-Best=C3=A4tigung=20bei=20Fot?= =?UTF-8?q?o-Einreichung=20(Checkbox=20+=20DB=20+=20Mod-Badge),=20SW=20by-?= =?UTF-8?q?v363?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/database.py | 2 ++ backend/routes/moderation.py | 1 + backend/routes/wiki.py | 12 ++++++++---- backend/static/js/pages/moderation.js | 9 ++++++++- backend/static/js/pages/wiki.js | 23 ++++++++++++++++++++++- backend/static/sw.js | 2 +- 6 files changed, 42 insertions(+), 7 deletions(-) diff --git a/backend/database.py b/backend/database.py index cb4264e..4d656d1 100644 --- a/backend/database.py +++ b/backend/database.py @@ -532,6 +532,8 @@ def _migrate(conn_factory): ("dogs", "rasse_id", "INTEGER"), # Pflege: Schere vs. Trimmen unterscheiden ("pflege_tipps", "fell_pflege_art", "TEXT"), + # Wiki-Foto-Einreichungen: Bildrechte-Bestätigung + ("wiki_foto_submissions", "rights_confirmed", "INTEGER NOT NULL DEFAULT 0"), ] with conn_factory() as conn: for table, column, col_type in migrations: diff --git a/backend/routes/moderation.py b/backend/routes/moderation.py index 128748b..a039942 100644 --- a/backend/routes/moderation.py +++ b/backend/routes/moderation.py @@ -173,6 +173,7 @@ async def mod_fotos(user=Depends(require_moderator)): try: rows = conn.execute(""" SELECT s.id, s.rasse_slug, s.foto_url, s.created_at, + COALESCE(s.rights_confirmed, 0) AS rights_confirmed, u.name AS user_name, r.name AS rasse_name, r.foto_url AS aktuell_foto FROM wiki_foto_submissions s diff --git a/backend/routes/wiki.py b/backend/routes/wiki.py index f662430..ecb7819 100644 --- a/backend/routes/wiki.py +++ b/backend/routes/wiki.py @@ -4,7 +4,7 @@ import os import shutil import time import logging -from fastapi import APIRouter, Depends, HTTPException, Query, Request, UploadFile, File +from fastapi import APIRouter, Depends, Form, HTTPException, Query, Request, UploadFile, File from fastapi.responses import JSONResponse from pydantic import BaseModel from database import db @@ -290,6 +290,7 @@ async def quiz_result( async def submit_foto( slug: str, file: UploadFile = File(...), + rights_confirmed: int = Form(0), user = Depends(get_current_user), ): with db() as conn: @@ -299,6 +300,9 @@ async def submit_foto( if not rasse: raise HTTPException(404, "Rasse nicht gefunden.") + if not rights_confirmed: + raise HTTPException(400, "Bildrechte-Bestätigung fehlt.") + # Dateiformat prüfen ct = file.content_type or "" if not ct.startswith("image/"): @@ -336,9 +340,9 @@ async def submit_foto( ) conn.execute(""" - INSERT INTO wiki_foto_submissions (user_id, rasse_id, foto_url) - VALUES (?,?,?) - """, (user["id"], rasse["id"], local_url)) + INSERT INTO wiki_foto_submissions (user_id, rasse_id, foto_url, rights_confirmed) + VALUES (?,?,?,?) + """, (user["id"], rasse["id"], local_url, 1)) logger.info(f"Foto-Einreichung: {rasse['name']} von User {user['id']}") return {"ok": True, "foto_url": local_url} diff --git a/backend/static/js/pages/moderation.js b/backend/static/js/pages/moderation.js index 7ca038e..285fd42 100644 --- a/backend/static/js/pages/moderation.js +++ b/backend/static/js/pages/moderation.js @@ -172,9 +172,16 @@ window.Page_moderation = (() => { ${_esc(f.rasse_name || f.rasse_slug)}
+ margin-bottom:var(--space-2)"> von ${_esc(f.user_name)}
+
+ ${f.rights_confirmed + ? `✓ Bildrechte bestätigt` + : `⚠ Keine Bestätigung`} +
${f.aktuell_foto ? ` Aktuell +
+ +
`; const footer = ` - `; @@ -859,6 +871,10 @@ window.Page_wiki = (() => { UI.modal.open({ title: 'Foto vorschlagen', body, footer }); document.getElementById('wiki-foto-cancel')?.addEventListener('click', UI.modal.close); + document.getElementById('wiki-foto-rights')?.addEventListener('change', e => { + document.getElementById('wiki-foto-submit').disabled = !e.target.checked; + }); + document.getElementById('wiki-foto-input')?.addEventListener('change', e => { const file = e.target.files?.[0]; if (!file) return; @@ -874,6 +890,10 @@ window.Page_wiki = (() => { const input = document.getElementById('wiki-foto-input'); const file = input?.files?.[0]; if (!file) return; + if (!document.getElementById('wiki-foto-rights')?.checked) { + UI.toast('Bitte Bildrechte bestätigen.', 'danger'); + return; + } const btn = document.getElementById('wiki-foto-submit'); btn.disabled = true; @@ -882,6 +902,7 @@ window.Page_wiki = (() => { try { const fd = new FormData(); fd.append('file', file); + fd.append('rights_confirmed', '1'); const token = localStorage.getItem('by_token'); const resp = await fetch(`/api/wiki/rassen/${encodeURIComponent(slug)}/foto`, { method: 'POST', diff --git a/backend/static/sw.js b/backend/static/sw.js index 3ba2ba5..5088f26 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-v362'; +const CACHE_VERSION = 'by-v363'; const CACHE_STATIC = `${CACHE_VERSION}-static`; const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten