Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 57 additions & 9 deletions internal/sections/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package sections

import (
"encoding/json"
"reflect"
"sort"
"strings"

"github.com/Silo-Server/silo-server/internal/sections/recipes"
)

const jsonNullLiteral = "null"
Expand Down Expand Up @@ -61,6 +65,7 @@ func Resolve(admin []*PageSection, overrides []ProfileSectionOverride) []Resolve
}
}

rs.Title = readableTitle(rs.SectionType, rs.Title, rs.Config)
result = append(result, rs)
}

Expand Down Expand Up @@ -102,14 +107,13 @@ func ResolveForSettings(admin []*PageSection, overrides []ProfileSectionOverride
continue
}
rs := ResolvedSection{
ID: s.ID,
SectionType: s.SectionType,
Title: s.Title,
DefaultTitle: s.Title,
Featured: s.Featured,
ItemLimit: s.ItemLimit,
Config: s.Config,
Position: s.Position,
ID: s.ID,
SectionType: s.SectionType,
Title: s.Title,
Featured: s.Featured,
ItemLimit: s.ItemLimit,
Config: s.Config,
Position: s.Position,
}

if hasOverride {
Expand All @@ -132,6 +136,11 @@ func ResolveForSettings(admin []*PageSection, overrides []ProfileSectionOverride
}
}

// Both titles get the same readable fallback from the same config, so
// an admin title saved as the raw key still equals Title when the
// profile has no title override.
rs.DefaultTitle = readableTitle(rs.SectionType, s.Title, rs.Config)
Comment thread
Quick104 marked this conversation as resolved.
rs.Title = readableTitle(rs.SectionType, rs.Title, rs.Config)
result = append(result, rs)
}

Expand Down Expand Up @@ -187,7 +196,7 @@ func resolveUserAdded(o ProfileSectionOverride) ResolvedSection {
return ResolvedSection{
ID: o.ID,
SectionType: sectionType,
Title: title,
Title: readableTitle(sectionType, title, cfg),
Featured: featured,
ItemLimit: limit,
Config: cfg,
Expand All @@ -196,3 +205,42 @@ func resolveUserAdded(o ProfileSectionOverride) ResolvedSection {
Hidden: o.Hidden,
}
}

// readableTitle replaces a blank title, or one that is just the raw
// section_type key (older editors saved that when no title was typed), with
// the recipe's display name: the preset whose default params match the
// section config on the most keys (as the web editor's matchRecipePreset
// picks), else the recipe's first preset. Other titles pass through.
func readableTitle(sectionType SectionType, title string, config json.RawMessage) string {
if t := strings.TrimSpace(title); t != "" && t != string(sectionType) {
return title
}
rec, ok := recipes.Get(string(sectionType))
if !ok {
return title
}
presets := rec.Definition().Presets
if len(presets) == 0 {
return title
}
var cfg map[string]any
_ = json.Unmarshal(config, &cfg)
best, bestScore := presets[0].DisplayName, -1
for _, p := range presets {
var params map[string]any
if json.Unmarshal(p.DefaultParams, &params) != nil {
continue
}
matched := true
for k, v := range params {
if !reflect.DeepEqual(cfg[k], v) {
matched = false
break
}
}
if matched && len(params) > bestScore {
best, bestScore = p.DisplayName, len(params)
}
}
return best
}
45 changes: 45 additions & 0 deletions internal/sections/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,48 @@ func TestResolveBackwardCompatLegacyUserAdded(t *testing.T) {
t.Fatalf("legacy user-added not resolved correctly: %+v", resolved)
}
}

func TestResolve_ReplacesRawSectionTypeTitle(t *testing.T) {
admin := []*PageSection{
{ID: "1", Position: 0, SectionType: "trending_on_server", Title: "trending_on_server", Config: json.RawMessage(`{"window":"7d"}`)},
{ID: "2", Position: 1, SectionType: "trending_on_server", Title: "Hot Right Now", Config: json.RawMessage(`{"window":"7d"}`)},
{ID: "3", Position: 2, SectionType: "format_showcase", Title: "format_showcase", Config: json.RawMessage(`{"format":"4k","sort":"recent"}`)},
}

result := Resolve(admin, nil)
if result[0].Title != "Trending This Week" {
t.Errorf("raw-key title = %q, want %q", result[0].Title, "Trending This Week")
}
if result[1].Title != "Hot Right Now" {
t.Errorf("custom title = %q, want unchanged", result[1].Title)
}
if result[2].Title != "New in 4K" {
t.Errorf("most specific preset = %q, want %q", result[2].Title, "New in 4K")
}
}

// TestResolveForSettings_RawKeyAdminTitleIsNotARename: an admin row saved with
// the raw section_type key gets the preset name in both Title and DefaultTitle,
// so settings does not report a rename the profile never made.
func TestResolveForSettings_RawKeyAdminTitleIsNotARename(t *testing.T) {
admin := []*PageSection{
{ID: "1", Position: 0, SectionType: "trending_on_server", Title: "trending_on_server", Config: json.RawMessage(`{"window":"7d"}`)},
{ID: "2", Position: 1, SectionType: "trending_on_server", Title: "trending_on_server", Config: json.RawMessage(`{"window":"7d"}`)},
}
overrides := []ProfileSectionOverride{{SectionID: "2", Title: "My trending"}}

result := ResolveForSettings(admin, overrides)
got := map[string][2]string{}
for _, r := range result {
got[r.ID] = [2]string{r.Title, r.DefaultTitle}
}
want := map[string][2]string{
"1": {"Trending This Week", "Trending This Week"},
"2": {"My trending", "Trending This Week"},
}
for id, w := range want {
if got[id] != w {
t.Errorf("section %s (title, default title) = %q, want %q", id, got[id], w)
}
}
}
Loading