Improve flash message handling

main
Jan Dittberner 2 years ago
parent be14a37b4d
commit 99a2cde144

@ -261,7 +261,11 @@ func (app *application) newMotionSubmit(w http.ResponseWriter, r *http.Request)
app.jobScheduler.Reschedule(JobIDCloseDecisions, JobIDRemindVoters) 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) 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.jobScheduler.Reschedule(JobIDCloseDecisions, JobIDRemindVoters)
app.sessionManager.Put( app.addFlash(r, &FlashMessage{
r.Context(), Variant: flashInfo,
"flash", Title: "Motion modified",
fmt.Sprintf("The motion %s has been modified!", decision.Tag), Message: fmt.Sprintf("The motion %s has been modified!", decision.Tag),
) })
http.Redirect(w, r, "/motions/", http.StatusSeeOther) 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.jobScheduler.Reschedule(JobIDCloseDecisions, JobIDRemindVoters)
app.sessionManager.Put( app.addFlash(r, &FlashMessage{
r.Context(), Variant: flashWarning,
"flash", Title: "Motion withdrawn",
fmt.Sprintf("Motion %s has been withdrawn!", motion.Tag), Message: fmt.Sprintf("The motion %s has been withdrawn!", motion.Tag),
) })
http.Redirect(w, r, "/motions/", http.StatusSeeOther) 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, Decision: motion, User: user, Choice: choice,
}) })
app.sessionManager.Put( app.addFlash(r, &FlashMessage{
r.Context(), Variant: flashSuccess,
"flash", Title: "Vote registered",
fmt.Sprintf("Your vote for motion %s has been registered.", motion.Tag), Message: fmt.Sprintf("Your vote for motion %s has been registered.", motion.Tag),
) })
http.Redirect(w, r, "/motions/", http.StatusSeeOther) 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, Decision: motion, User: user, Voter: voter, Choice: form.Choice, Justification: form.Justification,
}) })
app.sessionManager.Put( app.addFlash(r, &FlashMessage{
r.Context(), Variant: flashSuccess,
"flash", Title: "Proxy vote registered",
fmt.Sprintf("Your proxy vote for %s for motion %s has been registered.", voter.Name, motion.Tag), 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) http.Redirect(w, r, "/motions/", http.StatusSeeOther)
} }
@ -735,11 +743,11 @@ func (app *application) editUserSubmit(w http.ResponseWriter, r *http.Request) {
return return
} }
app.sessionManager.Put( app.addFlash(r, &FlashMessage{
r.Context(), Variant: flashInfo,
"flash", Title: "User modified",
fmt.Sprintf("User %s has been modified.", userToEdit.Name), Message: fmt.Sprintf("User %s has been modified.", userToEdit.Name),
) })
http.Redirect(w, r, "/users/", http.StatusSeeOther) http.Redirect(w, r, "/users/", http.StatusSeeOther)
} }
@ -835,11 +843,15 @@ func (app *application) userAddEmailSubmit(w http.ResponseWriter, r *http.Reques
return return
} }
app.sessionManager.Put( app.addFlash(r, &FlashMessage{
r.Context(), Variant: flashSuccess,
"flash", Title: "Email address added",
fmt.Sprintf("Added email address %s for user %s", form.EmailAddress, userToEdit.Name), 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) 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) { func (app *application) newUserSubmit(_ http.ResponseWriter, _ *http.Request) {
// TODO: implement userDeleteEmailSubmit // TODO: implement newUserSubmit
panic("not implemented") panic("not implemented")
} }
@ -928,11 +940,11 @@ func (app *application) deleteUserSubmit(w http.ResponseWriter, r *http.Request)
return return
} }
app.sessionManager.Put( app.addFlash(r, &FlashMessage{
r.Context(), Variant: flashWarning,
"flash", Title: "User deleted",
fmt.Sprintf("User %s has been deleted.", userToDelete.Name), Message: fmt.Sprintf("User %s has been deleted.", userToDelete.Name),
) })
http.Redirect(w, r, "/users/", http.StatusSeeOther) http.Redirect(w, r, "/users/", http.StatusSeeOther)
} }

@ -126,7 +126,7 @@ type templateData struct {
User *models.User User *models.User
Users []*models.User Users []*models.User
Request *http.Request Request *http.Request
Flash string Flashes []FlashMessage
Form any Form any
ActiveNav topLevelNavItem ActiveNav topLevelNavItem
ActiveSubNav subLevelNavItem ActiveSubNav subLevelNavItem
@ -145,7 +145,7 @@ func (app *application) newTemplateData(
User: user, User: user,
ActiveNav: nav, ActiveNav: nav,
ActiveSubNav: subNav, ActiveSubNav: subNav,
Flash: app.sessionManager.PopString(r.Context(), "flash"), Flashes: app.flashes(r),
CSRFToken: nosurf.Token(r), CSRFToken: nosurf.Token(r),
} }
} }
@ -253,3 +253,44 @@ func getPEMClientCert(r *http.Request) (string, error) {
return clientCertPEM.String(), nil 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)
}

@ -23,6 +23,7 @@ import (
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"database/sql" "database/sql"
"encoding/gob"
"flag" "flag"
"fmt" "fmt"
"html/template" "html/template"
@ -103,6 +104,8 @@ func main() {
sessionManager.Cookie.SameSite = http.SameSiteStrictMode sessionManager.Cookie.SameSite = http.SameSiteStrictMode
sessionManager.Cookie.Secure = true sessionManager.Cookie.Secure = true
gob.Register([]FlashMessage{})
app := &application{ app := &application{
errorLog: errorLog, errorLog: errorLog,
infoLog: infoLog, infoLog: infoLog,

@ -15,9 +15,7 @@
<img src="/static/images/CAcert-logo-colour.svg" alt="CAcert" height="40rem"/> <img src="/static/images/CAcert-logo-colour.svg" alt="CAcert" height="40rem"/>
</div> </div>
<div class="ui text container"> <div class="ui text container">
<h1 class="ui header"> <h1 class="ui header">CAcert Board Voting System</h1>
{{ template "title" . }}
</h1>
{{ with .User }} {{ with .User }}
<div class="ui label"> <div class="ui label">
<i class="id card outline icon"></i> <i class="id card outline icon"></i>
@ -29,14 +27,15 @@
</header> </header>
{{ template "nav" . }} {{ template "nav" . }}
<main class="ui container"> <main class="ui container">
{{ with .Flash }} {{ with .Flashes }}
<div class="basic segment"> <div class="basic segment">
<div class="ui info message"> {{ range . }}
<i class="close icon"></i> <div class="ui {{ .Variant }} message">
<div class="ui list"> <i class="close icon"></i>
<div class="ui item">{{ . }}</div> <div class="header">{{ .Title }}</div>
<p>{{ .Message }}</p>
</div> </div>
</div> {{ end }}
</div> </div>
{{ end }} {{ end }}
{{ template "main" . }} {{ template "main" . }}

Loading…
Cancel
Save