feat(strategy): add dynamic theme listing endpoint /strategies/dynamic/themes

This commit is contained in:
Alexis Couvreur
2022-10-31 17:41:20 +00:00
parent c47137edc7
commit cf9f2f8ae3
4 changed files with 118 additions and 5 deletions

View File

@@ -13,7 +13,7 @@ import (
)
//go:embed themes/*
var themes embed.FS
var Themes embed.FS
type RenderOptionsInstanceState struct {
Name string
@@ -54,7 +54,7 @@ func Render(options RenderOptions, writer io.Writer) error {
tpl, err = template.ParseFS(options.CustomThemes, fmt.Sprintf("%s.html", options.Theme))
} else {
// Load from the embedded FS
tpl, err = template.ParseFS(themes, fmt.Sprintf("themes/%s.html", options.Theme))
tpl, err = template.ParseFS(Themes, fmt.Sprintf("themes/%s.html", options.Theme))
}
if err != nil {

View File

@@ -40,7 +40,7 @@ func NewServeStrategy(sessionsManager sessions.Manager, conf config.Strategy) *S
if conf.Dynamic.CustomThemesPath != "" {
customThemesFs := osDirFS(conf.Dynamic.CustomThemesPath)
serveStrategy.customThemesFS = customThemesFs
serveStrategy.customThemes = loadAllowedThemes(customThemesFs)
serveStrategy.customThemes = listThemes(customThemesFs)
}
return serveStrategy
@@ -84,6 +84,26 @@ func (s *ServeStrategy) ServeDynamic(c *gin.Context) {
}
}
func (s *ServeStrategy) ServeDynamicThemes(c *gin.Context) {
customThemes := []string{}
for theme := range s.customThemes {
customThemes = append(customThemes, theme)
}
sort.Strings(customThemes)
embeddedThemes := []string{}
for theme := range listThemes(pages.Themes) {
embeddedThemes = append(embeddedThemes, strings.TrimPrefix(theme, "themes/"))
}
sort.Strings(embeddedThemes)
c.JSON(http.StatusOK, map[string]interface{}{
"custom": customThemes,
"embedded": embeddedThemes,
})
}
func (s *ServeStrategy) ServeBlocking(c *gin.Context) {
request := models.BlockingRequest{
Timeout: s.StrategyConfig.Blocking.DefaultTimeout,
@@ -142,7 +162,8 @@ func instanceStateToRenderOptionsRequestState(instanceState *instance.State) pag
}
}
func loadAllowedThemes(dir fs.FS) (allowedThemes map[string]bool) {
func listThemes(dir fs.FS) (themes map[string]bool) {
themes = make(map[string]bool)
fs.WalkDir(dir, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
@@ -154,7 +175,7 @@ func loadAllowedThemes(dir fs.FS) (allowedThemes map[string]bool) {
if strings.HasSuffix(d.Name(), ".html") {
log.Debugf("found theme at \"%s\" can be loaded using \"%s\"", path, strings.TrimSuffix(path, ".html"))
allowedThemes[strings.TrimSuffix(path, ".html")] = true
themes[strings.TrimSuffix(path, ".html")] = true
} else {
log.Tracef("ignoring file \"%s\" because it has no .html suffix", path)
}

View File

@@ -278,3 +278,94 @@ func TestNewServeStrategy(t *testing.T) {
})
}
}
func TestServeStrategy_ServeDynamicThemes(t *testing.T) {
type fields struct {
StrategyConfig config.Strategy
}
tests := []struct {
name string
fields fields
osDirFS fs.FS
expected map[string]any
}{
{
name: "load custom themes",
fields: fields{StrategyConfig: config.Strategy{
Dynamic: config.DynamicStrategy{
CustomThemesPath: "my/path/to/themes",
},
}},
osDirFS: fstest.MapFS{
"my/path/to/superman.html": {Data: []byte("superman")},
"my/path/to/themes/marvel.html": {Data: []byte("thor")},
"my/path/to/themes/dc-comics.html": {Data: []byte("batman")},
"my/path/to/themes/inner/dc-comics.html": {Data: []byte("batman")},
},
expected: map[string]any{
"custom": []any{
"dc-comics",
"inner/dc-comics",
"marvel",
},
"embedded": []any{
"ghost",
"hacker-terminal",
"matrix",
"shuffle",
},
},
},
{
name: "load without custom themes",
expected: map[string]any{
"custom": []any{},
"embedded": []any{
"ghost",
"hacker-terminal",
"matrix",
"shuffle",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
oldosDirFS := osDirFS
defer func() { osDirFS = oldosDirFS }()
myOsDirFS := func(dir string) fs.FS {
fs, err := fs.Sub(tt.osDirFS, dir)
if err != nil {
panic(err)
}
return fs
}
osDirFS = myOsDirFS
s := NewServeStrategy(nil, tt.fields.StrategyConfig)
recorder := httptest.NewRecorder()
c := GetTestGinContext(recorder)
s.ServeDynamicThemes(c)
res := recorder.Result()
defer res.Body.Close()
jsonRes := make(map[string]interface{})
err := json.NewDecoder(res.Body).Decode(&jsonRes)
if err != nil {
panic(err)
}
assert.DeepEqual(t, jsonRes, tt.expected)
})
}
}

View File

@@ -23,6 +23,7 @@ func Start(serverConf config.Server, strategyConf config.Strategy, sessionManage
{
strategy := routes.NewServeStrategy(sessionManager, strategyConf)
api.GET("/strategies/dynamic", strategy.ServeDynamic)
api.GET("/strategies/dynamic/themes", strategy.ServeDynamicThemes)
api.GET("/strategies/blocking", strategy.ServeBlocking)
}
}