From f0045ae2cff14e05b500e8fdb64383b56d1baa56 Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Sat, 10 Feb 2018 11:20:27 -0800 Subject: [PATCH] Move Flash and Redirect responses to subpackage --- core/admin.go | 13 ++++++----- core/auth.go | 29 ++++++++++++------------ core/blog.go | 15 +++++++------ core/comments.go | 21 +++++++++--------- core/contact.go | 7 +++--- core/{responses.go => errors.go} | 27 ----------------------- core/initial-setup.go | 5 +++-- core/internal/responses/responses.go | 33 ++++++++++++++++++++++++++++ core/pages.go | 3 ++- 9 files changed, 83 insertions(+), 70 deletions(-) rename core/{responses.go => errors.go} (63%) create mode 100644 core/internal/responses/responses.go diff --git a/core/admin.go b/core/admin.go index 91173ea..8f2a748 100644 --- a/core/admin.go +++ b/core/admin.go @@ -14,6 +14,7 @@ import ( "github.com/kirsle/blog/core/internal/middleware/auth" "github.com/kirsle/blog/core/internal/models/settings" "github.com/kirsle/blog/core/internal/render" + "github.com/kirsle/blog/core/internal/responses" "github.com/urfave/negroni" ) @@ -60,18 +61,18 @@ func (b *Blog) EditorHandler(w http.ResponseWriter, r *http.Request) { body = []byte(r.FormValue("body")) err := ioutil.WriteFile(fp, body, 0644) if err != nil { - b.Flash(w, r, "Error saving: %s", err) + responses.Flash(w, r, "Error saving: %s", err) } else { - b.FlashAndRedirect(w, r, "/admin/editor?file="+url.QueryEscape(file), "Page saved successfully!") + responses.FlashAndRedirect(w, r, "/admin/editor?file="+url.QueryEscape(file), "Page saved successfully!") return } } else if deleting { fp = filepath.Join(b.UserRoot, file) err := os.Remove(fp) if err != nil { - b.FlashAndRedirect(w, r, "/admin/editor", "Error deleting: %s", err) + responses.FlashAndRedirect(w, r, "/admin/editor", "Error deleting: %s", err) } else { - b.FlashAndRedirect(w, r, "/admin/editor", "Page deleted!") + responses.FlashAndRedirect(w, r, "/admin/editor", "Page deleted!") return } } else { @@ -94,7 +95,7 @@ func (b *Blog) EditorHandler(w http.ResponseWriter, r *http.Request) { if !os.IsNotExist(err) && !f.IsDir() { body, err = ioutil.ReadFile(fp) if err != nil { - b.Flash(w, r, "Error reading %s: %s", fp, err) + responses.Flash(w, r, "Error reading %s: %s", fp, err) } } @@ -225,7 +226,7 @@ func (b *Blog) SettingsHandler(w http.ResponseWriter, r *http.Request) { settings.Save() b.Configure() - b.FlashAndReload(w, r, "Settings have been saved!") + responses.FlashAndReload(w, r, "Settings have been saved!") return } } diff --git a/core/auth.go b/core/auth.go index 97428fa..fd8cf92 100644 --- a/core/auth.go +++ b/core/auth.go @@ -9,6 +9,7 @@ import ( "github.com/kirsle/blog/core/internal/log" "github.com/kirsle/blog/core/internal/middleware/auth" "github.com/kirsle/blog/core/internal/models/users" + "github.com/kirsle/blog/core/internal/responses" "github.com/kirsle/blog/core/internal/sessions" ) @@ -23,7 +24,7 @@ func (b *Blog) AuthRoutes(r *mux.Router) { // the user to the login page. func (b *Blog) MustLogin(w http.ResponseWriter, r *http.Request) { log.Info("MustLogin for %s", r.URL.Path) - b.Redirect(w, "/login?next="+r.URL.Path) + responses.Redirect(w, "/login?next="+r.URL.Path) } // Login logs the browser in as the given user. @@ -67,15 +68,15 @@ func (b *Blog) LoginHandler(w http.ResponseWriter, r *http.Request) { vars.Error = errors.New("bad username or password") } else { // Login OK! - b.Flash(w, r, "Login OK!") + responses.Flash(w, r, "Login OK!") b.Login(w, r, user) // A next URL given? TODO: actually get to work log.Info("Redirect after login to: %s", nextURL) if len(nextURL) > 0 && nextURL[0] == '/' { - b.Redirect(w, nextURL) + responses.Redirect(w, nextURL) } else { - b.Redirect(w, "/") + responses.Redirect(w, "/") } return } @@ -91,25 +92,25 @@ func (b *Blog) LogoutHandler(w http.ResponseWriter, r *http.Request) { delete(session.Values, "logged-in") delete(session.Values, "user-id") session.Save(r, w) - b.Redirect(w, "/") + responses.Redirect(w, "/") } // AccountHandler shows the account settings page. func (b *Blog) AccountHandler(w http.ResponseWriter, r *http.Request) { if !auth.LoggedIn(r) { - b.FlashAndRedirect(w, r, "/login?next=/account", "You must be logged in to do that!") + responses.FlashAndRedirect(w, r, "/login?next=/account", "You must be logged in to do that!") return } currentUser, err := auth.CurrentUser(r) if err != nil { - b.FlashAndRedirect(w, r, "/login?next=/account", "You must be logged in to do that!!") + responses.FlashAndRedirect(w, r, "/login?next=/account", "You must be logged in to do that!!") return } // Load an editable copy of the user. user, err := users.Load(currentUser.ID) if err != nil { - b.FlashAndRedirect(w, r, "/login?next=/account", "User ID %d not loadable?", currentUser.ID) + responses.FlashAndRedirect(w, r, "/login?next=/account", "User ID %d not loadable?", currentUser.ID) return } @@ -129,14 +130,14 @@ func (b *Blog) AccountHandler(w http.ResponseWriter, r *http.Request) { form.NewPassword = r.FormValue("newpassword") form.NewPassword2 = r.FormValue("newpassword2") if err = form.Validate(); err != nil { - b.Flash(w, r, err.Error()) + responses.Flash(w, r, err.Error()) } else { var ok = true // Validate the username is available. if form.Username != user.Username { if _, err = users.LoadUsername(form.Username); err == nil { - b.Flash(w, r, "That username already exists.") + responses.Flash(w, r, "That username already exists.") ok = false } } @@ -145,12 +146,12 @@ func (b *Blog) AccountHandler(w http.ResponseWriter, r *http.Request) { if len(form.OldPassword) > 0 { // Validate their old password. if _, err = users.CheckAuth(form.Username, form.OldPassword); err != nil { - b.Flash(w, r, "Your old password is incorrect.") + responses.Flash(w, r, "Your old password is incorrect.") ok = false } else { err = user.SetPassword(form.NewPassword) if err != nil { - b.Flash(w, r, "Change password error: %s", err) + responses.Flash(w, r, "Change password error: %s", err) ok = false } } @@ -163,9 +164,9 @@ func (b *Blog) AccountHandler(w http.ResponseWriter, r *http.Request) { user.Email = form.Email err = user.Save() if err != nil { - b.Flash(w, r, "Error saving user: %s", err) + responses.Flash(w, r, "Error saving user: %s", err) } else { - b.FlashAndRedirect(w, r, "/account", "Settings saved!") + responses.FlashAndRedirect(w, r, "/account", "Settings saved!") return } } diff --git a/core/blog.go b/core/blog.go index b5ceb85..4708d99 100644 --- a/core/blog.go +++ b/core/blog.go @@ -21,6 +21,7 @@ import ( "github.com/kirsle/blog/core/internal/models/settings" "github.com/kirsle/blog/core/internal/models/users" "github.com/kirsle/blog/core/internal/render" + "github.com/kirsle/blog/core/internal/responses" "github.com/urfave/negroni" ) @@ -57,7 +58,7 @@ func (b *Blog) BlogRoutes(r *mux.Router) { b.NotFound(w, r, "Not Found") return } - b.Redirect(w, "/tagged/"+tag) + responses.Redirect(w, "/tagged/"+tag) }) r.HandleFunc("/blog/entry/{fragment}", func(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) @@ -66,7 +67,7 @@ func (b *Blog) BlogRoutes(r *mux.Router) { b.NotFound(w, r, "Not Found") return } - b.Redirect(w, "/"+fragment) + responses.Redirect(w, "/"+fragment) }) // Login-required routers. @@ -517,8 +518,8 @@ func (b *Blog) EditBlog(w http.ResponseWriter, r *http.Request) { if err != nil { v.Error = err } else { - b.Flash(w, r, "Post created!") - b.Redirect(w, "/"+post.Fragment) + responses.Flash(w, r, "Post created!") + responses.Redirect(w, "/"+post.Fragment) } } } @@ -542,7 +543,7 @@ func (b *Blog) DeletePost(w http.ResponseWriter, r *http.Request) { idStr = r.URL.Query().Get("id") } if idStr == "" { - b.FlashAndRedirect(w, r, "/admin", "No post ID given for deletion!") + responses.FlashAndRedirect(w, r, "/admin", "No post ID given for deletion!") return } @@ -551,14 +552,14 @@ func (b *Blog) DeletePost(w http.ResponseWriter, r *http.Request) { if err == nil { post, err = posts.Load(id) if err != nil { - b.FlashAndRedirect(w, r, "/admin", "That post ID was not found.") + responses.FlashAndRedirect(w, r, "/admin", "That post ID was not found.") return } } if r.Method == http.MethodPost { post.Delete() - b.FlashAndRedirect(w, r, "/admin", "Blog entry deleted!") + responses.FlashAndRedirect(w, r, "/admin", "Blog entry deleted!") return } diff --git a/core/comments.go b/core/comments.go index 9e613d4..8af2624 100644 --- a/core/comments.go +++ b/core/comments.go @@ -17,6 +17,7 @@ import ( "github.com/kirsle/blog/core/internal/models/comments" "github.com/kirsle/blog/core/internal/models/users" "github.com/kirsle/blog/core/internal/render" + "github.com/kirsle/blog/core/internal/responses" "github.com/kirsle/blog/core/internal/sessions" ) @@ -152,7 +153,7 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) { c := &comments.Comment{} c.ParseForm(r) if c.ThreadID == "" { - b.FlashAndRedirect(w, r, "/", "No thread ID found in the comment form.") + responses.FlashAndRedirect(w, r, "/", "No thread ID found in the comment form.") return } @@ -173,13 +174,13 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) { id := r.FormValue("id") c, err = t.Find(id) if err != nil { - b.FlashAndRedirect(w, r, "/", "That comment was not found.") + responses.FlashAndRedirect(w, r, "/", "That comment was not found.") return } // Verify they have the matching edit token. Admin users are allowed. if c.EditToken != editToken && !currentUser.Admin { - b.FlashAndRedirect(w, r, origin, "You don't have permission to edit that comment.") + responses.FlashAndRedirect(w, r, origin, "You don't have permission to edit that comment.") return } @@ -190,7 +191,7 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) { // Are we deleting said post? if submit == "confirm-delete" { t.Delete(c.ID) - b.FlashAndRedirect(w, r, origin, "Comment deleted!") + responses.FlashAndRedirect(w, r, origin, "Comment deleted!") return } @@ -227,7 +228,7 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) { // Append their comment. err := t.Post(c) if err != nil { - b.FlashAndRedirect(w, r, c.OriginURL, "Error posting comment: %s", err) + responses.FlashAndRedirect(w, r, c.OriginURL, "Error posting comment: %s", err) return } b.NotifyComment(c) @@ -237,14 +238,14 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) { if _, err := mail.ParseAddress(c.Email); err == nil { m := comments.LoadMailingList() m.Subscribe(t.ID, c.Email) - b.FlashAndRedirect(w, r, c.OriginURL, + responses.FlashAndRedirect(w, r, c.OriginURL, "Comment posted, and you've been subscribed to "+ "future comments on this page.", ) return } } - b.FlashAndRedirect(w, r, c.OriginURL, "Comment posted!") + responses.FlashAndRedirect(w, r, c.OriginURL, "Comment posted!") log.Info("t: %v", t.Comments) return } @@ -273,7 +274,7 @@ func (b *Blog) SubscriptionHandler(w http.ResponseWriter, r *http.Request) { m := comments.LoadMailingList() m.UnsubscribeAll(email) - b.FlashAndRedirect(w, r, "/comments/subscription", + responses.FlashAndRedirect(w, r, "/comments/subscription", "You have been unsubscribed from all mailing lists.", ) return @@ -285,7 +286,7 @@ func (b *Blog) SubscriptionHandler(w http.ResponseWriter, r *http.Request) { if thread != "" && email != "" { m := comments.LoadMailingList() m.Unsubscribe(thread, email) - b.FlashAndRedirect(w, r, "/comments/subscription", "You have been unsubscribed successfully.") + responses.FlashAndRedirect(w, r, "/comments/subscription", "You have been unsubscribed successfully.") return } @@ -311,7 +312,7 @@ func (b *Blog) QuickDeleteHandler(w http.ResponseWriter, r *http.Request) { t.Delete(c.ID) } - b.FlashAndRedirect(w, r, "/", "Comment deleted!") + responses.FlashAndRedirect(w, r, "/", "Comment deleted!") } // GetEditToken gets or generates an edit token from the user's session, which diff --git a/core/contact.go b/core/contact.go index f4cb61e..11a8dcc 100644 --- a/core/contact.go +++ b/core/contact.go @@ -12,6 +12,7 @@ import ( "github.com/kirsle/blog/core/internal/forms" "github.com/kirsle/blog/core/internal/markdown" "github.com/kirsle/blog/core/internal/models/settings" + "github.com/kirsle/blog/core/internal/responses" ) // ContactRoutes attaches the contact URL to the app. @@ -38,7 +39,7 @@ func (b *Blog) ContactRoutes(r *mux.Router) { if r.Method == http.MethodPost { form.ParseForm(r) if err = form.Validate(); err != nil { - b.Flash(w, r, err.Error()) + responses.Flash(w, r, err.Error()) } else { go b.SendEmail(Email{ To: cfg.Site.AdminEmail, @@ -56,7 +57,7 @@ func (b *Blog) ContactRoutes(r *mux.Router) { // Log it to disk, too. fh, err := os.OpenFile(filepath.Join(b.UserRoot, ".contact.log"), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) if err != nil { - b.Flash(w, r, "Error logging the message to disk: %s", err) + responses.Flash(w, r, "Error logging the message to disk: %s", err) } else { fh.WriteString(fmt.Sprintf( "Date: %s\nName: %s\nEmail: %s\nSubject: %s\n\n%s\n\n--------------------\n\n", @@ -68,7 +69,7 @@ func (b *Blog) ContactRoutes(r *mux.Router) { )) fh.Close() } - b.FlashAndRedirect(w, r, "/contact", "Your message has been sent.") + responses.FlashAndRedirect(w, r, "/contact", "Your message has been sent.") } } diff --git a/core/responses.go b/core/errors.go similarity index 63% rename from core/responses.go rename to core/errors.go index 79e85b2..3219985 100644 --- a/core/responses.go +++ b/core/errors.go @@ -1,39 +1,12 @@ package core import ( - "fmt" "net/http" "github.com/kirsle/blog/core/internal/log" "github.com/kirsle/blog/core/internal/render" - "github.com/kirsle/blog/core/internal/sessions" ) -// Flash adds a flash message to the user's session. -func (b *Blog) Flash(w http.ResponseWriter, r *http.Request, message string, args ...interface{}) { - session := sessions.Get(r) - session.AddFlash(fmt.Sprintf(message, args...)) - session.Save(r, w) -} - -// FlashAndRedirect flashes and redirects in one go. -func (b *Blog) FlashAndRedirect(w http.ResponseWriter, r *http.Request, location, message string, args ...interface{}) { - b.Flash(w, r, message, args...) - b.Redirect(w, location) -} - -// FlashAndReload flashes and sends a redirect to the same path. -func (b *Blog) FlashAndReload(w http.ResponseWriter, r *http.Request, message string, args ...interface{}) { - b.Flash(w, r, message, args...) - b.Redirect(w, r.URL.Path) -} - -// Redirect sends an HTTP redirect response. -func (b *Blog) Redirect(w http.ResponseWriter, location string) { - w.Header().Set("Location", location) - w.WriteHeader(http.StatusFound) -} - // NotFound sends a 404 response. func (b *Blog) NotFound(w http.ResponseWriter, r *http.Request, message string) { if message == "" { diff --git a/core/initial-setup.go b/core/initial-setup.go index 6857365..3ad754b 100644 --- a/core/initial-setup.go +++ b/core/initial-setup.go @@ -8,6 +8,7 @@ import ( "github.com/kirsle/blog/core/internal/models/settings" "github.com/kirsle/blog/core/internal/models/users" "github.com/kirsle/blog/core/internal/render" + "github.com/kirsle/blog/core/internal/responses" "github.com/kirsle/blog/core/internal/sessions" ) @@ -20,7 +21,7 @@ func (b *Blog) SetupHandler(w http.ResponseWriter, r *http.Request) { // Reject if we're already set up. s, _ := settings.Load() if s.Initialized { - b.FlashAndRedirect(w, r, "/", "This website has already been configured.") + responses.FlashAndRedirect(w, r, "/", "This website has already been configured.") return } @@ -58,7 +59,7 @@ func (b *Blog) SetupHandler(w http.ResponseWriter, r *http.Request) { // All set! b.Login(w, r, user) - b.FlashAndRedirect(w, r, "/admin", "Admin user created and logged in.") + responses.FlashAndRedirect(w, r, "/admin", "Admin user created and logged in.") return } } diff --git a/core/internal/responses/responses.go b/core/internal/responses/responses.go new file mode 100644 index 0000000..8776768 --- /dev/null +++ b/core/internal/responses/responses.go @@ -0,0 +1,33 @@ +package responses + +import ( + "fmt" + "net/http" + + "github.com/kirsle/blog/core/internal/sessions" +) + +// Flash adds a flash message to the user's session. +func Flash(w http.ResponseWriter, r *http.Request, message string, args ...interface{}) { + session := sessions.Get(r) + session.AddFlash(fmt.Sprintf(message, args...)) + session.Save(r, w) +} + +// FlashAndRedirect flashes and redirects in one go. +func FlashAndRedirect(w http.ResponseWriter, r *http.Request, location, message string, args ...interface{}) { + Flash(w, r, message, args...) + Redirect(w, location) +} + +// FlashAndReload flashes and sends a redirect to the same path. +func FlashAndReload(w http.ResponseWriter, r *http.Request, message string, args ...interface{}) { + Flash(w, r, message, args...) + Redirect(w, r.URL.Path) +} + +// Redirect sends an HTTP redirect response. +func Redirect(w http.ResponseWriter, location string) { + w.Header().Set("Location", location) + w.WriteHeader(http.StatusFound) +} diff --git a/core/pages.go b/core/pages.go index a6f20b2..c2ce736 100644 --- a/core/pages.go +++ b/core/pages.go @@ -8,6 +8,7 @@ import ( "github.com/kirsle/blog/core/internal/markdown" "github.com/kirsle/blog/core/internal/render" + "github.com/kirsle/blog/core/internal/responses" ) // PageHandler is the catch-all route handler, for serving static web pages. @@ -17,7 +18,7 @@ func (b *Blog) PageHandler(w http.ResponseWriter, r *http.Request) { // Remove trailing slashes by redirecting them away. if len(path) > 1 && path[len(path)-1] == '/' { - b.Redirect(w, strings.TrimRight(path, "/")) + responses.Redirect(w, strings.TrimRight(path, "/")) return }