Skip to content

Commit

Permalink
Merge pull request #757 from nyaruka/fix-d3c-media-attach
Browse files Browse the repository at this point in the history
Adjust WA template to be send if present even when we have attachments
  • Loading branch information
rowanseymour authored Jun 17, 2024
2 parents 959457a + 29a169d commit 921f39f
Show file tree
Hide file tree
Showing 4 changed files with 439 additions and 367 deletions.
311 changes: 160 additions & 151 deletions handlers/dialog360/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,15 +311,24 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.Sen

var payloadAudio whatsapp.SendRequest

for i := 0; i < len(msgParts)+len(msg.Attachments()); i++ {
// do we have a template?
if msg.Templating() != nil {
payload := whatsapp.SendRequest{MessagingProduct: "whatsapp", RecipientType: "individual", To: msg.URN().Path()}
payload.Type = "template"
payload.Template = whatsapp.GetTemplatePayload(msg.Templating())

err := h.requestD3C(payload, accessToken, res, sendURL, clog)
if err != nil {
return err
}

} else {

for i := 0; i < len(msgParts)+len(msg.Attachments()); i++ {
payload := whatsapp.SendRequest{MessagingProduct: "whatsapp", RecipientType: "individual", To: msg.URN().Path()}

if len(msg.Attachments()) == 0 {

if len(msg.Attachments()) == 0 {
// do we have a template?
if msg.Templating() != nil {
payload.Type = "template"
payload.Template = whatsapp.GetTemplatePayload(msg.Templating())
} else {
if i < (len(msgParts) + len(msg.Attachments()) - 1) {
// this is still a msg part
text := &whatsapp.Text{PreviewURL: false}
Expand Down Expand Up @@ -395,169 +404,169 @@ func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.Sen
payload.Text = text
}
}
}

} else if i < len(msg.Attachments()) && (len(qrs) == 0 || len(qrs) > 3) {
attType, attURL := handlers.SplitAttachment(msg.Attachments()[i])
attType = strings.Split(attType, "/")[0]
if attType == "application" {
attType = "document"
}
payload.Type = attType
media := whatsapp.Media{Link: attURL}

if len(msgParts) == 1 && attType != "audio" && len(msg.Attachments()) == 1 && len(msg.QuickReplies()) == 0 {
media.Caption = msgParts[i]
hasCaption = true
}

if attType == "image" {
payload.Image = &media
} else if attType == "audio" {
payload.Audio = &media
} else if attType == "video" {
payload.Video = &media
} else if attType == "document" {
filename, err := utils.BasePathForURL(attURL)
if err != nil {
filename = ""
} else if i < len(msg.Attachments()) && (len(qrs) == 0 || len(qrs) > 3) {
attType, attURL := handlers.SplitAttachment(msg.Attachments()[i])
attType = strings.Split(attType, "/")[0]
if attType == "application" {
attType = "document"
}
if filename != "" {
media.Filename = filename
payload.Type = attType
media := whatsapp.Media{Link: attURL}

if len(msgParts) == 1 && attType != "audio" && len(msg.Attachments()) == 1 && len(msg.QuickReplies()) == 0 {
media.Caption = msgParts[i]
hasCaption = true
}
payload.Document = &media
}
} else {
if len(qrs) > 0 {
payload.Type = "interactive"
// if we have more than 10 quick replies, truncate and add channel error
if len(qrs) > 10 {
clog.Error(courier.NewChannelError("", "", "too many quick replies D3C supports only up to 10 quick replies"))
qrs = qrs[:10]

if attType == "image" {
payload.Image = &media
} else if attType == "audio" {
payload.Audio = &media
} else if attType == "video" {
payload.Video = &media
} else if attType == "document" {
filename, err := utils.BasePathForURL(attURL)
if err != nil {
filename = ""
}
if filename != "" {
media.Filename = filename
}
payload.Document = &media
}
} else {
if len(qrs) > 0 {
payload.Type = "interactive"
// if we have more than 10 quick replies, truncate and add channel error
if len(qrs) > 10 {
clog.Error(courier.NewChannelError("", "", "too many quick replies D3C supports only up to 10 quick replies"))
qrs = qrs[:10]
}

// We can use buttons
if len(qrs) <= 3 {
interactive := whatsapp.Interactive{Type: "button", Body: struct {
Text string "json:\"text\""
}{Text: msgParts[i]}}

if len(msg.Attachments()) > 0 {
hasCaption = true
attType, attURL := handlers.SplitAttachment(msg.Attachments()[i])
attType = strings.Split(attType, "/")[0]
if attType == "application" {
attType = "document"
}
if attType == "image" {
image := whatsapp.Media{
Link: attURL,
// We can use buttons
if len(qrs) <= 3 {
interactive := whatsapp.Interactive{Type: "button", Body: struct {
Text string "json:\"text\""
}{Text: msgParts[i]}}

if len(msg.Attachments()) > 0 {
hasCaption = true
attType, attURL := handlers.SplitAttachment(msg.Attachments()[i])
attType = strings.Split(attType, "/")[0]
if attType == "application" {
attType = "document"
}
interactive.Header = &struct {
Type string "json:\"type\""
Text string "json:\"text,omitempty\""
Video *whatsapp.Media "json:\"video,omitempty\""
Image *whatsapp.Media "json:\"image,omitempty\""
Document *whatsapp.Media "json:\"document,omitempty\""
}{Type: "image", Image: &image}
} else if attType == "video" {
video := whatsapp.Media{
Link: attURL,
}
interactive.Header = &struct {
Type string "json:\"type\""
Text string "json:\"text,omitempty\""
Video *whatsapp.Media "json:\"video,omitempty\""
Image *whatsapp.Media "json:\"image,omitempty\""
Document *whatsapp.Media "json:\"document,omitempty\""
}{Type: "video", Video: &video}
} else if attType == "document" {
filename, err := utils.BasePathForURL(attURL)
if err != nil {
return err
}
document := whatsapp.Media{
Link: attURL,
Filename: filename,
}
interactive.Header = &struct {
Type string "json:\"type\""
Text string "json:\"text,omitempty\""
Video *whatsapp.Media "json:\"video,omitempty\""
Image *whatsapp.Media "json:\"image,omitempty\""
Document *whatsapp.Media "json:\"document,omitempty\""
}{Type: "document", Document: &document}
} else if attType == "audio" {
payloadAudio = whatsapp.SendRequest{MessagingProduct: "whatsapp", RecipientType: "individual", To: msg.URN().Path(), Type: "audio", Audio: &whatsapp.Media{Link: attURL}}
err := h.requestD3C(payloadAudio, accessToken, res, sendURL, clog)
if err != nil {
return nil
if attType == "image" {
image := whatsapp.Media{
Link: attURL,
}
interactive.Header = &struct {
Type string "json:\"type\""
Text string "json:\"text,omitempty\""
Video *whatsapp.Media "json:\"video,omitempty\""
Image *whatsapp.Media "json:\"image,omitempty\""
Document *whatsapp.Media "json:\"document,omitempty\""
}{Type: "image", Image: &image}
} else if attType == "video" {
video := whatsapp.Media{
Link: attURL,
}
interactive.Header = &struct {
Type string "json:\"type\""
Text string "json:\"text,omitempty\""
Video *whatsapp.Media "json:\"video,omitempty\""
Image *whatsapp.Media "json:\"image,omitempty\""
Document *whatsapp.Media "json:\"document,omitempty\""
}{Type: "video", Video: &video}
} else if attType == "document" {
filename, err := utils.BasePathForURL(attURL)
if err != nil {
return err
}
document := whatsapp.Media{
Link: attURL,
Filename: filename,
}
interactive.Header = &struct {
Type string "json:\"type\""
Text string "json:\"text,omitempty\""
Video *whatsapp.Media "json:\"video,omitempty\""
Image *whatsapp.Media "json:\"image,omitempty\""
Document *whatsapp.Media "json:\"document,omitempty\""
}{Type: "document", Document: &document}
} else if attType == "audio" {
payloadAudio = whatsapp.SendRequest{MessagingProduct: "whatsapp", RecipientType: "individual", To: msg.URN().Path(), Type: "audio", Audio: &whatsapp.Media{Link: attURL}}
err := h.requestD3C(payloadAudio, accessToken, res, sendURL, clog)
if err != nil {
return nil
}
} else {
interactive.Type = "button"
interactive.Body.Text = msgParts[i]
}
} else {
interactive.Type = "button"
interactive.Body.Text = msgParts[i]
}
}

btns := make([]whatsapp.Button, len(qrs))
for i, qr := range qrs {
btns[i] = whatsapp.Button{
Type: "reply",
btns := make([]whatsapp.Button, len(qrs))
for i, qr := range qrs {
btns[i] = whatsapp.Button{
Type: "reply",
}
btns[i].Reply.ID = fmt.Sprint(i)
btns[i].Reply.Title = qr
}
btns[i].Reply.ID = fmt.Sprint(i)
btns[i].Reply.Title = qr
}
interactive.Action = &struct {
Button string "json:\"button,omitempty\""
Sections []whatsapp.Section "json:\"sections,omitempty\""
Buttons []whatsapp.Button "json:\"buttons,omitempty\""
}{Buttons: btns}
payload.Interactive = &interactive
interactive.Action = &struct {
Button string "json:\"button,omitempty\""
Sections []whatsapp.Section "json:\"sections,omitempty\""
Buttons []whatsapp.Button "json:\"buttons,omitempty\""
}{Buttons: btns}
payload.Interactive = &interactive

} else {
interactive := whatsapp.Interactive{Type: "list", Body: struct {
Text string "json:\"text\""
}{Text: msgParts[i-len(msg.Attachments())]}}
} else {
interactive := whatsapp.Interactive{Type: "list", Body: struct {
Text string "json:\"text\""
}{Text: msgParts[i-len(msg.Attachments())]}}

section := whatsapp.Section{
Rows: make([]whatsapp.SectionRow, len(qrs)),
}
for i, qr := range qrs {
section.Rows[i] = whatsapp.SectionRow{
ID: fmt.Sprint(i),
Title: qr,
section := whatsapp.Section{
Rows: make([]whatsapp.SectionRow, len(qrs)),
}
for i, qr := range qrs {
section.Rows[i] = whatsapp.SectionRow{
ID: fmt.Sprint(i),
Title: qr,
}
}
}

interactive.Action = &struct {
Button string "json:\"button,omitempty\""
Sections []whatsapp.Section "json:\"sections,omitempty\""
Buttons []whatsapp.Button "json:\"buttons,omitempty\""
}{Button: menuButton, Sections: []whatsapp.Section{
section,
}}
interactive.Action = &struct {
Button string "json:\"button,omitempty\""
Sections []whatsapp.Section "json:\"sections,omitempty\""
Buttons []whatsapp.Button "json:\"buttons,omitempty\""
}{Button: menuButton, Sections: []whatsapp.Section{
section,
}}

payload.Interactive = &interactive
}
} else {
// this is still a msg part
text := &whatsapp.Text{PreviewURL: false}
payload.Type = "text"
if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") {
text.PreviewURL = true
payload.Interactive = &interactive
}
} else {
// this is still a msg part
text := &whatsapp.Text{PreviewURL: false}
payload.Type = "text"
if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") {
text.PreviewURL = true
}
text.Body = msgParts[i-len(msg.Attachments())]
payload.Text = text
}
text.Body = msgParts[i-len(msg.Attachments())]
payload.Text = text
}
}

err := h.requestD3C(payload, accessToken, res, sendURL, clog)
if err != nil {
return err
}
err := h.requestD3C(payload, accessToken, res, sendURL, clog)
if err != nil {
return err
}

if hasCaption {
break
if hasCaption {
break
}
}
}

Expand Down
22 changes: 22 additions & 0 deletions handlers/dialog360/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,28 @@ var SendTestCasesD3C = []OutgoingTestCase{
}},
ExpectedExtIDs: []string{"157b5e14568e8"},
},
{
Label: "Template Send with attachment",
MsgText: "templated message",
MsgURN: "whatsapp:250788123123",
MsgLocale: "eng",
MsgAttachments: []string{"image/jpeg:https://foo.bar/example.jpg"},
MsgTemplating: `{
"template": {"uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3", "name": "revive_issue"},
"components": [{"name": "header","type": "header/media", "variables": {"1": 0}},{"type": "body/text", "name": "body", "variables": {"1": 1, "2": 2}}],
"variables": [{"type":"image", "value":"image/jpeg:https://foo.bar/image.jpg"},{"type":"text", "value":"Chef"}, {"type": "text" , "value": "tomorrow"}],
"language": "en_US"
}`,
MockResponses: map[string][]*httpx.MockResponse{
"https://waba-v2.360dialog.io/messages": {
httpx.NewMockResponse(200, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)),
},
},
ExpectedRequests: []ExpectedRequest{{
Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"header","parameters":[{"type":"image","image":{"link":"https://foo.bar/image.jpg"}}]},{"type":"body","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`,
}},
ExpectedExtIDs: []string{"157b5e14568e8"},
},
{
Label: "Interactive Button Message Send",
MsgText: "Interactive Button Msg",
Expand Down
Loading

0 comments on commit 921f39f

Please sign in to comment.