feat: Verlauf -- wer hat wann was abgelegt, ersetzt oder geloescht
Neuer Reiter, und dahinter eine eigene Tabelle. WARUM NICHT EINFACH
media.created_at -- drei Gruende, jeder allein wuerde reichen:
1. media kennt nur den JETZIGEN Stand. Was geloescht wurde, ist weg, samt
der Frage, wer es geloescht hat.
2. Ein Ueberschreiben hebt updated_at an und ueberschreibt damit die
Auskunft, wann die Datei urspruenglich kam.
3. media.token_id ist beim Upload aus dem Dashboard NULL -- dort hat niemand
einen Token, sondern eine Sitzung. Das "von wem" stand also nirgends.
Das ist NICHT das Logging, das die ROADMAP ablehnt: dort geht es um
Anfrage-Protokolle samt ClickHouse. Hier sind es ein paar Zeilen je Upload in
derselben SQLite-Datei, und nach einem halben Jahr raeumt pruneEvents auf.
DER VERLAUF STARTET NICHT LEER. Beim ersten Start wird er aus dem Bestand
nachgetragen (68 Eintraege) -- ein Tab, der am ersten Tag leer ist, obwohl 68
Bilder in der Ablage liegen, sieht aus wie ein kaputter Tab. Die nachgetragenen
Eintraege sind als solche gekennzeichnet: Zeitpunkt stimmt, Urheber steht als
"vor der Aufzeichnung", weil ihn niemand mehr kennt. Die Oberflaeche sagt das
unter der Tabelle, statt es zu verschweigen.
logEvent wirft nie: ein Verlauf, der einen Upload scheitern laesst, waere die
Buchhaltung, die das Geschaeft verhindert.
Nachgemessen: Upload, Ersetzen und Loeschen aus dem Dashboard erscheinen als
user:admin, die Uploads des Fotostudios als token:d4rk_photostudio; beim
Loeschen wird die Groesse VOR dem Loeschen geholt, sonst stuende dort nichts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3ddab937e7
commit
0b295a2302
6 files changed
+412
-3
No files matched your search
@@ -22,7 +22,7 @@
|
||||
import { Hono } from 'hono'
|
||||
import type { Context, Next } from 'hono'
|
||||
import { config } from '../config.js'
|
||||
import { db, now, type Media, type Token } from '../db.js'
|
||||
import { db, logEvent, now, type Media, type Token } from '../db.js'
|
||||
import { tokenAllows, tokenFromHeader } from '../auth.js'
|
||||
import {
|
||||
PathError,
|
||||
@@ -185,6 +185,8 @@ uploadRoutes.post('/upload', async (c) => {
|
||||
).run(path, data.length, digest, mime, token.id, timestamp, timestamp)
|
||||
}
|
||||
|
||||
logEvent(existing ? 'replace' : 'upload', path, data.length, 'token', token.name)
|
||||
|
||||
return c.json({
|
||||
url: publicUrlFor(path),
|
||||
path,
|
||||
@@ -221,8 +223,16 @@ uploadRoutes.delete('/media/:pfad{.+}', async (c) => {
|
||||
}
|
||||
if (!(await fileExists(path))) return c.json({ error: 'nicht gefunden', path }, 404)
|
||||
|
||||
// Die Groesse VOR dem Loeschen holen: danach steht sie nirgends mehr, und
|
||||
// ein Verlaufseintrag ohne Groesse beantwortet die Frage "wie viel Platz
|
||||
// wurde da frei" nicht.
|
||||
const zeile = db.prepare('SELECT size FROM media WHERE path = ?').get(path) as
|
||||
| { size: number }
|
||||
| undefined
|
||||
|
||||
await deleteFile(path)
|
||||
db.prepare('DELETE FROM media WHERE path = ?').run(path)
|
||||
logEvent('delete', path, zeile?.size ?? null, 'token', token.name)
|
||||
return c.json({ deleted: path })
|
||||
})
|
||||
|
||||
|
||||
Reference in new issue
Block a user