fix(platform): 外观主题 - 保证经典黑白主题不可被修改或删除
This commit is contained in:
@@ -47,8 +47,12 @@ func TestAppearanceButtonFillRoundTripAndValidation(t *testing.T) {
|
||||
})
|
||||
}
|
||||
input.SkinThemes[0].Tokens.Buttons.Light.Start = "#000000"
|
||||
if _, err := svc.UpdateAppearance(admin, input); err == nil {
|
||||
t.Fatal("classic fill mutation accepted")
|
||||
overwritten, err := svc.UpdateAppearance(admin, input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if overwritten.SkinThemes[0].Tokens.Buttons != defaultClassicAppearanceSkin().Tokens.Buttons {
|
||||
t.Fatal("classic fill mutation was stored")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -262,11 +262,20 @@ func normalizeAppearanceSkinThemes(themes []AppearanceSkinTheme) []AppearanceSki
|
||||
result := make([]AppearanceSkinTheme, len(themes))
|
||||
copy(result, themes)
|
||||
builtins := defaultAppearanceSkinThemes()
|
||||
classic := defaultClassicAppearanceSkin()
|
||||
replacedClassic := false
|
||||
for index := range result {
|
||||
result[index].ID = strings.ToLower(strings.TrimSpace(result[index].ID))
|
||||
if result[index].ID == defaultAppearanceSkinID {
|
||||
// The system default is not editable. Whatever was submitted is
|
||||
// discarded so a drifted client copy cannot reject the whole save.
|
||||
result[index] = classic
|
||||
replacedClassic = true
|
||||
continue
|
||||
}
|
||||
result[index].Name = strings.TrimSpace(result[index].Name)
|
||||
result[index].Description = strings.TrimSpace(result[index].Description)
|
||||
result[index].Locked = result[index].ID == defaultAppearanceSkinID
|
||||
result[index].Locked = false
|
||||
// Only a wholly absent legacy button block is upgraded. Partial or
|
||||
// malformed submitted parameters remain invalid on the write path.
|
||||
if result[index].Tokens.Buttons == (AppearanceSkinButtons{}) {
|
||||
@@ -285,6 +294,12 @@ func normalizeAppearanceSkinThemes(themes []AppearanceSkinTheme) []AppearanceSki
|
||||
normalizeAppearanceSkinModeColors(&result[index].Tokens.Dark)
|
||||
result[index].Tokens.Components.ShadowStyle = strings.ToLower(strings.TrimSpace(result[index].Tokens.Components.ShadowStyle))
|
||||
}
|
||||
if !replacedClassic {
|
||||
if len(result) >= maxAppearanceSkinThemes {
|
||||
result = result[:maxAppearanceSkinThemes-1]
|
||||
}
|
||||
result = append([]AppearanceSkinTheme{classic}, result...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -329,8 +344,6 @@ func validateAppearanceSkinThemes(themes []AppearanceSkinTheme, selectedID strin
|
||||
}
|
||||
seen := make(map[string]struct{}, len(themes))
|
||||
foundSelected := false
|
||||
foundClassic := false
|
||||
classic := defaultClassicAppearanceSkin()
|
||||
for _, skin := range themes {
|
||||
if !appearanceSkinIDPattern.MatchString(skin.ID) {
|
||||
return BadAuthRequest("皮肤主题 ID 无效")
|
||||
@@ -342,12 +355,6 @@ func validateAppearanceSkinThemes(themes []AppearanceSkinTheme, selectedID strin
|
||||
if skin.ID == selectedID {
|
||||
foundSelected = true
|
||||
}
|
||||
if skin.ID == defaultAppearanceSkinID {
|
||||
foundClassic = true
|
||||
if skin.Name != classic.Name || skin.Description != classic.Description || !reflect.DeepEqual(skin.Tokens, classic.Tokens) {
|
||||
return BadAuthRequest("经典黑白为系统默认主题,不能修改或删除")
|
||||
}
|
||||
}
|
||||
if err := validateAppearanceSkinText(skin.Name, "皮肤主题名称", 40, true); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -369,9 +376,6 @@ func validateAppearanceSkinThemes(themes []AppearanceSkinTheme, selectedID strin
|
||||
}
|
||||
}
|
||||
}
|
||||
if !foundClassic {
|
||||
return BadAuthRequest("经典黑白为系统默认主题,不能修改或删除")
|
||||
}
|
||||
if !foundSelected {
|
||||
return BadAuthRequest("当前启用的皮肤主题不存在")
|
||||
}
|
||||
|
||||
@@ -452,17 +452,25 @@ func TestAppearanceSkinLibrarySupportsEditableCopiesAndProtectsClassic(t *testin
|
||||
t.Fatalf("custom skin round trip = %#v", updated)
|
||||
}
|
||||
|
||||
classic := defaultClassicAppearanceSkin()
|
||||
withoutClassic := append([]AppearanceSkinTheme(nil), themes[1:]...)
|
||||
_, err = svc.UpdateAppearance(admin, AppearanceSetting{BrandName: "HIMA Studio", BrandSlug: "hima-studio", AuthHeroTitle: defaultAppearanceHeroTitle, SkinID: custom.ID, SkinThemes: withoutClassic})
|
||||
if err == nil || !strings.Contains(err.Error(), "不能修改或删除") {
|
||||
t.Fatalf("missing classic error = %v", err)
|
||||
restored, err := svc.UpdateAppearance(admin, AppearanceSetting{BrandName: "HIMA Studio", BrandSlug: "hima-studio", AuthHeroTitle: defaultAppearanceHeroTitle, SkinID: custom.ID, SkinThemes: withoutClassic})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if restored.SkinThemes[0] != classic {
|
||||
t.Fatalf("missing classic was not restored = %#v", restored.SkinThemes[0])
|
||||
}
|
||||
|
||||
mutatedClassic := append([]AppearanceSkinTheme(nil), themes...)
|
||||
mutatedClassic[0].Name = "改名"
|
||||
_, err = svc.UpdateAppearance(admin, AppearanceSetting{BrandName: "HIMA Studio", BrandSlug: "hima-studio", AuthHeroTitle: defaultAppearanceHeroTitle, SkinID: custom.ID, SkinThemes: mutatedClassic})
|
||||
if err == nil || !strings.Contains(err.Error(), "不能修改或删除") {
|
||||
t.Fatalf("mutated classic error = %v", err)
|
||||
mutatedClassic[0].Tokens.Light.Primary = "#000000"
|
||||
overwritten, err := svc.UpdateAppearance(admin, AppearanceSetting{BrandName: "HIMA Studio", BrandSlug: "hima-studio", AuthHeroTitle: defaultAppearanceHeroTitle, SkinID: custom.ID, SkinThemes: mutatedClassic})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if overwritten.SkinThemes[0] != classic || overwritten.Public.ActiveSkin.ID != custom.ID {
|
||||
t.Fatalf("mutated classic was not overwritten = %#v", overwritten.SkinThemes[0])
|
||||
}
|
||||
|
||||
invalidColor := append([]AppearanceSkinTheme(nil), themes...)
|
||||
|
||||
@@ -336,10 +336,10 @@ export const DEFAULT_CLASSIC_SKIN: SkinDefinition = {
|
||||
info: "#2563eb",
|
||||
workspace: "#ffffff",
|
||||
workspaceGrid: "#f3f3f3",
|
||||
adminBackground: "#f5f5f5",
|
||||
adminBackground: "#f3f4f6",
|
||||
adminSurface: "#ffffff",
|
||||
adminSubtle: "#f6f6f6",
|
||||
adminStrong: "#ececec",
|
||||
adminSubtle: "#f7f8fa",
|
||||
adminStrong: "#eceff3",
|
||||
authBackground: "#ffffff",
|
||||
authPanel: "#f7f7f7",
|
||||
authCard: "#ffffff",
|
||||
@@ -388,9 +388,9 @@ export const DEFAULT_CLASSIC_SKIN: SkinDefinition = {
|
||||
info: "#60a5fa",
|
||||
workspace: "#181818",
|
||||
workspaceGrid: "#222222",
|
||||
adminBackground: "#0f0f0f",
|
||||
adminBackground: "#101010",
|
||||
adminSurface: "#181818",
|
||||
adminSubtle: "#222222",
|
||||
adminSubtle: "#202020",
|
||||
adminStrong: "#2a2a2a",
|
||||
authBackground: "#08090c",
|
||||
authPanel: "#0b0c10",
|
||||
|
||||
Reference in New Issue
Block a user