-
Notifications
You must be signed in to change notification settings - Fork 19
/
template.go
148 lines (125 loc) · 4.65 KB
/
template.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package flows
import (
"fmt"
"strings"
"github.com/nyaruka/gocommon/i18n"
"github.com/nyaruka/gocommon/stringsx"
"github.com/nyaruka/goflow/assets"
"github.com/nyaruka/goflow/utils"
)
// Template represents messaging templates used by channels types such as WhatsApp
type Template struct {
assets.Template
}
// NewTemplate returns a new template objects based on the passed in asset
func NewTemplate(t assets.Template) *Template {
return &Template{Template: t}
}
// Asset returns the underlying asset
func (t *Template) Asset() assets.Template { return t.Template }
// Reference returns the reference for this template
func (t *Template) Reference() *assets.TemplateReference {
if t == nil {
return nil
}
return assets.NewTemplateReference(t.UUID(), t.Name())
}
// FindTranslation finds the matching translation for the passed in channel and languages (in priority order)
func (t *Template) FindTranslation(channel *Channel, locales []i18n.Locale) *TemplateTranslation {
// find all translations for this channel
candidates := make(map[string]*TemplateTranslation)
candidateLocales := make([]string, 0, 5)
for _, tr := range t.Template.Translations() {
if tr.Channel().UUID == channel.UUID() {
candidates[string(tr.Locale())] = NewTemplateTranslation(tr)
candidateLocales = append(candidateLocales, string(tr.Locale()))
}
}
if len(candidates) == 0 {
return nil
}
match := i18n.NewBCP47Matcher(candidateLocales...).ForLocales(locales...)
return candidates[match]
}
// Templating generates a templating object for the passed in translation and variables
func (t *Template) Templating(tt *TemplateTranslation, vars []string) *MsgTemplating {
// cross-reference with asset to get variable types and pad out any missing variables
variables := make([]*TemplatingVariable, len(tt.Variables()))
for i, v := range tt.Variables() {
value := ""
if i < len(vars) {
value = vars[i]
}
variables[i] = &TemplatingVariable{Type: v.Type(), Value: value}
}
// create a list of components that have variables
components := make([]*TemplatingComponent, 0, len(tt.Components()))
for _, comp := range tt.Components() {
if len(comp.Variables()) > 0 {
components = append(components, &TemplatingComponent{
Type: comp.Type(),
Name: comp.Name(),
Variables: comp.Variables(),
})
}
}
return NewMsgTemplating(t.Reference(), components, variables)
}
// TemplateTranslation represents a single translation for a template
type TemplateTranslation struct {
assets.TemplateTranslation
}
// NewTemplateTranslation returns a new TemplateTranslation for the passed in asset
func NewTemplateTranslation(t assets.TemplateTranslation) *TemplateTranslation {
return &TemplateTranslation{TemplateTranslation: t}
}
// Asset returns the underlying asset
func (t *TemplateTranslation) Asset() assets.TemplateTranslation { return t.TemplateTranslation }
// Preview returns message content which will act as a preview of a message sent with this template
func (t *TemplateTranslation) Preview(vars []*TemplatingVariable) *MsgContent {
var text []string
var attachments []utils.Attachment
var quickReplies []string
for _, comp := range t.Components() {
content := comp.Content()
for key, index := range comp.Variables() {
variable := vars[index]
if variable.Type == "text" {
content = strings.ReplaceAll(content, fmt.Sprintf("{{%s}}", key), variable.Value)
} else if variable.Type == "image" || variable.Type == "video" || variable.Type == "document" {
attachments = append(attachments, utils.Attachment(variable.Value))
}
}
if content != "" {
if comp.Type() == "header/text" || comp.Type() == "body/text" || comp.Type() == "footer/text" {
text = append(text, content)
} else if strings.HasPrefix(comp.Type(), "button/") {
quickReplies = append(quickReplies, stringsx.TruncateEllipsis(content, MaxQuickReplyLength))
}
}
}
return &MsgContent{Text: strings.Join(text, "\n\n"), Attachments: attachments, QuickReplies: quickReplies}
}
// TemplateAssets is our type for all the templates in an environment
type TemplateAssets struct {
templates []*Template
byUUID map[assets.TemplateUUID]*Template
}
// NewTemplateAssets creates a new template list
func NewTemplateAssets(ts []assets.Template) *TemplateAssets {
templates := make([]*Template, len(ts))
byUUID := make(map[assets.TemplateUUID]*Template)
for i, t := range ts {
template := NewTemplate(t)
templates[i] = template
byUUID[t.UUID()] = template
}
return &TemplateAssets{
templates: templates,
byUUID: byUUID,
}
}
// Get returns the template with the passed in UUID if any
func (a *TemplateAssets) Get(uuid assets.TemplateUUID) *Template {
return a.byUUID[uuid]
}