mirror of
https://github.com/usememos/memos.git
synced 2025-11-11 18:00:53 +08:00
chore: simplify update user settings
This commit is contained in:
parent
d86756f104
commit
76ca258f23
2 changed files with 38 additions and 218 deletions
|
|
@ -385,11 +385,46 @@ func (s *APIV1Service) UpdateUserSetting(ctx context.Context, request *v1pb.Upda
|
|||
return nil, status.Errorf(codes.NotFound, "%s not found", storeKey.String())
|
||||
}
|
||||
|
||||
// merge only the fields specified by UpdateMask
|
||||
merged := mergeUserSettingWithMask(existingUserSetting, request.Setting, storeKey, request.UpdateMask.Paths)
|
||||
// Only GENERAL settings are supported via UpdateUserSetting
|
||||
// Other setting types have dedicated service methods
|
||||
if storeKey != storepb.UserSetting_GENERAL {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "setting type %s should not be updated via UpdateUserSetting", storeKey.String())
|
||||
}
|
||||
|
||||
// Start with existing general setting values
|
||||
existingGeneral := existingUserSetting.GetGeneral()
|
||||
updatedGeneral := &v1pb.UserSetting_GeneralSetting{
|
||||
Appearance: existingGeneral.GetAppearance(),
|
||||
MemoVisibility: existingGeneral.GetMemoVisibility(),
|
||||
Locale: existingGeneral.GetLocale(),
|
||||
Theme: existingGeneral.GetTheme(),
|
||||
}
|
||||
|
||||
// Apply updates for fields specified in the update mask
|
||||
incomingGeneral := request.Setting.GetGeneralSetting()
|
||||
for _, field := range request.UpdateMask.Paths {
|
||||
switch field {
|
||||
case "appearance":
|
||||
updatedGeneral.Appearance = incomingGeneral.Appearance
|
||||
case "memoVisibility":
|
||||
updatedGeneral.MemoVisibility = incomingGeneral.MemoVisibility
|
||||
case "theme":
|
||||
updatedGeneral.Theme = incomingGeneral.Theme
|
||||
case "locale":
|
||||
updatedGeneral.Locale = incomingGeneral.Locale
|
||||
}
|
||||
}
|
||||
|
||||
// Create the updated setting
|
||||
updatedSetting := &v1pb.UserSetting{
|
||||
Name: request.Setting.Name,
|
||||
Value: &v1pb.UserSetting_GeneralSetting_{
|
||||
GeneralSetting: updatedGeneral,
|
||||
},
|
||||
}
|
||||
|
||||
// Convert API setting to store setting
|
||||
storeSetting, err := convertUserSettingToStore(merged, userID, storeKey)
|
||||
storeSetting, err := convertUserSettingToStore(updatedSetting, userID, storeKey)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "failed to convert setting: %v", err)
|
||||
}
|
||||
|
|
@ -1335,72 +1370,3 @@ func (s *APIV1Service) validateUserFilter(_ context.Context, filterStr string) e
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mergeUserSettingWithMask(existing *storepb.UserSetting, incoming *v1pb.UserSetting, key storepb.UserSetting_Key, paths []string) *v1pb.UserSetting {
|
||||
if incoming == nil {
|
||||
return &v1pb.UserSetting{}
|
||||
}
|
||||
|
||||
switch key {
|
||||
case storepb.UserSetting_GENERAL:
|
||||
var gs *v1pb.UserSetting_GeneralSetting
|
||||
|
||||
if existing == nil {
|
||||
gs = &v1pb.UserSetting_GeneralSetting{
|
||||
Locale: "en",
|
||||
Appearance: "system",
|
||||
MemoVisibility: "PRIVATE",
|
||||
Theme: "",
|
||||
}
|
||||
} else {
|
||||
gs = &v1pb.UserSetting_GeneralSetting{
|
||||
Appearance: existing.GetGeneral().GetAppearance(),
|
||||
MemoVisibility: existing.GetGeneral().GetMemoVisibility(),
|
||||
Locale: existing.GetGeneral().GetLocale(),
|
||||
Theme: existing.GetGeneral().GetTheme(),
|
||||
}
|
||||
}
|
||||
|
||||
for _, field := range paths {
|
||||
switch field {
|
||||
case "appearance":
|
||||
gs.Appearance = incoming.GetGeneralSetting().Appearance
|
||||
case "memoVisibility":
|
||||
gs.MemoVisibility = incoming.GetGeneralSetting().MemoVisibility
|
||||
case "theme":
|
||||
gs.Theme = incoming.GetGeneralSetting().Theme
|
||||
case "locale":
|
||||
gs.Locale = incoming.GetGeneralSetting().Locale
|
||||
}
|
||||
}
|
||||
|
||||
return &v1pb.UserSetting{
|
||||
Name: incoming.Name,
|
||||
Value: &v1pb.UserSetting_GeneralSetting_{
|
||||
GeneralSetting: gs,
|
||||
},
|
||||
}
|
||||
|
||||
case storepb.UserSetting_SHORTCUTS:
|
||||
// handled by the FE calling shortcut_service.CreateShortcut
|
||||
// if the FE wants to modify shortcuts by calling the user_service we need to handle below
|
||||
|
||||
return incoming
|
||||
case storepb.UserSetting_WEBHOOKS:
|
||||
// handled by the FE calling user_service.CreateUserWebhook
|
||||
// if the FE wants to modify webhooks by calling the user_service we need to handle below
|
||||
|
||||
return incoming
|
||||
case storepb.UserSetting_ACCESS_TOKENS:
|
||||
// handled by the FE calling user_service.CreateUserAccessToken
|
||||
// if the FE wants to modify access tokens by calling the user_service we need to handle below
|
||||
|
||||
return incoming
|
||||
case storepb.UserSetting_SESSIONS:
|
||||
// handled by the FE calling auth_service.CreateSession
|
||||
// if the FE wants to modify sessions by calling the user_service we need to handle below
|
||||
return incoming
|
||||
default:
|
||||
return incoming
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,146 +0,0 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
v1pb "github.com/usememos/memos/proto/gen/api/v1"
|
||||
storepb "github.com/usememos/memos/proto/gen/store"
|
||||
)
|
||||
|
||||
func TestMergeUserSettingWithMask(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
existing *storepb.UserSetting
|
||||
incoming *v1pb.UserSetting
|
||||
key storepb.UserSetting_Key
|
||||
paths []string
|
||||
expected *v1pb.UserSetting
|
||||
}{
|
||||
{
|
||||
name: "adds new field without removing existing fields",
|
||||
existing: &storepb.UserSetting{
|
||||
UserId: 1,
|
||||
Key: storepb.UserSetting_GENERAL,
|
||||
Value: &storepb.UserSetting_General{
|
||||
General: &storepb.GeneralUserSetting{
|
||||
MemoVisibility: "PROTECTED",
|
||||
},
|
||||
},
|
||||
},
|
||||
incoming: &v1pb.UserSetting{
|
||||
Value: &v1pb.UserSetting_GeneralSetting_{
|
||||
GeneralSetting: &v1pb.UserSetting_GeneralSetting{
|
||||
Appearance: "light",
|
||||
},
|
||||
},
|
||||
},
|
||||
key: storepb.UserSetting_GENERAL,
|
||||
paths: []string{"appearance"},
|
||||
expected: &v1pb.UserSetting{
|
||||
Value: &v1pb.UserSetting_GeneralSetting_{
|
||||
GeneralSetting: &v1pb.UserSetting_GeneralSetting{
|
||||
Appearance: "light",
|
||||
MemoVisibility: "PROTECTED",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "adds new field when no existing fields exist",
|
||||
existing: &storepb.UserSetting{
|
||||
UserId: 1,
|
||||
Key: storepb.UserSetting_GENERAL,
|
||||
Value: &storepb.UserSetting_General{},
|
||||
},
|
||||
incoming: &v1pb.UserSetting{
|
||||
Value: &v1pb.UserSetting_GeneralSetting_{
|
||||
GeneralSetting: &v1pb.UserSetting_GeneralSetting{
|
||||
Theme: "whitewall",
|
||||
},
|
||||
},
|
||||
},
|
||||
key: storepb.UserSetting_GENERAL,
|
||||
paths: []string{"theme"},
|
||||
expected: &v1pb.UserSetting{
|
||||
Value: &v1pb.UserSetting_GeneralSetting_{
|
||||
GeneralSetting: &v1pb.UserSetting_GeneralSetting{
|
||||
Theme: "whitewall",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "updates existing field without removing existing fields",
|
||||
existing: &storepb.UserSetting{
|
||||
UserId: 1,
|
||||
Key: storepb.UserSetting_GENERAL,
|
||||
Value: &storepb.UserSetting_General{
|
||||
General: &storepb.GeneralUserSetting{
|
||||
Appearance: "dark",
|
||||
MemoVisibility: "PUBLIC",
|
||||
},
|
||||
},
|
||||
},
|
||||
incoming: &v1pb.UserSetting{
|
||||
Value: &v1pb.UserSetting_GeneralSetting_{
|
||||
GeneralSetting: &v1pb.UserSetting_GeneralSetting{
|
||||
Appearance: "light",
|
||||
},
|
||||
},
|
||||
},
|
||||
key: storepb.UserSetting_GENERAL,
|
||||
paths: []string{"appearance"},
|
||||
expected: &v1pb.UserSetting{
|
||||
Value: &v1pb.UserSetting_GeneralSetting_{
|
||||
GeneralSetting: &v1pb.UserSetting_GeneralSetting{
|
||||
Appearance: "light",
|
||||
MemoVisibility: "PUBLIC",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "updates multiple fields without removing existing fields",
|
||||
existing: &storepb.UserSetting{
|
||||
UserId: 1,
|
||||
Key: storepb.UserSetting_GENERAL,
|
||||
Value: &storepb.UserSetting_General{
|
||||
General: &storepb.GeneralUserSetting{
|
||||
Appearance: "system",
|
||||
},
|
||||
},
|
||||
},
|
||||
incoming: &v1pb.UserSetting{
|
||||
Value: &v1pb.UserSetting_GeneralSetting_{
|
||||
GeneralSetting: &v1pb.UserSetting_GeneralSetting{
|
||||
Appearance: "dark",
|
||||
Theme: "paper",
|
||||
MemoVisibility: "PROTECTED",
|
||||
},
|
||||
},
|
||||
},
|
||||
key: storepb.UserSetting_GENERAL,
|
||||
paths: []string{"theme", "memoVisibility", "appearance"},
|
||||
expected: &v1pb.UserSetting{
|
||||
Value: &v1pb.UserSetting_GeneralSetting_{
|
||||
GeneralSetting: &v1pb.UserSetting_GeneralSetting{
|
||||
Appearance: "dark",
|
||||
MemoVisibility: "PROTECTED",
|
||||
Theme: "paper",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
actual := mergeUserSettingWithMask(tt.existing, tt.incoming, tt.key, tt.paths)
|
||||
|
||||
if !reflect.DeepEqual(actual, tt.expected) {
|
||||
t.Errorf("expected %v but got %v", tt.expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue