diff --git a/website/admin/home.go b/website/admin/home.go index 4675b4fe..359c05d3 100644 --- a/website/admin/home.go +++ b/website/admin/home.go @@ -28,6 +28,7 @@ func (s *State) GetHome(w http.ResponseWriter, r *http.Request) { err := s.TemplateExecutor.Execute(w, r, input) if err != nil { - s.errorHandler(w, r, err) + s.errorHandler(w, r, err, "input creation failure") + return } } diff --git a/website/admin/profiles.go b/website/admin/profiles.go index 67868611..0209e6a7 100644 --- a/website/admin/profiles.go +++ b/website/admin/profiles.go @@ -21,8 +21,6 @@ import ( "github.com/gorilla/schema" ) -const bcryptCost = 14 - var profileDecoder = schema.NewDecoder() // ProfileForm defines the form we use for the profile page diff --git a/website/admin/router.go b/website/admin/router.go index 6ae6e1e3..45b9325c 100644 --- a/website/admin/router.go +++ b/website/admin/router.go @@ -12,6 +12,7 @@ import ( "github.com/R-a-dio/valkyrie/util/secret" vmiddleware "github.com/R-a-dio/valkyrie/website/middleware" "github.com/R-a-dio/valkyrie/website/shared" + "github.com/rs/zerolog/hlog" "github.com/spf13/afero" "github.com/alexedwards/scs/v2" @@ -85,6 +86,8 @@ func Route(ctx context.Context, s State) func(chi.Router) { vmiddleware.RequirePermission(radio.PermDatabaseView, s.GetSongs)) r.Post("/songs", vmiddleware.RequirePermission(radio.PermDatabaseEdit, s.PostSongs)) + r.Get("/users", + vmiddleware.RequirePermission(radio.PermAdmin, s.GetUsersList)) // proxy to the grafana host grafana, _ := url.Parse("http://localhost:3000") @@ -100,7 +103,8 @@ func (s *State) PostStreamerStop(w http.ResponseWriter, r *http.Request) { s.Conf().Streamer.Client().Stop(r.Context(), false) } -func (s *State) errorHandler(w http.ResponseWriter, r *http.Request, err error) { +func (s *State) errorHandler(w http.ResponseWriter, r *http.Request, err error, msg string) { // TODO: implement this better + hlog.FromRequest(r).Error().Err(err).Msg(msg) http.Error(w, err.Error(), http.StatusInternalServerError) } diff --git a/website/admin/songs.go b/website/admin/songs.go index 7f5f8616..0af999c2 100644 --- a/website/admin/songs.go +++ b/website/admin/songs.go @@ -108,7 +108,7 @@ func (s *State) GetSongs(w http.ResponseWriter, r *http.Request) { func (s *State) PostSongs(w http.ResponseWriter, r *http.Request) { form, err := s.postSongs(w, r) if err != nil { - s.errorHandler(w, r, err) + s.errorHandler(w, r, err, "") return } diff --git a/website/admin/users.go b/website/admin/users.go new file mode 100644 index 00000000..ceeea873 --- /dev/null +++ b/website/admin/users.go @@ -0,0 +1,60 @@ +package admin + +import ( + "cmp" + "net/http" + "slices" + + radio "github.com/R-a-dio/valkyrie" + "github.com/R-a-dio/valkyrie/errors" + "github.com/R-a-dio/valkyrie/website/middleware" +) + +type UsersInput struct { + middleware.Input + + Users []radio.User +} + +func (UsersInput) TemplateBundle() string { + return "users" +} + +type UsersForm struct { + radio.User +} + +func NewUsersInput(us radio.UserStorage, r *http.Request) (*UsersInput, error) { + const op errors.Op = "website/admin.NewUsersInput" + + // get all the users + users, err := us.All() + if err != nil { + return nil, errors.E(op, err) + } + // sort users by their id + slices.SortFunc(users, func(a, b radio.User) int { + return cmp.Compare(a.ID, b.ID) + }) + // construct the input + input := &UsersInput{ + Input: middleware.InputFromRequest(r), + Users: users, + } + + return input, nil +} + +func (s State) GetUsersList(w http.ResponseWriter, r *http.Request) { + input, err := NewUsersInput(s.Storage.User(r.Context()), r) + if err != nil { + s.errorHandler(w, r, err, "input creation failure") + return + } + + err = s.TemplateExecutor.Execute(w, r, input) + if err != nil { + s.errorHandler(w, r, err, "template failure") + return + } +} diff --git a/website/api/v1/song.go b/website/api/v1/song.go index 0c9188af..8e7ec48b 100644 --- a/website/api/v1/song.go +++ b/website/api/v1/song.go @@ -16,7 +16,7 @@ func (a *API) GetSong(w http.ResponseWriter, r *http.Request) { tid, err := radio.ParseTrackID(query.Get("id")) if err != nil { - hlog.FromRequest(r).Error().Err(err) + hlog.FromRequest(r).Error().Err(err).Msg("") http.Error(w, "invalid or missing id", http.StatusBadRequest) return } @@ -25,7 +25,7 @@ func (a *API) GetSong(w http.ResponseWriter, r *http.Request) { song, err := a.storage.Track(r.Context()).Get(tid) if err != nil { - hlog.FromRequest(r).Error().Err(err) + hlog.FromRequest(r).Error().Err(err).Msg("") http.Error(w, "unknown id", http.StatusNotFound) return } @@ -44,7 +44,7 @@ func (a *API) GetSong(w http.ResponseWriter, r *http.Request) { if errors.IsE(err, os.ErrNotExist) { status = http.StatusNotFound } - hlog.FromRequest(r).Error().Err(err) + hlog.FromRequest(r).Error().Err(err).Msg("") http.Error(w, http.StatusText(status), status) return }