mark2web/pkg/mark2web/collection.go

197 lines
6.0 KiB
Go
Raw Normal View History

2019-03-21 14:55:40 +01:00
package mark2web
import (
2019-03-22 17:22:03 +01:00
"io/ioutil"
2019-03-21 14:55:40 +01:00
"path"
2019-03-22 17:22:03 +01:00
"regexp"
2019-03-21 14:55:40 +01:00
"strings"
"gitbase.de/apairon/mark2web/pkg/helper"
2019-03-25 09:28:58 +01:00
"gitbase.de/apairon/mark2web/pkg/logger"
2019-03-27 12:52:30 +01:00
"gitbase.de/apairon/mark2web/pkg/webrequest"
2019-03-21 14:55:40 +01:00
"github.com/davecgh/go-spew/spew"
2022-02-28 11:43:47 +01:00
"github.com/flosch/pongo2/v4"
2019-03-21 14:55:40 +01:00
)
type colCacheEntry struct {
data interface{}
hit int
navnames []string
}
var colCache = make(map[string]*colCacheEntry)
func (node *TreeNode) handleCollections() {
collections := append(node.Config.Collections, node.Config.This.Collections...)
for _, colConfig := range collections {
2019-03-22 17:22:03 +01:00
if colConfig.Name == nil || *colConfig.Name == "" {
2019-03-29 15:49:25 +01:00
logger.Exit("missing Name in collection config in '%s'", node.InputPath)
2019-03-22 17:22:03 +01:00
}
if (colConfig.URL == nil || *colConfig.URL == "") &&
(colConfig.Directory == nil) {
2019-03-29 15:49:25 +01:00
logger.Exit("missing URL and Directory in collection config in '%s'", node.InputPath)
2019-03-21 14:55:40 +01:00
}
if node.ColMap == nil {
node.ColMap = make(helper.MapString)
}
ctx := NewContext()
ctx["This"] = node.Config.This
ctx["Data"] = node.Config.Data
var colData interface{}
2019-03-22 17:22:03 +01:00
errSrcText := ""
cacheKey := ""
if colConfig.URL != nil {
url, err := pongo2.RenderTemplateString(*colConfig.URL, ctx)
2019-03-29 15:49:25 +01:00
logger.Eexit(err, "invalid template string for Collection Element.URL in '%s'", node.InputPath)
2019-03-22 17:22:03 +01:00
errSrcText = "URL " + url
cacheKey = url
if cacheEntry, ok := colCache[url]; ok {
colData = cacheEntry.data
cacheEntry.hit++
} else {
2019-03-29 15:49:25 +01:00
logger.N("reading collection from: %s", errSrcText)
2019-03-27 12:52:30 +01:00
colData = webrequest.GetJSON(url)
2019-03-22 17:22:03 +01:00
colCache[url] = &colCacheEntry{
data: colData,
navnames: make([]string, 0),
}
}
2019-03-21 14:55:40 +01:00
} else {
2019-03-22 17:22:03 +01:00
path := node.ResolveInputPath(colConfig.Directory.Path)
errSrcText = "DIR " + path
2019-03-29 15:49:25 +01:00
logger.N("reading collection from: %s", errSrcText)
2019-03-22 17:22:03 +01:00
d, err := ioutil.ReadDir(path)
2019-03-29 15:49:25 +01:00
logger.Eexit(err, "could not read directory '%s'", path)
2019-03-22 17:22:03 +01:00
mStr := "."
if colConfig.Directory.MatchFilename != "" {
mStr = colConfig.Directory.MatchFilename
}
matcher, err := regexp.Compile(mStr)
2019-03-29 15:49:25 +01:00
logger.Eexit(err, "could not compile regex for MatchFilename '%s' in '%s'", mStr, path)
2019-03-22 17:22:03 +01:00
if colConfig.Directory.ReverseOrder {
for i := len(d)/2 - 1; i >= 0; i-- {
opp := len(d) - 1 - i
d[i], d[opp] = d[opp], d[i]
}
2019-03-21 14:55:40 +01:00
}
2019-03-22 17:22:03 +01:00
fcolData := make([]pongo2.Context, 0)
for _, fh := range d {
if !fh.IsDir() && matcher.MatchString(fh.Name()) {
inFile := path + "/" + fh.Name()
md, err := ioutil.ReadFile(inFile)
2019-03-29 15:49:25 +01:00
logger.Eexit(err, "could not read file '%s'", inFile)
2019-03-22 17:22:03 +01:00
_, ctx := node.processMarkdownWithHeader(md, inFile)
(*ctx)["FilenameMatch"] = helper.GetRegexpParams(matcher, fh.Name())
fcolData = append(fcolData, *ctx)
}
}
colData = fcolData
2019-03-21 14:55:40 +01:00
}
node.ColMap[*colConfig.Name] = colData
if navT := colConfig.NavTemplate; navT != nil {
var entries []interface{}
var ok bool
if navT.EntriesAttribute != "" {
var colDataMap map[string]interface{}
if colDataMap, ok = colData.(map[string]interface{}); ok {
entries, ok = colDataMap[navT.EntriesAttribute].([]interface{})
if !ok {
2019-03-29 15:49:25 +01:00
logger.D(spew.Sdump(colDataMap))
logger.Exit("invalid json data in [%s] from '%s' for entries", navT.EntriesAttribute, errSrcText)
2019-03-21 14:55:40 +01:00
}
}
} else {
entries, ok = colData.([]interface{})
}
if !ok {
2019-03-29 15:49:25 +01:00
logger.D(spew.Sdump(colData))
logger.Exit("invalid json data from '%s', need array of objects for entries or object with configured NavTemplate.EntriesAttribute", errSrcText)
2019-03-21 14:55:40 +01:00
}
// build navigation with detail sites
for idx, colEl := range entries {
ctxE := make(pongo2.Context)
err := helper.Merge(&ctxE, ctx)
2019-03-29 15:49:25 +01:00
logger.Eexit(err, "could not merge context in '%s'", node.InputPath)
2019-03-21 14:55:40 +01:00
var jsonCtx map[string]interface{}
if jsonCtx, ok = colEl.(map[string]interface{}); !ok {
2019-03-29 15:49:25 +01:00
logger.D(spew.Sdump(colEl))
logger.Exit("no json object for entry index %d from '%s'", idx, errSrcText)
2019-03-21 14:55:40 +01:00
}
err = helper.Merge(&ctxE, pongo2.Context(jsonCtx))
2019-03-29 15:49:25 +01:00
logger.Eexit(err, "could not merge context in '%s'", node.InputPath)
2019-03-21 14:55:40 +01:00
tpl := ""
if navT.Template != "" {
tpl, err = pongo2.RenderTemplateString(navT.Template, ctxE)
2019-03-29 15:49:25 +01:00
logger.Eexit(err, "invalid template string for NavTemplate.Template in '%s'", node.InputPath)
2019-03-21 14:55:40 +01:00
}
if tpl == "" {
tpl = *node.Config.Template
}
dataKey := ""
if navT.DataKey != "" {
dataKey, err = pongo2.RenderTemplateString(navT.DataKey, ctxE)
2019-03-29 15:49:25 +01:00
logger.Eexit(err, "invalid template string for NavTemplate.DataKey in '%s'", node.InputPath)
2019-03-21 14:55:40 +01:00
}
goTo, err := pongo2.RenderTemplateString(navT.GoTo, ctxE)
2019-03-29 15:49:25 +01:00
logger.Eexit(err, "invalid template string for NavTemplate.GoTo in '%s'", node.InputPath)
2019-03-21 14:55:40 +01:00
goTo = strings.Trim(goTo, "/")
goTo = path.Clean(goTo)
if strings.Contains(goTo, "..") {
2019-03-29 15:49:25 +01:00
logger.Exit("going back via .. in NavTemplate.GoTo forbidden in collection config in '%s': %s", node.InputPath, goTo)
2019-03-21 14:55:40 +01:00
}
if goTo == "." {
2019-03-29 15:49:25 +01:00
logger.Exit("invalid config '.' for NavTemplate.GoTo in collection config in '%s'", node.InputPath)
2019-03-21 14:55:40 +01:00
}
if goTo == "" {
2019-03-29 15:49:25 +01:00
logger.Exit("missing NavTemplate.GoTo in collection config in '%s'", node.InputPath)
2019-03-21 14:55:40 +01:00
}
navname := ""
if navT.Navname != "" {
navname, err = pongo2.RenderTemplateString(navT.Navname, ctxE)
2019-03-29 15:49:25 +01:00
logger.Eexit(err, "invalid template string for NavTemplate.Navname in '%s'", node.InputPath)
2019-03-21 14:55:40 +01:00
}
body := ""
if navT.Body != "" {
body, err = pongo2.RenderTemplateString(navT.Body, ctxE)
2019-03-29 15:49:25 +01:00
logger.Eexit(err, "invalid template string for NavTemplate.Body in '%s'", node.InputPath)
2019-03-21 14:55:40 +01:00
}
2019-03-22 17:22:03 +01:00
if l := len(colCache[cacheKey].navnames); colCache[cacheKey].hit > 1 &&
2019-03-21 14:55:40 +01:00
l > 0 &&
2019-03-22 17:22:03 +01:00
navname == colCache[cacheKey].navnames[l-1] {
2019-03-21 14:55:40 +01:00
// navname before used same url, so recursion loop
2019-03-29 15:49:25 +01:00
logger.Exit("collection request loop detected for in '%s' for : %s", node.InputPath, errSrcText)
2019-03-21 14:55:40 +01:00
}
2019-03-22 17:22:03 +01:00
colCache[cacheKey].navnames = append(colCache[cacheKey].navnames, navname)
2019-03-21 14:55:40 +01:00
node.addSubNode(tpl, goTo, navname, colEl, dataKey, body, navT.Hidden)
}
}
}
}