v2.6.50: notifications overhaul, fix blank page, fix chapter review loading
- svelte.config.js: paths.relative=false so CSS uses absolute /_app/ paths (fixes blank home page after redirect)
- ai-jobs: fix openReview() mutating stale alias r instead of $state review — was causing 'Loading results...' to never resolve for chapter-names/image-gen/description
- notifications bell: redesign with All/Unread tabs, per-item dismiss (×), mark-all-read, clear-all, 'View all' footer link
- /admin/notifications: new dedicated full-page notifications view
- api/notifications proxy: add PATCH (mark-all-read) and DELETE (clear-all, dismiss) handlers
- runner: add CreateNotification calls on success/failure in runScrapeTask, runAudioTask, runTranslationTask
- storage/import.go: real PDF (dslipak/pdf) and EPUB (archive/zip + x/net/html) parsing replacing stubs
- translation admin page: stream jobs Promise instead of blocking navigation
- store.go: DeleteNotification, ClearAllNotifications, MarkAllNotificationsRead methods
- handlers_notifications.go + server.go: PATCH /api/notifications, DELETE /api/notifications, DELETE /api/notifications/{id}
This commit is contained in:
@@ -7,6 +7,63 @@ import (
|
||||
"github.com/libnovel/backend/internal/storage"
|
||||
)
|
||||
|
||||
// handleDismissNotification handles DELETE /api/notifications/{id}.
|
||||
func (s *Server) handleDismissNotification(w http.ResponseWriter, r *http.Request) {
|
||||
id := r.PathValue("id")
|
||||
if id == "" {
|
||||
jsonError(w, http.StatusBadRequest, "notification id required")
|
||||
return
|
||||
}
|
||||
store, ok := s.deps.Producer.(*storage.Store)
|
||||
if !ok {
|
||||
jsonError(w, http.StatusInternalServerError, "storage not available")
|
||||
return
|
||||
}
|
||||
if err := store.DeleteNotification(r.Context(), id); err != nil {
|
||||
jsonError(w, http.StatusInternalServerError, "dismiss notification: "+err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, 0, map[string]any{"success": true})
|
||||
}
|
||||
|
||||
// handleClearAllNotifications handles DELETE /api/notifications?user_id=...
|
||||
func (s *Server) handleClearAllNotifications(w http.ResponseWriter, r *http.Request) {
|
||||
userID := r.URL.Query().Get("user_id")
|
||||
if userID == "" {
|
||||
jsonError(w, http.StatusBadRequest, "user_id required")
|
||||
return
|
||||
}
|
||||
store, ok := s.deps.Producer.(*storage.Store)
|
||||
if !ok {
|
||||
jsonError(w, http.StatusInternalServerError, "storage not available")
|
||||
return
|
||||
}
|
||||
if err := store.ClearAllNotifications(r.Context(), userID); err != nil {
|
||||
jsonError(w, http.StatusInternalServerError, "clear notifications: "+err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, 0, map[string]any{"success": true})
|
||||
}
|
||||
|
||||
// handleMarkAllNotificationsRead handles PATCH /api/notifications?user_id=...
|
||||
func (s *Server) handleMarkAllNotificationsRead(w http.ResponseWriter, r *http.Request) {
|
||||
userID := r.URL.Query().Get("user_id")
|
||||
if userID == "" {
|
||||
jsonError(w, http.StatusBadRequest, "user_id required")
|
||||
return
|
||||
}
|
||||
store, ok := s.deps.Producer.(*storage.Store)
|
||||
if !ok {
|
||||
jsonError(w, http.StatusInternalServerError, "storage not available")
|
||||
return
|
||||
}
|
||||
if err := store.MarkAllNotificationsRead(r.Context(), userID); err != nil {
|
||||
jsonError(w, http.StatusInternalServerError, "mark all read: "+err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, 0, map[string]any{"success": true})
|
||||
}
|
||||
|
||||
type notification struct {
|
||||
ID string `json:"id"`
|
||||
UserID string `json:"user_id"`
|
||||
|
||||
@@ -251,7 +251,10 @@ func (s *Server) ListenAndServe(ctx context.Context) error {
|
||||
|
||||
// Notifications
|
||||
mux.HandleFunc("GET /api/notifications", s.handleListNotifications)
|
||||
mux.HandleFunc("PATCH /api/notifications", s.handleMarkAllNotificationsRead)
|
||||
mux.HandleFunc("PATCH /api/notifications/{id}", s.handleMarkNotificationRead)
|
||||
mux.HandleFunc("DELETE /api/notifications", s.handleClearAllNotifications)
|
||||
mux.HandleFunc("DELETE /api/notifications/{id}", s.handleDismissNotification)
|
||||
|
||||
// Voices list
|
||||
mux.HandleFunc("GET /api/voices", s.handleVoices)
|
||||
|
||||
Reference in New Issue
Block a user