diff --git a/docs/content/templates/functions.md b/docs/content/templates/functions.md index 1317ed2ab..d27e45035 100644 --- a/docs/content/templates/functions.md +++ b/docs/content/templates/functions.md @@ -650,3 +650,33 @@ In this version, we are now sorting the tags, converting them to links with "pos {{ end }} `apply` does not work when receiving the sequence as an argument through a pipeline. + +*** + +### base64Encode and base64Decode + +`base64Encode` and `base64Decode` let you easily decode content with a base64 enconding and vice versa through pipes. Let's take a look at an example: + + + {{ "Hello world" | base64Encode }} + + + {{ "SGVsbG8gd29ybGQ=" | base64Decode }} + + +You can also pass other datatypes as argument to the template function which tries +to convert them. Now we use an integer instead of a string: + + + {{ 42 | base64Encode | base64Decode }} + + +**Tip:** Using base64 to decode and encode becomes really powerful if we have to handle +responses of APIs. + + {{ $resp := getJSON "https://api.github.com/repos/spf13/hugo/readme" }} + {{ $resp.content | base64Decode | markdownify }} + + The response of the Github API contains the base64-encoded version of the [README.md](https://github.com/spf13/hugo/blob/master/README.md) in the Hugo repository. +Now we can decode it and parse the Markdown. The final output will look similar to the +rendered version in Github. diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go index fa9c9eda9..7af70b474 100644 --- a/tpl/template_funcs.go +++ b/tpl/template_funcs.go @@ -16,6 +16,7 @@ package tpl import ( "bitbucket.org/pkg/inflect" "bytes" + "encoding/base64" "errors" "fmt" "html" @@ -1318,60 +1319,88 @@ func ModBool(a, b interface{}) (bool, error) { return res == int64(0), nil } +func Base64Decode(content interface{}) (string, error) { + conv, err := cast.ToStringE(content) + + if err != nil { + return "", err + } + + dec, err := base64.StdEncoding.DecodeString(conv) + + if err != nil { + return "", err + } + + return string(dec), nil +} + +func Base64Encode(content interface{}) (string, error) { + conv, err := cast.ToStringE(content) + + if err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString([]byte(conv)), nil +} + func init() { funcMap = template.FuncMap{ - "urlize": helpers.URLize, - "sanitizeURL": helpers.SanitizeURL, - "sanitizeurl": helpers.SanitizeURL, - "eq": Eq, - "ne": Ne, - "gt": Gt, - "ge": Ge, - "lt": Lt, - "le": Le, - "in": In, - "slicestr": Slicestr, - "substr": Substr, - "split": Split, - "intersect": Intersect, - "isSet": IsSet, - "isset": IsSet, - "echoParam": ReturnWhenSet, - "safeHTML": SafeHTML, - "safeCSS": SafeCSS, - "safeURL": SafeURL, - "absURL": func(a string) template.HTML { return template.HTML(helpers.AbsURL(a)) }, - "relURL": func(a string) template.HTML { return template.HTML(helpers.RelURL(a)) }, - "markdownify": Markdownify, - "first": First, - "last": Last, - "after": After, - "where": Where, - "delimit": Delimit, - "sort": Sort, - "highlight": Highlight, - "add": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '+') }, - "sub": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '-') }, - "div": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '/') }, - "mod": Mod, - "mul": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '*') }, - "modBool": ModBool, - "lower": func(a string) string { return strings.ToLower(a) }, - "upper": func(a string) string { return strings.ToUpper(a) }, - "title": func(a string) string { return strings.Title(a) }, - "partial": Partial, - "ref": Ref, - "relref": RelRef, - "apply": Apply, - "chomp": Chomp, - "replace": Replace, - "trim": Trim, - "dateFormat": DateFormat, - "getJSON": GetJSON, - "getCSV": GetCSV, - "readDir": ReadDir, - "seq": helpers.Seq, - "getenv": func(varName string) string { return os.Getenv(varName) }, + "urlize": helpers.URLize, + "sanitizeURL": helpers.SanitizeURL, + "sanitizeurl": helpers.SanitizeURL, + "eq": Eq, + "ne": Ne, + "gt": Gt, + "ge": Ge, + "lt": Lt, + "le": Le, + "in": In, + "slicestr": Slicestr, + "substr": Substr, + "split": Split, + "intersect": Intersect, + "isSet": IsSet, + "isset": IsSet, + "echoParam": ReturnWhenSet, + "safeHTML": SafeHTML, + "safeCSS": SafeCSS, + "safeURL": SafeURL, + "absURL": func(a string) template.HTML { return template.HTML(helpers.AbsURL(a)) }, + "relURL": func(a string) template.HTML { return template.HTML(helpers.RelURL(a)) }, + "markdownify": Markdownify, + "first": First, + "last": Last, + "after": After, + "where": Where, + "delimit": Delimit, + "sort": Sort, + "highlight": Highlight, + "add": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '+') }, + "sub": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '-') }, + "div": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '/') }, + "mod": Mod, + "mul": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '*') }, + "modBool": ModBool, + "lower": func(a string) string { return strings.ToLower(a) }, + "upper": func(a string) string { return strings.ToUpper(a) }, + "title": func(a string) string { return strings.Title(a) }, + "partial": Partial, + "ref": Ref, + "relref": RelRef, + "apply": Apply, + "chomp": Chomp, + "replace": Replace, + "trim": Trim, + "dateFormat": DateFormat, + "getJSON": GetJSON, + "getCSV": GetCSV, + "readDir": ReadDir, + "seq": helpers.Seq, + "getenv": func(varName string) string { return os.Getenv(varName) }, + "base64Decode": Base64Decode, + "base64Encode": Base64Encode, "pluralize": func(in interface{}) (string, error) { word, err := cast.ToStringE(in) if err != nil { @@ -1387,5 +1416,4 @@ func init() { return inflect.Singularize(word), nil }, } - } diff --git a/tpl/template_funcs_test.go b/tpl/template_funcs_test.go index 3dbf1b0b9..e8b91efa3 100644 --- a/tpl/template_funcs_test.go +++ b/tpl/template_funcs_test.go @@ -2,6 +2,7 @@ package tpl import ( "bytes" + "encoding/base64" "errors" "fmt" "html/template" @@ -1581,3 +1582,36 @@ func TestSafeURL(t *testing.T) { } } } + +func TestBase64Decode(t *testing.T) { + testStr := "abc123!?$*&()'-=@~" + enc := base64.StdEncoding.EncodeToString([]byte(testStr)) + result, err := Base64Decode(enc) + + if err != nil { + t.Error("Base64Decode:", err) + } + + if result != testStr { + t.Errorf("Base64Decode: got '%s', expected '%s'", result, testStr) + } +} + +func TestBase64Encode(t *testing.T) { + testStr := "YWJjMTIzIT8kKiYoKSctPUB+" + dec, err := base64.StdEncoding.DecodeString(testStr) + + if err != nil { + t.Error("Base64Encode: the DecodeString function of the base64 package returned an error.", err) + } + + result, err := Base64Encode(string(dec)) + + if err != nil { + t.Errorf("Base64Encode: Can't cast arg '%s' into a string.", testStr) + } + + if result != testStr { + t.Errorf("Base64Encode: got '%s', expected '%s'", result, testStr) + } +}