Move Flash and Redirect responses to subpackage

This commit is contained in:
Noah 2018-02-10 11:20:27 -08:00
parent 60ccaf7b35
commit f0045ae2cf
9 changed files with 83 additions and 70 deletions

View File

@ -14,6 +14,7 @@ import (
"github.com/kirsle/blog/core/internal/middleware/auth" "github.com/kirsle/blog/core/internal/middleware/auth"
"github.com/kirsle/blog/core/internal/models/settings" "github.com/kirsle/blog/core/internal/models/settings"
"github.com/kirsle/blog/core/internal/render" "github.com/kirsle/blog/core/internal/render"
"github.com/kirsle/blog/core/internal/responses"
"github.com/urfave/negroni" "github.com/urfave/negroni"
) )
@ -60,18 +61,18 @@ func (b *Blog) EditorHandler(w http.ResponseWriter, r *http.Request) {
body = []byte(r.FormValue("body")) body = []byte(r.FormValue("body"))
err := ioutil.WriteFile(fp, body, 0644) err := ioutil.WriteFile(fp, body, 0644)
if err != nil { if err != nil {
b.Flash(w, r, "Error saving: %s", err) responses.Flash(w, r, "Error saving: %s", err)
} else { } 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 return
} }
} else if deleting { } else if deleting {
fp = filepath.Join(b.UserRoot, file) fp = filepath.Join(b.UserRoot, file)
err := os.Remove(fp) err := os.Remove(fp)
if err != nil { if err != nil {
b.FlashAndRedirect(w, r, "/admin/editor", "Error deleting: %s", err) responses.FlashAndRedirect(w, r, "/admin/editor", "Error deleting: %s", err)
} else { } else {
b.FlashAndRedirect(w, r, "/admin/editor", "Page deleted!") responses.FlashAndRedirect(w, r, "/admin/editor", "Page deleted!")
return return
} }
} else { } else {
@ -94,7 +95,7 @@ func (b *Blog) EditorHandler(w http.ResponseWriter, r *http.Request) {
if !os.IsNotExist(err) && !f.IsDir() { if !os.IsNotExist(err) && !f.IsDir() {
body, err = ioutil.ReadFile(fp) body, err = ioutil.ReadFile(fp)
if err != nil { 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() settings.Save()
b.Configure() b.Configure()
b.FlashAndReload(w, r, "Settings have been saved!") responses.FlashAndReload(w, r, "Settings have been saved!")
return return
} }
} }

View File

@ -9,6 +9,7 @@ import (
"github.com/kirsle/blog/core/internal/log" "github.com/kirsle/blog/core/internal/log"
"github.com/kirsle/blog/core/internal/middleware/auth" "github.com/kirsle/blog/core/internal/middleware/auth"
"github.com/kirsle/blog/core/internal/models/users" "github.com/kirsle/blog/core/internal/models/users"
"github.com/kirsle/blog/core/internal/responses"
"github.com/kirsle/blog/core/internal/sessions" "github.com/kirsle/blog/core/internal/sessions"
) )
@ -23,7 +24,7 @@ func (b *Blog) AuthRoutes(r *mux.Router) {
// the user to the login page. // the user to the login page.
func (b *Blog) MustLogin(w http.ResponseWriter, r *http.Request) { func (b *Blog) MustLogin(w http.ResponseWriter, r *http.Request) {
log.Info("MustLogin for %s", r.URL.Path) 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. // 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") vars.Error = errors.New("bad username or password")
} else { } else {
// Login OK! // Login OK!
b.Flash(w, r, "Login OK!") responses.Flash(w, r, "Login OK!")
b.Login(w, r, user) b.Login(w, r, user)
// A next URL given? TODO: actually get to work // A next URL given? TODO: actually get to work
log.Info("Redirect after login to: %s", nextURL) log.Info("Redirect after login to: %s", nextURL)
if len(nextURL) > 0 && nextURL[0] == '/' { if len(nextURL) > 0 && nextURL[0] == '/' {
b.Redirect(w, nextURL) responses.Redirect(w, nextURL)
} else { } else {
b.Redirect(w, "/") responses.Redirect(w, "/")
} }
return return
} }
@ -91,25 +92,25 @@ func (b *Blog) LogoutHandler(w http.ResponseWriter, r *http.Request) {
delete(session.Values, "logged-in") delete(session.Values, "logged-in")
delete(session.Values, "user-id") delete(session.Values, "user-id")
session.Save(r, w) session.Save(r, w)
b.Redirect(w, "/") responses.Redirect(w, "/")
} }
// AccountHandler shows the account settings page. // AccountHandler shows the account settings page.
func (b *Blog) AccountHandler(w http.ResponseWriter, r *http.Request) { func (b *Blog) AccountHandler(w http.ResponseWriter, r *http.Request) {
if !auth.LoggedIn(r) { 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 return
} }
currentUser, err := auth.CurrentUser(r) currentUser, err := auth.CurrentUser(r)
if err != nil { 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 return
} }
// Load an editable copy of the user. // Load an editable copy of the user.
user, err := users.Load(currentUser.ID) user, err := users.Load(currentUser.ID)
if err != nil { 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 return
} }
@ -129,14 +130,14 @@ func (b *Blog) AccountHandler(w http.ResponseWriter, r *http.Request) {
form.NewPassword = r.FormValue("newpassword") form.NewPassword = r.FormValue("newpassword")
form.NewPassword2 = r.FormValue("newpassword2") form.NewPassword2 = r.FormValue("newpassword2")
if err = form.Validate(); err != nil { if err = form.Validate(); err != nil {
b.Flash(w, r, err.Error()) responses.Flash(w, r, err.Error())
} else { } else {
var ok = true var ok = true
// Validate the username is available. // Validate the username is available.
if form.Username != user.Username { if form.Username != user.Username {
if _, err = users.LoadUsername(form.Username); err == nil { 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 ok = false
} }
} }
@ -145,12 +146,12 @@ func (b *Blog) AccountHandler(w http.ResponseWriter, r *http.Request) {
if len(form.OldPassword) > 0 { if len(form.OldPassword) > 0 {
// Validate their old password. // Validate their old password.
if _, err = users.CheckAuth(form.Username, form.OldPassword); err != nil { 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 ok = false
} else { } else {
err = user.SetPassword(form.NewPassword) err = user.SetPassword(form.NewPassword)
if err != nil { if err != nil {
b.Flash(w, r, "Change password error: %s", err) responses.Flash(w, r, "Change password error: %s", err)
ok = false ok = false
} }
} }
@ -163,9 +164,9 @@ func (b *Blog) AccountHandler(w http.ResponseWriter, r *http.Request) {
user.Email = form.Email user.Email = form.Email
err = user.Save() err = user.Save()
if err != nil { if err != nil {
b.Flash(w, r, "Error saving user: %s", err) responses.Flash(w, r, "Error saving user: %s", err)
} else { } else {
b.FlashAndRedirect(w, r, "/account", "Settings saved!") responses.FlashAndRedirect(w, r, "/account", "Settings saved!")
return return
} }
} }

View File

@ -21,6 +21,7 @@ import (
"github.com/kirsle/blog/core/internal/models/settings" "github.com/kirsle/blog/core/internal/models/settings"
"github.com/kirsle/blog/core/internal/models/users" "github.com/kirsle/blog/core/internal/models/users"
"github.com/kirsle/blog/core/internal/render" "github.com/kirsle/blog/core/internal/render"
"github.com/kirsle/blog/core/internal/responses"
"github.com/urfave/negroni" "github.com/urfave/negroni"
) )
@ -57,7 +58,7 @@ func (b *Blog) BlogRoutes(r *mux.Router) {
b.NotFound(w, r, "Not Found") b.NotFound(w, r, "Not Found")
return return
} }
b.Redirect(w, "/tagged/"+tag) responses.Redirect(w, "/tagged/"+tag)
}) })
r.HandleFunc("/blog/entry/{fragment}", func(w http.ResponseWriter, r *http.Request) { r.HandleFunc("/blog/entry/{fragment}", func(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r) params := mux.Vars(r)
@ -66,7 +67,7 @@ func (b *Blog) BlogRoutes(r *mux.Router) {
b.NotFound(w, r, "Not Found") b.NotFound(w, r, "Not Found")
return return
} }
b.Redirect(w, "/"+fragment) responses.Redirect(w, "/"+fragment)
}) })
// Login-required routers. // Login-required routers.
@ -517,8 +518,8 @@ func (b *Blog) EditBlog(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
v.Error = err v.Error = err
} else { } else {
b.Flash(w, r, "Post created!") responses.Flash(w, r, "Post created!")
b.Redirect(w, "/"+post.Fragment) 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") idStr = r.URL.Query().Get("id")
} }
if idStr == "" { 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 return
} }
@ -551,14 +552,14 @@ func (b *Blog) DeletePost(w http.ResponseWriter, r *http.Request) {
if err == nil { if err == nil {
post, err = posts.Load(id) post, err = posts.Load(id)
if err != nil { 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 return
} }
} }
if r.Method == http.MethodPost { if r.Method == http.MethodPost {
post.Delete() post.Delete()
b.FlashAndRedirect(w, r, "/admin", "Blog entry deleted!") responses.FlashAndRedirect(w, r, "/admin", "Blog entry deleted!")
return return
} }

View File

@ -17,6 +17,7 @@ import (
"github.com/kirsle/blog/core/internal/models/comments" "github.com/kirsle/blog/core/internal/models/comments"
"github.com/kirsle/blog/core/internal/models/users" "github.com/kirsle/blog/core/internal/models/users"
"github.com/kirsle/blog/core/internal/render" "github.com/kirsle/blog/core/internal/render"
"github.com/kirsle/blog/core/internal/responses"
"github.com/kirsle/blog/core/internal/sessions" "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 := &comments.Comment{}
c.ParseForm(r) c.ParseForm(r)
if c.ThreadID == "" { 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 return
} }
@ -173,13 +174,13 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) {
id := r.FormValue("id") id := r.FormValue("id")
c, err = t.Find(id) c, err = t.Find(id)
if err != nil { if err != nil {
b.FlashAndRedirect(w, r, "/", "That comment was not found.") responses.FlashAndRedirect(w, r, "/", "That comment was not found.")
return return
} }
// Verify they have the matching edit token. Admin users are allowed. // Verify they have the matching edit token. Admin users are allowed.
if c.EditToken != editToken && !currentUser.Admin { 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 return
} }
@ -190,7 +191,7 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) {
// Are we deleting said post? // Are we deleting said post?
if submit == "confirm-delete" { if submit == "confirm-delete" {
t.Delete(c.ID) t.Delete(c.ID)
b.FlashAndRedirect(w, r, origin, "Comment deleted!") responses.FlashAndRedirect(w, r, origin, "Comment deleted!")
return return
} }
@ -227,7 +228,7 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) {
// Append their comment. // Append their comment.
err := t.Post(c) err := t.Post(c)
if err != nil { 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 return
} }
b.NotifyComment(c) 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 { if _, err := mail.ParseAddress(c.Email); err == nil {
m := comments.LoadMailingList() m := comments.LoadMailingList()
m.Subscribe(t.ID, c.Email) 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 "+ "Comment posted, and you've been subscribed to "+
"future comments on this page.", "future comments on this page.",
) )
return return
} }
} }
b.FlashAndRedirect(w, r, c.OriginURL, "Comment posted!") responses.FlashAndRedirect(w, r, c.OriginURL, "Comment posted!")
log.Info("t: %v", t.Comments) log.Info("t: %v", t.Comments)
return return
} }
@ -273,7 +274,7 @@ func (b *Blog) SubscriptionHandler(w http.ResponseWriter, r *http.Request) {
m := comments.LoadMailingList() m := comments.LoadMailingList()
m.UnsubscribeAll(email) m.UnsubscribeAll(email)
b.FlashAndRedirect(w, r, "/comments/subscription", responses.FlashAndRedirect(w, r, "/comments/subscription",
"You have been unsubscribed from all mailing lists.", "You have been unsubscribed from all mailing lists.",
) )
return return
@ -285,7 +286,7 @@ func (b *Blog) SubscriptionHandler(w http.ResponseWriter, r *http.Request) {
if thread != "" && email != "" { if thread != "" && email != "" {
m := comments.LoadMailingList() m := comments.LoadMailingList()
m.Unsubscribe(thread, email) 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 return
} }
@ -311,7 +312,7 @@ func (b *Blog) QuickDeleteHandler(w http.ResponseWriter, r *http.Request) {
t.Delete(c.ID) 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 // GetEditToken gets or generates an edit token from the user's session, which

View File

@ -12,6 +12,7 @@ import (
"github.com/kirsle/blog/core/internal/forms" "github.com/kirsle/blog/core/internal/forms"
"github.com/kirsle/blog/core/internal/markdown" "github.com/kirsle/blog/core/internal/markdown"
"github.com/kirsle/blog/core/internal/models/settings" "github.com/kirsle/blog/core/internal/models/settings"
"github.com/kirsle/blog/core/internal/responses"
) )
// ContactRoutes attaches the contact URL to the app. // ContactRoutes attaches the contact URL to the app.
@ -38,7 +39,7 @@ func (b *Blog) ContactRoutes(r *mux.Router) {
if r.Method == http.MethodPost { if r.Method == http.MethodPost {
form.ParseForm(r) form.ParseForm(r)
if err = form.Validate(); err != nil { if err = form.Validate(); err != nil {
b.Flash(w, r, err.Error()) responses.Flash(w, r, err.Error())
} else { } else {
go b.SendEmail(Email{ go b.SendEmail(Email{
To: cfg.Site.AdminEmail, To: cfg.Site.AdminEmail,
@ -56,7 +57,7 @@ func (b *Blog) ContactRoutes(r *mux.Router) {
// Log it to disk, too. // 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) fh, err := os.OpenFile(filepath.Join(b.UserRoot, ".contact.log"), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil { 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 { } else {
fh.WriteString(fmt.Sprintf( fh.WriteString(fmt.Sprintf(
"Date: %s\nName: %s\nEmail: %s\nSubject: %s\n\n%s\n\n--------------------\n\n", "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() fh.Close()
} }
b.FlashAndRedirect(w, r, "/contact", "Your message has been sent.") responses.FlashAndRedirect(w, r, "/contact", "Your message has been sent.")
} }
} }

View File

@ -1,39 +1,12 @@
package core package core
import ( import (
"fmt"
"net/http" "net/http"
"github.com/kirsle/blog/core/internal/log" "github.com/kirsle/blog/core/internal/log"
"github.com/kirsle/blog/core/internal/render" "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. // NotFound sends a 404 response.
func (b *Blog) NotFound(w http.ResponseWriter, r *http.Request, message string) { func (b *Blog) NotFound(w http.ResponseWriter, r *http.Request, message string) {
if message == "" { if message == "" {

View File

@ -8,6 +8,7 @@ import (
"github.com/kirsle/blog/core/internal/models/settings" "github.com/kirsle/blog/core/internal/models/settings"
"github.com/kirsle/blog/core/internal/models/users" "github.com/kirsle/blog/core/internal/models/users"
"github.com/kirsle/blog/core/internal/render" "github.com/kirsle/blog/core/internal/render"
"github.com/kirsle/blog/core/internal/responses"
"github.com/kirsle/blog/core/internal/sessions" "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. // Reject if we're already set up.
s, _ := settings.Load() s, _ := settings.Load()
if s.Initialized { if s.Initialized {
b.FlashAndRedirect(w, r, "/", "This website has already been configured.") responses.FlashAndRedirect(w, r, "/", "This website has already been configured.")
return return
} }
@ -58,7 +59,7 @@ func (b *Blog) SetupHandler(w http.ResponseWriter, r *http.Request) {
// All set! // All set!
b.Login(w, r, user) 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 return
} }
} }

View File

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

View File

@ -8,6 +8,7 @@ import (
"github.com/kirsle/blog/core/internal/markdown" "github.com/kirsle/blog/core/internal/markdown"
"github.com/kirsle/blog/core/internal/render" "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. // 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. // Remove trailing slashes by redirecting them away.
if len(path) > 1 && path[len(path)-1] == '/' { if len(path) > 1 && path[len(path)-1] == '/' {
b.Redirect(w, strings.TrimRight(path, "/")) responses.Redirect(w, strings.TrimRight(path, "/"))
return return
} }