MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m21s
- Theme manager in settings: upload a .css file or paste CSS, template
download/copy/insert, edit and delete; custom themes show up in the
gallery and the quick switchers
- Themes are injected live as <style id="mindsift-custom-theme">; the
active one is cached so it applies on boot without flashing
- Backend: user_themes table and GET/POST /themes, DELETE /themes/{id}
(per user, max 200 KB)
- Docs: theming, REST, database
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
1.6 KiB
Go
51 lines
1.6 KiB
Go
package storage
|
|
|
|
import (
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestUserThemesArePrivateAndLimited(t *testing.T) {
|
|
store, err := NewStore(filepath.Join(t.TempDir(), "themes.db"))
|
|
if err != nil {
|
|
t.Fatalf("NewStore failed: %v", err)
|
|
}
|
|
defer store.Close()
|
|
anna, _ := store.CreateUser("anna@example.com", "hash", "Anna", "member")
|
|
ben, _ := store.CreateUser("ben@example.com", "hash", "Ben", "member")
|
|
|
|
css := `:root[data-theme="wald"] { --accent-primary: #15803d; }`
|
|
th, err := store.SaveUserTheme(anna.ID, "", "Wald", css)
|
|
if err != nil {
|
|
t.Fatalf("SaveUserTheme failed: %v", err)
|
|
}
|
|
if _, err := store.SaveUserTheme(anna.ID, th.ID, "Wald 2", css); err != nil {
|
|
t.Fatalf("update failed: %v", err)
|
|
}
|
|
if themes, _ := store.GetUserThemes(anna.ID); len(themes) != 1 || themes[0].Name != "Wald 2" {
|
|
t.Fatalf("expected one updated theme, got %+v", themes)
|
|
}
|
|
|
|
// Other users neither see, change nor delete it
|
|
if themes, _ := store.GetUserThemes(ben.ID); len(themes) != 0 {
|
|
t.Errorf("Ben must not see Anna's themes")
|
|
}
|
|
if _, err := store.SaveUserTheme(ben.ID, th.ID, "Gekapert", css); err == nil {
|
|
t.Errorf("Ben must not update Anna's theme")
|
|
}
|
|
if err := store.DeleteUserTheme(ben.ID, th.ID); err == nil {
|
|
t.Errorf("Ben must not delete Anna's theme")
|
|
}
|
|
|
|
if _, err := store.SaveUserTheme(anna.ID, "", "Riesig", strings.Repeat("a", MaxThemeCSSBytes+1)); err == nil {
|
|
t.Errorf("oversized theme must be rejected")
|
|
}
|
|
if _, err := store.SaveUserTheme(anna.ID, "", " ", css); err == nil {
|
|
t.Errorf("theme without name must be rejected")
|
|
}
|
|
if err := store.DeleteUserTheme(anna.ID, th.ID); err != nil {
|
|
t.Fatalf("delete failed: %v", err)
|
|
}
|
|
}
|