From 5b3658640ec1b0454074c2e16f54fc06e566dbbd Mon Sep 17 00:00:00 2001 From: marc Date: Tue, 25 Aug 2026 14:15:00 +0200 Subject: [PATCH] revert(admin): Knopf zum Neuerzeugen der Vorschaubilder wieder raus 130 Zeilen fuer einen einmaligen Bedarf - die Haelfte davon eine Karte im Admin-Bereich, die sonst dauerhaft dort steht. Die EXIF-Behebung selbst bleibt: Neu hochgeladene Bilder stehen richtig herum. Bestehende Vorschaubilder werden damit nicht mehr nachgezogen. Wer sie gerade ruecken will, laedt die Datei erneut hoch. Co-Authored-By: Claude Opus 5 --- TESTING.md | 12 ++-- backend/cmd/aether/main.go | 3 - backend/internal/admin/thumbnails_handler.go | 71 -------------------- backend/internal/files/store.go | 26 ------- frontend/src/api/client.ts | 6 -- frontend/src/pages/admin/AuditTab.tsx | 55 --------------- 6 files changed, 7 insertions(+), 166 deletions(-) delete mode 100644 backend/internal/admin/thumbnails_handler.go diff --git a/TESTING.md b/TESTING.md index be3ea6b..f44a0a0 100644 --- a/TESTING.md +++ b/TESTING.md @@ -1463,12 +1463,14 @@ Alle acht Fälle, beide Byte-Reihenfolgen (II und MM): - Bei Drehung 1 entsteht keine Kopie des Bildes. Bestehende Vorschaubilder ändern sich davon **nicht** – sie liegen fertig im -Speicher. Dafür neu: Admin → Audit → „Rebuild image previews". -Gemessen: 6 Bilder, 6 neu erzeugt, 0 Fehler; das quer liegende Testbild war -danach hochkant. +Speicher und werden nicht neu erzeugt. Ein Foto, das heute quer liegt, liegt +auch morgen quer, bis es erneut hochgeladen wird. -- [ ] Auf der produktiven Instanz einmal „Rebuild" drücken und mit echten - Handy-Fotos gegenprüfen +Ein Knopf zum Neuerzeugen war kurz da und wurde wieder entfernt (130 Zeilen +für einen einmaligen Bedarf). + +- [ ] Auf der produktiven Instanz mit echten Handy-Fotos gegenprüfen – + **neu hochgeladene**, nicht die bestehenden ## Automatisiert geprüft (22.08.2026) diff --git a/backend/cmd/aether/main.go b/backend/cmd/aether/main.go index a745a4b..bbbc98a 100644 --- a/backend/cmd/aether/main.go +++ b/backend/cmd/aether/main.go @@ -529,9 +529,6 @@ func main() { r.Get("/admin/audit", adminHandler.ListAudit) r.Get("/admin/audit/actions", adminHandler.ListAuditActions) r.Post("/admin/gc", adminHandler.RunGC) - // Vorschaubilder neu erzeugen – nötig für alles, was vor der - // Auswertung der EXIF-Drehung hochgeladen wurde. - r.Post("/admin/thumbnails/rebuild", adminHandler.RebuildThumbnails) // Immer erreichbar, auch wenn OCR aus ist – der Handler antwortet dann // mit enabled:false. Eine Route, die je nach Konfiguration 404 liefert, // wäre für die Oberfläche nicht von einem Fehler zu unterscheiden. diff --git a/backend/internal/admin/thumbnails_handler.go b/backend/internal/admin/thumbnails_handler.go deleted file mode 100644 index 44ac0c5..0000000 --- a/backend/internal/admin/thumbnails_handler.go +++ /dev/null @@ -1,71 +0,0 @@ -package admin - -import ( - "fmt" - "net/http" - - "aether/internal/audit" - "aether/internal/thumbnails" - "aether/pkg/response" -) - -/* -POST /api/v1/admin/thumbnails/rebuild – Vorschaubilder neu erzeugen. - -Anlass: Bis heute wurde die EXIF-Drehung beim Erzeugen nicht ausgewertet. -Jedes hochkant aufgenommene Foto liegt im bestehenden Bestand deshalb quer, -während dasselbe Bild in der großen Ansicht aufrecht steht – der Browser -befolgt die Notiz von selbst, der Server tat es nicht. - -Beim Hochladen entstehen Vorschaubilder von allein; für das, was schon da ist, -braucht es diesen einen Anstoß. Er läuft im Vordergrund und meldet Zahlen: -Ein Vorgang, der den halben Bestand neu schreibt, soll nicht stumm im -Hintergrund verschwinden. -*/ -func (h *Handler) RebuildThumbnails(w http.ResponseWriter, r *http.Request) { - if _, ok := requireAdmin(r); !ok { - response.Error(w, http.StatusForbidden, "admin required") - return - } - - list, err := h.files.ImageFiles(r.Context()) - if err != nil { - response.Error(w, http.StatusInternalServerError, "could not list images") - return - } - - var rebuilt, failed int - for _, f := range list { - if !thumbnails.SupportedMIME(f.MimeType) { - continue - } - rc, err := h.storage.Get(r.Context(), f.StorageKey) - if err != nil { - failed++ - continue - } - err = thumbnails.Generate(r.Context(), h.storage, f.ID.String(), f.MimeType, rc) - rc.Close() - if err != nil { - failed++ - continue - } - // Auch setzen, wenn es schon stand: Dateien, bei denen die Erzeugung - // beim Hochladen fehlschlug, bekommen so nachträglich eines. - if err := h.files.UpdateThumbnail(r.Context(), f.ID, true); err != nil { - failed++ - continue - } - rebuilt++ - } - - h.logAdmin(r, audit.ActionGarbageCollect, "storage", "", "", - fmt.Sprintf("thumbnails rebuilt: %d of %d images, %d failed", - rebuilt, len(list), failed)) - - response.JSON(w, http.StatusOK, map[string]any{ - "images": len(list), - "rebuilt": rebuilt, - "failed": failed, - }) -} diff --git a/backend/internal/files/store.go b/backend/internal/files/store.go index c9a749c..5e6c5d3 100644 --- a/backend/internal/files/store.go +++ b/backend/internal/files/store.go @@ -533,29 +533,3 @@ func isUniqueViolation(err error) bool { } return false } - -// ImageFiles nennt alle nicht gelöschten Dateien, aus denen ein Vorschaubild -// entstehen kann – für das Neuerzeugen von Hand. -// -// Ohne Papierkorb: Für eine Datei, die man weggeworfen hat, lohnt keine Runde -// durch den Dekodierer. -func (s *Store) ImageFiles(ctx context.Context) ([]*File, error) { - rows, err := s.db.Query(ctx, - `SELECT `+fileCols+` - FROM files - WHERE is_deleted = false AND mime_type LIKE 'image/%' - ORDER BY created_at`) - if err != nil { - return nil, fmt.Errorf("query image files: %w", err) - } - defer rows.Close() - var out []*File - for rows.Next() { - var f File - if err := scanFile(rows, &f); err != nil { - return nil, fmt.Errorf("scan image file: %w", err) - } - out = append(out, &f) - } - return out, rows.Err() -} diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index e69001b..34b64be 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -830,12 +830,6 @@ export const adminApi = { freed_bytes: number; skipped_young: number }>('POST', '/admin/gc'), - /** Vorschaubilder neu erzeugen – für alles, was vor der Auswertung der - * EXIF-Drehung hochgeladen wurde und deshalb quer liegt. */ - rebuildThumbnails: () => request<{ - images: number; rebuilt: number; failed: number - }>('POST', '/admin/thumbnails/rebuild'), - /** Stand der Texterkennung. `enabled: false` heißt: abgeschaltet oder die * Programme fehlen im Image – kein Fehler, sondern eine Auskunft. */ ocrStatus: () => request('GET', '/admin/ocr'), diff --git a/frontend/src/pages/admin/AuditTab.tsx b/frontend/src/pages/admin/AuditTab.tsx index 57c58f6..120ed8e 100644 --- a/frontend/src/pages/admin/AuditTab.tsx +++ b/frontend/src/pages/admin/AuditTab.tsx @@ -195,60 +195,6 @@ function StorageCleanup() { ) } -/** Vorschaubilder entstehen beim Hochladen von selbst. Dieser Knopf ist für - * den Bestand: Bis heute wurde die EXIF-Drehung nicht ausgewertet, hochkant - * aufgenommene Fotos liegen als Vorschaubild deshalb quer. */ -function RebuildThumbnails() { - const [running, setRunning] = useState(false) - const [result, setResult] = useState(null) - - async function run() { - setRunning(true) - setResult(null) - try { - const r = await adminApi.rebuildThumbnails() - setResult( - r.images === 0 - ? 'No images stored yet' - : `${r.rebuilt} of ${r.images} previews rebuilt` + (r.failed ? `, ${r.failed} failed` : ''), - ) - } catch { - setResult('Rebuild failed') - } finally { - setRunning(false) - } - } - - return ( -
-
-
- Rebuild image previews -
-
- {result ?? 'Regenerates every stored preview. Needed once: photos taken in portrait used to end up sideways, because the rotation flag was ignored.'} -
-
- -
- ) -} - export default function AuditTab() { const [entries, setEntries] = useState([]) const [total, setTotal] = useState(0) @@ -275,7 +221,6 @@ export default function AuditTab() {
-