package web import ( "errors" "net/http" "net/url" "strings" "github.com/go-chi/chi/v5" "plumber/internal/store" ) type adminUsersPage struct { page Users []store.User Error string Search string NextCursor string HasMore bool } func (s *Server) requireAdmin(w http.ResponseWriter, r *http.Request) *store.User { u := currentUser(r) if !u.Admin() { http.Error(w, "forbidden", http.StatusForbidden) return nil } return u } func (s *Server) handleAdminUsers(w http.ResponseWriter, r *http.Request) { if s.requireAdmin(w, r) == nil { return } search := strings.TrimSpace(r.URL.Query().Get("q")) cursorCreated := r.URL.Query().Get("cursor_created") cursorID := r.URL.Query().Get("cursor_id") users, nextCreated, nextID, err := s.store.ListUsers(r.Context(), store.ListUsersQuery{ Search: search, CursorCreated: cursorCreated, CursorID: cursorID, Limit: store.AdminUsersLimit, }) if err != nil { http.Error(w, "could not load users", http.StatusInternalServerError) return } next := "" if nextCreated != "" { v := url.Values{} if search != "" { v.Set("q", search) } v.Set("cursor_created", nextCreated) v.Set("cursor_id", nextID) next = "/admin/users?" + v.Encode() } s.exec(w, "admin-users", adminUsersPage{ page: s.basePage(r, "Users"), Users: users, Search: search, NextCursor: next, HasMore: next != "", }) } func (s *Server) handleAdminSetRole(w http.ResponseWriter, r *http.Request) { if !s.requireCSRF(w, r) { return } if s.requireAdmin(w, r) == nil { return } id := chi.URLParam(r, "id") role := store.Role(r.PostFormValue("role")) err := s.store.SetUserRole(r.Context(), id, role) if errors.Is(err, store.ErrLastAdmin) { users, _, _, listErr := s.store.ListUsers(r.Context(), store.ListUsersQuery{Limit: store.AdminUsersLimit}) if listErr != nil { http.Error(w, "could not demote last admin", http.StatusBadRequest) return } s.exec(w, "admin-users", adminUsersPage{ page: s.basePage(r, "Users"), Users: users, Error: "Cannot demote the last admin.", }) return } if err != nil { http.Error(w, "could not update role", http.StatusBadRequest) return } http.Redirect(w, r, "/admin/users", http.StatusSeeOther) }