json and dump filter

This commit is contained in:
Sebastian Frank 2019-03-11 15:29:05 +01:00
parent a2eaa3f4b4
commit 2f2454ee54
Signed by: apairon
GPG Key ID: 7270D06DDA7FE8C3
8 changed files with 107 additions and 20 deletions

View File

@ -1,11 +1,56 @@
package config
import (
"fmt"
"reflect"
"github.com/imdario/mergo"
)
// MapString is a map[string]interface{} which always unmarsahls yaml to map[string]interface{}
type MapString map[string]interface{}
// UnmarshalYAML handles all maps as map[string]interface{} for later JSON
// see https://github.com/elastic/beats/blob/6435194af9f42cbf778ca0a1a92276caf41a0da8/libbeat/common/mapstr.go
func (ms *MapString) UnmarshalYAML(unmarshal func(interface{}) error) error {
var result map[interface{}]interface{}
err := unmarshal(&result)
if err != nil {
return err
}
*ms = cleanUpInterfaceMap(result)
return nil
}
func cleanUpInterfaceArray(in []interface{}) []interface{} {
result := make([]interface{}, len(in))
for i, v := range in {
result[i] = cleanUpMapValue(v)
}
return result
}
func cleanUpInterfaceMap(in map[interface{}]interface{}) MapString {
result := make(MapString)
for k, v := range in {
result[fmt.Sprintf("%v", k)] = cleanUpMapValue(v)
}
return result
}
func cleanUpMapValue(v interface{}) interface{} {
switch v := v.(type) {
case []interface{}:
return cleanUpInterfaceArray(v)
case map[interface{}]interface{}:
return cleanUpInterfaceMap(v)
case string:
return v
default:
return fmt.Sprintf("%v", v)
}
}
// CollectionConfig describes a collection
type CollectionConfig struct {
Name *string `yaml:"Name"`
@ -26,7 +71,7 @@ type ThisPathConfig struct {
Navname *string `yaml:"Navname"`
GoTo *string `yaml:"GoTo"`
Collections []*CollectionConfig `yaml:"Collections"`
Data interface{} `yaml:"Data"`
Data MapString `yaml:"Data"`
}
// IndexConfig describes index input and output file
@ -85,7 +130,7 @@ type PathConfig struct {
Markdown *MarkdownConfig `yaml:"Markdown"`
Imaging *ImagingConfig `yaml:"Imaging"`
Data map[string]interface{} `yaml:"Data"`
Data MapString `yaml:"Data"`
}
// PathConfigTree is complete config tree of content dir
@ -94,7 +139,7 @@ type PathConfigTree struct {
OutputPath string
Hidden bool // for collections which are not part of the navigation
ColMap map[string]interface{}
ColMap MapString
InputFiles []string
OtherFiles []string

View File

@ -19,8 +19,8 @@ import (
"gopkg.in/yaml.v2"
)
func newContext() map[string]interface{} {
return map[string]interface{}{
func newContext() pongo2.Context {
return pongo2.Context{
"fnRequest": RequestFn,
"fnRender": RenderFn,
@ -106,7 +106,7 @@ func fillNodeConfig(node *config.PathConfigTree, inBase, outBase, dir string, co
}
if node.ColMap == nil {
node.ColMap = make(map[string]interface{})
node.ColMap = make(config.MapString)
}
ctx := newContext()
jsonStr, err := pongo2.RenderTemplateString(*colConfig.EntriesJSON, ctx)
@ -114,7 +114,7 @@ func fillNodeConfig(node *config.PathConfigTree, inBase, outBase, dir string, co
Log.Panicf("invalid template string in '%s': %s", inPath, err)
}
var colSlice []map[string]interface{}
var colSlice []config.MapString
err = json.Unmarshal([]byte(jsonStr), &colSlice)
if err != nil {
Log.Panicf("invalid JSON in EntriesJSON in '%s': %s", inPath, err)
@ -130,12 +130,12 @@ func fillNodeConfig(node *config.PathConfigTree, inBase, outBase, dir string, co
// build navigation with detail sites
for _, colEl := range colSlice {
ctxE := make(map[string]interface{})
ctxE := make(pongo2.Context)
err := config.Merge(&ctxE, ctx)
if err != nil {
Log.Panicf("could not merge context in '%s': %s", inPath, err)
}
err = config.Merge(&ctxE, colEl)
err = config.Merge(&ctxE, pongo2.Context(colEl))
if err != nil {
Log.Panicf("could not merge context in '%s': %s", inPath, err)
}

View File

@ -14,7 +14,7 @@ type NavElement struct {
GoTo string
Active bool
ColMap map[string]interface{}
ColMap config.MapString
Data interface{}
@ -93,7 +93,7 @@ func BuildNavigation(conf *config.PathConfigTree, curNavMap *map[string]*NavElem
navEl.GoTo = path.Clean(navEl.GoTo)
}
(*curNavMap)[navEl.Navname] = &navEl
(*curNavMap)[path.Base(el.OutputPath)] = &navEl
if curNavSlice != nil {
*curNavSlice = append(*curNavSlice, &navEl)
}

View File

@ -11,7 +11,7 @@ import (
)
var templateCache = make(map[string]*pongo2.Template)
var currentContext *map[string]interface{}
var currentContext *pongo2.Context
var currentTreeNodeConfig *config.PathConfigTree
var currentPathConfig *config.PathConfig
var templateDir string
@ -63,7 +63,7 @@ func SetTemplateDir(dir string) {
}
// RenderTemplate renders a pongo2 template with context
func RenderTemplate(filename string, treeNodeConfig *config.PathConfigTree, pathConfig *config.PathConfig, ctx *map[string]interface{}) (string, error) {
func RenderTemplate(filename string, treeNodeConfig *config.PathConfigTree, pathConfig *config.PathConfig, ctx *pongo2.Context) (string, error) {
currentContext = ctx
currentTreeNodeConfig = treeNodeConfig
currentPathConfig = pathConfig

View File

@ -15,6 +15,7 @@ import (
"strings"
"gitbase.de/apairon/mark2web/config"
"github.com/davecgh/go-spew/spew"
"github.com/ddliu/motto"
"github.com/disintegration/imaging"
"github.com/flosch/pongo2"
@ -32,6 +33,7 @@ func init() {
"image_process": ImageProcessFilter,
"relative_path": RelativePathFilter,
"json": JSONFilter,
"dump": DumpFilter,
}
for name, fn := range newFilters {
err := pongo2.RegisterFilter(name, fn)
@ -41,9 +43,29 @@ func init() {
}
}
// DumpFilter is a pongo2 filter, which returns a spew.Dump of the input
func DumpFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
dumpString := spew.Sdump(in.Interface())
return pongo2.AsValue(string(dumpString)), nil
}
// JSONFilter is a pongo2 filter, which returns a json string of the input
func JSONFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
jsonString, err := json.Marshal(in.Interface())
pretty := false
for _, s := range strings.Split(param.String(), ",") {
switch s {
case "pretty":
pretty = true
}
}
var err error
var jsonBytes []byte
if pretty {
jsonBytes, err = json.MarshalIndent(in.Interface(), "", " ")
} else {
jsonBytes, err = json.Marshal(in.Interface())
}
if err != nil {
return nil, &pongo2.Error{
Sender: "filter:json",
@ -51,7 +73,7 @@ func JSONFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.E
}
}
return pongo2.AsSafeValue(string(jsonString)), nil
return pongo2.AsSafeValue(string(jsonBytes)), nil
}
// MarkdownFilter is a pongo2 filter, which converts markdown to html

View File

@ -10,7 +10,7 @@ import (
"github.com/flosch/pongo2"
)
func jsonWebRequest(url string) map[string]interface{} {
func jsonWebRequest(url string) config.MapString {
Log.Noticef("requesting url via GET %s", url)
resp, err := http.Get(url)
@ -38,7 +38,7 @@ func jsonWebRequest(url string) map[string]interface{} {
Log.Panicf("is not json '%s' from url '%s'", contentType, url)
}
jsonMap := make(map[string]interface{})
jsonMap := make(config.MapString)
err = json.Unmarshal(body, &jsonMap)
if err != nil {
Log.Panicf("could not read json from '%s': %s", url, err)
@ -69,7 +69,7 @@ func add2Nav(currentNode *config.PathConfigTree, pathConfig *config.PathConfig,
}
if dataMapKey != "" {
if newNodeConfig.Config.Data == nil {
newNodeConfig.Config.Data = make(map[string]interface{})
newNodeConfig.Config.Data = make(config.MapString)
}
// as submap in Data
newNodeConfig.Config.Data[dataMapKey] = ctx

View File

@ -11,5 +11,6 @@ Markdown:
ChromaStyle: monokai
Data:
debug: True
matomoSiteId: 89
token: 89ff216524093123bf7a0a10f7b273 # cockpit api token

View File

@ -100,15 +100,34 @@
<!-- ========== Main Content ========== -->
<div class="maincontent">
{% if Data.background %}
<img src="{{ Data.background|relative_path }}" alt="{{ Meta.Title }}" class="img2bg">
<img
src="{{ Data.background|image_process:"p=fill,w=1440,h=810,q=30" }}"
srcset="{{ Data.background|image_process:"p=fill,w=768,h=768,q=30" }} 768w,
{{ Data.background|image_process:"p=fill,w=1440,h=810,q=30" }} 1440w,
{{ Data.background|image_process:"p=fill,w=1920,h=1020,q=30" }} 1920w"
alt="{{ Meta.Title }}" class="img2bg">
{% endif %}
<div class="white_section section_padding">
<div class="container">
{% block part1 %}
{{ BodyParts.1 }}
{% endblock part1 %}
{% if This.Data.img %}
{% if Data.debug %}
<hr>
<h2>DEBUG</h2>
<h3>This</h3>
<pre>{{ This|json:"pretty" }}</pre>
<h3>Data</h3>
<pre>{{ Data|json:"pretty" }}</pre>
<h3>NavMap</h3>
<pre>{{ NavMap|json: "pretty" }}</pre>
{% endif %}
</div>
</div>