@ -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
}