Skip to content

Commit

Permalink
Drop support for variables in display parts of template components
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanseymour committed Mar 20, 2024
1 parent 827d54a commit a22bb61
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 86 deletions.
2 changes: 1 addition & 1 deletion flows/actions/send_msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func (a *SendMsgAction) getTemplateMsg(run flows.Run, urn urns.URN, channelRef *
}

compTemplating := &flows.TemplatingComponent{Type: comp.Type(), Params: params}
previewContent, _ := compTemplating.Preview(comp)
previewContent := compTemplating.Preview(comp)

if previewContent != "" {
if comp.Type() == "header" || comp.Type() == "body" || comp.Type() == "footer" {
Expand Down
20 changes: 10 additions & 10 deletions flows/actions/testdata/_assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,9 @@
"locale": "eng-US",
"components": [
{
"content": "Hi {{1}}, who's an excellent {{2}}?",
"type": "body",
"name": "body",
"content": "Hi {{1}}, who's an excellent {{2}}?",
"params": [
{
"type": "text"
Expand All @@ -281,9 +281,9 @@
"locale": "spa",
"components": [
{
"content": "Hola {{1}}, quien es un {{2}} excelente?",
"type": "body",
"name": "body",
"content": "Hola {{1}}, quien es un {{2}} excelente?",
"params": [
{
"type": "text"
Expand All @@ -309,9 +309,9 @@
"locale": "eng",
"components": [
{
"content": "Hi there, it's time to get up!",
"type": "body",
"name": "body",
"content": "Hi there, it's time to get up!",
"params": []
}
]
Expand All @@ -330,19 +330,19 @@
"locale": "eng-US",
"components": [
{
"content": "",
"type": "header",
"name": "header",
"content": "",
"params": [
{
"type": "image"
}
]
},
{
"content": "Hey {{1}}, your gender is saved as {{2}}.",
"type": "body",
"name": "body",
"content": "Hey {{1}}, your gender is saved as {{2}}.",
"params": [
{
"type": "text"
Expand All @@ -353,9 +353,9 @@
]
},
{
"content": "{{1}}",
"type": "button/quick_reply",
"name": "button.1",
"content": "{{1}}",
"params": [
{
"type": "text"
Expand All @@ -372,19 +372,19 @@
"locale": "spa",
"components": [
{
"content": "",
"type": "header",
"name": "header",
"content": "",
"params": [
{
"type": "image"
}
]
},
{
"content": "Hola, {{1}}, tu género está guardado como {{2}}.",
"type": "body",
"name": "body",
"content": "Hola, {{1}}, tu género está guardado como {{2}}.",
"params": [
{
"type": "text"
Expand All @@ -395,19 +395,19 @@
]
},
{
"content": "{{1}}",
"type": "button/quick_reply",
"name": "button.0",
"content": "{{1}}",
"params": [
{
"type": "text"
}
]
},
{
"content": "No",
"type": "button/quick_reply",
"name": "button.1",
"content": "No",
"params": []
}
]
Expand Down
40 changes: 7 additions & 33 deletions flows/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"fmt"
"regexp"
"slices"
"strconv"
"strings"

"github.com/go-playground/validator/v10"
Expand Down Expand Up @@ -183,42 +182,17 @@ type TemplatingComponent struct {

var templateVariableRegex = regexp.MustCompile(`{{(\d+)}}`)

func getTemplateVariableCount(s string) int {
count := 0
for _, m := range templateVariableRegex.FindAllStringSubmatch(s, -1) {
if v, _ := strconv.Atoi(m[1]); v > count {
count = v
}
}
return count
}

// Preview returns the content and display for given template component using these templating params
func (tc *TemplatingComponent) Preview(c assets.TemplateComponent) (string, string) {
// Preview returns the content of the given template component rendered using these templating params
func (tc *TemplatingComponent) Preview(c assets.TemplateComponent) string {
content := c.Content()
display := c.Display()
numContentParams := getTemplateVariableCount(content)
numDisplayParams := getTemplateVariableCount(display)

// replace {{?}} placeholders in component content
for i := 0; i < numContentParams; i++ {
value := ""
if i < len(tc.Params) {
value = tc.Params[i].Value
}
content = strings.ReplaceAll(content, fmt.Sprintf("{{%d}}", i+1), value)
}

// replace {{?}} placeholders in component display using any remaining param values
for i := 0; i < numDisplayParams; i++ {
value := ""
if (numContentParams + i) < len(tc.Params) {
value = tc.Params[numContentParams+i].Value
}
display = strings.ReplaceAll(display, fmt.Sprintf("{{%d}}", i+1), value)
for i, p := range tc.Params {
content = strings.ReplaceAll(content, fmt.Sprintf("{{%d}}", i+1), p.Value)
}

return content, display
content = templateVariableRegex.ReplaceAllString(content, "")

return content
}

// MsgTemplating represents any substituted message template that should be applied when sending this message
Expand Down
79 changes: 37 additions & 42 deletions flows/msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ func TestMsgTemplating(t *testing.T) {
require.NoError(t, err)

test.AssertEqualJSON(t, []byte(`{
"template":{
"name":"Affirmation",
"uuid":"61602f3e-f603-4c70-8a8f-c477505bf4bf"
},
"namespace":"0162a7f4_dfe4_4c96_be07_854d5dba3b2b",
"params": {
"body": [
Expand All @@ -188,68 +192,59 @@ func TestMsgTemplating(t *testing.T) {
}
]
},
"components":[{
"type": "body",
"params":[
"components":[
{
"type": "text",
"value": "Ryan Lewis"
},
{
"type": "text",
"value": "boy"
"type": "body",
"params":[
{
"type": "text",
"value": "Ryan Lewis"
},
{
"type": "text",
"value": "boy"
}
]
}
]
}],
"template":{
"name":"Affirmation",
"uuid":"61602f3e-f603-4c70-8a8f-c477505bf4bf"
}
]
}`), marshaled, "JSON mismatch")
}

func TestTemplatingComponentPreview(t *testing.T) {
tcs := []struct {
templating *flows.TemplatingComponent
component assets.TemplateComponent
expectedContent string
expectedDisplay string
templating *flows.TemplatingComponent
component assets.TemplateComponent
expected string
}{
{ // 0: no params
component: static.NewTemplateComponent("body", "body", "Hello", "", []*static.TemplateParam{}),
templating: &flows.TemplatingComponent{Type: "body", Params: []flows.TemplatingParam{}},
expectedContent: "Hello",
expectedDisplay: "",
component: static.NewTemplateComponent("body", "body", "Hello", "", []*static.TemplateParam{}),
templating: &flows.TemplatingComponent{Type: "body", Params: []flows.TemplatingParam{}},
expected: "Hello",
},
{ // 1: two params on component and two params in templating
component: static.NewTemplateComponent("body", "body", "Hello {{1}} {{2}}", "", []*static.TemplateParam{{Type_: "text"}, {Type_: "text"}}),
templating: &flows.TemplatingComponent{Type: "body", Params: []flows.TemplatingParam{{Type: "text", Value: "Dr"}, {Type: "text", Value: "Bob"}}},
expectedContent: "Hello Dr Bob",
expectedDisplay: "",
component: static.NewTemplateComponent("body", "body", "Hello {{1}} {{2}}", "", []*static.TemplateParam{{Type_: "text"}, {Type_: "text"}}),
templating: &flows.TemplatingComponent{Type: "body", Params: []flows.TemplatingParam{{Type: "text", Value: "Dr"}, {Type: "text", Value: "Bob"}}},
expected: "Hello Dr Bob",
},
{ // 2: one less param in templating than on component
component: static.NewTemplateComponent("body", "body", "Hello {{1}} {{2}}", "", []*static.TemplateParam{{Type_: "text"}, {Type_: "text"}}),
templating: &flows.TemplatingComponent{Type: "body", Params: []flows.TemplatingParam{{Type: "text", Value: "Dr"}}},
expectedContent: "Hello Dr ",
expectedDisplay: "",
component: static.NewTemplateComponent("body", "body", "Hello {{1}} {{2}}", "", []*static.TemplateParam{{Type_: "text"}, {Type_: "text"}}),
templating: &flows.TemplatingComponent{Type: "body", Params: []flows.TemplatingParam{{Type: "text", Value: "Dr"}}},
expected: "Hello Dr ",
},
{ // 3
component: static.NewTemplateComponent("button/quick_reply", "button.0", "{{1}}", "", []*static.TemplateParam{{Type_: "text"}}),
templating: &flows.TemplatingComponent{Type: "button/quick_reply", Params: []flows.TemplatingParam{{Type: "text", Value: "Yes"}}},
expectedContent: "Yes",
expectedDisplay: "",
component: static.NewTemplateComponent("button/quick_reply", "button.0", "{{1}}", "", []*static.TemplateParam{{Type_: "text"}}),
templating: &flows.TemplatingComponent{Type: "button/quick_reply", Params: []flows.TemplatingParam{{Type: "text", Value: "Yes"}}},
expected: "Yes",
},
{ // 4: one param for content, one for display
component: static.NewTemplateComponent("button/url", "button.0", "example.com?p={{1}}", "{{1}}", []*static.TemplateParam{{Type_: "text"}}),
templating: &flows.TemplatingComponent{Type: "button/url", Params: []flows.TemplatingParam{{Type: "text", Value: "123"}, {Type: "text", Value: "Go"}}},
expectedContent: "example.com?p=123",
expectedDisplay: "Go",
component: static.NewTemplateComponent("button/url", "button.0", "example.com?p={{1}}", "{{1}}", []*static.TemplateParam{{Type_: "text"}}),
templating: &flows.TemplatingComponent{Type: "button/url", Params: []flows.TemplatingParam{{Type: "text", Value: "123"}, {Type: "text", Value: "Go"}}},
expected: "example.com?p=123",
},
}

for i, tc := range tcs {
actualContent, actualDisplay := tc.templating.Preview(tc.component)
assert.Equal(t, tc.expectedContent, actualContent, "content mismatch in test %d", i)
assert.Equal(t, tc.expectedDisplay, actualDisplay, "display mismatch in test %d", i)
actualContent := tc.templating.Preview(tc.component)
assert.Equal(t, tc.expected, actualContent, "content mismatch in test %d", i)
}
}

0 comments on commit a22bb61

Please sign in to comment.