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

@ -1,11 +1,56 @@
package config package config
import ( import (
"fmt"
"reflect" "reflect"
"github.com/imdario/mergo" "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 // CollectionConfig describes a collection
type CollectionConfig struct { type CollectionConfig struct {
Name *string `yaml:"Name"` Name *string `yaml:"Name"`
@ -26,7 +71,7 @@ type ThisPathConfig struct {
Navname *string `yaml:"Navname"` Navname *string `yaml:"Navname"`
GoTo *string `yaml:"GoTo"` GoTo *string `yaml:"GoTo"`
Collections []*CollectionConfig `yaml:"Collections"` Collections []*CollectionConfig `yaml:"Collections"`
Data interface{} `yaml:"Data"` Data MapString `yaml:"Data"`
} }
// IndexConfig describes index input and output file // IndexConfig describes index input and output file
@ -85,7 +130,7 @@ type PathConfig struct {
Markdown *MarkdownConfig `yaml:"Markdown"` Markdown *MarkdownConfig `yaml:"Markdown"`
Imaging *ImagingConfig `yaml:"Imaging"` Imaging *ImagingConfig `yaml:"Imaging"`
Data map[string]interface{} `yaml:"Data"` Data MapString `yaml:"Data"`
} }
// PathConfigTree is complete config tree of content dir // PathConfigTree is complete config tree of content dir
@ -94,7 +139,7 @@ type PathConfigTree struct {
OutputPath string OutputPath string
Hidden bool // for collections which are not part of the navigation Hidden bool // for collections which are not part of the navigation
ColMap map[string]interface{} ColMap MapString
InputFiles []string InputFiles []string
OtherFiles []string OtherFiles []string

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

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

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

@ -15,6 +15,7 @@ import (
"strings" "strings"
"gitbase.de/apairon/mark2web/config" "gitbase.de/apairon/mark2web/config"
"github.com/davecgh/go-spew/spew"
"github.com/ddliu/motto" "github.com/ddliu/motto"
"github.com/disintegration/imaging" "github.com/disintegration/imaging"
"github.com/flosch/pongo2" "github.com/flosch/pongo2"
@ -32,6 +33,7 @@ func init() {
"image_process": ImageProcessFilter, "image_process": ImageProcessFilter,
"relative_path": RelativePathFilter, "relative_path": RelativePathFilter,
"json": JSONFilter, "json": JSONFilter,
"dump": DumpFilter,
} }
for name, fn := range newFilters { for name, fn := range newFilters {
err := pongo2.RegisterFilter(name, fn) 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 // 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) { 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 { if err != nil {
return nil, &pongo2.Error{ return nil, &pongo2.Error{
Sender: "filter:json", 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 // MarkdownFilter is a pongo2 filter, which converts markdown to html

@ -10,7 +10,7 @@ import (
"github.com/flosch/pongo2" "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) Log.Noticef("requesting url via GET %s", url)
resp, err := http.Get(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) 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) err = json.Unmarshal(body, &jsonMap)
if err != nil { if err != nil {
Log.Panicf("could not read json from '%s': %s", url, err) 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 dataMapKey != "" {
if newNodeConfig.Config.Data == nil { if newNodeConfig.Config.Data == nil {
newNodeConfig.Config.Data = make(map[string]interface{}) newNodeConfig.Config.Data = make(config.MapString)
} }
// as submap in Data // as submap in Data
newNodeConfig.Config.Data[dataMapKey] = ctx newNodeConfig.Config.Data[dataMapKey] = ctx

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

@ -100,15 +100,34 @@
<!-- ========== Main Content ========== --> <!-- ========== Main Content ========== -->
<div class="maincontent"> <div class="maincontent">
{% if Data.background %} {% 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 %} {% endif %}
<div class="white_section section_padding"> <div class="white_section section_padding">
<div class="container"> <div class="container">
{% block part1 %} {% block part1 %}
{{ BodyParts.1 }} {{ BodyParts.1 }}
{% endblock part1 %} {% 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 %} {% endif %}
</div> </div>
</div> </div>