shithub: hugo

Download patch

ref: 79f8bb625d2a7379d8eb0afa7e144444b4567e3d
parent: a1e32439fbab314cab6f5c3ecb962b8ac7bd9069
author: digitalcraftsman <[email protected]>
date: Sat Sep 12 17:45:12 EDT 2015

Add base64Decode and base64Encode template functions

Fixes #1416

--- a/docs/content/templates/functions.md
+++ b/docs/content/templates/functions.md
@@ -650,3 +650,33 @@
     {{ 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 }}
+    <!-- will output "SGVsbG8gd29ybGQ=" and -->
+
+    {{ "SGVsbG8gd29ybGQ=" | base64Decode }}
+    <!-- becomes "Hello world" again. -->
+
+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 }}
+    <!-- will output "42". Both functions always return a string. -->
+
+**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.
--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -16,6 +16,7 @@
 import (
 	"bitbucket.org/pkg/inflect"
 	"bytes"
+	"encoding/base64"
 	"errors"
 	"fmt"
 	"html"
@@ -1318,60 +1319,88 @@
 	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 @@
 			return inflect.Singularize(word), nil
 		},
 	}
-
 }
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -2,6 +2,7 @@
 
 import (
 	"bytes"
+	"encoding/base64"
 	"errors"
 	"fmt"
 	"html/template"
@@ -1579,5 +1580,38 @@
 		if buf.String() != this.expectWithEscape {
 			t.Errorf("[%d] execute template with an escaped string value by SafeURL, got %v but expected %v", i, buf.String(), this.expectWithEscape)
 		}
+	}
+}
+
+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)
 	}
 }