Commit 63c017aa authored by ale's avatar ale

Factor out common JSON request decoding

parent 496a4c6f
package server
import (
"context"
"encoding/json"
"errors"
"log"
"net/http"
......@@ -28,171 +30,67 @@ func New(service *as.AccountService, backend as.Backend) *AccountServer {
var emptyResponse struct{}
func errToStatus(err error) int {
switch {
case err == as.ErrUserNotFound, err == as.ErrResourceNotFound:
return http.StatusNotFound
case as.IsAuthError(err):
return http.StatusUnauthorized
case as.IsRequestError(err):
return http.StatusBadRequest
default:
return http.StatusInternalServerError
}
}
func (s *AccountServer) handleGetUser(tx as.TX, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var req as.GetUserRequest
if !serverutil.DecodeJSONRequest(w, r, &req) {
return nil, errBadRequest
}
user, err := s.service.GetUser(r.Context(), tx, &req)
if err != nil {
log.Printf("GetUser(%s): error: %v", req.Username, err)
http.Error(w, err.Error(), errToStatus(err))
return nil, err
}
return user, nil
return handleJSON(w, r, &req, func(ctx context.Context) (interface{}, error) {
return s.service.GetUser(ctx, tx, &req)
})
}
func (s *AccountServer) handleChangeUserPassword(tx as.TX, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var req as.ChangeUserPasswordRequest
if !serverutil.DecodeJSONRequest(w, r, &req) {
return nil, errBadRequest
}
if err := s.service.ChangeUserPassword(r.Context(), tx, &req); err != nil {
log.Printf("ChangeUserPassword(%s): error: %v", req.Username, err)
http.Error(w, err.Error(), errToStatus(err))
return nil, err
}
return &emptyResponse, nil
return handleJSON(w, r, &req, func(ctx context.Context) (interface{}, error) {
return &emptyResponse, s.service.ChangeUserPassword(ctx, tx, &req)
})
}
func (s *AccountServer) handleCreateApplicationSpecificPassword(tx as.TX, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var req as.CreateApplicationSpecificPasswordRequest
if !serverutil.DecodeJSONRequest(w, r, &req) {
return nil, errBadRequest
}
resp, err := s.service.CreateApplicationSpecificPassword(r.Context(), tx, &req)
if err != nil {
log.Printf("CreateApplicationSpecificPassword(%s): error: %v", req.Username, err)
http.Error(w, err.Error(), errToStatus(err))
return nil, err
}
return resp, nil
return handleJSON(w, r, &req, func(ctx context.Context) (interface{}, error) {
return s.service.CreateApplicationSpecificPassword(ctx, tx, &req)
})
}
func (s *AccountServer) handleDeleteApplicationSpecificPassword(tx as.TX, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var req as.DeleteApplicationSpecificPasswordRequest
if !serverutil.DecodeJSONRequest(w, r, &req) {
return nil, errBadRequest
}
if err := s.service.DeleteApplicationSpecificPassword(r.Context(), tx, &req); err != nil {
log.Printf("DeleteApplicationSpecificPassword(%s): error: %v", req.Username, err)
http.Error(w, err.Error(), errToStatus(err))
return nil, err
}
return &emptyResponse, nil
return handleJSON(w, r, &req, func(ctx context.Context) (interface{}, error) {
return &emptyResponse, s.service.DeleteApplicationSpecificPassword(ctx, tx, &req)
})
}
func (s *AccountServer) handleEnableResource(tx as.TX, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var req as.EnableResourceRequest
if !serverutil.DecodeJSONRequest(w, r, &req) {
return nil, errBadRequest
}
if err := s.service.EnableResource(r.Context(), tx, &req); err != nil {
log.Printf("EnableResource(%s): error: %v", req.Username, err)
http.Error(w, err.Error(), errToStatus(err))
return nil, err
}
return &emptyResponse, nil
return handleJSON(w, r, &req, func(ctx context.Context) (interface{}, error) {
return &emptyResponse, s.service.EnableResource(ctx, tx, &req)
})
}
func (s *AccountServer) handleDisableResource(tx as.TX, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var req as.DisableResourceRequest
if !serverutil.DecodeJSONRequest(w, r, &req) {
return nil, errBadRequest
}
if err := s.service.DisableResource(r.Context(), tx, &req); err != nil {
log.Printf("DisableResource(%s): error: %v", req.Username, err)
http.Error(w, err.Error(), errToStatus(err))
return nil, err
}
return &emptyResponse, nil
}
func (s *AccountServer) handleChangeResourcePassword(tx as.TX, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var req as.ChangeResourcePasswordRequest
if !serverutil.DecodeJSONRequest(w, r, &req) {
return nil, errBadRequest
}
if err := s.service.ChangeResourcePassword(r.Context(), tx, &req); err != nil {
log.Printf("ChangeResourcePassword(%s): error: %v", req.Username, err)
http.Error(w, err.Error(), errToStatus(err))
return nil, err
}
return &emptyResponse, nil
return handleJSON(w, r, &req, func(ctx context.Context) (interface{}, error) {
return &emptyResponse, s.service.DisableResource(ctx, tx, &req)
})
}
func (s *AccountServer) handleMoveResource(tx as.TX, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var req as.MoveResourceRequest
if !serverutil.DecodeJSONRequest(w, r, &req) {
return nil, errBadRequest
}
resp, err := s.service.MoveResource(r.Context(), tx, &req)
if err != nil {
log.Printf("MoveResource(%s): error: %v", req.Username, err)
http.Error(w, err.Error(), errToStatus(err))
return nil, err
}
return resp, nil
return handleJSON(w, r, &req, func(ctx context.Context) (interface{}, error) {
return s.service.MoveResource(ctx, tx, &req)
})
}
func (s *AccountServer) handleEnableOTP(tx as.TX, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var req as.EnableOTPRequest
if !serverutil.DecodeJSONRequest(w, r, &req) {
return nil, errBadRequest
}
resp, err := s.service.EnableOTP(r.Context(), tx, &req)
if err != nil {
log.Printf("EnableOTP(%s): error: %v", req.Username, err)
http.Error(w, err.Error(), errToStatus(err))
return nil, err
}
return resp, nil
return handleJSON(w, r, &req, func(ctx context.Context) (interface{}, error) {
return s.service.EnableOTP(ctx, tx, &req)
})
}
func (s *AccountServer) handleDisableOTP(tx as.TX, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var req as.DisableOTPRequest
if !serverutil.DecodeJSONRequest(w, r, &req) {
return nil, errBadRequest
}
if err := s.service.DisableOTP(r.Context(), tx, &req); err != nil {
log.Printf("DisableOTP(%s): error: %v", req.Username, err)
http.Error(w, err.Error(), errToStatus(err))
return nil, err
}
return &emptyResponse, nil
return handleJSON(w, r, &req, func(ctx context.Context) (interface{}, error) {
return &emptyResponse, s.service.DisableOTP(ctx, tx, &req)
})
}
func (s *AccountServer) withTx(f txHandler) http.HandlerFunc {
......@@ -230,7 +128,37 @@ func (s *AccountServer) Handler() http.Handler {
h.HandleFunc("/api/app_specific_password/delete", s.withTx(s.handleDeleteApplicationSpecificPassword))
h.HandleFunc("/api/resource/enable", s.withTx(s.handleEnableResource))
h.HandleFunc("/api/resource/disable", s.withTx(s.handleDisableResource))
h.HandleFunc("/api/resource/change_password", s.withTx(s.handleChangeResourcePassword))
h.HandleFunc("/api/resource/move", s.withTx(s.handleMoveResource))
return h
}
func errToStatus(err error) int {
switch {
case err == as.ErrUserNotFound, err == as.ErrResourceNotFound:
return http.StatusNotFound
case as.IsAuthError(err):
return http.StatusUnauthorized
case as.IsRequestError(err):
return http.StatusBadRequest
default:
return http.StatusInternalServerError
}
}
func handleJSON(w http.ResponseWriter, r *http.Request, req interface{}, f func(context.Context) (interface{}, error)) (interface{}, error) {
if !serverutil.DecodeJSONRequest(w, r, req) {
return nil, errBadRequest
}
resp, err := f(r.Context())
if err != nil {
log.Printf("error in %s: %v, request=%s", r.URL.Path, err, dumpRequest(req))
http.Error(w, err.Error(), errToStatus(err))
return nil, err
}
return resp, nil
}
func dumpRequest(req interface{}) string {
data, _ := json.Marshal(req)
return string(data)
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment