Skip to content

Commit f42aadb

Browse files
committed
Add media support config for D3C
1 parent fe66ad4 commit f42aadb

File tree

3 files changed

+85
-44
lines changed

3 files changed

+85
-44
lines changed

handlers/dialog360/dialog360.go

+35-22
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ var (
2828
maxMsgLength = 1000
2929
)
3030

31+
// see https://developers.facebook.com/docs/whatsapp/cloud-api/reference/media#supported-media-types
32+
var mediaSupport = map[handlers.MediaType]handlers.MediaTypeSupport{
33+
handlers.MediaType("image/webp"): {Types: []string{"image/webp"}, MaxBytes: 100 * 1024, MaxWidth: 512, MaxHeight: 512},
34+
handlers.MediaTypeImage: {Types: []string{"image/jpeg", "image/png"}, MaxBytes: 5 * 1024 * 1024},
35+
handlers.MediaTypeAudio: {Types: []string{"audio/aac", "audio/mp4", "audio/mpeg", "audio/amr", "audio/ogg"}, MaxBytes: 16 * 1024 * 1024},
36+
handlers.MediaTypeVideo: {Types: []string{"video/mp4", "video/3gp"}, MaxBytes: 16 * 1024 * 1024},
37+
handlers.MediaTypeApplication: {MaxBytes: 100 * 1024 * 1024},
38+
}
39+
3140
func init() {
3241
courier.RegisterHandler(newWAHandler(courier.ChannelType("D3C"), "360Dialog"))
3342
}
@@ -549,10 +558,15 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann
549558

550559
var payloadAudio wacMTPayload
551560

552-
for i := 0; i < len(msgParts)+len(msg.Attachments()); i++ {
561+
attachments, err := handlers.ResolveAttachments(ctx, h.Backend(), msg.Attachments(), mediaSupport, false)
562+
if err != nil {
563+
return nil, errors.Wrap(err, "error resolving attachments")
564+
}
565+
566+
for i := 0; i < len(msgParts)+len(attachments); i++ {
553567
payload := wacMTPayload{MessagingProduct: "whatsapp", RecipientType: "individual", To: msg.URN().Path()}
554568

555-
if len(msg.Attachments()) == 0 {
569+
if len(attachments) == 0 {
556570
// do we have a template?
557571
templating, err := h.getTemplating(msg)
558572
if err != nil {
@@ -573,14 +587,14 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann
573587
template.Components = append(payload.Template.Components, component)
574588

575589
} else {
576-
if i < (len(msgParts) + len(msg.Attachments()) - 1) {
590+
if i < (len(msgParts) + len(attachments) - 1) {
577591
// this is still a msg part
578592
text := &wacText{PreviewURL: false}
579593
payload.Type = "text"
580-
if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") {
594+
if strings.Contains(msgParts[i-len(attachments)], "https://") || strings.Contains(msgParts[i-len(attachments)], "http://") {
581595
text.PreviewURL = true
582596
}
583-
text.Body = msgParts[i-len(msg.Attachments())]
597+
text.Body = msgParts[i-len(attachments)]
584598
payload.Text = text
585599
} else {
586600
if len(qrs) > 0 {
@@ -589,7 +603,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann
589603
if len(qrs) <= 3 {
590604
interactive := wacInteractive{Type: "button", Body: struct {
591605
Text string "json:\"text\""
592-
}{Text: msgParts[i-len(msg.Attachments())]}}
606+
}{Text: msgParts[i-len(attachments)]}}
593607

594608
btns := make([]wacMTButton, len(qrs))
595609
for i, qr := range qrs {
@@ -608,7 +622,7 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann
608622
} else if len(qrs) <= 10 {
609623
interactive := wacInteractive{Type: "list", Body: struct {
610624
Text string "json:\"text\""
611-
}{Text: msgParts[i-len(msg.Attachments())]}}
625+
}{Text: msgParts[i-len(attachments)]}}
612626

613627
section := wacMTSection{
614628
Rows: make([]wacMTSectionRow, len(qrs)),
@@ -636,33 +650,32 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann
636650
// this is still a msg part
637651
text := &wacText{PreviewURL: false}
638652
payload.Type = "text"
639-
if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") {
653+
if strings.Contains(msgParts[i-len(attachments)], "https://") || strings.Contains(msgParts[i-len(attachments)], "http://") {
640654
text.PreviewURL = true
641655
}
642-
text.Body = msgParts[i-len(msg.Attachments())]
656+
text.Body = msgParts[i-len(attachments)]
643657
payload.Text = text
644658
}
645659
}
646660
}
647661

648-
} else if i < len(msg.Attachments()) && (len(qrs) == 0 || len(qrs) > 3) {
649-
attType, attURL := handlers.SplitAttachment(msg.Attachments()[i])
650-
splitedAttType := strings.Split(attType, "/")
651-
attType = splitedAttType[0]
652-
attFormat := splitedAttType[1]
662+
} else if i < len(attachments) && (len(qrs) == 0 || len(qrs) > 3) {
663+
attURL := attachments[i].Media.URL()
664+
attType := attachments[i].Type
665+
attContentType := attachments[i].Media.ContentType()
653666
if attType == "application" {
654667
attType = "document"
655668
}
656-
payload.Type = attType
669+
payload.Type = string(attType)
657670
media := wacMTMedia{Link: attURL}
658671

659-
if len(msgParts) == 1 && attType != "audio" && len(msg.Attachments()) == 1 && len(msg.QuickReplies()) == 0 {
672+
if len(msgParts) == 1 && attType != "audio" && len(attachments) == 1 && len(msg.QuickReplies()) == 0 {
660673
media.Caption = msgParts[i]
661674
hasCaption = true
662675
}
663676

664677
if attType == "image" {
665-
if attFormat == "webp" {
678+
if attContentType == "image/webp" {
666679
payload.Type = "sticker"
667680
payload.Sticker = &media
668681
} else {
@@ -692,10 +705,10 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann
692705
Text string "json:\"text\""
693706
}{Text: msgParts[i]}}
694707

695-
if len(msg.Attachments()) > 0 {
708+
if len(attachments) > 0 {
696709
hasCaption = true
697-
attType, attURL := handlers.SplitAttachment(msg.Attachments()[i])
698-
attType = strings.Split(attType, "/")[0]
710+
attURL := attachments[i].Media.URL()
711+
attType := attachments[i].Type
699712
if attType == "application" {
700713
attType = "document"
701714
}
@@ -799,10 +812,10 @@ func (h *handler) Send(ctx context.Context, msg courier.Msg, clog *courier.Chann
799812
// this is still a msg part
800813
text := &wacText{PreviewURL: false}
801814
payload.Type = "text"
802-
if strings.Contains(msgParts[i-len(msg.Attachments())], "https://") || strings.Contains(msgParts[i-len(msg.Attachments())], "http://") {
815+
if strings.Contains(msgParts[i-len(attachments)], "https://") || strings.Contains(msgParts[i-len(attachments)], "http://") {
803816
text.PreviewURL = true
804817
}
805-
text.Body = msgParts[i-len(msg.Attachments())]
818+
text.Body = msgParts[i-len(attachments)]
806819
payload.Text = text
807820
}
808821
}

handlers/dialog360/dialog360_test.go

+49-21
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,10 @@ func buildMockD3MediaService(testChannels []courier.Channel, testCases []Channel
289289
fileURL = "https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=id_audio"
290290
}
291291

292+
if strings.HasSuffix(r.URL.Path, "id_sticker") {
293+
fileURL = "https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=id_sticker"
294+
}
295+
292296
w.WriteHeader(http.StatusOK)
293297
w.Write([]byte(fmt.Sprintf(`{ "url": "%s" }`, fileURL)))
294298
}))
@@ -364,12 +368,12 @@ var SendTestCasesD3C = []ChannelSendTestCase{
364368
Label: "Audio Send",
365369
MsgText: "audio caption",
366370
MsgURN: "whatsapp:250788123123",
367-
MsgAttachments: []string{"audio/mpeg:https://foo.bar/audio.mp3"},
371+
MsgAttachments: []string{"audio/mpeg:http://mock.com/3456/test.mp3"},
368372
MockResponses: map[MockedRequest]*httpx.MockResponse{
369373
{
370374
Method: "POST",
371375
Path: "/messages",
372-
Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`,
376+
Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"audio","audio":{"link":"http://mock.com/3456/test.mp3"}}`,
373377
}: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)),
374378
{
375379
Method: "POST",
@@ -385,10 +389,10 @@ var SendTestCasesD3C = []ChannelSendTestCase{
385389
Label: "Document Send",
386390
MsgText: "document caption",
387391
MsgURN: "whatsapp:250788123123",
388-
MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"},
392+
MsgAttachments: []string{"application/pdf:http://mock.com/7890/test.pdf"},
389393
MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`,
390394
MockResponseStatus: 201,
391-
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf","caption":"document caption","filename":"document.pdf"}}`,
395+
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"document","document":{"link":"http://mock.com/7890/test.pdf","caption":"document caption","filename":"test.pdf"}}`,
392396
ExpectedRequestPath: "/messages",
393397
ExpectedMsgStatus: "W",
394398
ExpectedExternalID: "157b5e14568e8",
@@ -398,10 +402,10 @@ var SendTestCasesD3C = []ChannelSendTestCase{
398402
Label: "Image Send",
399403
MsgText: "image caption",
400404
MsgURN: "whatsapp:250788123123",
401-
MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"},
405+
MsgAttachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"},
402406
MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`,
403407
MockResponseStatus: 201,
404-
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg","caption":"image caption"}}`,
408+
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"http://mock.com/1234/test.jpg","caption":"image caption"}}`,
405409
ExpectedRequestPath: "/messages",
406410
ExpectedMsgStatus: "W",
407411
ExpectedExternalID: "157b5e14568e8",
@@ -411,10 +415,10 @@ var SendTestCasesD3C = []ChannelSendTestCase{
411415
Label: "Sticker Send",
412416
MsgText: "sticker caption",
413417
MsgURN: "whatsapp:250788123123",
414-
MsgAttachments: []string{"image/webp:https://foo.bar/sticker.webp"},
418+
MsgAttachments: []string{"image/webp:http://mock.com/8901/test.webp"},
415419
MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`,
416420
MockResponseStatus: 201,
417-
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"sticker","sticker":{"link":"https://foo.bar/sticker.webp","caption":"sticker caption"}}`,
421+
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"sticker","sticker":{"link":"http://mock.com/8901/test.webp","caption":"sticker caption"}}`,
418422
ExpectedRequestPath: "/messages",
419423
ExpectedMsgStatus: "W",
420424
ExpectedExternalID: "157b5e14568e8",
@@ -424,10 +428,10 @@ var SendTestCasesD3C = []ChannelSendTestCase{
424428
Label: "Video Send",
425429
MsgText: "video caption",
426430
MsgURN: "whatsapp:250788123123",
427-
MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"},
431+
MsgAttachments: []string{"video/mp4:http://mock.com/5678/test.mp4"},
428432
MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`,
429433
MockResponseStatus: 201,
430-
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"video","video":{"link":"https://foo.bar/video.mp4","caption":"video caption"}}`,
434+
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"video","video":{"link":"http://mock.com/5678/test.mp4","caption":"video caption"}}`,
431435
ExpectedRequestPath: "/messages",
432436
ExpectedMsgStatus: "W",
433437
ExpectedExternalID: "157b5e14568e8",
@@ -514,10 +518,10 @@ var SendTestCasesD3C = []ChannelSendTestCase{
514518
MsgText: "Interactive Button Msg",
515519
MsgURN: "whatsapp:250788123123",
516520
MsgQuickReplies: []string{"BUTTON1"},
517-
MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"},
521+
MsgAttachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"},
518522
MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`,
519523
MockResponseStatus: 201,
520-
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","header":{"type":"image","image":{"link":"https://foo.bar/image.jpg"}},"body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`,
524+
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","header":{"type":"image","image":{"link":"http://mock.com/1234/test.jpg"}},"body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`,
521525
ExpectedRequestPath: "/messages",
522526
ExpectedMsgStatus: "W",
523527
ExpectedExternalID: "157b5e14568e8",
@@ -528,10 +532,10 @@ var SendTestCasesD3C = []ChannelSendTestCase{
528532
MsgText: "Interactive Button Msg",
529533
MsgURN: "whatsapp:250788123123",
530534
MsgQuickReplies: []string{"BUTTON1"},
531-
MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"},
535+
MsgAttachments: []string{"video/mp4:http://mock.com/5678/test.mp4"},
532536
MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`,
533537
MockResponseStatus: 201,
534-
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","header":{"type":"video","video":{"link":"https://foo.bar/video.mp4"}},"body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`,
538+
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","header":{"type":"video","video":{"link":"http://mock.com/5678/test.mp4"}},"body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`,
535539
ExpectedRequestPath: "/messages",
536540
ExpectedMsgStatus: "W",
537541
ExpectedExternalID: "157b5e14568e8",
@@ -542,10 +546,10 @@ var SendTestCasesD3C = []ChannelSendTestCase{
542546
MsgText: "Interactive Button Msg",
543547
MsgURN: "whatsapp:250788123123",
544548
MsgQuickReplies: []string{"BUTTON1"},
545-
MsgAttachments: []string{"document/pdf:https://foo.bar/document.pdf"},
549+
MsgAttachments: []string{"document/pdf:http://mock.com/7890/test.pdf"},
546550
MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`,
547551
MockResponseStatus: 201,
548-
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","header":{"type":"document","document":{"link":"https://foo.bar/document.pdf","filename":"document.pdf"}},"body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`,
552+
ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","header":{"type":"document","document":{"link":"http://mock.com/7890/test.pdf","filename":"test.pdf"}},"body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`,
549553
ExpectedRequestPath: "/messages",
550554
ExpectedMsgStatus: "W",
551555
ExpectedExternalID: "157b5e14568e8",
@@ -556,12 +560,12 @@ var SendTestCasesD3C = []ChannelSendTestCase{
556560
MsgText: "Interactive Button Msg",
557561
MsgURN: "whatsapp:250788123123",
558562
MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3"},
559-
MsgAttachments: []string{"audio/mp3:https://foo.bar/audio.mp3"},
563+
MsgAttachments: []string{"audio/mp3:http://mock.com/3456/test.mp3"},
560564
MockResponses: map[MockedRequest]*httpx.MockResponse{
561565
{
562566
Method: "POST",
563567
Path: "/messages",
564-
Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`,
568+
Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"audio","audio":{"link":"http://mock.com/3456/test.mp3"}}`,
565569
}: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)),
566570
{
567571
Method: "POST",
@@ -578,12 +582,12 @@ var SendTestCasesD3C = []ChannelSendTestCase{
578582
MsgText: "Interactive List Msg",
579583
MsgURN: "whatsapp:250788123123",
580584
MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"},
581-
MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"},
585+
MsgAttachments: []string{"image/jpeg:http://mock.com/1234/test.jpg"},
582586
MockResponses: map[MockedRequest]*httpx.MockResponse{
583587
{
584588
Method: "POST",
585589
Path: "/messages",
586-
Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`,
590+
Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"http://mock.com/1234/test.jpg"}}`,
587591
}: httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)),
588592
{
589593
Method: "POST",
@@ -629,6 +633,30 @@ var SendTestCasesD3C = []ChannelSendTestCase{
629633
},
630634
}
631635

636+
// setupMedia takes care of having the media files needed to our test server host
637+
func setupMedia(mb *test.MockBackend) {
638+
imageJPG := test.NewMockMedia("test.jpg", "image/jpeg", "http://mock.com/1234/test.jpg", 1024*1024, 640, 480, 0, nil)
639+
640+
audioM4A := test.NewMockMedia("test.m4a", "audio/mp4", "http://mock.com/2345/test.m4a", 1024*1024, 0, 0, 200, nil)
641+
audioMP3 := test.NewMockMedia("test.mp3", "audio/mpeg", "http://mock.com/3456/test.mp3", 1024*1024, 0, 0, 200, []courier.Media{audioM4A})
642+
643+
thumbJPG := test.NewMockMedia("test.jpg", "image/jpeg", "http://mock.com/4567/test.jpg", 1024*1024, 640, 480, 0, nil)
644+
videoMP4 := test.NewMockMedia("test.mp4", "video/mp4", "http://mock.com/5678/test.mp4", 1024*1024, 0, 0, 1000, []courier.Media{thumbJPG})
645+
646+
videoMOV := test.NewMockMedia("test.mov", "video/quicktime", "http://mock.com/6789/test.mov", 100*1024*1024, 0, 0, 2000, nil)
647+
648+
filePDF := test.NewMockMedia("test.pdf", "application/pdf", "http://mock.com/7890/test.pdf", 100*1024*1024, 0, 0, 0, nil)
649+
650+
stickerWEBP := test.NewMockMedia("test.webp", "image/webp", "http://mock.com/8901/test.webp", 50*1024, 480, 480, 0, nil)
651+
652+
mb.MockMedia(imageJPG)
653+
mb.MockMedia(audioMP3)
654+
mb.MockMedia(videoMP4)
655+
mb.MockMedia(videoMOV)
656+
mb.MockMedia(filePDF)
657+
mb.MockMedia(stickerWEBP)
658+
}
659+
632660
func TestSending(t *testing.T) {
633661
// shorter max msg length for testing
634662
maxMsgLength = 100
@@ -639,7 +667,7 @@ func TestSending(t *testing.T) {
639667
})
640668
checkRedacted := []string{"the-auth-token"}
641669

642-
RunChannelSendTestCases(t, ChannelWAC, newWAHandler(courier.ChannelType("D3C"), "360Dialog"), SendTestCasesD3C, checkRedacted, nil)
670+
RunChannelSendTestCases(t, ChannelWAC, newWAHandler(courier.ChannelType("D3C"), "360Dialog"), SendTestCasesD3C, checkRedacted, setupMedia)
643671
}
644672
func TestGetSupportedLanguage(t *testing.T) {
645673
assert.Equal(t, languageInfo{"en", "Menu"}, getSupportedLanguage(courier.NilLocale))

handlers/dialog360/testdata/wac/audioWAC.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"audio": {
2727
"file": "/usr/local/wamedia/shared/b1cf38-8734-4ad3-b4a1-ef0c10d0d683",
2828
"id": "id_audio",
29-
"mime_type": "image/jpeg",
29+
"mime_type": "audio/mpeg",
3030
"sha256": "29ed500fa64eb55fc19dc4124acb300e5dcc54a0f822a301ae99944db",
3131
"caption": "Check out my new phone!"
3232
},

0 commit comments

Comments
 (0)