Improve error handling and handle errors in token

This commit is contained in:
Andrea Fazzi 2020-02-19 14:57:31 +01:00
parent 290fe238ac
commit 9d99f56385
16 changed files with 174 additions and 85 deletions

View file

@ -270,7 +270,6 @@ func (h *Handlers) cookieExtractor(r *http.Request) (string, error) {
if err != nil { if err != nil {
return "", nil return "", nil
} }
if session.Values["token"] == nil { if session.Values["token"] == nil {
return "", nil return "", nil
} }
@ -344,7 +343,10 @@ func (h *Handlers) get(w http.ResponseWriter, r *http.Request, model string, pat
return err return err
} }
format := r.URL.Query().Get("format") format := r.URL.Query().Get("format")
h.Renderer[format].Render(w, r, h.CookieStore, data, r.URL.Query()) err = h.Renderer[format].Render(w, r, h.CookieStore, data, r.URL.Query())
if err != nil {
return err
}
return nil return nil
} }
@ -363,7 +365,10 @@ func (h *Handlers) post(w http.ResponseWriter, r *http.Request, model string, pa
} }
} else { } else {
format := renderer.GetContentFormat(r) format := renderer.GetContentFormat(r)
h.Renderer[format].Render(w, r, h.CookieStore, data.(orm.IDer).GetID()) err := h.Renderer[format].Render(w, r, h.CookieStore, data.(orm.IDer).GetID())
if err != nil {
return err
}
} }
return nil return nil
@ -385,7 +390,10 @@ func (h *Handlers) delete(w http.ResponseWriter, r *http.Request, model string,
json.NewEncoder(w).Encode(data) json.NewEncoder(w).Encode(data)
} else { } else {
format := renderer.GetContentFormat(r) format := renderer.GetContentFormat(r)
h.Renderer[format].Render(w, r, h.CookieStore, data.(orm.IDer).GetID()) err := h.Renderer[format].Render(w, r, h.CookieStore, data.(orm.IDer).GetID())
if err != nil {
return err
}
} }
return nil return nil
@ -399,10 +407,12 @@ func respondWithError(h *Handlers, w http.ResponseWriter, r *http.Request, err e
format = renderer.GetContentFormat(r) format = renderer.GetContentFormat(r)
} }
if h.Config.LogLevel > config.LOG_LEVEL_OFF { if h.Config.LogLevel > config.LOG_LEVEL_OFF {
log.Println(err) log.Println("Error:", err)
} }
// FIXME: this call could be superflous when an error occurs
// in a template execution
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
h.Renderer[format].Render(w, r, h.CookieStore, err) h.Renderer[format].WriteError(w, r, err)
} }
func (h *Handlers) Create(model interface{}) http.Handler { func (h *Handlers) Create(model interface{}) http.Handler {
@ -550,10 +560,6 @@ func (m *rootMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
// This is where our error handling logic starts. // This is where our error handling logic starts.
if m.h.Config.LogLevel > config.LOG_LEVEL_OFF {
log.Printf("An error accured: %v", err) // Log the error.
}
if err, ok := err.(*errors.Error); ok { if err, ok := err.(*errors.Error); ok {
err.Referer = r.Header.Get("Referer") err.Referer = r.Header.Get("Referer")
} }

View file

@ -7,8 +7,8 @@ import (
"strconv" "strconv"
"time" "time"
"git.andreafazzi.eu/andrea/oef/orm"
oef_errors "git.andreafazzi.eu/andrea/oef/errors" oef_errors "git.andreafazzi.eu/andrea/oef/errors"
"git.andreafazzi.eu/andrea/oef/orm"
jwt "github.com/dgrijalva/jwt-go" jwt "github.com/dgrijalva/jwt-go"
"github.com/gorilla/sessions" "github.com/gorilla/sessions"
) )
@ -25,17 +25,28 @@ type UserToken struct {
UserID string UserID string
} }
func clearSession(response http.ResponseWriter) {
cookie := &http.Cookie{
Name: "login-session",
Value: "",
Path: "/",
MaxAge: -1,
}
http.SetCookie(response, cookie)
}
func DefaultLogoutHandler(store *sessions.CookieStore) http.Handler { func DefaultLogoutHandler(store *sessions.CookieStore) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) { fn := func(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "login-session") // session, err := store.Get(r, "login-session")
if err != nil { // if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) // // http.Error(w, err.Error(), http.StatusInternalServerError)
return // store.Set(w)
} // return
// }
session.Values["token"] = []uint8{}
session.Save(r, w)
// session.Values["token"] = []uint8{}
// session.Save(r, w)
clearSession(w)
http.Redirect(w, r, "/", http.StatusSeeOther) http.Redirect(w, r, "/", http.StatusSeeOther)
} }

View file

@ -18,8 +18,7 @@ import (
"strings" "strings"
"time" "time"
"git.andreafazzi.eu/andrea/oef/errors" oef_errors "git.andreafazzi.eu/andrea/oef/errors"
"github.com/gocarina/gocsv" "github.com/gocarina/gocsv"
"github.com/gorilla/schema" "github.com/gorilla/schema"
"github.com/gorilla/sessions" "github.com/gorilla/sessions"
@ -29,6 +28,7 @@ import (
type Renderer interface { type Renderer interface {
Render(http.ResponseWriter, *http.Request, *sessions.CookieStore, interface{}, ...url.Values) error Render(http.ResponseWriter, *http.Request, *sessions.CookieStore, interface{}, ...url.Values) error
WriteError(http.ResponseWriter, *http.Request, interface{})
} }
type JSONRenderer struct{} type JSONRenderer struct{}
@ -69,6 +69,10 @@ func NewJSONRenderer() (*JSONRenderer, error) {
return &JSONRenderer{}, nil return &JSONRenderer{}, nil
} }
func (rend *JSONRenderer) WriteError(w http.ResponseWriter, r *http.Request, data interface{}) {
}
func (rend *JSONRenderer) Render(w http.ResponseWriter, r *http.Request, store *sessions.CookieStore, data interface{}, options ...url.Values) error { func (rend *JSONRenderer) Render(w http.ResponseWriter, r *http.Request, store *sessions.CookieStore, data interface{}, options ...url.Values) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("Content-Type", "application/json; charset=utf-8")
if isErrorType(data) { if isErrorType(data) {
@ -180,9 +184,16 @@ func NewHTMLRenderer(templatePath string) (*HTMLRenderer, error) {
} }
func (rend *HTMLRenderer) writeError(w http.ResponseWriter, r *http.Request, data interface{}) { func (rend *HTMLRenderer) writeError(w http.ResponseWriter, r *http.Request, data interface{}) {
var t *template.Template var (
t *template.Template
claims jwt.MapClaims
)
err, ok := data.(*htmlTemplateData).Data.(*errors.Error) if r.Context().Value("user") != nil {
claims = r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
}
err, ok := data.(*oef_errors.Error)
if ok { if ok {
t, ok = rend.templates[err.TemplateName] t, ok = rend.templates[err.TemplateName]
if !ok { if !ok {
@ -197,12 +208,25 @@ func (rend *HTMLRenderer) writeError(w http.ResponseWriter, r *http.Request, dat
} }
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
e := t.ExecuteTemplate(w, "error_not_authorized", err)
if e != nil { if claims != nil {
panic(e) e := t.ExecuteTemplate(w, "base", &htmlTemplateData{data, nil, claims})
if e != nil {
panic(e)
}
} else {
e := t.ExecuteTemplate(w, "error", &htmlTemplateData{data, nil, nil})
if e != nil {
panic(e)
}
} }
} }
func (rend *HTMLRenderer) WriteError(w http.ResponseWriter, r *http.Request, data interface{}) {
rend.writeError(w, r, data)
}
func (rend *HTMLRenderer) Render(w http.ResponseWriter, r *http.Request, store *sessions.CookieStore, data interface{}, options ...url.Values) error { func (rend *HTMLRenderer) Render(w http.ResponseWriter, r *http.Request, store *sessions.CookieStore, data interface{}, options ...url.Values) error {
var claims jwt.MapClaims var claims jwt.MapClaims
@ -210,26 +234,22 @@ func (rend *HTMLRenderer) Render(w http.ResponseWriter, r *http.Request, store *
claims = r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims) claims = r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
} }
if data != nil { if err, ok := data.(*oef_errors.Error); ok {
err, ok := data.(*errors.Error) // rend.writeError(w, r, &htmlTemplateData{data, nil, claims})
if ok { return err
rend.writeError(w, r, &htmlTemplateData{data, nil, claims}) }
return err
}
t, ok := rend.templates[options[0]["tpl_content"][0]] t, ok := rend.templates[options[0]["tpl_content"][0]]
if !ok { if !ok {
err := fmt.Errorf("Template %s not found", options[0]["tpl_content"][0]) err := fmt.Errorf("Template %s not found", options[0]["tpl_content"][0])
rend.writeError(w, r, &htmlTemplateData{err, nil, claims}) // rend.writeError(w, r, &htmlTemplateData{err, nil, claims})
return err return err
} }
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := t.ExecuteTemplate(w, options[0]["tpl_layout"][0], &htmlTemplateData{data, options[0], claims}); err != nil {
if err := t.ExecuteTemplate(w, options[0]["tpl_layout"][0], &htmlTemplateData{data, options[0], claims}); err != nil { // rend.writeError(w, r, &htmlTemplateData{err, nil, claims})
rend.writeError(w, r, &htmlTemplateData{err, nil, claims}) return err
return err
}
} }
return nil return nil

View file

@ -1,4 +1,4 @@
{{ define "content" }} {{ define "content" }}
{{$options := `title: "Errore durante l'iscrizione della scuola"`}} {{$options := `title: "Errore durante l'iscrizione di un partecipante"`}}
{{template "error" dict "options" ($options|yaml) "data" .Data}} {{template "show_error" dict "options" ($options|yaml) "data" .Data}}
{{end}} {{end}}

View file

@ -1,4 +1,4 @@
{{ define "content" }} {{ define "content" }}
{{$options := `title: "Errore nella creazione/aggiornamento di un partecipante"`}} {{$options := `title: "Errore nella creazione/aggiornamento di un partecipante"`}}
{{template "error" dict "options" ($options|yaml) "data" .Data}} {{template "show_error" dict "options" ($options|yaml) "data" .Data}}
{{end}} {{end}}

View file

@ -1,4 +1,13 @@
{{ define "content" }} {{ define "content" }}
{{$options := `title: "Errore di autorizzazione"`}} <div class="container">
{{template "error" dict "options" ($options|yaml) "data" .Data}} <div class="alert alert-danger" role="alert">
<h4 class="alert-heading">
Errore di autorizzazione
</h4>
{{.Data}}
Clicca {{"/logout"|alertLink "qui"}} per effettuare il logout e ritornare alla pagina di autenticazione.
</div>
<p>
</p>
</div>
{{end}} {{end}}

View file

@ -1,4 +1,4 @@
{{ define "content" }} {{ define "content" }}
{{$options := `title: "Errore nella gestione della prova di gara"`}} {{$options := `title: "Errore nella gestione della prova di gara"`}}
{{template "error" dict "options" ($options|yaml) "data" .Data}} {{template "show_error" dict "options" ($options|yaml) "data" .Data}}
{{end}} {{end}}

View file

@ -1,4 +1,4 @@
{{ define "content" }} {{ define "content" }}
{{$options := `title: "Errore nella creazione/aggiornamento di un partecipante"`}} {{$options := `title: "Errore nella creazione/aggiornamento di un partecipante"`}}
{{template "error" dict "options" ($options|yaml) "data" .Data}} {{template "show_error" dict "options" ($options|yaml) "data" .Data}}
{{end}} {{end}}

View file

@ -1,4 +1,4 @@
{{ define "content" }} {{ define "content" }}
{{$options := `title: "Errore nell'apertura della prova di gara"`}} {{$options := `title: "Errore nell'apertura della prova di gara"`}}
{{template "error" dict "options" ($options|yaml) "data" .Data}} {{template "show_error" dict "options" ($options|yaml) "data" .Data}}
{{end}} {{end}}

View file

@ -1,4 +1,4 @@
{{ define "content" }} {{ define "content" }}
{{$options := `title: "Errore nella creazione/aggiornamento di una scuola"`}} {{$options := `title: "Errore nella creazione/aggiornamento di una scuola"`}}
{{template "error" dict "options" ($options|yaml) "data" .Data}} {{template "show_error" dict "options" ($options|yaml) "data" .Data}}
{{end}} {{end}}

View file

@ -1,4 +1,4 @@
{{ define "content" }} {{ define "content" }}
{{$options := `title: "Errore durante l'iscrizione di una scuola"`}} {{$options := `title: "Errore durante l'iscrizione di una scuola"`}}
{{template "error" dict "options" ($options|yaml) "data" .Data}} {{template "show_error" dict "options" ($options|yaml) "data" .Data}}
{{end}} {{end}}

View file

@ -61,16 +61,6 @@
</ul> </ul>
</div><!--/.nav-collapse --> </div><!--/.nav-collapse -->
</nav> </nav>
{{- if .FlashMessages -}}
{{range $message := .FlashMessages}}
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<strong>Attenzione!</strong> {{$message}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{{end}}
{{- end -}}
<div class="base-template"> <div class="base-template">
{{ template "content" . }} {{ template "content" . }}
</div> </div>

View file

@ -1,15 +1,55 @@
{{define "error"}} {{- define "error" -}}
<div class="container"> <!DOCTYPE html>
<div class="alert alert-danger" role="alert"> <html lang="it">
<h4 class="alert-heading"> <head>
{{.data.Title}} <meta charset="utf-8">
</h4> <meta http-equiv="X-UA-Compatible" content="IE=edge">
{{.data}} <meta name="viewport" content="width=device-width, initial-scale=1">
{{if .data.Referer}} <link
Clicca {{.data.Referer|alertLink "qui"}} per tornare all'azione precedente. rel="stylesheet"
{{end}} href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
</div> integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
<p> crossorigin="anonymous">
</p> <link
</div> rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.css">
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-select@1.13.9/dist/css/bootstrap-select.min.css">
<link rel="stylesheet" href="/styles.css" />
<title>Olimpiadi di Economia e Finanza - Piattaforma di gara</title>
</head>
<body data-spy="scroll">
<nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-primary">
{{- $homeURL := "" -}}
<a class="navbar-brand" href="{{$homeURL}}">
<span class="fa fa-landmark"></span>
OEF 2020
</a>
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="navbar-toggler-icon"></span>
</button>
</nav>
<div class="base-template">
{{ template "content" . }}
</div>
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous">
</script>
<script
src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous">
</script>
<script
src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-select@1.13.9/dist/js/bootstrap-select.min.js"></script>
<script src="/main.bundle.js"></script>
</body>
</html>
{{end}} {{end}}

View file

@ -0,0 +1,15 @@
{{define "show_error"}}
<div class="container">
<div class="alert alert-danger" role="alert">
<h4 class="alert-heading">
{{.options.title}}
</h4>
{{.data}}
{{if .data.Referer}}
Clicca {{.data.Referer|alertLink "qui"}} per tornare all'azione precedente.
{{end}}
</div>
<p>
</p>
</div>
{{end}}

View file

@ -127,6 +127,7 @@
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<h2 class="karmen-relation-header">Suggerimenti</h2> <h2 class="karmen-relation-header">Suggerimenti</h2>
{{if .Data.School}}
{{if le (len .Data.School.Participants) 1}} {{if le (len .Data.School.Participants) 1}}
<p> <p>
E' possibile iscrivere fino a due partecipanti alla gara (di diversa categoria). E' possibile iscrivere fino a due partecipanti alla gara (di diversa categoria).
@ -141,7 +142,7 @@
<strong>Iscrizione completa.</strong> Non è possibile aggiungere ulteriori partecipanti. <strong>Iscrizione completa.</strong> Non è possibile aggiungere ulteriori partecipanti.
</div> </div>
{{end}} {{end}}
{{end}}
<div class="alert alert-danger text-justify"> <div class="alert alert-danger text-justify">
<span class="fa <span class="fa
fa-exclamation-triangle mr-1"> fa-exclamation-triangle mr-1">
@ -155,9 +156,9 @@
</div> </div>
</div> </div>
</div>
</div> </div>
{{end}} </div>
{{end}}
</div> </div>

View file

@ -6,9 +6,6 @@
<div class="container"> <div class="container">
{{if $isSubscriber}} {{if $isSubscriber}}
{{if .FlashMessages}}
<p>Si è verificato un errore. Clicca <a href="/logout">qui</a> per uscire da questa sessione.</p>
{{else}}
<p> <p>
Grazie per aver iscritto la scuola <strong>{{.Data.Name}}</strong> Grazie per aver iscritto la scuola <strong>{{.Data.Name}}</strong>
alle Olimpiadi di Economia e Finanza. alle Olimpiadi di Economia e Finanza.
@ -27,7 +24,7 @@
utilizzare le credenziali ricevute per iscrivere gli studenti alla utilizzare le credenziali ricevute per iscrivere gli studenti alla
competizione. competizione.
</p> </p>
{{end}}
{{else}} {{else}}
{{$deletePath := ""}} {{$deletePath := ""}}