package documents import ( "net/http" "github.com/google/uuid" "aether/pkg/response" ) // Handler zeigt den Stand der Texterkennung. // // Ohne diese Auskunft ist nicht zu erkennen, ob der Volltext funktioniert: // Eine Suche, die nichts findet, sieht genauso aus wie eine Suche in einem // Bestand, der noch gar nicht erkannt wurde. Nach dem ersten Start läuft der // Arbeiter je nach Menge Stunden – ohne Zähler weiß niemand, ob er // vorankommt. type Handler struct { store *Store // isAdmin und userID trennen die Rechteprüfung von diesem Paket. // documents kennt weder Sessions noch Rollen, und soll es auch nicht. isAdmin func(r *http.Request) bool userID func(r *http.Request) uuid.UUID } func NewHandler(store *Store, isAdmin func(r *http.Request) bool, userID func(r *http.Request) uuid.UUID) *Handler { return &Handler{store: store, isAdmin: isAdmin, userID: userID} } // Status beantwortet GET /api/v1/admin/ocr – der Gesamtstand des Servers. func (h *Handler) Status(w http.ResponseWriter, r *http.Request) { if !h.isAdmin(r) { response.Error(w, http.StatusForbidden, "admin required") return } // h.store nil heißt: OCR ist abgeschaltet oder die Programme fehlen. Das // ist eine Auskunft, kein Fehler – die Oberfläche soll „aus" anzeigen // können, statt in einen Fehlerzustand zu laufen. if h == nil || h.store == nil { response.JSON(w, http.StatusOK, map[string]any{"enabled": false}) return } stats, err := h.store.Stats(r.Context()) if err != nil { response.Error(w, http.StatusInternalServerError, "ocr status failed") return } response.JSON(w, http.StatusOK, map[string]any{ "enabled": true, "pending": stats.Pending, "running": stats.Running, "done": stats.Done, "failed": stats.Failed, "indexed": stats.Indexed, }) } // MyStatus beantwortet GET /api/v1/ocr – der Stand der **eigenen** Dateien. // // Ohne diesen Endpunkt wüsste nur der Administrator, ob ein Dokument schon // gelesen wurde. Das ist die falsche Person: Wissen muss es, wer die Rechnung // hochgeladen hat und sie gerade nicht findet. func (h *Handler) MyStatus(w http.ResponseWriter, r *http.Request) { uid := h.userID(r) if uid == uuid.Nil { response.Error(w, http.StatusUnauthorized, "not signed in") return } if h == nil || h.store == nil { response.JSON(w, http.StatusOK, map[string]any{"enabled": false}) return } stats, err := h.store.StatsForUser(r.Context(), uid) if err != nil { response.Error(w, http.StatusInternalServerError, "ocr status failed") return } response.JSON(w, http.StatusOK, map[string]any{ "enabled": true, "pending": stats.Pending, "running": stats.Running, "done": stats.Done, "failed": stats.Failed, "indexed": stats.Indexed, }) }