From 17c4778b307316b59de96a40b42992965c482617 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Sat, 17 Oct 2026 10:21:48 +0000 Subject: [PATCH] state: write every user column in UpdateUser --- hscontrol/state/persist_test.go | 39 +++++++++++++++++++++++++++++++++ hscontrol/state/state.go | 5 +++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/hscontrol/state/persist_test.go b/hscontrol/state/persist_test.go index b7bcbbb0e..0833bb04f 100644 --- a/hscontrol/state/persist_test.go +++ b/hscontrol/state/persist_test.go @@ -2311,3 +2311,42 @@ func TestReauthKeepsAnnouncedRoutes(t *testing.T) { assert.Equal(t, []netip.Prefix{route}, relogged.AnnouncedRoutes()) assert.Equal(t, []netip.Prefix{route}, s.GetNodePrimaryRoutes(nodeID)) } + +func TestUpdateUserClearsColumns(t *testing.T) { + _, s, nodeID := persistTestSetup(t) + t.Cleanup(func() { _ = s.Close() }) + + node, ok := s.GetNodeByID(nodeID) + require.True(t, ok) + + userID := types.UserID(node.UserID().Get()) + _, _, err := s.UpdateUser(userID, func(user *types.User) error { + user.DisplayName = "Display" + user.Email = "persist@example.com" + user.ProfilePicURL = "https://example.com/picture" + + return nil + }) + require.NoError(t, err) + _, _, err = s.RenameUser(userID, "renamed") + require.NoError(t, err) + user, err := s.GetUserByID(userID) + require.NoError(t, err) + assert.Equal(t, "Display", user.DisplayName) + assert.Equal(t, "persist@example.com", user.Email) + assert.Equal(t, "https://example.com/picture", user.ProfilePicURL) + _, _, err = s.UpdateUser(userID, func(user *types.User) error { + user.DisplayName = "" + user.Email = "" + user.ProfilePicURL = "" + + return nil + }) + require.NoError(t, err) + user, err = s.GetUserByID(userID) + require.NoError(t, err) + assert.Empty(t, user.DisplayName) + assert.Empty(t, user.Email) + assert.Empty(t, user.ProfilePicURL) + assert.Equal(t, "renamed", user.Name) +} diff --git a/hscontrol/state/state.go b/hscontrol/state/state.go index d2d1701b8..ec6160952 100644 --- a/hscontrol/state/state.go +++ b/hscontrol/state/state.go @@ -538,8 +538,9 @@ func (s *State) UpdateUser(userID types.UserID, updateFn func(*types.User) error return nil, err } - // Use Updates() to only update modified fields, preserving unchanged values. - err = tx.Updates(user).Error + // Select every column so cleared fields are written. Save would also + // insert the row again if a delete removed it meanwhile. + err = tx.Select("*").Updates(user).Error //nolint:unqueryvet // UPDATE, not a read if err != nil { return nil, fmt.Errorf("updating user: %w", err) }