Simplify API endpoints; add endpoint tests

This commit is contained in:
binwiederhier 2022-12-28 19:55:11 -05:00
parent 7ca9afad57
commit 367d024a2d
6 changed files with 113 additions and 75 deletions

View file

@ -5,10 +5,13 @@ import (
"errors"
"heckel.io/ntfy/user"
"heckel.io/ntfy/util"
"io"
"net/http"
)
const (
jsonBodyBytesLimit = 4096
)
func (s *Server) handleAccountCreate(w http.ResponseWriter, r *http.Request, v *visitor) error {
admin := v.user != nil && v.user.Role == user.RoleAdmin
if !admin {
@ -18,15 +21,10 @@ func (s *Server) handleAccountCreate(w http.ResponseWriter, r *http.Request, v *
return errHTTPUnauthorized // Cannot create account from user context
}
}
body, err := util.Peek(r.Body, 4096) // FIXME
newAccount, err := util.ReadJSONWithLimit[apiAccountCreateRequest](r.Body, jsonBodyBytesLimit)
if err != nil {
return err
}
defer r.Body.Close()
var newAccount apiAccountCreateRequest
if err := json.NewDecoder(body).Decode(&newAccount); err != nil {
return err
}
if existingUser, _ := s.userManager.User(newAccount.Username); existingUser != nil {
return errHTTPConflictUserExists
}
@ -38,13 +36,10 @@ func (s *Server) handleAccountCreate(w http.ResponseWriter, r *http.Request, v *
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*") // FIXME remove this
// FIXME return something
return nil
}
func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *visitor) error {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*") // FIXME remove this
stats, err := v.Info()
if err != nil {
return err
@ -105,6 +100,8 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *vis
Upgradable: true,
}
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*") // FIXME remove this
if err := json.NewEncoder(w).Encode(response); err != nil {
return err
}
@ -125,32 +122,20 @@ func (s *Server) handleAccountDelete(w http.ResponseWriter, r *http.Request, v *
}
func (s *Server) handleAccountPasswordChange(w http.ResponseWriter, r *http.Request, v *visitor) error {
if v.user == nil {
return errHTTPUnauthorized
}
body, err := util.Peek(r.Body, 4096) // FIXME
newPassword, err := util.ReadJSONWithLimit[apiAccountCreateRequest](r.Body, jsonBodyBytesLimit)
if err != nil {
return err
}
defer r.Body.Close()
var newPassword apiAccountCreateRequest // Re-use!
if err := json.NewDecoder(body).Decode(&newPassword); err != nil {
return err
}
if err := s.userManager.ChangePassword(v.user.Name, newPassword.Password); err != nil {
return err
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*") // FIXME remove this
// FIXME return something
return nil
}
func (s *Server) handleAccountTokenIssue(w http.ResponseWriter, r *http.Request, v *visitor) error {
// TODO rate limit
if v.user == nil {
return errHTTPUnauthorized
}
token, err := s.userManager.CreateToken(v.user)
if err != nil {
return err
@ -192,7 +177,7 @@ func (s *Server) handleAccountTokenExtend(w http.ResponseWriter, r *http.Request
func (s *Server) handleAccountTokenDelete(w http.ResponseWriter, r *http.Request, v *visitor) error {
// TODO rate limit
if v.user == nil || v.user.Token == "" {
if v.user.Token == "" {
return errHTTPUnauthorized
}
if err := s.userManager.RemoveToken(v.user); err != nil {
@ -203,20 +188,10 @@ func (s *Server) handleAccountTokenDelete(w http.ResponseWriter, r *http.Request
}
func (s *Server) handleAccountSettingsChange(w http.ResponseWriter, r *http.Request, v *visitor) error {
if v.user == nil {
return errors.New("no user")
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*") // FIXME remove this
body, err := util.Peek(r.Body, 4096) // FIXME
newPrefs, err := util.ReadJSONWithLimit[user.Prefs](r.Body, jsonBodyBytesLimit)
if err != nil {
return err
}
defer r.Body.Close()
var newPrefs user.Prefs
if err := json.NewDecoder(body).Decode(&newPrefs); err != nil {
return err
}
if v.user.Prefs == nil {
v.user.Prefs = &user.Prefs{}
}
@ -238,14 +213,16 @@ func (s *Server) handleAccountSettingsChange(w http.ResponseWriter, r *http.Requ
prefs.Notification.MinPriority = newPrefs.Notification.MinPriority
}
}
return s.userManager.ChangeSettings(v.user)
if err := s.userManager.ChangeSettings(v.user); err != nil {
return err
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*") // FIXME remove this
return nil
}
func (s *Server) handleAccountSubscriptionAdd(w http.ResponseWriter, r *http.Request, v *visitor) error {
if v.user == nil {
return errors.New("no user")
}
newSubscription, err := readJSONBody[user.Subscription](r.Body)
newSubscription, err := util.ReadJSONWithLimit[user.Subscription](r.Body, jsonBodyBytesLimit)
if err != nil {
return err
}
@ -275,16 +252,11 @@ func (s *Server) handleAccountSubscriptionAdd(w http.ResponseWriter, r *http.Req
}
func (s *Server) handleAccountSubscriptionChange(w http.ResponseWriter, r *http.Request, v *visitor) error {
if v.user == nil {
return errors.New("no user") // FIXME s.ensureUser
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*") // FIXME remove this
matches := accountSubscriptionSingleRegex.FindStringSubmatch(r.URL.Path)
if len(matches) != 2 {
return errHTTPInternalErrorInvalidFilePath // FIXME
}
updatedSubscription, err := readJSONBody[user.Subscription](r.Body)
updatedSubscription, err := util.ReadJSONWithLimit[user.Subscription](r.Body, jsonBodyBytesLimit)
if err != nil {
return err
}
@ -342,16 +314,3 @@ func (s *Server) handleAccountSubscriptionDelete(w http.ResponseWriter, r *http.
}
return nil
}
func readJSONBody[T any](body io.ReadCloser) (*T, error) {
body, err := util.Peek(body, 4096)
if err != nil {
return nil, err
}
defer body.Close()
var obj T
if err := json.NewDecoder(body).Decode(&obj); err != nil {
return nil, err
}
return &obj, nil
}