From ff544f59bbafbaa4830d3c07dac049e8db6f4310 Mon Sep 17 00:00:00 2001 From: Jonni Liljamo Date: Tue, 22 Aug 2023 22:38:13 +0300 Subject: [PATCH] feat: some reworks and the first real interaction * that interaction being the ability to change your display name --- api/user_settings.go | 46 +++++++++++++++++++++++++++++ handlers/auth.go | 14 +++++---- handlers/settings.go | 29 ++++++++++++++++++ static/styles.css | 24 +++++++++++++++ template/templates/common/base.tmpl | 4 +-- template/templates/settings.tmpl | 11 +++++++ tixe.go | 15 +++++++--- types/user.go | 6 ++++ 8 files changed, 137 insertions(+), 12 deletions(-) create mode 100644 api/user_settings.go create mode 100644 handlers/settings.go create mode 100644 template/templates/settings.tmpl create mode 100644 types/user.go diff --git a/api/user_settings.go b/api/user_settings.go new file mode 100644 index 0000000..c6922f5 --- /dev/null +++ b/api/user_settings.go @@ -0,0 +1,46 @@ +package api + +import ( + "context" + "log" + "net/http" + "tixe/db" + "tixe/types" + + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" +) + +type postDisplayName struct { + DisplayName string `form:"display_name"` +} + +func UserUpdateDisplayName(c *gin.Context) { + data := &postDisplayName{} + if err := c.Bind(data); err != nil { + log.Printf("[tixe/api] ERROR: Could not bind display name update data: %v", err) + c.String(http.StatusBadRequest, "Could not bind display name update data") + return; + } + + session := sessions.Default(c) + user := session.Get("user").(types.User) + + _, err := db.PgPool.Exec(context.Background(), + "UPDATE users SET display_name = $1 WHERE id = $2", data.DisplayName, user.Id) + if err != nil { + log.Printf("[tixe/api] ERROR: Could not update display name in database: %v", err) + c.String(http.StatusInternalServerError, "Could not update display name in database") + return; + } + + // Update session data + session.Set("user", types.User { Id: user.Id, DisplayName: data.DisplayName }) + if err := session.Save(); err != nil { + log.Printf("[tixe/auth] ERROR: Failed to save session: %v", err) + c.String(http.StatusInternalServerError, "Failed to save session!") + return + } + + c.Redirect(http.StatusFound, "/settings") +} diff --git a/handlers/auth.go b/handlers/auth.go index d68f167..1b319ec 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -6,6 +6,7 @@ import ( "net/http" "tixe/auth" "tixe/db" + "tixe/types" "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" @@ -41,18 +42,19 @@ func AuthCallback(auth *auth.Auth) gin.HandlerFunc { } // Try to get the relevant details of the user - var userId string + var userId, userDisplayName string // idToken.Subject should be unique and should not change. // I think. Maybe. Possibly. Hopefully. scanErr := db.PgPool.QueryRow(context.Background(), - "SELECT id FROM users WHERE oidc_subject = $1", idToken.Subject).Scan(&userId) + "SELECT id, display_name FROM users WHERE oidc_subject = $1", idToken.Subject).Scan(&userId, &userDisplayName) if scanErr == pgx.ErrNoRows { log.Printf("[tixe/auth] New user detected logging in, creating entry in database") // The user does not exist in the db, create it userId = ulid.Make().String() + userDisplayName = profile["name"].(string) _, err = db.PgPool.Exec(context.Background(), "INSERT INTO users(id, display_name, oidc_subject) VALUES($1, $2, $3)", - userId, profile["name"].(string), idToken.Subject) + userId, userDisplayName, idToken.Subject) if err != nil { log.Printf("[tixe/auth] ERROR: Could not create database entry for oidc user") c.String(http.StatusInternalServerError, "Could not create database entry for oidc user") @@ -65,12 +67,12 @@ func AuthCallback(auth *auth.Auth) gin.HandlerFunc { return } - // The user_id field is read in other requests to read user data from the db - session.Set("user_id", userId) + // The user.Id field is read in other requests to read user data from the db + session.Set("user", types.User { Id: userId, DisplayName: userDisplayName }) session.Set("access_token", token.AccessToken) session.Set("profile", profile) if err := session.Save(); err != nil { - log.Printf("[tixe/auth] ERROR: Failed to save session") + log.Printf("[tixe/auth] ERROR: Failed to save session: %v", err) c.String(http.StatusInternalServerError, "Failed to save session!") return } diff --git a/handlers/settings.go b/handlers/settings.go new file mode 100644 index 0000000..15e8ada --- /dev/null +++ b/handlers/settings.go @@ -0,0 +1,29 @@ +package handlers + +import ( + "net/http" + "tixe/template" + "tixe/types" + + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" +) + +type SettingsData struct { +} + +func Settings(c *gin.Context) { + session := sessions.Default(c) + user := session.Get("user").(types.User) + + // This now comes from the session data, but kept as reference for other things + //var displayName string + //_ = db.PgPool.QueryRow(context.Background(), + // "SELECT display_name FROM users WHERE id = $1", user.Id).Scan(&displayName) + + settingsData := SettingsData { + } + + html := template.TmplEngine.Render("settings.tmpl", map[string]interface{}{"user": user, "data": settingsData}) + c.Data(http.StatusOK, "text/html", html) +} diff --git a/static/styles.css b/static/styles.css index 8789b75..a14b5dc 100644 --- a/static/styles.css +++ b/static/styles.css @@ -567,6 +567,11 @@ video { width: max-content; } +.w-fit { + width: -moz-fit-content; + width: fit-content; +} + .min-w-max { min-width: -moz-max-content; min-width: max-content; @@ -661,6 +666,10 @@ video { padding: 1rem; } +.p-1 { + padding: 0.25rem; +} + .text-lg { font-size: 1.125rem; line-height: 1.75rem; @@ -689,6 +698,16 @@ video { color: transparent; } +.placeholder-slate-800::-moz-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(30 41 59 / var(--tw-placeholder-opacity)); +} + +.placeholder-slate-800::placeholder { + --tw-placeholder-opacity: 1; + color: rgb(30 41 59 / var(--tw-placeholder-opacity)); +} + .opacity-0 { opacity: 0; } @@ -727,6 +746,11 @@ video { text-decoration-line: underline; } +.focus\:outline-none:focus { + outline: 2px solid transparent; + outline-offset: 2px; +} + .group:hover .group-hover\:visible { visibility: visible; } diff --git a/template/templates/common/base.tmpl b/template/templates/common/base.tmpl index 3c90bc5..406bac1 100644 --- a/template/templates/common/base.tmpl +++ b/template/templates/common/base.tmpl @@ -26,10 +26,10 @@
{{ if eq .notauthed true }} Not logged in - {{ else if ne .profile nil }} + {{ else if ne .user nil }}

Display Name

+
+ + +
+ +{{ end }} diff --git a/tixe.go b/tixe.go index 34d76d5..32d96e9 100644 --- a/tixe.go +++ b/tixe.go @@ -11,6 +11,7 @@ import ( "tixe/handlers" "tixe/middlewares" "tixe/template" + "tixe/types" "github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions/cookie" @@ -23,17 +24,17 @@ func ping(c *gin.Context) { func root(c *gin.Context) { session := sessions.Default(c) - profile := session.Get("profile") + user := session.Get("user") - html := template.TmplEngine.Render("index.tmpl", map[string]interface{}{"title": "tixë", "profile": profile}) + html := template.TmplEngine.Render("index.tmpl", map[string]interface{}{"title": "tixë", "user": user}) c.Data(http.StatusOK, "text/html", html) } func handleNoRoute(c *gin.Context) { session := sessions.Default(c) - profile := session.Get("profile") + user := session.Get("user") - html := template.TmplEngine.Render("404.tmpl", map[string]interface{}{"profile": profile}) + html := template.TmplEngine.Render("404.tmpl", map[string]interface{}{"user": user}) c.Data(http.StatusNotFound, "text/html", html) } @@ -41,7 +42,10 @@ func setupRouter(auth *auth.Auth) *gin.Engine { r := gin.Default() r.Static("/static", "./static") + // Register types that will be saved in sessions gob.Register(map[string]interface{}{}) + gob.Register(types.User{}) + store := cookie.NewStore([]byte(config.TixeConfig.CookieSecret)) r.Use(sessions.Sessions("auth-session", store)) @@ -60,10 +64,13 @@ func setupRouter(auth *auth.Auth) *gin.Engine { { reqAuth.GET("/", root) + reqAuth.GET("/settings", handlers.Settings) + apiRoute := reqAuth.Group("/api") { apiRoute.GET("/", api.Root) apiRoute.GET("/ping", ping) + apiRoute.POST("/settings/user/display_name", api.UserUpdateDisplayName) } } diff --git a/types/user.go b/types/user.go new file mode 100644 index 0000000..4d89014 --- /dev/null +++ b/types/user.go @@ -0,0 +1,6 @@ +package types + +type User struct { + Id string + DisplayName string +} -- 2.44.1