From 8ddd9904a07eb14c943eb55c1b8b82a14c6e0368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferdinand=20M=C3=BCtsch?= Date: Fri, 6 Nov 2020 21:19:54 +0100 Subject: [PATCH] refactor: alert handling --- config/config.go | 1 - main.go | 15 +++--- models/view/home.go | 16 ++++++ models/view/imprint.go | 22 +++++++++ models/view/settings.go | 20 ++++++++ models/view/summary.go | 16 ++++++ routes/heartbeat.go | 7 --- routes/{public.go => home.go} | 91 ++++++++++++++++------------------- routes/imprint.go | 41 ++++++++++++++++ routes/routes.go | 31 ------------ routes/settings.go | 77 +++++++++++++++++------------ routes/summary.go | 14 +++++- version.txt | 2 +- 13 files changed, 225 insertions(+), 128 deletions(-) create mode 100644 models/view/home.go create mode 100644 models/view/imprint.go create mode 100644 models/view/settings.go create mode 100644 models/view/summary.go rename routes/{public.go => home.go} (55%) create mode 100644 routes/imprint.go diff --git a/config/config.go b/config/config.go index 2b9787b..70b3370 100644 --- a/config/config.go +++ b/config/config.go @@ -229,7 +229,6 @@ func Load() *Config { config.Version = readVersion() config.App.LanguageColors = readLanguageColors() - // TODO: Read keys from env, so that users are not logged out every time the server is restarted config.Security.SecureCookie = securecookie.New( securecookie.GenerateRandomKey(64), securecookie.GenerateRandomKey(32), diff --git a/main.go b/main.go index 631b20d..66dbae3 100644 --- a/main.go +++ b/main.go @@ -107,7 +107,8 @@ func main() { healthHandler := routes.NewHealthHandler(db) heartbeatHandler := routes.NewHeartbeatHandler(heartbeatService, languageMappingService) settingsHandler := routes.NewSettingsHandler(userService, summaryService, aggregationService, languageMappingService) - publicHandler := routes.NewIndexHandler(userService, keyValueService) + homeHandler := routes.NewHomeHandler(userService) + imprintHandler := routes.NewImprintHandler(keyValueService) wakatimeV1AllHandler := wtV1Routes.NewAllTimeHandler(summaryService) wakatimeV1SummariesHandler := wtV1Routes.NewSummariesHandler(summaryService) shieldV1BadgeHandler := shieldsV1Routes.NewBadgeHandler(summaryService, userService) @@ -138,12 +139,12 @@ func main() { apiRouter.Use(corsMiddleware, authenticateMiddleware) // Public Routes - publicRouter.Path("/").Methods(http.MethodGet).HandlerFunc(publicHandler.GetIndex) - publicRouter.Path("/login").Methods(http.MethodPost).HandlerFunc(publicHandler.PostLogin) - publicRouter.Path("/logout").Methods(http.MethodPost).HandlerFunc(publicHandler.PostLogout) - publicRouter.Path("/signup").Methods(http.MethodGet).HandlerFunc(publicHandler.GetSignup) - publicRouter.Path("/signup").Methods(http.MethodPost).HandlerFunc(publicHandler.PostSignup) - publicRouter.Path("/imprint").Methods(http.MethodGet).HandlerFunc(publicHandler.GetImprint) + publicRouter.Path("/").Methods(http.MethodGet).HandlerFunc(homeHandler.GetIndex) + publicRouter.Path("/login").Methods(http.MethodPost).HandlerFunc(homeHandler.PostLogin) + publicRouter.Path("/logout").Methods(http.MethodPost).HandlerFunc(homeHandler.PostLogout) + publicRouter.Path("/signup").Methods(http.MethodGet).HandlerFunc(homeHandler.GetSignup) + publicRouter.Path("/signup").Methods(http.MethodPost).HandlerFunc(homeHandler.PostSignup) + publicRouter.Path("/imprint").Methods(http.MethodGet).HandlerFunc(imprintHandler.GetImprint) // Summary Routes summaryRouter.Methods(http.MethodGet).HandlerFunc(summaryHandler.GetIndex) diff --git a/models/view/home.go b/models/view/home.go new file mode 100644 index 0000000..eaf44b8 --- /dev/null +++ b/models/view/home.go @@ -0,0 +1,16 @@ +package view + +type HomeViewModel struct { + Success string + Error string +} + +func (s *HomeViewModel) WithSuccess(m string) *HomeViewModel { + s.Success = m + return s +} + +func (s *HomeViewModel) WithError(m string) *HomeViewModel { + s.Error = m + return s +} diff --git a/models/view/imprint.go b/models/view/imprint.go new file mode 100644 index 0000000..c709910 --- /dev/null +++ b/models/view/imprint.go @@ -0,0 +1,22 @@ +package view + +type ImprintViewModel struct { + HtmlText string + Success string + Error string +} + +func (s *ImprintViewModel) WithSuccess(m string) *ImprintViewModel { + s.Success = m + return s +} + +func (s *ImprintViewModel) WithError(m string) *ImprintViewModel { + s.Error = m + return s +} + +func (s *ImprintViewModel) WithHtmlText(t string) *ImprintViewModel { + s.HtmlText = t + return s +} diff --git a/models/view/settings.go b/models/view/settings.go new file mode 100644 index 0000000..cbcd281 --- /dev/null +++ b/models/view/settings.go @@ -0,0 +1,20 @@ +package view + +import "github.com/muety/wakapi/models" + +type SettingsViewModel struct { + User *models.User + LanguageMappings []*models.LanguageMapping + Success string + Error string +} + +func (s *SettingsViewModel) WithSuccess(m string) *SettingsViewModel { + s.Success = m + return s +} + +func (s *SettingsViewModel) WithError(m string) *SettingsViewModel { + s.Error = m + return s +} diff --git a/models/view/summary.go b/models/view/summary.go new file mode 100644 index 0000000..5797b7f --- /dev/null +++ b/models/view/summary.go @@ -0,0 +1,16 @@ +package view + +type SummaryViewModel struct { + Success string + Error string +} + +func (s *SummaryViewModel) WithSuccess(m string) *SummaryViewModel { + s.Success = m + return s +} + +func (s *SummaryViewModel) WithError(m string) *SummaryViewModel { + s.Error = m + return s +} diff --git a/routes/heartbeat.go b/routes/heartbeat.go index 4a8ec79..1686ba3 100644 --- a/routes/heartbeat.go +++ b/routes/heartbeat.go @@ -43,13 +43,6 @@ func (h *HeartbeatHandler) ApiPost(w http.ResponseWriter, r *http.Request) { return } - /*languageMappings, err := h.languageMappingSrvc.ResolveByUser(user.ID) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) - return - }*/ - for _, hb := range heartbeats { hb.OperatingSystem = opSys hb.Editor = editor diff --git a/routes/public.go b/routes/home.go similarity index 55% rename from routes/public.go rename to routes/home.go index 016d9d8..b9c3769 100644 --- a/routes/public.go +++ b/routes/home.go @@ -6,6 +6,7 @@ import ( conf "github.com/muety/wakapi/config" "github.com/muety/wakapi/middlewares" "github.com/muety/wakapi/models" + "github.com/muety/wakapi/models/view" "github.com/muety/wakapi/services" "github.com/muety/wakapi/utils" "net/http" @@ -13,24 +14,22 @@ import ( "time" ) -type IndexHandler struct { - config *conf.Config - userSrvc *services.UserService - keyValueSrvc *services.KeyValueService +type HomeHandler struct { + config *conf.Config + userSrvc *services.UserService } var loginDecoder = schema.NewDecoder() var signupDecoder = schema.NewDecoder() -func NewIndexHandler(userService *services.UserService, keyValueService *services.KeyValueService) *IndexHandler { - return &IndexHandler{ - config: conf.Get(), - userSrvc: userService, - keyValueSrvc: keyValueService, +func NewHomeHandler(userService *services.UserService) *HomeHandler { + return &HomeHandler{ + config: conf.Get(), + userSrvc: userService, } } -func (h *IndexHandler) GetIndex(w http.ResponseWriter, r *http.Request) { +func (h *HomeHandler) GetIndex(w http.ResponseWriter, r *http.Request) { if h.config.IsDev() { loadTemplates() } @@ -40,29 +39,10 @@ func (h *IndexHandler) GetIndex(w http.ResponseWriter, r *http.Request) { return } - if handleAlerts(w, r, "") { - return - } - - templates[conf.IndexTemplate].Execute(w, nil) + templates[conf.IndexTemplate].Execute(w, h.buildViewModel(r)) } -func (h *IndexHandler) GetImprint(w http.ResponseWriter, r *http.Request) { - if h.config.IsDev() { - loadTemplates() - } - - text := "failed to load content" - if data, err := h.keyValueSrvc.GetString(models.ImprintKey); err == nil { - text = data.Value - } - - templates[conf.ImprintTemplate].Execute(w, &struct { - HtmlText string - }{HtmlText: text}) -} - -func (h *IndexHandler) PostLogin(w http.ResponseWriter, r *http.Request) { +func (h *HomeHandler) PostLogin(w http.ResponseWriter, r *http.Request) { if h.config.IsDev() { loadTemplates() } @@ -74,29 +54,34 @@ func (h *IndexHandler) PostLogin(w http.ResponseWriter, r *http.Request) { var login models.Login if err := r.ParseForm(); err != nil { - respondAlert(w, "missing parameters", "", "", http.StatusBadRequest) + w.WriteHeader(http.StatusBadRequest) + templates[conf.IndexTemplate].Execute(w, h.buildViewModel(r).WithError("missing parameters")) return } if err := loginDecoder.Decode(&login, r.PostForm); err != nil { - respondAlert(w, "missing parameters", "", "", http.StatusBadRequest) + w.WriteHeader(http.StatusBadRequest) + templates[conf.IndexTemplate].Execute(w, h.buildViewModel(r).WithError("missing parameters")) return } user, err := h.userSrvc.GetUserById(login.Username) if err != nil { - respondAlert(w, "resource not found", "", "", http.StatusNotFound) + w.WriteHeader(http.StatusNotFound) + templates[conf.IndexTemplate].Execute(w, h.buildViewModel(r).WithError("resource not found")) return } // TODO: depending on middleware package here is a hack if !middlewares.CheckAndMigratePassword(user, &login, h.config.Security.PasswordSalt, h.userSrvc) { - respondAlert(w, "invalid credentials", "", "", http.StatusUnauthorized) + w.WriteHeader(http.StatusUnauthorized) + templates[conf.IndexTemplate].Execute(w, h.buildViewModel(r).WithError("invalid credentials")) return } encoded, err := h.config.Security.SecureCookie.Encode(models.AuthCookieKey, login) if err != nil { - respondAlert(w, "internal server error", "", "", http.StatusInternalServerError) + w.WriteHeader(http.StatusInternalServerError) + templates[conf.IndexTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error")) return } @@ -114,7 +99,7 @@ func (h *IndexHandler) PostLogin(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, fmt.Sprintf("%s/summary", h.config.Server.BasePath), http.StatusFound) } -func (h *IndexHandler) PostLogout(w http.ResponseWriter, r *http.Request) { +func (h *HomeHandler) PostLogout(w http.ResponseWriter, r *http.Request) { if h.config.IsDev() { loadTemplates() } @@ -123,7 +108,7 @@ func (h *IndexHandler) PostLogout(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, fmt.Sprintf("%s/", h.config.Server.BasePath), http.StatusFound) } -func (h *IndexHandler) GetSignup(w http.ResponseWriter, r *http.Request) { +func (h *HomeHandler) GetSignup(w http.ResponseWriter, r *http.Request) { if h.config.IsDev() { loadTemplates() } @@ -133,14 +118,10 @@ func (h *IndexHandler) GetSignup(w http.ResponseWriter, r *http.Request) { return } - if handleAlerts(w, r, conf.SignupTemplate) { - return - } - - templates[conf.SignupTemplate].Execute(w, nil) + templates[conf.SignupTemplate].Execute(w, h.buildViewModel(r)) } -func (h *IndexHandler) PostSignup(w http.ResponseWriter, r *http.Request) { +func (h *HomeHandler) PostSignup(w http.ResponseWriter, r *http.Request) { if h.config.IsDev() { loadTemplates() } @@ -152,29 +133,41 @@ func (h *IndexHandler) PostSignup(w http.ResponseWriter, r *http.Request) { var signup models.Signup if err := r.ParseForm(); err != nil { - respondAlert(w, "missing parameters", "", conf.SignupTemplate, http.StatusBadRequest) + w.WriteHeader(http.StatusBadRequest) + templates[conf.SignupTemplate].Execute(w, h.buildViewModel(r).WithError("missing parameters")) return } if err := signupDecoder.Decode(&signup, r.PostForm); err != nil { - respondAlert(w, "missing parameters", "", conf.SignupTemplate, http.StatusBadRequest) + w.WriteHeader(http.StatusBadRequest) + templates[conf.SignupTemplate].Execute(w, h.buildViewModel(r).WithError("missing parameters")) return } if !signup.IsValid() { - respondAlert(w, "invalid parameters", "", conf.SignupTemplate, http.StatusBadRequest) + w.WriteHeader(http.StatusBadRequest) + templates[conf.SignupTemplate].Execute(w, h.buildViewModel(r).WithError("invalid parameters")) return } _, created, err := h.userSrvc.CreateOrGet(&signup) if err != nil { - respondAlert(w, "failed to create new user", "", conf.SignupTemplate, http.StatusInternalServerError) + w.WriteHeader(http.StatusInternalServerError) + templates[conf.SignupTemplate].Execute(w, h.buildViewModel(r).WithError("failed to create new user")) return } if !created { - respondAlert(w, "user already existing", "", conf.SignupTemplate, http.StatusConflict) + w.WriteHeader(http.StatusConflict) + templates[conf.SignupTemplate].Execute(w, h.buildViewModel(r).WithError("user already existing")) return } msg := url.QueryEscape("account created successfully") http.Redirect(w, r, fmt.Sprintf("%s/?success=%s", h.config.Server.BasePath, msg), http.StatusFound) } + +func (h *HomeHandler) buildViewModel(r *http.Request) *view.HomeViewModel { + return &view.HomeViewModel{ + Success: r.URL.Query().Get("success"), + Error: r.URL.Query().Get("error"), + } +} diff --git a/routes/imprint.go b/routes/imprint.go new file mode 100644 index 0000000..554ef46 --- /dev/null +++ b/routes/imprint.go @@ -0,0 +1,41 @@ +package routes + +import ( + conf "github.com/muety/wakapi/config" + "github.com/muety/wakapi/models" + "github.com/muety/wakapi/models/view" + "github.com/muety/wakapi/services" + "net/http" +) + +type ImprintHandler struct { + config *conf.Config + keyValueSrvc *services.KeyValueService +} + +func NewImprintHandler(keyValueService *services.KeyValueService) *ImprintHandler { + return &ImprintHandler{ + config: conf.Get(), + keyValueSrvc: keyValueService, + } +} + +func (h *ImprintHandler) GetImprint(w http.ResponseWriter, r *http.Request) { + if h.config.IsDev() { + loadTemplates() + } + + text := "failed to load content" + if data, err := h.keyValueSrvc.GetString(models.ImprintKey); err == nil { + text = data.Value + } + + templates[conf.ImprintTemplate].Execute(w, h.buildViewModel(r).WithHtmlText(text)) +} + +func (h *ImprintHandler) buildViewModel(r *http.Request) *view.ImprintViewModel { + return &view.ImprintViewModel{ + Success: r.URL.Query().Get("success"), + Error: r.URL.Query().Get("error"), + } +} diff --git a/routes/routes.go b/routes/routes.go index e057d29..e3f42d5 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -6,7 +6,6 @@ import ( "github.com/muety/wakapi/utils" "html/template" "io/ioutil" - "net/http" "path" "strings" ) @@ -58,33 +57,3 @@ func loadTemplates() { templates[tplName] = tpl } } - -func respondAlert(w http.ResponseWriter, error, success, tplName string, status int) { - w.WriteHeader(status) - if tplName == "" { - tplName = config.IndexTemplate - } - templates[tplName].Execute(w, struct { - Error string - Success string - }{Error: error, Success: success}) -} - -// TODO: do better -func handleAlerts(w http.ResponseWriter, r *http.Request, tplName string) bool { - if err := r.URL.Query().Get("error"); err != "" { - if err == "unauthorized" { - respondAlert(w, err, "", tplName, http.StatusUnauthorized) - } else { - respondAlert(w, err, "", tplName, http.StatusInternalServerError) - } - return true - } - - if success := r.URL.Query().Get("success"); success != "" { - respondAlert(w, "", success, tplName, http.StatusOK) - return true - } - - return false -} diff --git a/routes/settings.go b/routes/settings.go index 07f9c35..87b6061 100644 --- a/routes/settings.go +++ b/routes/settings.go @@ -5,6 +5,7 @@ import ( "github.com/gorilla/schema" conf "github.com/muety/wakapi/config" "github.com/muety/wakapi/models" + "github.com/muety/wakapi/models/view" "github.com/muety/wakapi/services" "github.com/muety/wakapi/utils" "log" @@ -38,16 +39,7 @@ func (h *SettingsHandler) GetIndex(w http.ResponseWriter, r *http.Request) { loadTemplates() } - user := r.Context().Value(models.UserKey).(*models.User) - mappings, _ := h.languageMappingSrvc.GetByUser(user.ID) - data := map[string]interface{}{ - "User": user, - "LanguageMappings": mappings, - "Success": r.FormValue("success"), - "Error": r.FormValue("error"), - } - - templates[conf.SettingsTemplate].Execute(w, data) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r)) } func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request) { @@ -59,34 +51,40 @@ func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request var credentials models.CredentialsReset if err := r.ParseForm(); err != nil { - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("missing parameters")), http.StatusFound) + w.WriteHeader(http.StatusBadRequest) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("missing parameters")) return } if err := credentialsDecoder.Decode(&credentials, r.PostForm); err != nil { - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("missing parameters")), http.StatusFound) + w.WriteHeader(http.StatusBadRequest) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("missing parameters")) return } if !utils.CompareBcrypt(user.Password, credentials.PasswordOld, h.config.Security.PasswordSalt) { - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("invalid credentials")), http.StatusFound) + w.WriteHeader(http.StatusUnauthorized) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("invalid credentials")) return } if !credentials.IsValid() { - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("invalid parameters")), http.StatusFound) + w.WriteHeader(http.StatusBadRequest) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("invalid parameters")) return } user.Password = credentials.PasswordNew if hash, err := utils.HashBcrypt(user.Password, h.config.Security.PasswordSalt); err != nil { - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("internal server error")), http.StatusFound) + w.WriteHeader(http.StatusInternalServerError) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error")) return } else { user.Password = hash } if _, err := h.userSrvc.Update(user); err != nil { - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("internal server error")), http.StatusFound) + w.WriteHeader(http.StatusInternalServerError) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error")) return } @@ -96,7 +94,8 @@ func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request } encoded, err := h.config.Security.SecureCookie.Encode(models.AuthCookieKey, login) if err != nil { - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("internal server error")), http.StatusFound) + w.WriteHeader(http.StatusInternalServerError) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error")) return } @@ -109,7 +108,7 @@ func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request } http.SetCookie(w, cookie) - http.Redirect(w, r, fmt.Sprintf("%s/settings?success=%s", h.config.Server.BasePath, url.QueryEscape("password was updated successfully")), http.StatusFound) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("password was updated successfully")) } func (h *SettingsHandler) DeleteLanguageMapping(w http.ResponseWriter, r *http.Request) { @@ -120,7 +119,8 @@ func (h *SettingsHandler) DeleteLanguageMapping(w http.ResponseWriter, r *http.R user := r.Context().Value(models.UserKey).(*models.User) id, err := strconv.Atoi(r.PostFormValue("mapping_id")) if err != nil { - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("could not delete mapping")), http.StatusFound) + w.WriteHeader(http.StatusInternalServerError) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("could not delete mapping")) return } @@ -131,11 +131,12 @@ func (h *SettingsHandler) DeleteLanguageMapping(w http.ResponseWriter, r *http.R err = h.languageMappingSrvc.Delete(mapping) if err != nil { - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("could not delete mapping")), http.StatusFound) + w.WriteHeader(http.StatusInternalServerError) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("could not delete mapping")) return } - http.Redirect(w, r, fmt.Sprintf("%s/settings?success=%s", h.config.Server.BasePath, url.QueryEscape("mapping deleted successfully")), http.StatusFound) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("mapping deleted successfully")) } func (h *SettingsHandler) PostLanguageMapping(w http.ResponseWriter, r *http.Request) { @@ -157,11 +158,12 @@ func (h *SettingsHandler) PostLanguageMapping(w http.ResponseWriter, r *http.Req } if _, err := h.languageMappingSrvc.Create(mapping); err != nil { - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("mapping already exists")), http.StatusFound) + w.WriteHeader(http.StatusConflict) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("mapping already exists")) return } - http.Redirect(w, r, fmt.Sprintf("%s/settings?success=%s", h.config.Server.BasePath, url.QueryEscape("mapping added successfully")), http.StatusFound) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("mapping added successfully")) } func (h *SettingsHandler) PostResetApiKey(w http.ResponseWriter, r *http.Request) { @@ -171,12 +173,13 @@ func (h *SettingsHandler) PostResetApiKey(w http.ResponseWriter, r *http.Request user := r.Context().Value(models.UserKey).(*models.User) if _, err := h.userSrvc.ResetApiKey(user); err != nil { - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("internal server error")), http.StatusFound) + w.WriteHeader(http.StatusInternalServerError) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error")) return } msg := url.QueryEscape(fmt.Sprintf("your new api key is: %s", user.ApiKey)) - http.Redirect(w, r, fmt.Sprintf("%s/settings?success=%s", h.config.Server.BasePath, msg), http.StatusFound) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess(msg)) } func (h *SettingsHandler) PostToggleBadges(w http.ResponseWriter, r *http.Request) { @@ -186,11 +189,12 @@ func (h *SettingsHandler) PostToggleBadges(w http.ResponseWriter, r *http.Reques user := r.Context().Value(models.UserKey).(*models.User) if _, err := h.userSrvc.ToggleBadges(user); err != nil { - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("internal server error")), http.StatusFound) + w.WriteHeader(http.StatusInternalServerError) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error")) return } - http.Redirect(w, r, fmt.Sprintf("%s/settings", h.config.Server.BasePath), http.StatusFound) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r)) } func (h *SettingsHandler) PostRegenerateSummaries(w http.ResponseWriter, r *http.Request) { @@ -203,15 +207,28 @@ func (h *SettingsHandler) PostRegenerateSummaries(w http.ResponseWriter, r *http log.Printf("clearing summaries for user '%s'\n", user.ID) if err := h.summarySrvc.DeleteByUser(user.ID); err != nil { log.Printf("failed to clear summaries: %v\n", err) - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("failed to delete old summaries")), http.StatusFound) + w.WriteHeader(http.StatusInternalServerError) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("failed to delete old summaries")) return } if err := h.aggregationSrvc.Run(map[string]bool{user.ID: true}); err != nil { log.Printf("failed to regenerate summaries: %v\n", err) - http.Redirect(w, r, fmt.Sprintf("%s/settings?error=%s", h.config.Server.BasePath, url.QueryEscape("failed to generate aggregations")), http.StatusFound) + w.WriteHeader(http.StatusInternalServerError) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("failed to generate aggregations")) return } - http.Redirect(w, r, fmt.Sprintf("%s/settings?success=%s", h.config.Server.BasePath, url.QueryEscape("summaries are being regenerated – this may take a few second")), http.StatusFound) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("summaries are being regenerated – this may take a few seconds")) +} + +func (h *SettingsHandler) buildViewModel(r *http.Request) *view.SettingsViewModel { + user := r.Context().Value(models.UserKey).(*models.User) + mappings, _ := h.languageMappingSrvc.GetByUser(user.ID) + return &view.SettingsViewModel{ + User: user, + LanguageMappings: mappings, + Success: r.URL.Query().Get("success"), + Error: r.URL.Query().Get("error"), + } } diff --git a/routes/summary.go b/routes/summary.go index a81ba26..3f1745d 100644 --- a/routes/summary.go +++ b/routes/summary.go @@ -3,6 +3,7 @@ package routes import ( conf "github.com/muety/wakapi/config" "github.com/muety/wakapi/models" + "github.com/muety/wakapi/models/view" "github.com/muety/wakapi/services" "github.com/muety/wakapi/utils" "net/http" @@ -44,13 +45,15 @@ func (h *SummaryHandler) GetIndex(w http.ResponseWriter, r *http.Request) { summary, err, status := h.loadUserSummary(r) if err != nil { - respondAlert(w, err.Error(), "", conf.SummaryTemplate, status) + w.WriteHeader(status) + templates[conf.SummaryTemplate].Execute(w, h.buildViewModel(r).WithError(err.Error())) return } user := r.Context().Value(models.UserKey).(*models.User) if user == nil { - respondAlert(w, "unauthorized", "", conf.SummaryTemplate, http.StatusUnauthorized) + w.WriteHeader(http.StatusUnauthorized) + templates[conf.SummaryTemplate].Execute(w, h.buildViewModel(r).WithError("unauthorized")) return } @@ -78,3 +81,10 @@ func (h *SummaryHandler) loadUserSummary(r *http.Request) (*models.Summary, erro return summary, nil, http.StatusOK } + +func (h *SummaryHandler) buildViewModel(r *http.Request) *view.SummaryViewModel { + return &view.SummaryViewModel{ + Success: r.URL.Query().Get("success"), + Error: r.URL.Query().Get("error"), + } +} diff --git a/version.txt b/version.txt index 141f2e8..ace4423 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.15.0 +1.15.1