@@ -1,5 +1,5 @@
/*
* Copyright © 2018 A Bunch Tell LLC.
* Copyright © 2018-2019 A Bunch Tell LLC.
*
* This file is part of WriteFreely.
*
@@ -36,16 +36,17 @@ const (
)
type (
handlerFunc func(app *App, w http.ResponseWriter, r *http.Request) error
userHandlerFunc func(app *App, u *User, w http.ResponseWriter, r *http.Request) error
dataHandlerFunc func(app *App, w http.ResponseWriter, r *http.Request) ([]byte, string, error)
authFunc func(app *App, r *http.Request) (*User, error)
handlerFunc func(app *App, w http.ResponseWriter, r *http.Request) error
userHandlerFunc func(app *App, u *User, w http.ResponseWriter, r *http.Request) error
userApperHandlerFunc func(apper Apper, u *User, w http.ResponseWriter, r *http.Request) error
dataHandlerFunc func(app *App, w http.ResponseWriter, r *http.Request) ([]byte, string, error)
authFunc func(app *App, r *http.Request) (*User, error)
)
type Handler struct {
errors *ErrorPages
sessionStore *sessions.CookieStore
app * App
app Apper
}
// ErrorPages hold template HTML error pages for displaying errors to the user.
@@ -59,7 +60,7 @@ type ErrorPages struct {
// NewHandler returns a new Handler instance, using the given StaticPage data,
// and saving alias to the application's CookieStore.
func NewHandler(app * App) *Handler {
func NewHandler(apper Apper ) *Handler {
h := &Handler{
errors: &ErrorPages{
NotFound: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>404</title></head><body><p>Not found.</p></body></html>{{end}}")),
@@ -67,8 +68,8 @@ func NewHandler(app *App) *Handler {
InternalServerError: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>500</title></head><body><p>Internal server error.</p></body></html>{{end}}")),
Blank: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>{{.Title}}</title></head><body><p>{{.Content}}</p></body></html>{{end}}")),
},
sessionStore: app.sessionStore,
app: app,
sessionStore: apper.App() .sessionStore,
app: apper ,
}
return h
@@ -76,8 +77,8 @@ func NewHandler(app *App) *Handler {
// NewWFHandler returns a new Handler instance, using WriteFreely template files.
// You MUST call writefreely.InitTemplates() before this.
func NewWFHandler(app * App) *Handler {
h := NewHandler(app)
func NewWFHandler(apper Apper ) *Handler {
h := NewHandler(apper )
h.SetErrorPages(&ErrorPages{
NotFound: pages["404-general.tmpl"],
Gone: pages["410.tmpl"],
@@ -104,21 +105,21 @@ func (h *Handler) User(f userHandlerFunc) http.HandlerFunc {
defer func() {
if e := recover(); e != nil {
log.Error("%s: %s", e, debug.Stack())
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app, r))
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App() , r))
status = http.StatusInternalServerError
}
log.Info("\"%s %s\" %d %s \"%s\"", r.Method, r.RequestURI, status, time.Since(start), r.UserAgent())
}()
u := getUserSession(h.app, r)
u := getUserSession(h.app.App() , r)
if u == nil {
err := ErrNotLoggedIn
status = err.Status
return err
}
err := f(h.app, u, w, r)
err := f(h.app.App() , u, w, r)
if err == nil {
status = http.StatusOK
} else if err, ok := err.(impart.HTTPError); ok {
@@ -142,14 +143,52 @@ func (h *Handler) Admin(f userHandlerFunc) http.HandlerFunc {
defer func() {
if e := recover(); e != nil {
log.Error("%s: %s", e, debug.Stack())
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app, r))
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
status = http.StatusInternalServerError
}
log.Info(fmt.Sprintf("\"%s %s\" %d %s \"%s\"", r.Method, r.RequestURI, status, time.Since(start), r.UserAgent()))
}()
u := getUserSession(h.app.App(), r)
if u == nil || !u.IsAdmin() {
err := impart.HTTPError{http.StatusNotFound, ""}
status = err.Status
return err
}
err := f(h.app.App(), u, w, r)
if err == nil {
status = http.StatusOK
} else if err, ok := err.(impart.HTTPError); ok {
status = err.Status
} else {
status = http.StatusInternalServerError
}
return err
}())
}
}
// AdminApper handles requests on /admin routes that require an Apper.
func (h *Handler) AdminApper(f userApperHandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
h.handleHTTPError(w, r, func() error {
var status int
start := time.Now()
defer func() {
if e := recover(); e != nil {
log.Error("%s: %s", e, debug.Stack())
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
status = http.StatusInternalServerError
}
log.Info(fmt.Sprintf("\"%s %s\" %d %s \"%s\"", r.Method, r.RequestURI, status, time.Since(start), r.UserAgent()))
}()
u := getUserSession(h.app, r)
u := getUserSession(h.app.App() , r)
if u == nil || !u.IsAdmin() {
err := impart.HTTPError{http.StatusNotFound, ""}
status = err.Status
@@ -204,7 +243,7 @@ func (h *Handler) UserAll(web bool, f userHandlerFunc, a authFunc) http.HandlerF
log.Info("\"%s %s\" %d %s \"%s\"", r.Method, r.RequestURI, status, time.Since(start), r.UserAgent())
}()
u, err := a(h.app, r)
u, err := a(h.app.App() , r)
if err != nil {
if err, ok := err.(impart.HTTPError); ok {
status = err.Status
@@ -214,7 +253,7 @@ func (h *Handler) UserAll(web bool, f userHandlerFunc, a authFunc) http.HandlerF
return err
}
err = f(h.app, u, w, r)
err = f(h.app.App() , u, w, r)
if err == nil {
status = 200
} else if err, ok := err.(impart.HTTPError); ok {
@@ -277,13 +316,13 @@ func (h *Handler) WebErrors(f handlerFunc, ul UserLevel) http.HandlerFunc {
defer func() {
if e := recover(); e != nil {
u := getUserSession(h.app, r)
u := getUserSession(h.app.App() , r)
username := "None"
if u != nil {
username = u.Username
}
log.Error("User: %s\n\n%s: %s", username, e, debug.Stack())
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app, r))
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App() , r))
status = 500
}
@@ -315,13 +354,13 @@ func (h *Handler) WebErrors(f handlerFunc, ul UserLevel) http.HandlerFunc {
}
// TODO: pass User object to function
err = f(h.app, w, r)
err = f(h.app.App() , w, r)
if err == nil {
status = 200
} else if httpErr, ok := err.(impart.HTTPError); ok {
status = httpErr.Status
if status < 300 || status > 399 {
addSessionFlash(h.app, w, r, httpErr.Message, session)
addSessionFlash(h.app.App() , w, r, httpErr.Message, session)
return impart.HTTPError{http.StatusFound, r.Referer()}
}
} else {
@@ -332,7 +371,7 @@ func (h *Handler) WebErrors(f handlerFunc, ul UserLevel) http.HandlerFunc {
log.Error(e)
}
log.Info("Web handler internal error render")
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app, r))
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App() , r))
status = 500
}
@@ -351,14 +390,14 @@ func (h *Handler) Web(f handlerFunc, ul UserLevel) http.HandlerFunc {
defer func() {
if e := recover(); e != nil {
u := getUserSession(h.app, r)
u := getUserSession(h.app.App() , r)
username := "None"
if u != nil {
username = u.Username
}
log.Error("User: %s\n\n%s: %s", username, e, debug.Stack())
log.Info("Web deferred internal error render")
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app, r))
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App() , r))
status = 500
}
@@ -388,7 +427,7 @@ func (h *Handler) Web(f handlerFunc, ul UserLevel) http.HandlerFunc {
}
// TODO: pass User object to function
err := f(h.app, w, r)
err := f(h.app.App() , w, r)
if err == nil {
status = 200
} else if httpErr, ok := err.(impart.HTTPError); ok {
@@ -397,7 +436,7 @@ func (h *Handler) Web(f handlerFunc, ul UserLevel) http.HandlerFunc {
e := fmt.Sprintf("[Web handler] 500: %v", err)
log.Error(e)
log.Info("Web internal error render")
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app, r))
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App() , r))
status = 500
}
@@ -425,7 +464,7 @@ func (h *Handler) All(f handlerFunc) http.HandlerFunc {
// TODO: do any needed authentication
err := f(h.app, w, r)
err := f(h.app.App() , w, r)
if err != nil {
if err, ok := err.(impart.HTTPError); ok {
status = err.Status
@@ -447,14 +486,14 @@ func (h *Handler) Download(f dataHandlerFunc, ul UserLevel) http.HandlerFunc {
defer func() {
if e := recover(); e != nil {
log.Error("%s: %s", e, debug.Stack())
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app, r))
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App() , r))
status = 500
}
log.Info("\"%s %s\" %d %s \"%s\"", r.Method, r.RequestURI, status, time.Since(start), r.UserAgent())
}()
data, filename, err := f(h.app, w, r)
data, filename, err := f(h.app.App() , w, r)
if err != nil {
if err, ok := err.(impart.HTTPError); ok {
status = err.Status
@@ -543,7 +582,7 @@ func (h *Handler) handleHTTPError(w http.ResponseWriter, r *http.Request, err er
page.StaticPage
Content *template.HTML
}{
StaticPage: pageForReq(h.app, r),
StaticPage: pageForReq(h.app.App() , r),
}
if err.Message != "" {
co := template.HTML(err.Message)
@@ -553,12 +592,12 @@ func (h *Handler) handleHTTPError(w http.ResponseWriter, r *http.Request, err er
return
} else if err.Status == http.StatusNotFound {
w.WriteHeader(err.Status)
h.errors.NotFound.ExecuteTemplate(w, "base", pageForReq(h.app, r))
h.errors.NotFound.ExecuteTemplate(w, "base", pageForReq(h.app.App() , r))
return
} else if err.Status == http.StatusInternalServerError {
w.WriteHeader(err.Status)
log.Info("handleHTTPErorr internal error render")
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app, r))
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App() , r))
return
} else if err.Status == http.StatusAccepted {
impart.WriteSuccess(w, "", err.Status)
@@ -569,7 +608,7 @@ func (h *Handler) handleHTTPError(w http.ResponseWriter, r *http.Request, err er
Title string
Content template.HTML
}{
pageForReq(h.app, r),
pageForReq(h.app.App() , r),
fmt.Sprintf("Uh oh (%d)", err.Status),
template.HTML(fmt.Sprintf("<p style=\"text-align: center\" class=\"introduction\">%s</p>", err.Message)),
}
@@ -604,7 +643,7 @@ func (h *Handler) handleError(w http.ResponseWriter, r *http.Request, err error)
impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "This is an unhelpful error message for a miscellaneous internal error."})
return
}
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app, r))
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App() , r))
}
func correctPageFromLoginAttempt(r *http.Request) string {
@@ -626,7 +665,7 @@ func (h *Handler) LogHandlerFunc(f http.HandlerFunc) http.HandlerFunc {
defer func() {
if e := recover(); e != nil {
log.Error("Handler.LogHandlerFunc\n\n%s: %s", e, debug.Stack())
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app, r))
h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App() , r))
status = 500
}