From 16a159acec94fd391e840fab061ed08cf894369f Mon Sep 17 00:00:00 2001 From: Steve Date: Thu, 26 Jan 2017 10:48:40 -0800 Subject: [PATCH] [core] Embedded and implement http.Pusher into http.ResponseWriter+gzip Writer (#47) * added http Pusher interface to gzip response writer * implement Pusher on gzipResponseWriter and pass encoding header to pusher options * providing a generic error view fuction for code that calls a interface method which will have access to the response * fix []byte -> string type for fmt string * adding the res, req pattern for method arguments in interfaces and their method calls * fix for spacing in generic error message * remove default error views displayed in lifecycle hooks - will rely on custom views or redirects inside hook now that user has ResponseWriter. Otherwise, multiple WriteHeader calls would be warned * removing WriteHeader calls before return in external handlers * bump version 0.8.1 --- cmd/ponzu/ponzu.json | 2 +- management/editor/editor.go | 2 +- system/admin/admin.go | 20 ++++++ system/admin/handlers.go | 122 ++++++------------------------------ system/api/external.go | 27 ++++---- system/api/handlers.go | 2 +- system/item/item.go | 34 +++++----- 7 files changed, 70 insertions(+), 139 deletions(-) diff --git a/cmd/ponzu/ponzu.json b/cmd/ponzu/ponzu.json index a997bfb0..af543156 100644 --- a/cmd/ponzu/ponzu.json +++ b/cmd/ponzu/ponzu.json @@ -1,3 +1,3 @@ { - "version": "0.8.0" + "version": "0.8.1" } \ No newline at end of file diff --git a/management/editor/editor.go b/management/editor/editor.go index 7bc5f351..39bb25f2 100644 --- a/management/editor/editor.go +++ b/management/editor/editor.go @@ -18,7 +18,7 @@ type Editable interface { type Mergeable interface { // Approve copies an external post to the internal collection and triggers // a re-sort of its content type posts - Approve(req *http.Request) error + Approve(http.ResponseWriter, *http.Request) error } // Editor is a view containing fields to manage content diff --git a/system/admin/admin.go b/system/admin/admin.go index 3df68059..7761e712 100644 --- a/system/admin/admin.go +++ b/system/admin/admin.go @@ -5,6 +5,7 @@ package admin import ( "bytes" "encoding/json" + "fmt" "html/template" "net/http" @@ -607,3 +608,22 @@ var err500HTML = []byte(` func Error500() ([]byte, error) { return Admin(err500HTML) } + +var errMessageHTML = ` +
+
+
+
Error: %s
+
%s
+
+
+
+` + +// ErrorMessage is a generic error message container, similar to Error500() and +// others in this package, ecxept it expects the caller to provide a title and +// message to describe to a view why the error is being shown +func ErrorMessage(title, message string) ([]byte, error) { + eHTML := fmt.Sprintf(errMessageHTML, title, message) + return Admin([]byte(eHTML)) +} diff --git a/system/admin/handlers.go b/system/admin/handlers.go index a99a62cf..c5b30582 100644 --- a/system/admin/handlers.go +++ b/system/admin/handlers.go @@ -1357,56 +1357,28 @@ func approveContentHandler(res http.ResponseWriter, req *http.Request) { return } - err = hook.BeforeApprove(req) + err = hook.BeforeApprove(res, req) if err != nil { log.Println("Error running BeforeApprove hook in approveContentHandler for:", t, err) - res.WriteHeader(http.StatusInternalServerError) - errView, err := Error500() - if err != nil { - return - } - - res.Write(errView) return } // call its Approve method - err = m.Approve(req) + err = m.Approve(res, req) if err != nil { log.Println("Error running Approve method in approveContentHandler for:", t, err) - res.WriteHeader(http.StatusInternalServerError) - errView, err := Error500() - if err != nil { - return - } - - res.Write(errView) return } - err = hook.AfterApprove(req) + err = hook.AfterApprove(res, req) if err != nil { log.Println("Error running AfterApprove hook in approveContentHandler for:", t, err) - res.WriteHeader(http.StatusInternalServerError) - errView, err := Error500() - if err != nil { - return - } - - res.Write(errView) return } - err = hook.BeforeSave(req) + err = hook.BeforeSave(res, req) if err != nil { log.Println("Error running BeforeSave hook in approveContentHandler for:", t, err) - res.WriteHeader(http.StatusInternalServerError) - errView, err := Error500() - if err != nil { - return - } - - res.Write(errView) return } @@ -1428,16 +1400,9 @@ func approveContentHandler(res http.ResponseWriter, req *http.Request) { ctx := context.WithValue(req.Context(), "target", fmt.Sprintf("%s:%d", t, id)) req = req.WithContext(ctx) - err = hook.AfterSave(req) + err = hook.AfterSave(res, req) if err != nil { log.Println("Error running AfterSave hook in approveContentHandler for:", t, err) - res.WriteHeader(http.StatusInternalServerError) - errView, err := Error500() - if err != nil { - return - } - - res.Write(errView) return } @@ -1669,16 +1634,9 @@ func editHandler(res http.ResponseWriter, req *http.Request) { return } - err = hook.BeforeSave(req) + err = hook.BeforeSave(res, req) if err != nil { - log.Println(err) - res.WriteHeader(http.StatusInternalServerError) - errView, err := Error500() - if err != nil { - return - } - - res.Write(errView) + log.Println("Error running BeforeSave method in editHandler for:", t, err) return } @@ -1699,16 +1657,9 @@ func editHandler(res http.ResponseWriter, req *http.Request) { ctx := context.WithValue(req.Context(), "target", fmt.Sprintf("%s:%d", t, id)) req = req.WithContext(ctx) - err = hook.AfterSave(req) + err = hook.AfterSave(res, req) if err != nil { - log.Println(err) - res.WriteHeader(http.StatusInternalServerError) - errView, err := Error500() - if err != nil { - return - } - - res.Write(errView) + log.Println("Error running AfterSave method in editHandler for:", t, err) return } @@ -1792,30 +1743,16 @@ func deleteHandler(res http.ResponseWriter, req *http.Request) { reject := req.URL.Query().Get("reject") if reject == "true" { - err = hook.BeforeReject(req) + err = hook.BeforeReject(res, req) if err != nil { - log.Println(err) - res.WriteHeader(http.StatusInternalServerError) - errView, err := Error500() - if err != nil { - return - } - - res.Write(errView) + log.Println("Error running BeforeReject method in deleteHandler for:", t, err) return } } - err = hook.BeforeDelete(req) + err = hook.BeforeDelete(res, req) if err != nil { - log.Println(err) - res.WriteHeader(http.StatusInternalServerError) - errView, err := Error500() - if err != nil { - return - } - - res.Write(errView) + log.Println("Error running BeforeDelete method in deleteHandler for:", t, err) return } @@ -1826,30 +1763,16 @@ func deleteHandler(res http.ResponseWriter, req *http.Request) { return } - err = hook.AfterDelete(req) + err = hook.AfterDelete(res, req) if err != nil { - log.Println(err) - res.WriteHeader(http.StatusInternalServerError) - errView, err := Error500() - if err != nil { - return - } - - res.Write(errView) + log.Println("Error running AfterDelete method in deleteHandler for:", t, err) return } if reject == "true" { - err = hook.AfterReject(req) + err = hook.AfterReject(res, req) if err != nil { - log.Println(err) - res.WriteHeader(http.StatusInternalServerError) - errView, err := Error500() - if err != nil { - return - } - - res.Write(errView) + log.Println("Error running AfterReject method in deleteHandler for:", t, err) return } } @@ -2272,16 +2195,9 @@ func addonHandler(res http.ResponseWriter, req *http.Request) { // if Hookable, call BeforeSave prior to saving h, ok := at().(item.Hookable) if ok { - err := h.BeforeSave(req) + err := h.BeforeSave(res, req) if err != nil { - log.Println(err) - res.WriteHeader(http.StatusInternalServerError) - errView, err := Error500() - if err != nil { - return - } - - res.Write(errView) + log.Println("Error running BeforeSave method in addonHandler for:", id, err) return } } diff --git a/system/api/external.go b/system/api/external.go index 5a741077..168575ac 100644 --- a/system/api/external.go +++ b/system/api/external.go @@ -17,13 +17,13 @@ import ( // /external/content?type=Review type Externalable interface { // Accept allows external content submissions of a specific type - Accept(req *http.Request) error + Accept(http.ResponseWriter, *http.Request) error } // Trustable allows external content to be auto-approved, meaning content sent // as an Externalable will be stored in the public content bucket type Trustable interface { - AutoApprove(req *http.Request) error + AutoApprove(http.ResponseWriter, *http.Request) error } func externalContentHandler(res http.ResponseWriter, req *http.Request) { @@ -125,10 +125,9 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { // call Accept with the request, enabling developer to add or chack data // before saving to DB - err = ext.Accept(req) + err = ext.Accept(res, req) if err != nil { - log.Println(err) - res.WriteHeader(http.StatusInternalServerError) + log.Println("[External} error calling Accept:", err) return } @@ -139,10 +138,9 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { return } - err = hook.BeforeSave(req) + err = hook.BeforeSave(res, req) if err != nil { - log.Println("[External] error:", err) - res.WriteHeader(http.StatusInternalServerError) + log.Println("[External] error calling BeforeSave:", err) return } @@ -152,10 +150,9 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { // check if the content is Trustable should be auto-approved trusted, ok := post.(Trustable) if ok { - err := trusted.AutoApprove(req) + err := trusted.AutoApprove(res, req) if err != nil { - log.Println("[External] error:", err) - res.WriteHeader(http.StatusInternalServerError) + log.Println("[External] error calling AutoApprove:", err) return } } else { @@ -164,8 +161,7 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { id, err := db.SetContent(t+spec+":-1", req.PostForm) if err != nil { - log.Println("[External] error:", err) - res.WriteHeader(http.StatusInternalServerError) + log.Println("[External] error calling SetContent:", err) return } @@ -173,10 +169,9 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { ctx := context.WithValue(req.Context(), "target", fmt.Sprintf("%s:%d", t, id)) req = req.WithContext(ctx) - err = hook.AfterSave(req) + err = hook.AfterSave(res, req) if err != nil { - log.Println("[External] error:", err) - res.WriteHeader(http.StatusInternalServerError) + log.Println("[External] error calling AfterSave:", err) return } diff --git a/system/api/handlers.go b/system/api/handlers.go index 2e70fdc0..91b10f95 100644 --- a/system/api/handlers.go +++ b/system/api/handlers.go @@ -180,7 +180,7 @@ func contentHandlerBySlug(res http.ResponseWriter, req *http.Request) { func hide(it interface{}, res http.ResponseWriter, req *http.Request) bool { // check if should be hidden if h, ok := it.(item.Hideable); ok { - err := h.Hide(req) + err := h.Hide(res, req) if err == item.ErrAllowHiddenItem { return false } diff --git a/system/item/item.go b/system/item/item.go index e631b360..e356c7c2 100644 --- a/system/item/item.go +++ b/system/item/item.go @@ -42,22 +42,22 @@ type Sortable interface { // to the different lifecycles/events a struct may encounter. Item implements // Hookable with no-ops so our user can override only whichever ones necessary. type Hookable interface { - BeforeSave(req *http.Request) error - AfterSave(req *http.Request) error + BeforeSave(http.ResponseWriter, *http.Request) error + AfterSave(http.ResponseWriter, *http.Request) error - BeforeDelete(req *http.Request) error - AfterDelete(req *http.Request) error + BeforeDelete(http.ResponseWriter, *http.Request) error + AfterDelete(http.ResponseWriter, *http.Request) error - BeforeApprove(req *http.Request) error - AfterApprove(req *http.Request) error + BeforeApprove(http.ResponseWriter, *http.Request) error + AfterApprove(http.ResponseWriter, *http.Request) error - BeforeReject(req *http.Request) error - AfterReject(req *http.Request) error + BeforeReject(http.ResponseWriter, *http.Request) error + AfterReject(http.ResponseWriter, *http.Request) error } // Hideable lets a user keep items hidden type Hideable interface { - Hide(*http.Request) error + Hide(http.ResponseWriter, *http.Request) error } // Pushable lets a user define which values of certain struct fields are @@ -122,42 +122,42 @@ func (i Item) String() string { } // BeforeSave is a no-op to ensure structs which embed Item implement Hookable -func (i Item) BeforeSave(req *http.Request) error { +func (i Item) BeforeSave(res http.ResponseWriter, req *http.Request) error { return nil } // AfterSave is a no-op to ensure structs which embed Item implement Hookable -func (i Item) AfterSave(req *http.Request) error { +func (i Item) AfterSave(res http.ResponseWriter, req *http.Request) error { return nil } // BeforeDelete is a no-op to ensure structs which embed Item implement Hookable -func (i Item) BeforeDelete(req *http.Request) error { +func (i Item) BeforeDelete(res http.ResponseWriter, req *http.Request) error { return nil } // AfterDelete is a no-op to ensure structs which embed Item implement Hookable -func (i Item) AfterDelete(req *http.Request) error { +func (i Item) AfterDelete(res http.ResponseWriter, req *http.Request) error { return nil } // BeforeApprove is a no-op to ensure structs which embed Item implement Hookable -func (i Item) BeforeApprove(req *http.Request) error { +func (i Item) BeforeApprove(res http.ResponseWriter, req *http.Request) error { return nil } // AfterApprove is a no-op to ensure structs which embed Item implement Hookable -func (i Item) AfterApprove(req *http.Request) error { +func (i Item) AfterApprove(res http.ResponseWriter, req *http.Request) error { return nil } // BeforeReject is a no-op to ensure structs which embed Item implement Hookable -func (i Item) BeforeReject(req *http.Request) error { +func (i Item) BeforeReject(res http.ResponseWriter, req *http.Request) error { return nil } // AfterReject is a no-op to ensure structs which embed Item implement Hookable -func (i Item) AfterReject(req *http.Request) error { +func (i Item) AfterReject(res http.ResponseWriter, req *http.Request) error { return nil }