From 99a2cde144c9693e22409bb316bf39064bb126d6 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 4 Jun 2022 13:52:53 +0200 Subject: [PATCH] Improve flash message handling --- cmd/boardvoting/handlers.go | 86 +++++++++++++++++++++---------------- cmd/boardvoting/helpers.go | 45 ++++++++++++++++++- cmd/boardvoting/main.go | 3 ++ ui/html/base.html | 17 ++++---- 4 files changed, 103 insertions(+), 48 deletions(-) diff --git a/cmd/boardvoting/handlers.go b/cmd/boardvoting/handlers.go index c62ed97..e1948ac 100644 --- a/cmd/boardvoting/handlers.go +++ b/cmd/boardvoting/handlers.go @@ -261,7 +261,11 @@ func (app *application) newMotionSubmit(w http.ResponseWriter, r *http.Request) app.jobScheduler.Reschedule(JobIDCloseDecisions, JobIDRemindVoters) - app.sessionManager.Put(r.Context(), "flash", fmt.Sprintf("Started new motion %s: %s", decision.Tag, decision.Title)) + app.addFlash(r, &FlashMessage{ + Variant: flashSuccess, + Title: "New motion started", + Message: fmt.Sprintf("Started new motion %s: %s", decision.Tag, decision.Title), + }) http.Redirect(w, r, "/motions/", http.StatusSeeOther) } @@ -357,11 +361,11 @@ func (app *application) editMotionSubmit(w http.ResponseWriter, r *http.Request) app.jobScheduler.Reschedule(JobIDCloseDecisions, JobIDRemindVoters) - app.sessionManager.Put( - r.Context(), - "flash", - fmt.Sprintf("The motion %s has been modified!", decision.Tag), - ) + app.addFlash(r, &FlashMessage{ + Variant: flashInfo, + Title: "Motion modified", + Message: fmt.Sprintf("The motion %s has been modified!", decision.Tag), + }) http.Redirect(w, r, "/motions/", http.StatusSeeOther) } @@ -412,11 +416,11 @@ func (app *application) withdrawMotionSubmit(w http.ResponseWriter, r *http.Requ app.jobScheduler.Reschedule(JobIDCloseDecisions, JobIDRemindVoters) - app.sessionManager.Put( - r.Context(), - "flash", - fmt.Sprintf("Motion %s has been withdrawn!", motion.Tag), - ) + app.addFlash(r, &FlashMessage{ + Variant: flashWarning, + Title: "Motion withdrawn", + Message: fmt.Sprintf("The motion %s has been withdrawn!", motion.Tag), + }) http.Redirect(w, r, "/motions/", http.StatusSeeOther) } @@ -490,11 +494,11 @@ func (app *application) voteSubmit(w http.ResponseWriter, r *http.Request) { Decision: motion, User: user, Choice: choice, }) - app.sessionManager.Put( - r.Context(), - "flash", - fmt.Sprintf("Your vote for motion %s has been registered.", motion.Tag), - ) + app.addFlash(r, &FlashMessage{ + Variant: flashSuccess, + Title: "Vote registered", + Message: fmt.Sprintf("Your vote for motion %s has been registered.", motion.Tag), + }) http.Redirect(w, r, "/motions/", http.StatusSeeOther) } @@ -598,11 +602,15 @@ func (app *application) proxyVoteSubmit(w http.ResponseWriter, r *http.Request) Decision: motion, User: user, Voter: voter, Choice: form.Choice, Justification: form.Justification, }) - app.sessionManager.Put( - r.Context(), - "flash", - fmt.Sprintf("Your proxy vote for %s for motion %s has been registered.", voter.Name, motion.Tag), - ) + app.addFlash(r, &FlashMessage{ + Variant: flashSuccess, + Title: "Proxy vote registered", + Message: fmt.Sprintf( + "Your proxy vote for %s for motion %s has been registered.", + voter.Name, + motion.Tag, + ), + }) http.Redirect(w, r, "/motions/", http.StatusSeeOther) } @@ -735,11 +743,11 @@ func (app *application) editUserSubmit(w http.ResponseWriter, r *http.Request) { return } - app.sessionManager.Put( - r.Context(), - "flash", - fmt.Sprintf("User %s has been modified.", userToEdit.Name), - ) + app.addFlash(r, &FlashMessage{ + Variant: flashInfo, + Title: "User modified", + Message: fmt.Sprintf("User %s has been modified.", userToEdit.Name), + }) http.Redirect(w, r, "/users/", http.StatusSeeOther) } @@ -835,11 +843,15 @@ func (app *application) userAddEmailSubmit(w http.ResponseWriter, r *http.Reques return } - app.sessionManager.Put( - r.Context(), - "flash", - fmt.Sprintf("Added email address %s for user %s", form.EmailAddress, userToEdit.Name), - ) + app.addFlash(r, &FlashMessage{ + Variant: flashSuccess, + Title: "Email address added", + Message: fmt.Sprintf( + "Added email address %s for user %s", + form.EmailAddress, + userToEdit.Name, + ), + }) http.Redirect(w, r, fmt.Sprintf("/users/%d/", userToEdit.ID), http.StatusSeeOther) } @@ -860,7 +872,7 @@ func (app *application) newUserForm(_ http.ResponseWriter, _ *http.Request) { } func (app *application) newUserSubmit(_ http.ResponseWriter, _ *http.Request) { - // TODO: implement userDeleteEmailSubmit + // TODO: implement newUserSubmit panic("not implemented") } @@ -928,11 +940,11 @@ func (app *application) deleteUserSubmit(w http.ResponseWriter, r *http.Request) return } - app.sessionManager.Put( - r.Context(), - "flash", - fmt.Sprintf("User %s has been deleted.", userToDelete.Name), - ) + app.addFlash(r, &FlashMessage{ + Variant: flashWarning, + Title: "User deleted", + Message: fmt.Sprintf("User %s has been deleted.", userToDelete.Name), + }) http.Redirect(w, r, "/users/", http.StatusSeeOther) } diff --git a/cmd/boardvoting/helpers.go b/cmd/boardvoting/helpers.go index f41b295..b6cfdef 100644 --- a/cmd/boardvoting/helpers.go +++ b/cmd/boardvoting/helpers.go @@ -126,7 +126,7 @@ type templateData struct { User *models.User Users []*models.User Request *http.Request - Flash string + Flashes []FlashMessage Form any ActiveNav topLevelNavItem ActiveSubNav subLevelNavItem @@ -145,7 +145,7 @@ func (app *application) newTemplateData( User: user, ActiveNav: nav, ActiveSubNav: subNav, - Flash: app.sessionManager.PopString(r.Context(), "flash"), + Flashes: app.flashes(r), CSRFToken: nosurf.Token(r), } } @@ -253,3 +253,44 @@ func getPEMClientCert(r *http.Request) (string, error) { return clientCertPEM.String(), nil } + +type FlashVariant string + +const ( + flashWarning FlashVariant = "warning" + flashInfo FlashVariant = "info" + flashSuccess FlashVariant = "success" + flashError FlashVariant = "error" +) + +type FlashMessage struct { + Variant FlashVariant + Title string + Message string +} + +func (app *application) addFlash(r *http.Request, message *FlashMessage) { + flashes := app.flashes(r) + + flashes = append(flashes, *message) + + app.sessionManager.Put( + r.Context(), + "flashes", + flashes, + ) +} + +func (app *application) flashes(r *http.Request) []FlashMessage { + flashInstance := app.sessionManager.Pop(r.Context(), "flashes") + + if flashInstance != nil { + flashes, ok := flashInstance.([]FlashMessage) + + if ok { + return flashes + } + } + + return make([]FlashMessage, 0) +} diff --git a/cmd/boardvoting/main.go b/cmd/boardvoting/main.go index 10dbb65..d11953c 100644 --- a/cmd/boardvoting/main.go +++ b/cmd/boardvoting/main.go @@ -23,6 +23,7 @@ import ( "crypto/tls" "crypto/x509" "database/sql" + "encoding/gob" "flag" "fmt" "html/template" @@ -103,6 +104,8 @@ func main() { sessionManager.Cookie.SameSite = http.SameSiteStrictMode sessionManager.Cookie.Secure = true + gob.Register([]FlashMessage{}) + app := &application{ errorLog: errorLog, infoLog: infoLog, diff --git a/ui/html/base.html b/ui/html/base.html index 553453d..40b15dc 100644 --- a/ui/html/base.html +++ b/ui/html/base.html @@ -15,9 +15,7 @@ CAcert
-

- {{ template "title" . }} -

+

CAcert Board Voting System

{{ with .User }}
@@ -29,14 +27,15 @@ {{ template "nav" . }}
- {{ with .Flash }} + {{ with .Flashes }}
-
- -
-
{{ . }}
+ {{ range . }} +
+ +
{{ .Title }}
+

{{ .Message }}

-
+ {{ end }}
{{ end }} {{ template "main" . }}