Notiz-Medien & Sprachnachrichten: Fotos/Videos/Dateien + Audio an Notizen
Wiederverwendbarer UI.noteMediaAttacher für beide Notiz-Stellen (UI.noteModal
+ Notizblock-Seite). note_media-Tabelle + POST/DELETE /api/notes/{id}/media
(vor der gierigen /{parent_type}/{parent_id}-Route). Audio per MediaRecorder,
serverseitig nach m4a/AAC transkodiert (ffmpeg) — iOS spielt Chrome-Opus-webm
nicht ab. UI.lightbox global eingeführt. Mikrofon-Policy microphone=(self) +
CSP media-src 'self' blob:, Datenschutz v6. Disk-Cleanup für note_media bei
Notiz-, Account- und Admin-User-Delete. Reine Medien-Notiz ohne Text erlaubt.
noteModal-Bug gefixt: notes.get() liefert Array -> existing[0] statt
existing?.id (verhinderte Bearbeiten, erzeugte Duplikate). 12 neue Tests.
admin.py enthält außerdem KI-Vision-Statusfelder aus paralleler Arbeit
(nicht sauber trennbar ohne interaktives Staging).
This commit is contained in:
parent
203da50e1d
commit
e86d89f3d9
12 changed files with 947 additions and 59 deletions
|
|
@ -483,6 +483,16 @@ async def delete_user(uid: int, user=Depends(require_admin)):
|
|||
conn.execute("DELETE FROM push_subscriptions WHERE user_id=?", (uid,))
|
||||
conn.execute("DELETE FROM notifications WHERE user_id=?", (uid,))
|
||||
conn.execute("DELETE FROM forum_posts WHERE user_id=?", (uid,))
|
||||
# Notiz-Medien: erst Dateien von Disk, dann DB-Zeilen (note_media + notes).
|
||||
import os as _os
|
||||
from media_utils import delete_media_files
|
||||
_nm_urls = [r["url"] for r in conn.execute(
|
||||
"SELECT nm.url FROM note_media nm JOIN notes n ON n.id = nm.note_id WHERE n.user_id=?",
|
||||
(uid,)
|
||||
).fetchall()]
|
||||
delete_media_files(_os.getenv("MEDIA_DIR", "/data/media"), _nm_urls)
|
||||
conn.execute("DELETE FROM note_media WHERE note_id IN (SELECT id FROM notes WHERE user_id=?)", (uid,))
|
||||
conn.execute("DELETE FROM notes WHERE user_id=?", (uid,))
|
||||
conn.execute("DELETE FROM users WHERE id=?", (uid,))
|
||||
_audit(conn, user, "user_delete", f"user:{uid} ({target['name']})")
|
||||
|
||||
|
|
@ -728,7 +738,7 @@ async def ki_history(user=Depends(require_mod)):
|
|||
@router.get("/ki/status")
|
||||
async def ki_status(user=Depends(require_mod)):
|
||||
import httpx
|
||||
from ki import KI_MODE, LOCAL_BASE_URL, LOCAL_MODEL, CLOUD_MODEL, ANTHROPIC_KEY
|
||||
from ki import KI_MODE, LOCAL_BASE_URL, LOCAL_MODEL, CLOUD_MODEL, VISION_MODEL, ANTHROPIC_KEY
|
||||
|
||||
result = {
|
||||
"mode": KI_MODE,
|
||||
|
|
@ -737,6 +747,7 @@ async def ki_status(user=Depends(require_mod)):
|
|||
"local_reachable": False,
|
||||
"local_model_loaded": None,
|
||||
"cloud_model": CLOUD_MODEL,
|
||||
"vision_model": VISION_MODEL,
|
||||
"cloud_key_set": bool(ANTHROPIC_KEY),
|
||||
}
|
||||
|
||||
|
|
@ -944,7 +955,7 @@ async def wiki_enrich(data: WikiEnrichBody, user=Depends(require_mod)):
|
|||
async def wiki_evaluate(sample: int = 20, user=Depends(require_mod)):
|
||||
from scraper.breed_evaluator import evaluate_enrichment
|
||||
sample = max(5, min(sample, 50))
|
||||
return await evaluate_enrichment(sample_size=sample)
|
||||
return await evaluate_enrichment(sample_size=sample, user_id=user["id"])
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue