2021-03-30 10:48:42 +00:00
|
|
|
package errors
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"html/template"
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"github.com/go-kit/kit/log/level"
|
|
|
|
"go.mindeco.de/http/auth"
|
|
|
|
"go.mindeco.de/http/render"
|
|
|
|
"go.mindeco.de/logging"
|
|
|
|
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/web/i18n"
|
|
|
|
)
|
|
|
|
|
|
|
|
type ErrorHandler struct {
|
|
|
|
locHelper *i18n.Helper
|
|
|
|
render *render.Renderer
|
2021-04-05 07:12:05 +00:00
|
|
|
flashes *FlashHelper
|
2021-03-30 10:48:42 +00:00
|
|
|
}
|
|
|
|
|
2021-04-05 07:12:05 +00:00
|
|
|
func NewErrorHandler(locHelper *i18n.Helper, flashes *FlashHelper) *ErrorHandler {
|
2021-03-30 10:48:42 +00:00
|
|
|
return &ErrorHandler{
|
|
|
|
locHelper: locHelper,
|
2021-04-05 07:12:05 +00:00
|
|
|
flashes: flashes,
|
2021-03-30 10:48:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetRenderer needs to update the rendere later since we need to pass ErrorHandler into render.New (ie. befor we get the pointer for r)
|
|
|
|
func (eh *ErrorHandler) SetRenderer(r *render.Renderer) {
|
|
|
|
eh.render = r
|
|
|
|
}
|
|
|
|
|
|
|
|
func (eh *ErrorHandler) Handle(rw http.ResponseWriter, req *http.Request, code int, err error) {
|
2021-04-01 07:04:38 +00:00
|
|
|
var redirectErr ErrRedirect
|
|
|
|
if errors.As(err, &redirectErr) {
|
2021-04-05 07:21:48 +00:00
|
|
|
if redirectErr.Reason != nil {
|
|
|
|
eh.flashes.AddError(rw, req, redirectErr.Reason)
|
|
|
|
}
|
2021-04-05 07:12:05 +00:00
|
|
|
http.Redirect(rw, req, redirectErr.Path, http.StatusSeeOther)
|
2021-04-01 07:04:38 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var ih = eh.locHelper.FromRequest(req)
|
|
|
|
|
|
|
|
code, msg := localizeError(ih, err)
|
|
|
|
|
|
|
|
data := errorTemplateData{
|
|
|
|
Err: template.HTML(msg),
|
|
|
|
// TODO: localize status codes? might be fine with a few
|
|
|
|
Status: http.StatusText(code),
|
|
|
|
StatusCode: code,
|
2021-04-05 07:21:48 +00:00
|
|
|
|
|
|
|
BackURL: req.URL.Path,
|
|
|
|
}
|
|
|
|
|
|
|
|
if code == http.StatusNotFound {
|
|
|
|
data.BackURL = "/"
|
|
|
|
referer := req.Header.Get("Referer")
|
|
|
|
if referer != "" {
|
|
|
|
data.BackURL = referer
|
|
|
|
}
|
2021-04-01 07:04:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
renderErr := eh.render.Render(rw, req, "error.tmpl", code, data)
|
|
|
|
if renderErr != nil {
|
|
|
|
logger := logging.FromContext(req.Context())
|
|
|
|
level.Error(logger).Log("event", "error template renderfailed",
|
|
|
|
"orig-err", err,
|
|
|
|
"render-err", renderErr,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type errorTemplateData struct {
|
|
|
|
StatusCode int
|
|
|
|
Status string
|
|
|
|
Err template.HTML
|
2021-04-05 07:21:48 +00:00
|
|
|
|
|
|
|
BackURL string
|
2021-04-01 07:04:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func localizeError(ih *i18n.Localizer, err error) (int, string) {
|
2021-03-30 10:48:42 +00:00
|
|
|
|
|
|
|
// default, unlocalized message
|
|
|
|
msg := err.Error()
|
|
|
|
|
|
|
|
// localize some specific error messages
|
|
|
|
var (
|
|
|
|
aa roomdb.ErrAlreadyAdded
|
|
|
|
pnf PageNotFound
|
|
|
|
br ErrBadRequest
|
|
|
|
f ErrForbidden
|
|
|
|
)
|
|
|
|
|
2021-04-01 07:04:38 +00:00
|
|
|
code := http.StatusInternalServerError
|
|
|
|
|
2021-03-30 10:48:42 +00:00
|
|
|
switch {
|
2021-04-01 07:04:38 +00:00
|
|
|
|
2021-03-30 10:48:42 +00:00
|
|
|
case err == ErrNotAuthorized:
|
|
|
|
code = http.StatusForbidden
|
2021-04-01 07:04:38 +00:00
|
|
|
msg = ih.LocalizeSimple("ErrorNotAuthorized")
|
2021-03-30 10:48:42 +00:00
|
|
|
|
|
|
|
case err == auth.ErrBadLogin:
|
|
|
|
msg = ih.LocalizeSimple("ErrorAuthBadLogin")
|
|
|
|
|
|
|
|
case errors.Is(err, roomdb.ErrNotFound):
|
|
|
|
code = http.StatusNotFound
|
|
|
|
msg = ih.LocalizeSimple("ErrorNotFound")
|
|
|
|
|
|
|
|
case errors.As(err, &aa):
|
|
|
|
msg = ih.LocalizeWithData("ErrorAlreadyAdded", map[string]string{
|
|
|
|
"Feed": aa.Ref.Ref(),
|
|
|
|
})
|
|
|
|
|
|
|
|
case errors.As(err, &pnf):
|
|
|
|
code = http.StatusNotFound
|
|
|
|
msg = ih.LocalizeWithData("ErrorPageNotFound", map[string]string{
|
|
|
|
"Path": pnf.Path,
|
|
|
|
})
|
|
|
|
|
|
|
|
case errors.As(err, &br):
|
|
|
|
code = http.StatusBadRequest
|
|
|
|
// TODO: we could localize all the "Where:" as labels, too
|
|
|
|
// buttt it feels like overkill right now
|
|
|
|
msg = ih.LocalizeWithData("ErrorBadRequest", map[string]string{
|
|
|
|
"Where": br.Where,
|
|
|
|
"Details": br.Details.Error(),
|
|
|
|
})
|
|
|
|
|
|
|
|
case errors.As(err, &f):
|
|
|
|
code = http.StatusForbidden
|
|
|
|
msg = ih.LocalizeWithData("ErrorForbidden", map[string]string{
|
|
|
|
"Details": f.Details.Error(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-04-01 07:04:38 +00:00
|
|
|
return code, msg
|
2021-03-30 10:48:42 +00:00
|
|
|
}
|