template

package module
v1.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 8, 2023 License: Unlicense Imports: 24 Imported by: 1

Documentation

Index

Constants

This section is empty.

Variables

View Source
var RootTemplate = template.New("root").Funcs(TemplateFuncs)

RootTemplate can be loaded with partials to be used in other templates It will be cloned

View Source
var TemplateFuncs = map[string]interface{}{
	"randomFloat64": func() float64 {
		return rand.Float64()
	},
	"randomInt": func(min int, max int) int {
		return rand.Intn(max-min+1) + min
	},
	"uuid": func() (string, error) {
		id, err := uuid.NewRandom()
		if err != nil {
			return "", err
		}
		return id.String(), nil
	},
	"toJSON": func(v interface{}) string {
		a, _ := json.Marshal(v)
		return string(a)
	},
	"now": func(layout string) string {
		return time.Now().Format(layout)
	},
	"timestamp": func() int64 {
		return time.Now().Unix()
	},
	"env": func(key string) string {
		return os.Getenv(key)
	},
	"trim": func(v, cutset string) string {
		return strings.Trim(v, cutset)
	},
	"multiply": func(x interface{}, y interface{}) float64 {
		var xFloat float64
		var yFloat float64
		switch v := x.(type) {
		case int:
			xFloat = float64(v)
		case float64:
			xFloat = v
		case string:
			f, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return 0
			}
			xFloat = f
		case json.Number:
			f, err := v.Float64()
			if err != nil {
				return 0
			}
			xFloat = f
		default:
			xFloat = 0
		}
		switch v := y.(type) {
		case int:
			yFloat = float64(v)
		case float64:
			yFloat = v
		case string:
			f, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return 0
			}
			yFloat = f
		case json.Number:
			f, err := v.Float64()
			if err != nil {
				return 0
			}
			yFloat = f
		default:
			yFloat = 0
		}
		return xFloat * yFloat
	},
	"ge": func(x interface{}, y interface{}) (bool, error) {
		var xFloat float64
		var yFloat float64
		switch v := x.(type) {
		case int:
			xFloat = float64(v)
		case float64:
			xFloat = v
		case string:
			f, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return false, err
			}
			xFloat = f
		case json.Number:
			f, err := v.Float64()
			if err != nil {
				return false, err
			}
			xFloat = f
		default:
			return false, fmt.Errorf(`unsupported type %T found in x-value of comparison "ge"`, x)
		}
		switch v := y.(type) {
		case int:
			yFloat = float64(v)
		case float64:
			yFloat = v
		case string:
			f, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return false, err
			}
			yFloat = f
		case json.Number:
			f, err := v.Float64()
			if err != nil {
				return false, err
			}
			yFloat = f
		default:
			return false, fmt.Errorf(`unsupported type %T found in y-value of comparison "ge"`, y)
		}
		return xFloat >= yFloat, nil
	},
	"normalize_email": func(email string) string {

		email = strings.Split(email, "+")[0]

		email = strings.Split(email, "@")[0]
		email = strings.ReplaceAll(email, ".", "")
		re := regexp.MustCompile("[0-9]")
		email = re.ReplaceAllString(email, "")
		email = strings.TrimSpace(email)
		email = strings.ToLower(email)
		return email
	},
	"toLower": func(str string) string {
		return strings.ToLower(str)
	},
	"fingerprint": func(vars ...string) (fingerprint string) {
		fingerprint = strings.Join(vars, "_")
		re := regexp.MustCompile(`[^\p{L}0-9]`)
		fingerprint = re.ReplaceAllString(fingerprint, "_")
		fingerprint = strings.ToLower(fingerprint)
		return
	},
	"fingerprint_address": func(address, city, state, zip, plus4Code interface{}) string {
		var addressStr, cityStr, stateStr, zipStr, plus4CodeStr string
		addressStr, _ = address.(string)
		cityStr, _ = city.(string)
		stateStr, _ = state.(string)
		zipStr, _ = zip.(string)
		plus4CodeStr, _ = plus4Code.(string)
		fingerprint := strings.Join([]string{addressStr, cityStr, stateStr, zipStr, plus4CodeStr}, "_")
		re := regexp.MustCompile(`[^\p{L}0-9]`)
		fingerprint = re.ReplaceAllString(fingerprint, "_")
		fingerprint = strings.ToLower(fingerprint)
		return fingerprint
	},
	"dict": func(keysAndValues ...interface{}) map[interface{}]interface{} {
		var dict = map[interface{}]interface{}{}
		for i, s := range keysAndValues {
			if i%2 != 0 {
				dict[keysAndValues[i-1]] = s
			}
		}
		return dict
	},
	"http": func(method, url string, headers map[interface{}]interface{}) (*http.Response, error) {
		var req *http.Request
		var err error
		req, err = http.NewRequest(method, url, nil)
		if err != nil {
			return nil, err
		}
		for k, v := range headers {
			req.Header.Set(k.(string), v.(string))
		}
		return http.DefaultClient.Do(req)
	},
	"http_data": func(method, url string, headers map[interface{}]interface{}, data string) (*http.Response, error) {
		var req *http.Request
		var err error
		req, err = http.NewRequest(method, url, nil)
		if err != nil {
			return nil, err
		}
		req.Body = io.NopCloser(bytes.NewBufferString(data))

		for k, v := range headers {
			req.Header.Set(k.(string), v.(string))
		}

		return http.DefaultClient.Do(req)
	},
	"parseJSON": func(data interface{}) (interface{}, error) {
		var v interface{}
		var err error
		switch d := data.(type) {
		case []byte:
			err = json.Unmarshal(d, &v)
			return v, err
		case string:
			err = json.Unmarshal([]byte(d), &v)
			return v, err
		case bytes.Buffer:
			err = json.Unmarshal(d.Bytes(), &v)
			return v, err
		case io.Reader:
			var buf bytes.Buffer
			buf.ReadFrom(d)
			err = json.Unmarshal(buf.Bytes(), &v)
			return v, err
		}
		return nil, fmt.Errorf("TypeAssertionError")
	},
	"formatTime": func(srcLayout, targetLayout, input string) (string, error) {
		t, err := time.Parse(srcLayout, input)
		if err != nil {
			return "", err
		}
		return t.Format(targetLayout), nil
	},

	"formatUnix": func(targetLayout string, input interface{}) (string, error) {
		switch v := input.(type) {
		case int64:
			return time.Unix(v, 0).Format(targetLayout), nil
		case float64:
			return time.Unix(int64(v), 0).Format(targetLayout), nil
		case int:
			return time.Unix(int64(v), 0).Format(targetLayout), nil
		case string:
			intVal, err := strconv.Atoi(v)
			if err != nil {
				return "", err
			}
			return time.Unix(int64(intVal), 0).Format(targetLayout), nil
		case json.Number:
			intVal, err := v.Int64()
			if err != nil {
				return "", err
			}
			return time.Unix(intVal, 0).Format(targetLayout), nil
		case time.Time:
			return v.Format(targetLayout), nil
		default:
			return "", fmt.Errorf("invalid type for time.Unix in formatUnix")
		}
	},

	"formatUnixFull": func(targetLayout string, seconds interface{}, nanoseconds interface{}) (string, error) {
		var secs, nanos int64
		var err error
		secs, err = interfaceToInt64(seconds)
		if err != nil {
			return "", err
		}
		nanos, err = interfaceToInt64(nanoseconds)
		if err != nil {
			return "", err
		}
		return time.Unix(secs, nanos).Format(targetLayout), nil
	},
	"formatUnixTZ": func(targetLayout string, timezone string, input interface{}) (string, error) {
		tz, err := time.LoadLocation(timezone)
		if err != nil {
			return "", err
		}
		switch v := input.(type) {
		case int64:
			return time.Unix(v, 0).In(tz).Format(targetLayout), nil
		case float64:
			return time.Unix(int64(v), 0).In(tz).Format(targetLayout), nil
		case int:
			return time.Unix(int64(v), 0).In(tz).Format(targetLayout), nil
		case string:
			intVal, err := strconv.Atoi(v)
			if err != nil {
				return "", err
			}
			return time.Unix(int64(intVal), 0).In(tz).Format(targetLayout), nil
		case json.Number:
			intVal, err := v.Int64()
			if err != nil {
				return "", err
			}
			return time.Unix(intVal, 0).In(tz).Format(targetLayout), nil
		case time.Time:
			return v.In(tz).Format(targetLayout), nil
		default:
			return "", fmt.Errorf("invalid type for time.Unix in formatUnix")
		}
	},
	"formatUnixFullTZ": func(targetLayout string, timezone string, seconds interface{}, nanoseconds interface{}) (string, error) {
		var secs, nanos int64
		var err error
		secs, err = interfaceToInt64(seconds)
		if err != nil {
			return "", err
		}
		nanos, err = interfaceToInt64(nanoseconds)
		if err != nil {
			return "", err
		}
		tz, err := time.LoadLocation(timezone)
		if err != nil {
			return "", err
		}
		return time.Unix(secs, nanos).In(tz).Format(targetLayout), nil
	},
	"split": func(sep, input string) []string {
		return strings.Split(input, sep)
	},
	"first": func(input interface{}) interface{} {
		list := interfaceSlice(input)
		if list == nil {
			return nil
		}
		if len(list) == 0 {
			return nil
		}
		return list[0]
	},
	"last": func(input interface{}) interface{} {
		list := interfaceSlice(input)
		if list == nil {
			return nil
		}
		if len(list) == 0 {
			return nil
		}
		return list[len(list)-1]
	},
	"coalesce": func(values ...interface{}) interface{} {
		for _, v := range values {
			if v != nil && (reflect.ValueOf(v).Kind() != reflect.Ptr || !reflect.ValueOf(v).IsNil()) {
				return v
			}
		}
		return nil
	},
	"sortMap": func(list []interface{}, sortKey string, dir string) ([]interface{}, error) {
		if dir != "asc" && dir != "desc" {
			return nil, fmt.Errorf("invalid sort direction for sortMap")
		}

		var err error
		sort.SliceStable(list, func(i, j int) bool {
			var a, b string
			switch _a := list[i].(map[string]interface{})[sortKey].(type) {
			case float64:
				a = fmt.Sprintf("%.0f", _a)
			case int64:
				a = fmt.Sprintf("%d", _a)
			case string:
				a = _a
			case nil:
				a = ""
			default:
				err = fmt.Errorf("invalid value type in sortMap: %T", _a)
				return false
			}
			switch _b := list[j].(map[string]interface{})[sortKey].(type) {
			case float64:
				b = fmt.Sprintf("%.0f", _b)
			case int64:
				b = fmt.Sprintf("%d", _b)
			case string:
				b = _b
			case nil:
				b = ""
			default:
				err = fmt.Errorf("invalid value type in sortMap: %T", _b)
				return false
			}
			if dir == "asc" {
				return a < b
			}
			return a > b
		})
		if err != nil {
			return nil, err
		}
		return list, nil
	},
	"add": func(a, b int) int {
		return a + b
	},
	"addInt64": func(a, b int64) int64 {
		return a + b
	},
	"unquote": func(s string) string {
		if len(s) > 0 && s[0] == '"' {
			s = s[1:]
		}
		if len(s) > 0 && s[len(s)-1] == '"' {
			s = s[:len(s)-1]
		}
		return s
	},
	"getAuthXBearerToken": func(authxURL, authxToken, authorizationId string) (string, error) {
		var cacheKey = strings.Join([]string{authxURL, authxToken, authorizationId}, "::")
		cachedToken, _ := authxTokenCache.Get(cacheKey)
		if cachedTokenString, ok := cachedToken.(string); ok {
			return cachedTokenString, nil
		}
		var err error
		var graphqlQuery = fmt.Sprintf(`query {
			authorization(id: %q) {
				token(format:BEARER)
			}
		}`, authorizationId)
		var requestQuery = map[string]interface{}{
			"query": graphqlQuery,
		}
		var requestBody []byte
		requestBody, err = json.Marshal(requestQuery)
		if err != nil {
			return "", err
		}
		var req *http.Request
		req, err = http.NewRequest("POST", authxURL, bytes.NewBuffer(requestBody))
		if err != nil {
			return "", err
		}
		req.Header.Set("Authorization", authxToken)
		req.Header.Set("Content-Type", "application/json")
		var res *http.Response
		res, err = http.DefaultClient.Do(req)
		if err != nil {
			return "", err
		}
		var body []byte
		body, err = io.ReadAll(res.Body)
		if err != nil {
			return "", err
		}
		defer res.Body.Close()
		var tokenResponse struct {
			Errors []struct {
				Message string
			}
			Data struct {
				Authorization struct {
					Token string
				}
			}
		}
		err = json.Unmarshal(body, &tokenResponse)
		if err != nil {
			return "", err
		}
		if tokenResponse.Errors != nil && len(tokenResponse.Errors) > 0 {
			return "", fmt.Errorf("authx error: %s", tokenResponse.Errors[0].Message)
		}
		var authxBearerToken = tokenResponse.Data.Authorization.Token
		tokenParts := strings.Split(strings.Split(authxBearerToken, " ")[1], ".")
		jwtBase64 := tokenParts[1]
		var jwtBytes []byte
		jwtBytes, err = base64.RawURLEncoding.DecodeString(jwtBase64)
		if err != nil {
			return "", err
		}
		var jwt struct {
			AID    string
			Scopes []string
			IAT    int64
			EXP    int64
			ISS    string
			SUB    string
			JTI    string
		}
		err = json.Unmarshal(jwtBytes, &jwt)
		if err != nil {
			return "", err
		}
		var expireAt = time.Duration(jwt.EXP-time.Now().Unix())*time.Second - time.Minute
		authxTokenCache.SetEx(cacheKey, authxBearerToken, expireAt)
		return authxBearerToken, nil
	},
	"cacheSet": func(key string, value interface{}, expire interface{}) (interface{}, error) {
		exp, err := timeutils.InterfaceToApproxBigDuration(expire)
		if err != nil {
			return value, err
		}
		return value, templateCache.SetEx(key, value, time.Duration(exp))
	},
	"cacheGet": func(key string) interface{} {
		v, _ := templateCache.Get(key)
		return v
	},
	"parseCIDR": func(cidr string) (*net.IPNet, error) {
		_, ipnet, err := net.ParseCIDR(cidr)
		return ipnet, err
	},
	"toApproxBigDuration": func(i interface{}) (timeutils.ApproxBigDuration, error) {
		return timeutils.InterfaceToApproxBigDuration(i)
	},
	"int":             sprigFuncs["int"],
	"int64":           sprigFuncs["int64"],
	"atoi":            sprigFuncs["atoi"],
	"b64dec":          sprigFuncs["b64dec"],
	"b64enc":          sprigFuncs["b64enc"],
	"ternary":         sprigFuncs["ternary"],
	"sha1sum":         sprigFuncs["sha1sum"],
	"sha256sum":       sprigFuncs["sha256sum"],
	"encryptAES":      sprigFuncs["encryptAES"],
	"decryptAES":      sprigFuncs["decryptAES"],
	"nospace":         sprigFuncs["nospace"],
	"substr":          sprigFuncs["substr"],
	"regexMatch":      sprigFuncs["regexMatch"],
	"regexReplaceAll": sprigFuncs["regexReplaceAll"],
	"parseTime":       timeutils.ParseAny,
	"maybeParseTime":  timeutils.ParseAnyMaybe,
	"formatAnyTime": func(targetLayout, input string) (string, error) {
		t, err := timeutils.ParseAny(input)
		if err != nil {
			return "", err
		}
		return t.Format(targetLayout), nil
	},
	"maybeFormatAnyTime": func(targetLayout string, input interface{}) *string {
		switch v := input.(type) {
		case string:
			if v == "" {
				return nil
			}
			t := timeutils.ParseAnyMaybe(v)
			if t == nil {
				return nil
			}
			s := t.Format(targetLayout)
			return &s
		default:
			return nil
		}
	},
	"left": func(str string, n int) string {
		if len(str) <= n {
			return str
		}
		return str[:n]
	},
	"right": func(str string, n int) string {
		if len(str) <= n {
			return str
		}
		return str[len(str)-n:]
	},
	"toAmount": func(input interface{}) (amt *currency.Amount, err error) {
		var str string
		str, err = interfaceToString(input)
		if err != nil {
			return nil, err
		}
		json.Unmarshal([]byte(str), &amt)
		return
	},
	"onlyDigits": func(input string) string {
		return reNonDigit.ReplaceAllString(input, "")
	},
	"onlyAlpha": func(input string) string {
		return reNonAlpha.ReplaceAllString(input, "")
	},
	"joseSign": func(payload string, key string, alg jose.SignatureAlgorithm) (string, error) {
		var jwk jose.JSONWebKey
		err := jwk.UnmarshalJSON([]byte(key))
		if err != nil {
			return "unable to parse", err
		}

		signer, err := jose.NewSigner(jose.SigningKey{
			Algorithm: alg,
			Key:       jwk,
		}, nil)

		if err != nil {
			return "unable to create signer", err
		}

		jws, err := signer.Sign([]byte(payload))
		if err != nil {
			return "unable to sign", err
		}

		cs, err := jws.CompactSerialize()
		if err != nil {
			return "unable to sign", err
		}
		return cs, nil
	},
	"joseVerifySignature": func(payload, key string) (string, error) {
		var jwk jose.JSONWebKey

		err := jwk.UnmarshalJSON([]byte(key))
		if err != nil {
			fmt.Println("unmarshal error")
			return "", err
		}

		jws, err := jose.ParseSigned(payload)
		if err != nil {
			fmt.Println("parse error")
			return "", err
		}

		p, err := jws.Verify(jwk.Public().Key)
		if err != nil {
			fmt.Println("verify error")
			return "", err
		}

		return string(p), nil
	},
	"joseEncrypt": func(payload string, key string, enc jose.ContentEncryption, alg jose.KeyAlgorithm) (string, error) {
		var jwk jose.JSONWebKey

		err := jwk.UnmarshalJSON([]byte(key))
		if err != nil {
			return "unable to parse", err
		}

		encryptor, err := jose.NewEncrypter(enc, jose.Recipient{
			Algorithm: alg,
			Key:       jwk.Public(),
		}, nil)

		if err != nil {
			return "unable to create encrypter", err
		}

		jws, err := encryptor.Encrypt([]byte(payload))
		if err != nil {
			return "unable to encrypt", err
		}

		cs, err := jws.CompactSerialize()
		if err != nil {
			return "unable to serialize", err
		}
		return cs, nil
	},
	"joseDecrypt": func(payload, key string) (string, error) {
		var jwk jose.JSONWebKey

		err := jwk.UnmarshalJSON([]byte(key))
		if err != nil {
			return "unable to get key", err
		}

		decryptor, err := jose.ParseEncrypted(payload)

		if err != nil {
			return "unable to create decryptor", err
		}

		jws, err := decryptor.Decrypt(jwk)
		if err != nil {
			return "unable to decrypt", err
		}
		return string(jws), nil
	},
	"UNSAFE_render": disabledUnsafeRender,
}

TemplateFuncs ... DEPRECATED will become private variable in a future release Add functions to the RootTemplate instead

Functions

func AllowUnsafeRender added in v1.4.0

func AllowUnsafeRender(allow bool)

AllowUnsafeRender adds `USAFE_render` to the RootTemplate funcs Is is potentially unsafe because it exposes the ability for a template to read any file into a template.

func Configure added in v1.7.0

func Configure(cfg Config) (err error)

Configure calls each of the configuration functions based on the config provided

func Interpolate

func Interpolate(data interface{}, text string) (string, error)

Interpolate simplifies interpolating a template string with data

func InterpolateMap

func InterpolateMap(data interface{}, templateMap map[string]interface{}) (map[string]interface{}, error)

InterpolateMap interpolates a recursive map

func LoadPartial added in v1.4.0

func LoadPartial(name, template string) (err error)

LoadPartial parses the given template strings and adds it to the RootTemplate

func LoadPartialFiles added in v1.4.0

func LoadPartialFiles(filenames ...string) (err error)

LoadPartialFiles parses the given filenames and adds them to the RootTemplate

Types

type Config added in v1.5.0

type Config struct {
	// Allows use of the UNSAFE_render method from go-template
	AllowUnsafeRender bool `json:"allowUnsafeRender"`
	// Partials to load
	Partials []string `json:"partials"`
}

Config is a convenience struct for importing packages

type Template

type Template struct {
	*template.Template
}

Template is a wrapper that implements unmarshalJSON

func Must

func Must(t *Template, err error) *Template

Must is an feature copy of template.Must

func Parse

func Parse(src string) (*Template, error)

Parse is a shorthand for template.Parse using templatefuncs Uses a clone of RootTemplate as a base

func (*Template) ExecuteToInt

func (t *Template) ExecuteToInt(data interface{}) (int, error)

ExecuteToInt executes the template and returns the result as an int

func (*Template) ExecuteToString

func (t *Template) ExecuteToString(data interface{}) (string, error)

ExecuteToString executes the template and returns the result as a string

func (Template) MarshalJSON added in v1.10.0

func (t Template) MarshalJSON() ([]byte, error)

func (*Template) UnmarshalJSON

func (t *Template) UnmarshalJSON(data []byte) (err error)

UnmarshalJSON implementation for Template

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL