summaryrefslogtreecommitdiff
path: root/internal/api/handlers_admin.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-01 21:10:43 +0300
committerPaul Buetow <paul@buetow.org>2026-05-01 21:10:43 +0300
commitaf29deb33ee25800976b7122236bf7895a5ff39e (patch)
treeb138a6dfe2bb9636ff1c58ff8d255223cd145901 /internal/api/handlers_admin.go
parent74c2e0982f336ab135d8b63d26fa49bcd58e57a9 (diff)
refactor(api): split monolithic handlers.go into domain-specific files (task 3)
Split internal/api/handlers.go (1045 lines) to improve KISS/SRP: - handlers_auth.go – bootstrap, login, logout, health, session cookies - handlers_media.go – sets, media CRUD, tags, favorites, notes, progress - handlers_share.go – create/list/revoke shares, share page, share stream - handlers_admin.go – trash, rescan, users, permissions - handlers_file.go – stream, download, thumbnail, regenerate thumbnail Shared helpers (writeJSON, readJSON, pathID, serveFileResult, mimeTypeForFilename, etc.) remain in handlers.go. All tests pass: go test ./... -race -cover.
Diffstat (limited to 'internal/api/handlers_admin.go')
-rw-r--r--internal/api/handlers_admin.go135
1 files changed, 135 insertions, 0 deletions
diff --git a/internal/api/handlers_admin.go b/internal/api/handlers_admin.go
new file mode 100644
index 0000000..246a466
--- /dev/null
+++ b/internal/api/handlers_admin.go
@@ -0,0 +1,135 @@
+package api
+
+import (
+ "net/http"
+
+ "codeberg.org/snonux/player/internal/model"
+)
+
+// ------------------------------------------------------------------
+// Admin
+// ------------------------------------------------------------------
+
+func (s *Server) handleListTrash(w http.ResponseWriter, r *http.Request) {
+ if !requireService(w, s.adminSvc) {
+ return
+ }
+ items, err := s.adminSvc.ListTrash(r.Context())
+ if err != nil {
+ writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
+ return
+ }
+ writeJSON(w, http.StatusOK, items)
+}
+
+func (s *Server) handleRescan(w http.ResponseWriter, r *http.Request) {
+ if !requireService(w, s.adminSvc) {
+ return
+ }
+ if err := s.adminSvc.TriggerRescan(r.Context()); err != nil {
+ writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
+ return
+ }
+ writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
+}
+
+func (s *Server) handleListUsers(w http.ResponseWriter, r *http.Request) {
+ if !requireService(w, s.adminSvc) {
+ return
+ }
+ users, err := s.adminSvc.ListUsers(r.Context())
+ if err != nil {
+ writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
+ return
+ }
+ writeJSON(w, http.StatusOK, users)
+}
+
+func (s *Server) handleCreateUser(w http.ResponseWriter, r *http.Request) {
+ if !requireService(w, s.adminSvc) {
+ return
+ }
+ var req struct {
+ Username string `json:"username"`
+ Password string `json:"password"`
+ IsAdmin bool `json:"is_admin"`
+ }
+ if err := readJSON(r, &req); err != nil || req.Username == "" || req.Password == "" {
+ writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid request"})
+ return
+ }
+ user, err := s.adminSvc.CreateUser(r.Context(), req.Username, req.Password, req.IsAdmin)
+ if err != nil {
+ writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
+ return
+ }
+ writeJSON(w, http.StatusOK, user)
+}
+
+func (s *Server) handleDeleteUser(w http.ResponseWriter, r *http.Request) {
+ if !requireService(w, s.adminSvc) {
+ return
+ }
+ id := pathID(r, "id")
+ adminUser, _ := r.Context().Value(userCtxKey).(*model.User)
+ if adminUser != nil && adminUser.ID == id {
+ writeJSON(w, http.StatusBadRequest, map[string]string{"error": "cannot delete self"})
+ return
+ }
+ if err := s.adminSvc.DeleteUser(r.Context(), id); err != nil {
+ writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
+ return
+ }
+ writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
+}
+
+func (s *Server) handleListPermissions(w http.ResponseWriter, r *http.Request) {
+ if !requireService(w, s.adminSvc) {
+ return
+ }
+ perms, err := s.adminSvc.ListPermissions(r.Context())
+ if err != nil {
+ writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
+ return
+ }
+ writeJSON(w, http.StatusOK, perms)
+}
+
+func (s *Server) handleGrantPermission(w http.ResponseWriter, r *http.Request) {
+ if !requireService(w, s.adminSvc) {
+ return
+ }
+ var req struct {
+ SetID int64 `json:"set_id"`
+ UserID int64 `json:"user_id"`
+ Role model.Role `json:"role"`
+ }
+ if err := readJSON(r, &req); err != nil {
+ writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid request"})
+ return
+ }
+ if err := s.adminSvc.GrantPermission(r.Context(), req.SetID, req.UserID, req.Role); err != nil {
+ writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
+ return
+ }
+ writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
+}
+
+func (s *Server) handleRevokePermission(w http.ResponseWriter, r *http.Request) {
+ if !requireService(w, s.adminSvc) {
+ return
+ }
+ var req struct {
+ SetID int64 `json:"set_id"`
+ UserID int64 `json:"user_id"`
+ }
+ if err := readJSON(r, &req); err != nil {
+ writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid request"})
+ return
+ }
+ if err := s.adminSvc.RevokePermission(r.Context(), req.SetID, req.UserID); err != nil {
+ writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
+ return
+ }
+ writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
+}