From 3c59c31689c3120df834dc5ece3a2b2123b34eea Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 24 Jul 2024 23:01:44 -0700 Subject: [PATCH] show logged in user in web ui --- README.md | 4 +-- web/static/main.css | 30 +++++++++++++++++++++ web/templates.go | 60 +++++++++++++++++++++++++++++++++++++++-- web/templates/base.html | 13 ++++++++- 4 files changed, 102 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8122eea..b6b5a4e 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ This template is intended for use with [gonew](https://go.dev/blog/gonew), but c After you run gonew or update the package name manually, you will also want to: -* search for the string `go-project-template` and replace it with the name of your project. +* search for the string `go-project-template` and replace it with the name of your project, as that string appears in a few places other than the package name itself. * Rename the sample config file in the root from `go-project-template.sample.json` -* You might want to put a human-readable project name in the `` element in `httpserver/templates/base.html` +* You might want to put a human-readable project name in `httpserver/templates/base.html`, where `go-project-template` appears multiple times. * Rewrite this README ## Project Usage diff --git a/web/static/main.css b/web/static/main.css index c5c0376..76bf2d1 100644 --- a/web/static/main.css +++ b/web/static/main.css @@ -16,7 +16,37 @@ html, body { flex-grow: 1; } + header { + display: flex; + justify-content: space-between; + border-bottom: solid black 1px; + padding-bottom: 1em; +} + +footer { + display: flex; + justify-content: space-between; +} + +.version { + color: #aaa; + font-family: 'Courier New', Courier, monospace; + font-size: 8pt; +} + +.brand { font-size: 1.5em; font-weight: bold; } + +.btn-login { + background-color: #aaa; + border: solid #555 1px; + border-radius: 0.5em; + padding-top: 0.25em; + padding-bottom: 0.25em; + padding-left: 0.5em; + padding-right: 0.5em; + text-decoration: none; +} diff --git a/web/templates.go b/web/templates.go index 32e4c17..3023370 100644 --- a/web/templates.go +++ b/web/templates.go @@ -2,13 +2,18 @@ package web import ( "embed" + "errors" "fmt" "html/template" "io" "io/fs" "git.janky.solutions/finn/go-project-template/config" + "git.janky.solutions/finn/go-project-template/db" + "github.com/gorilla/sessions" + pgx "github.com/jackc/pgx/v5" echo "github.com/labstack/echo/v4" + "github.com/sirupsen/logrus" ) var ( @@ -50,11 +55,62 @@ func init() { type Template struct { } -func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error { +type templateData struct { + Authenticated bool + User db.User + Version string + Data any +} + +func (t *templateData) dataFromContext(c echo.Context) error { + sessionInterface := c.Get(contextKeySession) + if sessionInterface == nil { + return nil // no session, no data to populate + } + + session := sessionInterface.(*sessions.Session) + + userIDInterface, ok := session.Values[sessionValueAuthUser] + if !ok { + return nil + } + + userID, ok := userIDInterface.(int32) + if !ok { + logrus.WithField("userID", userIDInterface).Warn("unexpected session error: user ID is not an int32") + return errors.New("user ID is not an in32") + } + + ctx := c.Request().Context() + queries, conn, err := db.Get(ctx) + if err != nil { + return err + } + defer conn.Close(ctx) + + user, err := queries.GetUser(ctx, userID) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return nil + } + return err + } + + t.Authenticated = true + t.User = user + t.Version = fmt.Sprintf("%s %s", config.BuildInfo.Main.Path, config.Version) + + return nil +} + +func (t *Template) Render(w io.Writer, name string, data any, c echo.Context) error { + td := templateData{Data: data} + td.dataFromContext(c) + // Why does it work like this? because go's templating system doesn't handle multiple templates extending from a common base well // just doing it normally causes every template to render the same (the import form, at time of writing, probably the last template alphabetically) // https://stackoverflow.com/a/69244593/21894038 tmpl := template.Must(allTemplates.Clone()) tmpl = template.Must(tmpl.ParseFS(templatesSubFS, name)) - return tmpl.ExecuteTemplate(w, name, data) + return tmpl.ExecuteTemplate(w, name, td) } diff --git a/web/templates/base.html b/web/templates/base.html index 250b0e1..c809d54 100644 --- a/web/templates/base.html +++ b/web/templates/base.html @@ -10,11 +10,22 @@ <body> <div id="wrapper"> + <header> + <span class="brand">go-project-template</span> + <span class="right"> + {{ if .Authenticated }} + Signed in as <span class="username">{{ .User.Username }}</span> + {{ else }} + <a href="/auth/begin" class="btn-login">login</a> + {{ end }} + </span> + </header> <div id="main"> {{ block "body" .}}{{ end }} </div> <footer> - <code>{{ version }}</code> + <span></span> + <span class="version">{{ .Version }}</span> </footer> </div> </body>