Move Flash and Redirect responses to subpackage

pull/4/head
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/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
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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 == "" {

View File

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

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