diff --git a/flows/actions/base.go b/flows/actions/base.go index b7265d6d5..bce62db41 100644 --- a/flows/actions/base.go +++ b/flows/actions/base.go @@ -22,12 +22,6 @@ import ( // max number of bytes to be saved to extra on a result const resultExtraMaxBytes = 10000 -// max length of a message attachment (type:url) -const maxAttachmentLength = 2048 - -// max length of a quick reply -const maxQuickReplyLength = 64 - // common category names const ( CategorySuccess = "Success" @@ -96,8 +90,8 @@ func (a *baseAction) evaluateMessage(run flows.Run, languages []i18n.Language, a logEvent(events.NewErrorf("attachment text evaluated to empty string, skipping")) continue } - if len(evaluatedAttachment) > maxAttachmentLength { - logEvent(events.NewErrorf("evaluated attachment is longer than %d limit, skipping", maxAttachmentLength)) + if len(evaluatedAttachment) > flows.MaxAttachmentLength { + logEvent(events.NewErrorf("evaluated attachment is longer than %d limit, skipping", flows.MaxAttachmentLength)) continue } evaluatedAttachments = append(evaluatedAttachments, utils.Attachment(evaluatedAttachment)) @@ -112,7 +106,7 @@ func (a *baseAction) evaluateMessage(run flows.Run, languages []i18n.Language, a logEvent(events.NewErrorf("quick reply text evaluated to empty string, skipping")) continue } - evaluatedQuickReplies = append(evaluatedQuickReplies, stringsx.TruncateEllipsis(evaluatedQuickReply, maxQuickReplyLength)) + evaluatedQuickReplies = append(evaluatedQuickReplies, stringsx.TruncateEllipsis(evaluatedQuickReply, flows.MaxQuickReplyLength)) } // although it's possible for the different parts of the message to have different languages, we want to resolve diff --git a/flows/actions/send_msg.go b/flows/actions/send_msg.go index 5555f17c1..dd759ad25 100644 --- a/flows/actions/send_msg.go +++ b/flows/actions/send_msg.go @@ -1,17 +1,12 @@ package actions import ( - "fmt" - "strings" - "github.com/nyaruka/gocommon/i18n" - "github.com/nyaruka/gocommon/stringsx" "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/gocommon/uuids" "github.com/nyaruka/goflow/assets" "github.com/nyaruka/goflow/flows" "github.com/nyaruka/goflow/flows/events" - "github.com/nyaruka/goflow/utils" ) func init() { @@ -153,33 +148,9 @@ func (a *SendMsgAction) getTemplateMsg(run flows.Run, urn urns.URN, channelRef * } // the message we return is an approximate preview of what the channel will send using the template - var previewText []string - var previewAttachments []utils.Attachment - var previewQRs []string - - for _, comp := range translation.Components() { - previewContent := comp.Content() - for key, index := range comp.Variables() { - variable := variables[index] - - if variable.Type == "text" { - previewContent = strings.ReplaceAll(previewContent, fmt.Sprintf("{{%s}}", key), variable.Value) - } else if variable.Type == "image" || variable.Type == "video" || variable.Type == "document" { - previewAttachments = append(previewAttachments, utils.Attachment(variable.Value)) - } - } - - if previewContent != "" { - if comp.Type() == "header/text" || comp.Type() == "body/text" || comp.Type() == "footer/text" { - previewText = append(previewText, previewContent) - } else if strings.HasPrefix(comp.Type(), "button/") { - previewQRs = append(previewQRs, stringsx.TruncateEllipsis(previewContent, maxQuickReplyLength)) - } - } - } - + preview := translation.Preview(variables) locale := translation.Locale() templating := flows.NewMsgTemplating(a.Template, translation.Namespace(), components, variables) - return flows.NewMsgOut(urn, channelRef, strings.Join(previewText, "\n\n"), previewAttachments, previewQRs, templating, flows.NilMsgTopic, locale, unsendableReason) + return flows.NewMsgOut(urn, channelRef, preview.Text, preview.Attachments, preview.QuickReplies, templating, flows.NilMsgTopic, locale, unsendableReason) } diff --git a/flows/msg.go b/flows/msg.go index d356fd78e..f6bbb46d2 100644 --- a/flows/msg.go +++ b/flows/msg.go @@ -22,6 +22,12 @@ func init() { type UnsendableReason string const ( + // max length of a message attachment (type:url) + MaxAttachmentLength = 2048 + + // max length of a quick reply + MaxQuickReplyLength = 64 + NilUnsendableReason UnsendableReason = "" UnsendableReasonNoDestination UnsendableReason = "no_destination" // no sendable channel+URN pair UnsendableReasonContactStatus UnsendableReason = "contact_status" // contact is blocked or stopped or archived diff --git a/flows/template.go b/flows/template.go index 33dad7446..82b0f4c16 100644 --- a/flows/template.go +++ b/flows/template.go @@ -1,8 +1,13 @@ 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 @@ -58,6 +63,36 @@ func NewTemplateTranslation(t assets.TemplateTranslation) *TemplateTranslation { // 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