diff --git a/pkg/sqlite/migrations/58_postmigrate.go b/pkg/sqlite/migrations/58_postmigrate.go index 68516b50e..1afdd78e7 100644 --- a/pkg/sqlite/migrations/58_postmigrate.go +++ b/pkg/sqlite/migrations/58_postmigrate.go @@ -13,6 +13,7 @@ import ( "github.com/stashapp/stash/internal/manager/config" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/sqlite" + "github.com/stashapp/stash/pkg/utils" ) type schema58Migrator struct { @@ -93,6 +94,31 @@ func (m *schema58Migrator) fromSnakeCaseValue(val interface{}) interface{} { } } +// renameKey renames a fully qualified key name in a map +func (m *schema58Migrator) renameKey(mm map[string]interface{}, from, to string) { + nm := utils.NestedMap(mm) + v, found := nm.Get(from) + if !found { + return + } + + nm.Delete(from) + nm.Set(to, v) +} + +func (m *schema58Migrator) renameFrontPageContentKeys(ui map[string]interface{}) { + frontPageContent, found := ui["frontPageContent"].([]interface{}) + if !found { + return + } + + for _, v := range frontPageContent { + vm := v.(map[string]interface{}) + m.renameKey(vm, "savedfilterid", "savedFilterId") + m.renameKey(vm, "sortby", "sortBy") + } +} + func (m *schema58Migrator) migrateConfig() error { c := config.GetInstance() @@ -120,6 +146,10 @@ func (m *schema58Migrator) migrateConfig() error { ui := c.GetUIConfiguration() if ui != nil { ui = m.fromSnakeCaseMap(ui) + + // find and rename specific frontEndPage keys + m.renameFrontPageContentKeys(ui) + c.SetUIConfiguration(ui) } diff --git a/pkg/utils/map.go b/pkg/utils/map.go index ad3c51024..0c5558574 100644 --- a/pkg/utils/map.go +++ b/pkg/utils/map.go @@ -47,6 +47,23 @@ func (m NestedMap) Set(key string, value interface{}) { current[fields[len(fields)-1]] = value } +func (m NestedMap) Delete(key string) { + fields := strings.Split(key, ".") + + current := m + + for _, f := range fields[:len(fields)-1] { + v, ok := current[f].(map[string]interface{}) + if !ok { + return + } + + current = v + } + + delete(current, fields[len(fields)-1]) +} + // MergeMaps merges src into dest. If a key exists in both maps, the value from src is used. func MergeMaps(dest map[string]interface{}, src map[string]interface{}) { for k, v := range src { diff --git a/pkg/utils/map_test.go b/pkg/utils/map_test.go index d8e8a2db8..54dfacedd 100644 --- a/pkg/utils/map_test.go +++ b/pkg/utils/map_test.go @@ -122,6 +122,69 @@ func TestNestedMapSet(t *testing.T) { } } +func TestNestedMapDelete(t *testing.T) { + tests := []struct { + name string + key string + existing NestedMap + want NestedMap + }{ + { + name: "Delete non existing value", + key: "foo.bar.baa", + existing: NestedMap{ + "foo": map[string]interface{}{ + "bar": map[string]interface{}{ + "baz": "qux", + }, + }, + }, + want: NestedMap{ + "foo": map[string]interface{}{ + "bar": map[string]interface{}{ + "baz": "qux", + }, + }, + }, + }, + { + name: "Delete existing value", + key: "foo.bar", + existing: NestedMap{ + "foo": map[string]interface{}{ + "bar": "old", + }, + }, + want: NestedMap{ + "foo": map[string]interface{}{}, + }, + }, + { + name: "Delete existing map", + key: "foo.bar", + existing: NestedMap{ + "foo": map[string]interface{}{ + "bar": map[string]interface{}{ + "baz": "qux", + }, + }, + }, + want: NestedMap{ + "foo": map[string]interface{}{}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.existing.Delete(tt.key) + if !reflect.DeepEqual(tt.existing, tt.want) { + t.Errorf("NestedMap.Set() got = %v, want %v", tt.existing, tt.want) + } + }) + } +} + func TestMergeMaps(t *testing.T) { tests := []struct { name string