Templates: fix quoting certain parameters (#20376)

This commit is contained in:
andig 2025-04-04 16:13:08 +02:00 • committed by GitHub
parent 506ac15745
commit 0ec3d2525d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 45 additions and 39 deletions

View file

@ -21,8 +21,8 @@ render: |
power: # power reading
source: http # use http plugin
{{- if .host }}
uri: http://{{ .host }}:{{ .port }}/api/data/{{ trimAll "'" .uuid }}.json?from=now
uri: http://{{ .host }}:{{ .port }}/api/data/{{ unquote .uuid }}.json?from=now
{{ else }}
uri: {{ trimSuffix "/" .url }}/{{ trimAll "'" .uuid }}.json?from=now
uri: {{ trimSuffix "/" .url }}/{{ unquote .uuid }}.json?from=now
{{- end }}
jq: .data.tuples[0][1] # parse response json

View file

@ -25,16 +25,16 @@ render: |
add:
- source: http # import channel
{{- if .host }}
uri: http://{{ .host }}:{{ .port }}/api/data/{{ trimAll "'" .importuuid }}.json?from=now
uri: http://{{ .host }}:{{ .port }}/api/data/{{ unquote .importuuid }}.json?from=now
{{ else }}
uri: {{ trimSuffix "/" .url }}/{{ trimAll "'" .importuuid }}.json?from=now
uri: {{ trimSuffix "/" .url }}/{{ unquote .importuuid }}.json?from=now
{{- end }}
jq: .data.tuples[0][1] # parse response json
- source: http # export channel
{{- if .host }}
uri: http://{{ .host }}:{{ .port }}/api/data/{{ trimAll "'" .exportuuid }}.json?from=now
uri: http://{{ .host }}:{{ .port }}/api/data/{{ unquote .exportuuid }}.json?from=now
{{ else }}
uri: {{ trimSuffix "/" .url }}/{{ trimAll "'" .exportuuid }}.json?from=now
uri: {{ trimSuffix "/" .url }}/{{ unquote .exportuuid }}.json?from=now
{{- end }}
jq: .data.tuples[0][1] # parse response json
scale: -1 # export must result in negative values

View file

@ -19,6 +19,6 @@ render: |
power: # power reading
source: ws # use websocket plugin
uri: ws://{{ .host }}:{{ .port }}/socket
jq: .data | select(.uuid=={{ quote (trimAll "'" .uuid) }}) .tuples[0][1] # parse response json
jq: .data | select(.uuid=="{{ unquote .uuid }}") .tuples[0][1] # parse response json
timeout: 30s
scale: 1

View file

@ -73,7 +73,7 @@ render: |
power: # power reading
source: http # use http plugin
uri: http://{{ .host }}:{{ .port }}/
jq: .data[] | select(.uuid=={{ quote (trimAll "'" .uuid) }}) | .tuples[0][1] # parse response json
jq: .data[] | select(.uuid=="{{ unquote .uuid }}") | .tuples[0][1] # parse response json
cache: {{ .cache }}
{{- if .scale }}
scale: {{ .scale }}
@ -82,44 +82,44 @@ render: |
currents:
- source: http
uri: http://{{ .host }}:{{ .port }}/
jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l1currentuuid) }}) | .tuples[0][1]
jq: .data[] | select(.uuid=="{{ unquote .l1currentuuid }}") | .tuples[0][1]
cache: {{ .cache }}
- source: http
uri: http://{{ .host }}:{{ .port }}/
jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l2currentuuid) }}) | .tuples[0][1]
jq: .data[] | select(.uuid=="{{ unquote .l2currentuuid }}") | .tuples[0][1]
cache: {{ .cache }}
- source: http
uri: http://{{ .host }}:{{ .port }}/
jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l3currentuuid) }}) | .tuples[0][1]
jq: .data[] | select(.uuid=="{{ unquote .l3currentuuid }}") | .tuples[0][1]
cache: {{ .cache }}
{{ end -}}
{{ if and .l1poweruuid .l2poweruuid .l3poweruuid -}}
powers:
- source: http
uri: http://{{ .host }}:{{ .port }}/
jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l1poweruuid) }}) | .tuples[0][1]
jq: .data[] | select(.uuid=="{{ unquote .l1poweruuid }}") | .tuples[0][1]
cache: {{ .cache }}
- source: http
uri: http://{{ .host }}:{{ .port }}/
jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l2poweruuid) }}) | .tuples[0][1]
jq: .data[] | select(.uuid=="{{ unquote .l2poweruuid }}") | .tuples[0][1]
cache: {{ .cache }}
- source: http
uri: http://{{ .host }}:{{ .port }}/
jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l3poweruuid) }}) | .tuples[0][1]
jq: .data[] | select(.uuid=="{{ unquote .l3poweruuid }}") | .tuples[0][1]
cache: {{ .cache }}
{{ end -}}
{{ if and .l1voltageuuid .l2voltageuuid .l3voltageuuid -}}
voltages:
- source: http
uri: http://{{ .host }}:{{ .port }}/
jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l1voltageuuid) }}) | .tuples[0][1]
jq: .data[] | select(.uuid=="{{ unquote .l1voltageuuid }}") | .tuples[0][1]
cache: {{ .cache }}
- source: http
uri: http://{{ .host }}:{{ .port }}/
jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l2voltageuuid) }}) | .tuples[0][1]
jq: .data[] | select(.uuid=="{{ unquote .l2voltageuuid }}") | .tuples[0][1]
cache: {{ .cache }}
- source: http
uri: http://{{ .host }}:{{ .port }}/
jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l3voltageuuid) }}) | .tuples[0][1]
jq: .data[] | select(.uuid=="{{ unquote .l3voltageuuid }}") | .tuples[0][1]
cache: {{ .cache }}
{{ end -}}

View file

@ -31,7 +31,7 @@ onIdentify:
{{- if len .identifiers }}
identifiers:
{{- range .identifiers }}
- {{ . }}
- {{ quote . }}
{{- end }}
{{- end }}

View file

@ -31,7 +31,7 @@ var (
func init() {
ConfigDefaults.Load()
baseTmpl = template.Must(template.ParseFS(includeFS, "includes/*.tpl"))
baseTmpl = template.Must(FuncMap(template.New("base")).ParseFS(includeFS, "includes/*.tpl"))
for _, class := range []Class{Charger, Meter, Vehicle, Tariff} {
load(class)

View file

@ -8,7 +8,6 @@ import (
"strings"
"dario.cat/mergo"
"gopkg.in/yaml.v3"
)
const (
@ -250,22 +249,7 @@ func (p *Param) yamlQuote(value string) string {
return value
}
input := fmt.Sprintf("key: %s", value)
var res struct {
Value string `yaml:"key"`
}
if err := yaml.Unmarshal([]byte(input), &res); err != nil || value != res.Value {
return quote(value)
}
// fix 0815, but not 0
if strings.HasPrefix(value, "0") && len(value) > 1 {
return quote(value)
}
return value
return yamlQuote(value)
}
// Product contains naming information about a product a template supports

View file

@ -8,8 +8,30 @@ import (
"text/template"
"github.com/Masterminds/sprig/v3"
"gopkg.in/yaml.v3"
)
func yamlQuote(value string) string {
if value == "" {
return value
}
input := fmt.Sprintf("key: %s", value)
var res struct {
Value any `yaml:"key"`
}
if err := yaml.Unmarshal([]byte(input), &res); err == nil {
b, err := yaml.Marshal(res)
if err == nil && strings.TrimSpace(strings.TrimPrefix(string(b), "key: ")) == value {
return value
}
}
return quote(value)
}
func quote(value string) string {
quoted := strings.ReplaceAll(value, `'`, `''`)
return fmt.Sprintf("'%s'", quoted)
@ -41,6 +63,7 @@ func FuncMap(tmpl *template.Template) *template.Template {
},
"urlEncode": url.QueryEscape,
"unquote": unquote,
"quote": yamlQuote,
}
return tmpl.Funcs(sprig.FuncMap()).Funcs(funcMap)

View file

@ -10,10 +10,9 @@ import (
)
func TestYamlDecode(t *testing.T) {
p := Param{Type: TypeString}
for _, value := range []string{`value`, `!value`, `@value`, `"value"`, `"va"lue"`, `va'lue`, `@va'lue`, `0815`, `"0815"`, `4711`, `#pwd`, ``} {
for _, value := range []string{`value`, `!value`, `@value`, `"va"lue"`, `va'lue`, `@va'lue`, `0815`, `4711`, `#pwd`, ``} {
t.Run(value, func(t *testing.T) {
quoted := p.yamlQuote(value)
quoted := yamlQuote(value)
input := fmt.Sprintf("key: %s", quoted)
var res struct {