Refactor error handling
This commit is contained in:
parent
ae15f35792
commit
819a3caad6
3 changed files with 70 additions and 28 deletions
|
@ -13,6 +13,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.andreafazzi.eu/andrea/oef/config"
|
"git.andreafazzi.eu/andrea/oef/config"
|
||||||
|
"git.andreafazzi.eu/andrea/oef/errors"
|
||||||
"git.andreafazzi.eu/andrea/oef/i18n"
|
"git.andreafazzi.eu/andrea/oef/i18n"
|
||||||
"git.andreafazzi.eu/andrea/oef/orm"
|
"git.andreafazzi.eu/andrea/oef/orm"
|
||||||
"git.andreafazzi.eu/andrea/oef/reflect"
|
"git.andreafazzi.eu/andrea/oef/reflect"
|
||||||
|
@ -24,6 +25,19 @@ import (
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type handlerFuncWithError func(http.ResponseWriter, *http.Request) error
|
||||||
|
|
||||||
|
type rootMiddleware struct {
|
||||||
|
h *Handlers
|
||||||
|
fn handlerFuncWithError
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRootMiddleware(h *Handlers, fn func(http.ResponseWriter, *http.Request) error) *rootMiddleware {
|
||||||
|
return &rootMiddleware{h, fn}
|
||||||
|
}
|
||||||
|
|
||||||
|
// type rootHandler func(http.ResponseWriter, *http.Request) error
|
||||||
|
|
||||||
type Handlers struct {
|
type Handlers struct {
|
||||||
Config *config.ConfigT
|
Config *config.ConfigT
|
||||||
|
|
||||||
|
@ -61,10 +75,12 @@ func (h *Handlers) generateModelHandlers(r *mux.Router, model interface{}) {
|
||||||
),
|
),
|
||||||
h.JWTCookieMiddleware.Handler(
|
h.JWTCookieMiddleware.Handler(
|
||||||
h.Recover(
|
h.Recover(
|
||||||
h.modelHandler(
|
newRootMiddleware(
|
||||||
reflect.ModelNameLowerPlural(model),
|
h,
|
||||||
pattern,
|
h.modelHandler(
|
||||||
)))).Methods(pattern.Methods...)
|
reflect.ModelNameLowerPlural(model),
|
||||||
|
pattern,
|
||||||
|
))))).Methods(pattern.Methods...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install API paths
|
// Install API paths
|
||||||
|
@ -75,10 +91,13 @@ func (h *Handlers) generateModelHandlers(r *mux.Router, model interface{}) {
|
||||||
),
|
),
|
||||||
h.JWTHeaderMiddleware.Handler(
|
h.JWTHeaderMiddleware.Handler(
|
||||||
h.Recover(
|
h.Recover(
|
||||||
h.modelHandler(
|
newRootMiddleware(
|
||||||
reflect.ModelNameLowerPlural(model),
|
h,
|
||||||
pattern,
|
|
||||||
)))).Methods(pattern.Methods...)
|
h.modelHandler(
|
||||||
|
reflect.ModelNameLowerPlural(model),
|
||||||
|
pattern,
|
||||||
|
))))).Methods(pattern.Methods...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set permissions
|
// Set permissions
|
||||||
|
@ -265,18 +284,16 @@ func (h *Handlers) hasPermission(role, path string) bool {
|
||||||
return h.permissions[role][path]
|
return h.permissions[role][path]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handlers) get(w http.ResponseWriter, r *http.Request, model string, pattern config.PathPattern) {
|
func (h *Handlers) get(w http.ResponseWriter, r *http.Request, model string, pattern config.PathPattern) error {
|
||||||
format := r.URL.Query().Get("format")
|
format := r.URL.Query().Get("format")
|
||||||
getFn, err := h.Database.GetFunc(pattern.Path(model))
|
getFn, err := h.Database.GetFunc(pattern.Path(model))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error:", err)
|
return err
|
||||||
respondWithError(h, w, r, err)
|
|
||||||
} else {
|
} else {
|
||||||
claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
|
claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
|
||||||
role := claims["role"].(string)
|
role := claims["role"].(string)
|
||||||
if !h.hasPermission(role, pattern.Path(model)) {
|
if !h.hasPermission(role, pattern.Path(model)) {
|
||||||
h.setFlashMessage(w, r, "notAuthorized")
|
return errors.NotAuthorized
|
||||||
h.Renderer[format].Render(w, r, h.CookieStore, fmt.Errorf("%s", "Errore di autorizzazione"))
|
|
||||||
} else {
|
} else {
|
||||||
data, err := getFn(h.Database, mux.Vars(r), w, r)
|
data, err := getFn(h.Database, mux.Vars(r), w, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -287,6 +304,7 @@ func (h *Handlers) get(w http.ResponseWriter, r *http.Request, model string, pat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handlers) post(w http.ResponseWriter, r *http.Request, model string, pattern config.PathPattern) error {
|
func (h *Handlers) post(w http.ResponseWriter, r *http.Request, model string, pattern config.PathPattern) error {
|
||||||
|
@ -299,17 +317,17 @@ func (h *Handlers) post(w http.ResponseWriter, r *http.Request, model string, pa
|
||||||
postFn, err := h.Database.GetFunc(pattern.Path(model))
|
postFn, err := h.Database.GetFunc(pattern.Path(model))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
respondWithError(h, w, r, err)
|
return err
|
||||||
} else {
|
} else {
|
||||||
claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
|
claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
|
||||||
|
|
||||||
role := claims["role"].(string)
|
role := claims["role"].(string)
|
||||||
if !h.hasPermission(role, pattern.Path(model)) {
|
if !h.hasPermission(role, pattern.Path(model)) {
|
||||||
h.Renderer[respFormat].Render(w, r, h.CookieStore, fmt.Errorf("%s", "Errore di autorizzazione"))
|
return errors.NotAuthorized
|
||||||
} else {
|
} else {
|
||||||
data, err = postFn(h.Database, mux.Vars(r), w, r)
|
data, err = postFn(h.Database, mux.Vars(r), w, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
respondWithError(h, w, r, err)
|
return err
|
||||||
} else if pattern.RedirectPattern != "" {
|
} else if pattern.RedirectPattern != "" {
|
||||||
if id := mux.Vars(r)["id"]; id != "" {
|
if id := mux.Vars(r)["id"]; id != "" {
|
||||||
modelId, _ := strconv.Atoi(id)
|
modelId, _ := strconv.Atoi(id)
|
||||||
|
@ -327,16 +345,15 @@ func (h *Handlers) post(w http.ResponseWriter, r *http.Request, model string, pa
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handlers) delete(w http.ResponseWriter, r *http.Request, model string, pattern config.PathPattern) {
|
func (h *Handlers) delete(w http.ResponseWriter, r *http.Request, model string, pattern config.PathPattern) error {
|
||||||
var data interface{}
|
var data interface{}
|
||||||
|
|
||||||
respFormat := renderer.GetContentFormat(r)
|
respFormat := renderer.GetContentFormat(r)
|
||||||
|
|
||||||
claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
|
claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
|
||||||
|
|
||||||
role := claims["role"].(string)
|
role := claims["role"].(string)
|
||||||
if !h.hasPermission(role, pattern.Path(model)) {
|
if !h.hasPermission(role, pattern.Path(model)) {
|
||||||
h.Renderer[respFormat].Render(w, r, h.CookieStore, fmt.Errorf("%s", "Errore di autorizzazione"))
|
return errors.NotAuthorized
|
||||||
} else {
|
} else {
|
||||||
postFn, err := h.Database.GetFunc(pattern.Path(model))
|
postFn, err := h.Database.GetFunc(pattern.Path(model))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -357,12 +374,19 @@ func (h *Handlers) delete(w http.ResponseWriter, r *http.Request, model string,
|
||||||
h.Renderer[respFormat].Render(w, r, h.CookieStore, data.(orm.IDer).GetID())
|
h.Renderer[respFormat].Render(w, r, h.CookieStore, data.(orm.IDer).GetID())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func respondWithError(h *Handlers, w http.ResponseWriter, r *http.Request, err error) {
|
func respondWithError(h *Handlers, w http.ResponseWriter, r *http.Request, err error) {
|
||||||
respFormat := renderer.GetContentFormat(r)
|
var format string
|
||||||
|
|
||||||
|
format = r.URL.Query().Get("format")
|
||||||
|
if format == "" {
|
||||||
|
format = renderer.GetContentFormat(r)
|
||||||
|
}
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
h.Renderer[respFormat].Render(w, r, h.CookieStore, err)
|
h.Renderer[format].Render(w, r, h.CookieStore, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handlers) Create(model interface{}) http.Handler {
|
func (h *Handlers) Create(model interface{}) http.Handler {
|
||||||
|
@ -389,25 +413,29 @@ func (h *Handlers) Read(model interface{}) http.Handler {
|
||||||
return http.HandlerFunc(fn)
|
return http.HandlerFunc(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handlers) modelHandler(model string, pattern config.PathPattern) http.Handler {
|
func (h *Handlers) modelHandler(model string, pattern config.PathPattern) handlerFuncWithError {
|
||||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
fn := func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
// Replace the "api" prefix.
|
// Replace the "api" prefix.
|
||||||
pattern.PathPattern = strings.Replace(pattern.PathPattern, "/api", "", -1)
|
pattern.PathPattern = strings.Replace(pattern.PathPattern, "/api", "", -1)
|
||||||
|
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case "GET":
|
case "GET":
|
||||||
h.get(w, r, model, pattern)
|
err = h.get(w, r, model, pattern)
|
||||||
|
|
||||||
case "POST":
|
case "POST":
|
||||||
h.post(w, r, model, pattern)
|
err = h.post(w, r, model, pattern)
|
||||||
|
|
||||||
case "DELETE":
|
case "DELETE":
|
||||||
h.delete(w, r, model, pattern)
|
err = h.delete(w, r, model, pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(fn)
|
return handlerFuncWithError(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultHomeHandler() http.Handler {
|
func DefaultHomeHandler() http.Handler {
|
||||||
|
@ -458,3 +486,14 @@ func DefaultHomeHandler() http.Handler {
|
||||||
}
|
}
|
||||||
return http.HandlerFunc(fn)
|
return http.HandlerFunc(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *rootMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
err := m.fn(w, r) // Call handler function
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// This is where our error handling logic starts.
|
||||||
|
log.Printf("An error accured: %v", err) // Log the error.
|
||||||
|
|
||||||
|
respondWithError(m.h, w, r, err)
|
||||||
|
}
|
||||||
|
|
|
@ -41,5 +41,9 @@ var (
|
||||||
"outOfTime": map[string]string{
|
"outOfTime": map[string]string{
|
||||||
"it": "Il tempo utile per consegnare la prova è scaduto.",
|
"it": "Il tempo utile per consegnare la prova è scaduto.",
|
||||||
},
|
},
|
||||||
|
"notAuthorized": map[string]string{
|
||||||
|
"it": "Non si è autorizzati ad accedere a questa pagina",
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -196,7 +196,6 @@ func (rend *HTMLRenderer) writeError(w http.ResponseWriter, r *http.Request, dat
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Errorf("Error template not found! Can't proceed, sorry."))
|
panic(fmt.Errorf("Error template not found! Can't proceed, sorry."))
|
||||||
}
|
}
|
||||||
log.Println(data.(*htmlTemplateData).Data.(error))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
|
Loading…
Reference in a new issue