fix(auth): new users inherit the system-wide default timezone

default_timezone existed as a system setting (admin-editable, exposed
via SettingsRegistry.DefaultTimezone) but nothing read it at user
creation — the CreateUser query didn't even carry the column, so every
new user got the DB default UTC regardless. Both creation paths
(public register + admin create) now seed the user's timezone from the
setting, validated with time.LoadLocation and falling back to UTC when
unwired/empty/invalid.

Test-infra fixes surfaced by the run: TestUpdateProfileSelfEdit was
self-editing the SHARED admin (renaming it past the harness cleanup's
preserve-list, leaking a second admin row that broke the last-admin
tests) — it now edits a dedicated user with a unique name; the
last-admin tests get an ensureSingleAdmin precondition helper; the
websocket collection name is run-unique (non-test names persist in the
shared DB and UNIQUE(user_id,name) 409s on rerun).
This commit is contained in:
John O'Keefe committed 2026-10-13 13:17:12 -04:00
1 parent bc6ce41762
commit 740213f0a4
9 files changed
+108 -14

No files matched your search

+20
View File
@@ -39,6 +39,23 @@ var SessionDurationSec = int(DefaultSessionDuration.Seconds())
// SetSettings wires the tunable settings registry (optional).
func (h *AuthHandler) SetSettings(s *database.SettingsRegistry) { h.settings = s }
// defaultTimezone returns the system-wide default timezone for new users.
// Falls back to UTC when no registry is wired, the setting is empty, or
// the value is not a valid IANA location.
func (h *AuthHandler) defaultTimezone() string {
if h.settings == nil {
return "UTC"
}
tz := h.settings.DefaultTimezone()
if tz == "" {
return "UTC"
}
if _, err := time.LoadLocation(tz); err != nil {
return "UTC"
}
return tz
}
// sessionDuration returns the active session duration from the registry.
func (h *AuthHandler) sessionDuration() time.Duration {
if h.settings != nil {
@@ -263,6 +280,7 @@ func (h *AuthHandler) Register(c *echo.Context) error {
LastName: pgtype.Text{String: req.LastName, Valid: req.LastName != ""},
Theme: pgtype.Text{String: "tokyo-night", Valid: true},
Role: userRole,
Timezone: pgtype.Text{String: h.defaultTimezone(), Valid: true},
})
if err != nil {
if c.Request().Header.Get("HX-Request") == "true" {
@@ -735,6 +753,7 @@ func (h *AuthHandler) AdminCreateUser(c *echo.Context) error {
LastName: pgtype.Text{String: req.LastName, Valid: req.LastName != ""},
Theme: pgtype.Text{String: "tokyo-night", Valid: true},
Role: role,
Timezone: pgtype.Text{String: h.defaultTimezone(), Valid: true},
})
if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
@@ -756,6 +775,7 @@ func (h *AuthHandler) AdminCreateUser(c *echo.Context) error {
"email": user.Email,
"username": user.Username,
"role": user.Role,
"timezone": user.Timezone,
"created_at": user.CreatedAt,
})
}