From 9dbc4751459c60e26794e4662992536f2718d69a Mon Sep 17 00:00:00 2001 From: leo Date: Sat, 6 May 2023 21:50:35 +0200 Subject: [PATCH] go: implement the Echo renderer for templates --- app/routes.go | 1 + handlers/handlers.go | 110 ++++++++++++------------------------------ handlers/helper.go | 15 +++--- handlers/templates.go | 22 +++++++++ 4 files changed, 61 insertions(+), 87 deletions(-) create mode 100644 handlers/templates.go diff --git a/app/routes.go b/app/routes.go index 966b177..0363efa 100644 --- a/app/routes.go +++ b/app/routes.go @@ -16,6 +16,7 @@ func (a *App) SetupRoutes() { // run this before declaring any handler funcs. handlers.InitHandlers(setting, tmpls) + e.Renderer = handlers.Renderer // keep /static/* as a compatibility fallback for /assets. e.GET( diff --git a/handlers/handlers.go b/handlers/handlers.go index 894dbf3..3f17ac9 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -23,7 +23,7 @@ type tplMap map[string]*template.Template var ( // tmpl *template.Template. - tmpls = template.New("") + // tmpls = template.New(""). templateMap tplMap tmplFS fs.FS bluemondayPolicy = bluemonday.UGCPolicy() @@ -65,13 +65,13 @@ func initTemplates(f fs.FS) { tmplFS = f } - setFuncMap(tmpls) + setFuncMap(Renderer.tmpls) allTmpls := listAllTmpls() // ensure this fails at compile time, if at all ("Must"). - tmpls = template.Must(tmpls.ParseFS(tmplFS, allTmpls...)) - makeTplMap(tmpls) + Renderer.tmpls = template.Must(Renderer.tmpls.ParseFS(tmplFS, allTmpls...)) + makeTplMap(Renderer.tmpls) } func makeTplMap(tpl *template.Template) { @@ -105,10 +105,10 @@ func getTmpl(name string) *template.Template { allTmpls := listAllTmpls() // ensure this fails at compile time, if at all ("Must"). - tmpls = template.Must(tpl.ParseFS(tmplFS, allTmpls...)) + Renderer.tmpls = template.Must(tpl.ParseFS(tmplFS, allTmpls...)) } - return tmpls.Lookup(name) + return Renderer.tmpls.Lookup(name) } func Admin() echo.HandlerFunc { @@ -157,9 +157,9 @@ func Signin() echo.HandlerFunc { return c.Redirect(http.StatusFound, "/home") } - tpl := getTmpl("signin.tmpl") - - err := tpl.Execute(c.Response().Writer, + return c.Render( + http.StatusOK, + "signin.tmpl", page{ AppName: setting.AppName(), AppVer: appver, @@ -168,11 +168,6 @@ func Signin() echo.HandlerFunc { Current: "signin", }, ) - if err != nil { - return err - } - - return nil } } @@ -246,16 +241,12 @@ func SigninPost(client *ent.Client) echo.HandlerFunc { if err != nil { c.Logger().Error("failed to save session") - err = renderErrorPage( - c.Response().Writer, + return renderErrorPage( + c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)+" (make sure you've got cookies enabled)", err.Error(), ) - - if err != nil { - return err - } } } @@ -275,8 +266,6 @@ func Signup() echo.HandlerFunc { } } - tpl := getTmpl("signup.tmpl") - csrf := c.Get("csrf").(string) // secure := c.Request().URL.Scheme == "https" @@ -291,7 +280,9 @@ func Signup() echo.HandlerFunc { // } // c.SetCookie(cookieCSRF) - err := tpl.Execute(c.Response().Writer, + err := c.Render( + http.StatusOK, + "signup.tmpl", page{ AppName: setting.AppName(), AppVer: appver, @@ -304,16 +295,12 @@ func Signup() echo.HandlerFunc { if err != nil { log.Warnf("error: %q", err) - err = renderErrorPage( - c.Response().Writer, + return renderErrorPage( + c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), err.Error(), ) - - if err != nil { - return err - } } return nil @@ -360,7 +347,7 @@ func SignupPost(client *ent.Client) echo.HandlerFunc { c.Logger().Error("error checking whether user exists", err) return renderErrorPage( - c.Response().Writer, + c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), err.Error(), @@ -387,18 +374,13 @@ func SignupPost(client *ent.Client) echo.HandlerFunc { // stating what went wrong. return c.Redirect(http.StatusSeeOther, "/signup") } - // TODO: don't return the error to the user, perhaps based - // on the devel mode. - err = renderErrorPage( - c.Response().Writer, + + return renderErrorPage( + c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)+" - failed to create schema resources", err.Error(), ) - if err != nil { - c.Logger().Error("error: %q", err) - return err - } } log.Infof("successfully registered user '%s'", username) @@ -421,16 +403,12 @@ func SignupPost(client *ent.Client) echo.HandlerFunc { if err != nil { c.Logger().Error("failed to save session") - err = renderErrorPage( - c.Response().Writer, + return renderErrorPage( + c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)+" (make sure you've got cookies enabled)", err.Error(), ) - - if err != nil { - return err - } } return c.Redirect(http.StatusMovedPermanently, "/home") @@ -441,8 +419,6 @@ func Home(client *ent.Client) echo.HandlerFunc { return func(c echo.Context) error { var username string - tpl := getTmpl("home.tmpl") - sess, _ := session.Get(setting.SessionCookieName(), c) if sess == nil { log.Info("no session, redirecting to /signin", "endpoint", "/home") @@ -483,20 +459,15 @@ func Home(client *ent.Client) echo.HandlerFunc { } else { c.Logger().Error("failed to query usr", username) - err = renderErrorPage( - c.Response().Writer, + return renderErrorPage( + c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)+" failed to query usr (make sure you've got cookies enabled)", err.Error(), ) - if err != nil { - return err - } - - return err } - err := tpl.Execute(c.Response().Writer, + err := c.Render(http.StatusInternalServerError, "home.tmpl", page{ AppName: setting.AppName(), AppVer: appver, @@ -508,24 +479,13 @@ func Home(client *ent.Client) echo.HandlerFunc { }, ) if err != nil { - log.Warnf("error: %q", err) - c.Logger().Errorf("error: %q", err) - err = renderErrorPage( - c.Response().Writer, + return renderErrorPage( + c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), err.Error(), ) - - if err != nil { - c.Logger().Errorf("error: %q", err) - - return echo.NewHTTPError( - http.StatusInternalServerError, - http.StatusText(http.StatusInternalServerError), - ) - } } return nil @@ -554,9 +514,9 @@ func Logout() echo.HandlerFunc { return c.Redirect(http.StatusMovedPermanently, "/logout") case c.Request().Method == "GET": - tpl := getTmpl("logout.tmpl") - - err := tpl.Execute(c.Response().Writer, + err := c.Render( + http.StatusOK, + "logout.tmpl", page{ AppName: setting.AppName(), AppVer: appver, @@ -568,18 +528,12 @@ func Logout() echo.HandlerFunc { if err != nil { c.Logger().Errorf("error: %q", err) - err = renderErrorPage( - c.Response().Writer, + return renderErrorPage( + c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), err.Error(), ) - - if err != nil { - c.Logger().Errorf("error: %q", err) - - return err - } } } diff --git a/handlers/helper.go b/handlers/helper.go index bc7012d..23c2add 100644 --- a/handlers/helper.go +++ b/handlers/helper.go @@ -2,15 +2,17 @@ package handlers import ( "fmt" - "io" "strconv" + + "github.com/labstack/echo/v4" ) -func renderErrorPage(wr io.Writer, status int, statusText, error string) error { - tpl := getTmpl("errorPage.tmpl") +func renderErrorPage(c echo.Context, status int, statusText, error string) error { strStatus := strconv.Itoa(status) - err := tpl.Execute(wr, + return c.Render( + status, + "errorPage.tmpl", page{ AppName: setting.AppName(), AppVer: appver, @@ -22,9 +24,4 @@ func renderErrorPage(wr io.Writer, status int, statusText, error string) error { StatusText: statusText, }, ) - if err != nil { - return err - } - - return nil } diff --git a/handlers/templates.go b/handlers/templates.go new file mode 100644 index 0000000..3c7e8d4 --- /dev/null +++ b/handlers/templates.go @@ -0,0 +1,22 @@ +package handlers + +import ( + "html/template" + "io" + + "github.com/labstack/echo/v4" +) + +type TemplateRenderer struct { + tmpls *template.Template +} + +var Renderer = &TemplateRenderer{tmpls: template.New("")} + +func (t *TemplateRenderer) Render(w io.Writer, name string, data any, c echo.Context) error { + c.Logger().Debugf("rendering template %s", name) + + tpl := getTmpl(name) + + return tpl.Execute(w, data) +}