diff --git a/handlers/dart/handler.go b/handlers/dart/handler.go index a5cf0fd42..a46b84d2c 100644 --- a/handlers/dart/handler.go +++ b/handlers/dart/handler.go @@ -146,22 +146,12 @@ func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWr } func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.SendResult, clog *courier.ChannelLog) error { - // TODO convert functionality from legacy method below - return nil -} - -func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *courier.ChannelLog) (courier.StatusUpdate, error) { username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "") - if username == "" { - return nil, fmt.Errorf("no username set for %s channel", msg.Channel().ChannelType()) - } - password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "") - if password == "" { - return nil, fmt.Errorf("no password set for %s channel", msg.Channel().ChannelType()) + if username == "" || password == "" { + return courier.ErrChannelConfig } - status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), h.maxLength) for i, part := range parts { form := url.Values{ @@ -185,24 +175,24 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour req, err := http.NewRequest(http.MethodGet, partSendURL.String(), nil) if err != nil { - return nil, err + return err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") resp, respBody, err := h.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { - return status, nil + if err != nil || resp.StatusCode/100 == 5 { + return courier.ErrConnectionFailed + } else if resp.StatusCode/100 != 2 { + return courier.ErrResponseStatus } responseCode := stringsx.Truncate(string(respBody), 3) if responseCode != "000" { - clog.Error(courier.ErrorExternal(responseCode, errorCodes[responseCode])) - return status, nil + return courier.ErrFailedWithReason(responseCode, errorCodes[responseCode]) } - status.SetStatus(courier.MsgStatusWired) - } - return status, nil + + return nil } diff --git a/handlers/dart/handler_test.go b/handlers/dart/handler_test.go index 3425f29b0..e593dac99 100644 --- a/handlers/dart/handler_test.go +++ b/handlers/dart/handler_test.go @@ -1,13 +1,13 @@ package dart import ( - "net/http/httptest" "net/url" "testing" "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var daTestChannels = []courier.Channel{ @@ -94,88 +94,90 @@ func BenchmarkHandler(b *testing.B) { RunChannelBenchmarks(b, daTestChannels, NewHandler("DA", "DartMedia", sendURL, maxMsgLength), daTestCases) } -// setSendURL takes care of setting the sendURL to call -func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.MsgOut) { - daHandler := h.(*handler) - daHandler.sendURL = s.URL -} - var defaultSendTestCases = []OutgoingTestCase{ { - Label: "Plain Send", - MsgText: "Simple Message", - MsgURN: "tel:+250788383383", - MockResponseBody: "000", - MockResponseStatus: 200, + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "http://202.43.169.11/APIhttpU/receive2waysms.php*": { + httpx.NewMockResponse(200, nil, []byte(`000`)), + }, + }, ExpectedRequests: []ExpectedRequest{ {Params: url.Values{"message": {"Simple Message"}, "sendto": {"250788383383"}, "original": {"2020"}, "userid": {"Username"}, "password": {"Password"}, "dcs": {"0"}, "udhl": {"0"}, "messageid": {"10"}}}, }, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, }, { - Label: "Long Send", - MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", - MsgURN: "tel:+250788383383", - MockResponseBody: "000", - MockResponseStatus: 200, + Label: "Long Send", + MsgText: "This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say, I need to keep adding more things to make it work", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "http://202.43.169.11/APIhttpU/receive2waysms.php*": { + httpx.NewMockResponse(200, nil, []byte(`000`)), + httpx.NewMockResponse(200, nil, []byte(`000`)), + }, + }, ExpectedRequests: []ExpectedRequest{ {Params: url.Values{"message": {"This is a longer message than 160 characters and will cause us to split it into two separate parts, isn't that right but it is even longer than before I say,"}, "sendto": {"250788383383"}, "original": {"2020"}, "userid": {"Username"}, "password": {"Password"}, "dcs": {"0"}, "udhl": {"0"}, "messageid": {"10"}}}, {Params: url.Values{"message": {"I need to keep adding more things to make it work"}, "sendto": {"250788383383"}, "original": {"2020"}, "userid": {"Username"}, "password": {"Password"}, "dcs": {"0"}, "udhl": {"0"}, "messageid": {"10.2"}}}, }, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, }, { - Label: "Send Attachment", - MsgText: "My pic!", - MsgURN: "tel:+250788383383", - MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponseBody: "000", - MockResponseStatus: 200, + Label: "Send Attachment", + MsgText: "My pic!", + MsgURN: "tel:+250788383383", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[string][]*httpx.MockResponse{ + "http://202.43.169.11/APIhttpU/receive2waysms.php*": { + httpx.NewMockResponse(200, nil, []byte(`000`)), + }, + }, ExpectedRequests: []ExpectedRequest{ {Params: url.Values{"message": {"My pic!\nhttps://foo.bar/image.jpg"}, "sendto": {"250788383383"}, "original": {"2020"}, "userid": {"Username"}, "password": {"Password"}, "dcs": {"0"}, "udhl": {"0"}, "messageid": {"10"}}}, }, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, }, { - Label: "Error Sending", - MsgText: "Error Message", - MsgURN: "tel:+250788383383", - MockResponseBody: `Error`, - MockResponseStatus: 400, + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "http://202.43.169.11/APIhttpU/receive2waysms.php*": { + httpx.NewMockResponse(400, nil, []byte(`Error`)), + }, + }, ExpectedRequests: []ExpectedRequest{ {Params: url.Values{"message": {"Error Message"}, "sendto": {"250788383383"}, "original": {"2020"}, "userid": {"Username"}, "password": {"Password"}, "dcs": {"0"}, "udhl": {"0"}, "messageid": {"10"}}}, }, - ExpectedMsgStatus: "E", - SendPrep: setSendURL, + ExpectedError: courier.ErrResponseStatus, }, { - Label: "Authentication Error", - MsgText: "Simple Message", - MsgURN: "tel:+250788383383", - MockResponseBody: "001", - MockResponseStatus: 200, + Label: "Authentication Error", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "http://202.43.169.11/APIhttpU/receive2waysms.php*": { + httpx.NewMockResponse(200, nil, []byte(`001`)), + }, + }, ExpectedRequests: []ExpectedRequest{ {Params: url.Values{"message": {"Simple Message"}, "sendto": {"250788383383"}, "original": {"2020"}, "userid": {"Username"}, "password": {"Password"}, "dcs": {"0"}, "udhl": {"0"}, "messageid": {"10"}}}, }, - ExpectedMsgStatus: "E", - ExpectedLogErrors: []*courier.ChannelError{courier.ErrorExternal("001", "Authentication error.")}, - SendPrep: setSendURL, + ExpectedError: courier.ErrFailedWithReason("001", "Authentication error."), }, { - Label: "Account Expired", - MsgText: "Simple Message", - MsgURN: "tel:+250788383383", - MockResponseBody: "101", - MockResponseStatus: 200, + Label: "Account Expired", + MsgText: "Simple Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "http://202.43.169.11/APIhttpU/receive2waysms.php*": { + httpx.NewMockResponse(200, nil, []byte(`101`)), + }, + }, ExpectedRequests: []ExpectedRequest{ {Params: url.Values{"message": {"Simple Message"}, "sendto": {"250788383383"}, "original": {"2020"}, "userid": {"Username"}, "password": {"Password"}, "dcs": {"0"}, "udhl": {"0"}, "messageid": {"10"}}}, }, - ExpectedMsgStatus: "E", - ExpectedLogErrors: []*courier.ChannelError{courier.ErrorExternal("101", "Account expired or invalid parameters.")}, - SendPrep: setSendURL, + ExpectedError: courier.ErrFailedWithReason("101", "Account expired or invalid parameters."), }, } diff --git a/handlers/dialog360/handler.go b/handlers/dialog360/handler.go index f25f09c94..29fc0b07f 100644 --- a/handlers/dialog360/handler.go +++ b/handlers/dialog360/handler.go @@ -289,29 +289,17 @@ func (h *handler) resolveMediaURL(channel courier.Channel, mediaID string, clog } func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.SendResult, clog *courier.ChannelLog) error { - // TODO convert functionality from legacy method below - return nil -} - -func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *courier.ChannelLog) (courier.StatusUpdate, error) { - conn := h.Backend().RedisPool().Get() - defer conn.Close() - // get our token - // can't do anything without an access token accessToken := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") - if accessToken == "" { - return nil, fmt.Errorf("missing token for D3C channel") - } - urlStr := msg.Channel().StringConfigForKey(courier.ConfigBaseURL, "") url, err := url.Parse(urlStr) - if err != nil { - return nil, fmt.Errorf("invalid base url set for D3C channel: %s", err) + if accessToken == "" || err != nil { + return courier.ErrChannelConfig } sendURL, _ := url.Parse("/messages") - status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) + conn := h.Backend().RedisPool().Get() + defer conn.Close() hasCaption := false @@ -331,7 +319,7 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour // do we have a template? templating, err := whatsapp.GetTemplating(msg) if err != nil { - return nil, errors.Wrapf(err, "unable to decode template: %s for channel: %s", string(msg.Metadata()), msg.Channel().UUID()) + return errors.Wrapf(err, "unable to decode template: %s for channel: %s", string(msg.Metadata()), msg.Channel().UUID()) } if templating != nil { payload.Type = "template" @@ -349,6 +337,13 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour } 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 { @@ -369,7 +364,7 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour Buttons []whatsapp.Button "json:\"buttons,omitempty\"" }{Buttons: btns} payload.Interactive = &interactive - } else if len(qrs) <= 10 { + } else { interactive := whatsapp.Interactive{Type: "list", Body: struct { Text string "json:\"text\"" }{Text: msgParts[i-len(msg.Attachments())]}} @@ -393,8 +388,6 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour }} payload.Interactive = &interactive - } else { - return nil, fmt.Errorf("too many quick replies WAC supports only up to 10 quick replies") } } else { // this is still a msg part @@ -442,6 +435,12 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour } 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 { @@ -480,7 +479,7 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour } else if attType == "document" { filename, err := utils.BasePathForURL(attURL) if err != nil { - return nil, err + return err } document := whatsapp.Media{ Link: attURL, @@ -494,14 +493,10 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour Document *whatsapp.Media "json:\"document,omitempty\"" }{Type: "document", Document: &document} } else if attType == "audio" { - var zeroIndex bool - if i == 0 { - zeroIndex = true - } payloadAudio = whatsapp.SendRequest{MessagingProduct: "whatsapp", RecipientType: "individual", To: msg.URN().Path(), Type: "audio", Audio: &whatsapp.Media{Link: attURL}} - status, err := h.requestD3C(payloadAudio, accessToken, status, sendURL, zeroIndex, clog) + err := h.requestD3C(payloadAudio, accessToken, res, sendURL, clog) if err != nil { - return status, nil + return nil } } else { interactive.Type = "button" @@ -524,7 +519,7 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour }{Buttons: btns} payload.Interactive = &interactive - } else if len(qrs) <= 10 { + } else { interactive := whatsapp.Interactive{Type: "list", Body: struct { Text string "json:\"text\"" }{Text: msgParts[i-len(msg.Attachments())]}} @@ -548,8 +543,6 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour }} payload.Interactive = &interactive - } else { - return nil, fmt.Errorf("too many quick replies WAC supports only up to 10 quick replies") } } else { // this is still a msg part @@ -563,53 +556,48 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour } } - var zeroIndex bool - if i == 0 { - zeroIndex = true - } - - status, err := h.requestD3C(payload, accessToken, status, sendURL, zeroIndex, clog) + err := h.requestD3C(payload, accessToken, res, sendURL, clog) if err != nil { - return status, err + return err } if hasCaption { break } } - return status, nil + + return nil } -func (h *handler) requestD3C(payload whatsapp.SendRequest, accessToken string, status courier.StatusUpdate, wacPhoneURL *url.URL, zeroIndex bool, clog *courier.ChannelLog) (courier.StatusUpdate, error) { +func (h *handler) requestD3C(payload whatsapp.SendRequest, accessToken string, res *courier.SendResult, wacPhoneURL *url.URL, clog *courier.ChannelLog) error { jsonBody := jsonx.MustMarshal(payload) req, err := http.NewRequest(http.MethodPost, wacPhoneURL.String(), bytes.NewReader(jsonBody)) if err != nil { - return nil, err + return err } req.Header.Set(d3AuthorizationKey, accessToken) req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") - _, respBody, _ := h.RequestHTTP(req, clog) + resp, respBody, err := h.RequestHTTP(req, clog) + if err != nil || resp.StatusCode/100 == 5 { + return courier.ErrConnectionFailed + } respPayload := &whatsapp.SendResponse{} err = json.Unmarshal(respBody, respPayload) if err != nil { - clog.Error(courier.ErrorResponseUnparseable("JSON")) - return status, nil + return courier.ErrResponseUnparseable } if respPayload.Error.Code != 0 { - clog.Error(courier.ErrorExternal(strconv.Itoa(respPayload.Error.Code), respPayload.Error.Message)) - return status, nil + return courier.ErrFailedWithReason(strconv.Itoa(respPayload.Error.Code), respPayload.Error.Message) } externalID := respPayload.Messages[0].ID - if zeroIndex && externalID != "" { - status.SetExternalID(externalID) + if externalID != "" { + res.AddExternalID(externalID) } - // this was wired successfully - status.SetStatus(courier.MsgStatusWired) - return status, nil + return nil } diff --git a/handlers/dialog360/handler_test.go b/handlers/dialog360/handler_test.go index 97291e8f5..8d2d3af06 100644 --- a/handlers/dialog360/handler_test.go +++ b/handlers/dialog360/handler_test.go @@ -314,43 +314,40 @@ func TestBuildAttachmentRequest(t *testing.T) { } -// setSendURL takes care of setting the base_url to our test server host -func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.MsgOut) { - c.(*test.MockChannel).SetConfig("base_url", s.URL) -} - var SendTestCasesD3C = []OutgoingTestCase{ { - Label: "Plain Send", - MsgText: "Simple Message", - MsgURN: "whatsapp:250788123123", - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 201, + Label: "Plain Send", + MsgText: "Simple Message", + MsgURN: "whatsapp:250788123123", + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(200, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, ExpectedRequests: []ExpectedRequest{ { Path: "/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Simple Message","preview_url":false}}`, }, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, + ExpectedExtIDs: []string{"157b5e14568e8"}, }, { - Label: "Unicode Send", - MsgText: "☺", - MsgURN: "whatsapp:250788123123", - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 201, + Label: "Unicode Send", + MsgText: "☺", + MsgURN: "whatsapp:250788123123", + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(200, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, ExpectedRequests: []ExpectedRequest{ { Path: "/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"☺","preview_url":false}}`, }, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, + ExpectedExtIDs: []string{"157b5e14568e8"}, }, { Label: "Audio Send", @@ -367,164 +364,198 @@ var SendTestCasesD3C = []OutgoingTestCase{ {Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`}, {Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"audio caption","preview_url":false}}`}, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, + ExpectedExtIDs: []string{"157b5e14568e8", "157b5e14568e8"}, }, { - Label: "Document Send", - MsgText: "document caption", - MsgURN: "whatsapp:250788123123", - MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 201, + Label: "Document Send", + MsgText: "document caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"application/pdf:https://foo.bar/document.pdf"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, ExpectedRequests: []ExpectedRequest{ { Path: "/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"document","document":{"link":"https://foo.bar/document.pdf","caption":"document caption","filename":"document.pdf"}}`, }, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, + ExpectedExtIDs: []string{"157b5e14568e8"}, }, { - Label: "Image Send", - MsgText: "image caption", - MsgURN: "whatsapp:250788123123", - MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 201, + Label: "Image Send", + MsgText: "image caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, ExpectedRequests: []ExpectedRequest{ { Path: "/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg","caption":"image caption"}}`, }, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, + ExpectedExtIDs: []string{"157b5e14568e8"}, }, { - Label: "Video Send", - MsgText: "video caption", - MsgURN: "whatsapp:250788123123", - MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 201, + Label: "Video Send", + MsgText: "video caption", + MsgURN: "whatsapp:250788123123", + MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, ExpectedRequests: []ExpectedRequest{ { Path: "/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"video","video":{"link":"https://foo.bar/video.mp4","caption":"video caption"}}`, }, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, - }, - { - Label: "Template Send", - MsgText: "templated message", - MsgURN: "whatsapp:250788123123", - MsgLocale: "eng", - MsgMetadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "params": {"body": [{"type":"text", "value":"Chef"}, {"type": "text" , "value": "tomorrow"}]}, "language": "en_US"}}`), - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 200, + ExpectedExtIDs: []string{"157b5e14568e8"}, + }, + { + Label: "Template Send", + MsgText: "templated message", + MsgURN: "whatsapp:250788123123", + MsgLocale: "eng", + MsgMetadata: json.RawMessage(`{ "templating": { "template": { "name": "revive_issue", "uuid": "171f8a4d-f725-46d7-85a6-11aceff0bfe3" }, "params": {"body": [{"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"}] }`)), + }, + }, + ExpectedExtIDs: []string{"157b5e14568e8"}, + ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"template","template":{"name":"revive_issue","language":{"policy":"deterministic","code":"en_US"},"components":[{"type":"body","sub_type":"","index":"","parameters":[{"type":"text","text":"Chef"},{"type":"text","text":"tomorrow"}]}]}}`, - SendPrep: setSendURL, - }, - { - Label: "Interactive Button Message Send", - MsgText: "Interactive Button Msg", - MsgURN: "whatsapp:250788123123", - MsgQuickReplies: []string{"BUTTON1"}, - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 201, - ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, - }, - { - Label: "Interactive List Message Send", - MsgText: "Interactive List Msg", - MsgURN: "whatsapp:250788123123", - MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 201, - ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, - }, - { - Label: "Interactive List Message Send In Spanish", - MsgText: "Hola", - MsgURN: "whatsapp:250788123123", - MsgLocale: "spa", - MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 201, - ExpectedRequestBody: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Hola"},"action":{"button":"Menú","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, - }, - { - Label: "Interactive Button Message Send with image attachment", - MsgText: "Interactive Button Msg", - MsgURN: "whatsapp:250788123123", - MsgQuickReplies: []string{"BUTTON1"}, - MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 201, + }, + { + Label: "Interactive Button Message Send", + MsgText: "Interactive Button Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"BUTTON1"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"BUTTON1"}}]}}}`, + }}, + ExpectedExtIDs: []string{"157b5e14568e8"}, + }, + { + Label: "Interactive List Message Send", + MsgText: "Interactive List Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, + }}, + ExpectedExtIDs: []string{"157b5e14568e8"}, + }, + { + Label: "Interactive List Message Send more than 10 QRs", + MsgText: "Interactive List Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4", "ROW5", "ROW6", "ROW7", "ROW8", "ROW9", "ROW10", "ROW11", "ROW12"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"},{"id":"4","title":"ROW5"},{"id":"5","title":"ROW6"},{"id":"6","title":"ROW7"},{"id":"7","title":"ROW8"},{"id":"8","title":"ROW9"},{"id":"9","title":"ROW10"}]}]}}}`, + }}, + ExpectedExtIDs: []string{"157b5e14568e8"}, + ExpectedLogErrors: []*courier.ChannelError{courier.NewChannelError("", "", "too many quick replies D3C supports only up to 10 quick replies")}, + }, + { + Label: "Interactive List Message Send In Spanish", + MsgText: "Hola", + MsgURN: "whatsapp:250788123123", + MsgLocale: "spa", + MsgQuickReplies: []string{"ROW1", "ROW2", "ROW3", "ROW4"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Hola"},"action":{"button":"Menú","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`, + }}, + ExpectedExtIDs: []string{"157b5e14568e8"}, + }, + { + Label: "Interactive Button Message Send with image attachment", + MsgText: "Interactive Button Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"BUTTON1"}, + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{ { Path: "/messages", Body: `{"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"}}]}}}`, }, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, + ExpectedExtIDs: []string{"157b5e14568e8"}, }, { - Label: "Interactive Button Message Send with video attachment", - MsgText: "Interactive Button Msg", - MsgURN: "whatsapp:250788123123", - MsgQuickReplies: []string{"BUTTON1"}, - MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 201, + Label: "Interactive Button Message Send with video attachment", + MsgText: "Interactive Button Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"BUTTON1"}, + MsgAttachments: []string{"video/mp4:https://foo.bar/video.mp4"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{ { Path: "/messages", Body: `{"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"}}]}}}`, }, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, + ExpectedExtIDs: []string{"157b5e14568e8"}, }, { - Label: "Interactive Button Message Send with document attachment", - MsgText: "Interactive Button Msg", - MsgURN: "whatsapp:250788123123", - MsgQuickReplies: []string{"BUTTON1"}, - MsgAttachments: []string{"document/pdf:https://foo.bar/document.pdf"}, - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 201, + Label: "Interactive Button Message Send with document attachment", + MsgText: "Interactive Button Msg", + MsgURN: "whatsapp:250788123123", + MsgQuickReplies: []string{"BUTTON1"}, + MsgAttachments: []string{"document/pdf:https://foo.bar/document.pdf"}, + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{ { Path: "/messages", Body: `{"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"}}]}}}`, }, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, + ExpectedExtIDs: []string{"157b5e14568e8"}, }, { Label: "Interactive Button Message Send with audio attachment", @@ -542,9 +573,7 @@ var SendTestCasesD3C = []OutgoingTestCase{ {Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"audio","audio":{"link":"https://foo.bar/audio.mp3"}}`}, {Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"button","body":{"text":"Interactive Button Msg"},"action":{"buttons":[{"type":"reply","reply":{"id":"0","title":"ROW1"}},{"type":"reply","reply":{"id":"1","title":"ROW2"}},{"type":"reply","reply":{"id":"2","title":"ROW3"}}]}}}`}, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, + ExpectedExtIDs: []string{"157b5e14568e8", "157b5e14568e8"}, }, { Label: "Interactive List Message Send with attachment", @@ -562,45 +591,76 @@ var SendTestCasesD3C = []OutgoingTestCase{ {Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"image","image":{"link":"https://foo.bar/image.jpg"}}`}, {Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"interactive","interactive":{"type":"list","body":{"text":"Interactive List Msg"},"action":{"button":"Menu","sections":[{"rows":[{"id":"0","title":"ROW1"},{"id":"1","title":"ROW2"},{"id":"2","title":"ROW3"},{"id":"3","title":"ROW4"}]}]}}}`}, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, + ExpectedExtIDs: []string{"157b5e14568e8", "157b5e14568e8"}, }, { - Label: "Link Sending", - MsgText: "Link Sending https://link.com", - MsgURN: "whatsapp:250788123123", - MockResponseBody: `{ "messages": [{"id": "157b5e14568e8"}] }`, - MockResponseStatus: 201, + Label: "Link Sending", + MsgText: "Link Sending https://link.com", + MsgURN: "whatsapp:250788123123", + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(201, nil, []byte(`{ "messages": [{"id": "157b5e14568e8"}] }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{ { Path: "/messages", Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Link Sending https://link.com","preview_url":true}}`, }, }, - ExpectedMsgStatus: "W", - ExpectedExtIDs: []string{"157b5e14568e8"}, - SendPrep: setSendURL, - }, - { - Label: "Error Bad JSON", - MsgText: "Error", - MsgURN: "whatsapp:250788123123", - MockResponseBody: `bad json`, - MockResponseStatus: 403, - ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseUnparseable("JSON")}, - ExpectedMsgStatus: "E", - SendPrep: setSendURL, - }, - { - Label: "Error", - MsgText: "Error", - MsgURN: "whatsapp:250788123123", - MockResponseBody: `{ "error": {"message": "(#130429) Rate limit hit","code": 130429 }}`, - MockResponseStatus: 403, - ExpectedLogErrors: []*courier.ChannelError{courier.ErrorExternal("130429", "(#130429) Rate limit hit")}, - ExpectedMsgStatus: "E", - SendPrep: setSendURL, + ExpectedExtIDs: []string{"157b5e14568e8"}, + }, + { + Label: "Error Bad JSON", + MsgText: "Error", + MsgURN: "whatsapp:250788123123", + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(403, nil, []byte(`bad json`)), + }, + }, + ExpectedRequests: []ExpectedRequest{ + { + Path: "/messages", + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Error","preview_url":false}}`, + }, + }, + ExpectedError: courier.ErrResponseUnparseable, + }, + { + Label: "Error", + MsgText: "Error", + MsgURN: "whatsapp:250788123123", + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(403, nil, []byte(`{ "error": {"message": "(#130429) Rate limit hit","code": 130429 }}`)), + }, + }, + ExpectedRequests: []ExpectedRequest{ + { + Path: "/messages", + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Error","preview_url":false}}`, + }, + }, + ExpectedError: courier.ErrFailedWithReason("130429", "(#130429) Rate limit hit"), + }, + { + Label: "Error Connection", + MsgText: "Error", + MsgURN: "whatsapp:250788123123", + MockResponses: map[string][]*httpx.MockResponse{ + "https://waba-v2.360dialog.io/messages": { + httpx.NewMockResponse(500, nil, []byte(`Bad gateway`)), + }, + }, + ExpectedRequests: []ExpectedRequest{ + { + Path: "/messages", + Body: `{"messaging_product":"whatsapp","recipient_type":"individual","to":"250788123123","type":"text","text":{"body":"Error","preview_url":false}}`, + }, + }, + ExpectedError: courier.ErrConnectionFailed, }, } diff --git a/handlers/discord/handler.go b/handlers/discord/handler.go index d95609e96..19df1c856 100644 --- a/handlers/discord/handler.go +++ b/handlers/discord/handler.go @@ -143,22 +143,14 @@ func (h *handler) receiveStatus(ctx context.Context, statusString string, channe } func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.SendResult, clog *courier.ChannelLog) error { - // TODO convert functionality from legacy method below - return nil -} -func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *courier.ChannelLog) (courier.StatusUpdate, error) { sendURL := msg.Channel().StringConfigForKey(courier.ConfigSendURL, "") if sendURL == "" { - return nil, fmt.Errorf("no send url set for DS channel") + return courier.ErrChannelConfig } - // figure out what encoding to tell kannel to send as sendMethod := http.MethodPost - // sendBody := msg.Channel().StringConfigForKey(courier.ConfigSendBody, "") contentTypeHeader := jsonMimeTypeType - - status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) attachmentURLs := []string{} for _, attachment := range msg.Attachments() { _, attachmentURL := handlers.SplitAttachment(attachment) @@ -186,13 +178,13 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour var body io.Reader marshalled, err := json.Marshal(ourMessage) if err != nil { - return nil, err + return err } body = bytes.NewReader(marshalled) req, err := http.NewRequest(sendMethod, sendURL, body) if err != nil { - return nil, err + return err } req.Header.Set("Content-Type", contentTypeHeader) @@ -202,12 +194,11 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour } resp, _, err := h.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { - return status, nil + if err != nil || resp.StatusCode/100 == 5 { + return courier.ErrConnectionFailed + } else if resp.StatusCode/100 != 2 { + return courier.ErrResponseStatus } - // If we don't have an error, set the message as wired and move on - status.SetStatus(courier.MsgStatusWired) - - return status, nil + return nil } diff --git a/handlers/discord/handler_test.go b/handlers/discord/handler_test.go index 6ba2fa044..a4b4419b4 100644 --- a/handlers/discord/handler_test.go +++ b/handlers/discord/handler_test.go @@ -1,13 +1,12 @@ package discord import ( - "net/http/httptest" "testing" "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" - "github.com/nyaruka/courier/utils" + "github.com/nyaruka/gocommon/httpx" ) func TestIncoming(t *testing.T) { @@ -19,7 +18,7 @@ func BenchmarkHandler(b *testing.B) { } var testChannels = []courier.Channel{ - test.NewMockChannel("bac782c2-7aeb-4389-92f5-97887744f573", "DS", "discord", "US", map[string]any{courier.ConfigSendAuthorization: "sesame"}), + test.NewMockChannel("bac782c2-7aeb-4389-92f5-97887744f573", "DS", "discord", "US", map[string]any{courier.ConfigSendAuthorization: "sesame", courier.ConfigSendURL: "http://example.com/discord/rp/send"}), } var testCases = []IncomingTestCase{ @@ -79,55 +78,90 @@ var testCases = []IncomingTestCase{ var sendTestCases = []OutgoingTestCase{ { - Label: "Simple Send", - MsgText: "Hello World", - MsgURN: "discord:694634743521607802", - MockResponseStatus: 200, + Label: "Simple Send", + MsgText: "Hello World", + MsgURN: "discord:694634743521607802", + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/discord/rp/send": { + httpx.NewMockResponse(200, nil, []byte(``)), + }, + }, ExpectedRequests: []ExpectedRequest{ { Path: "/discord/rp/send", Body: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":[],"quick_replies":null}`, }, }, - SendPrep: setSendURL, }, { - Label: "Attachment", - MsgText: "Hello World", - MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MsgURN: "discord:694634743521607802", - MockResponseStatus: 200, + Label: "Attachment", + MsgText: "Hello World", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgURN: "discord:694634743521607802", + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/discord/rp/send": { + httpx.NewMockResponse(200, nil, []byte(``)), + }, + }, ExpectedRequests: []ExpectedRequest{ { Path: "/discord/rp/send", Body: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":["https://foo.bar/image.jpg"],"quick_replies":null}`, }, }, - SendPrep: setSendURL, }, { - Label: "Attachement and quick replies", - MsgText: "Hello World", - MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, - MsgQuickReplies: []string{"hello", "world"}, - MsgURN: "discord:694634743521607802", - MockResponseStatus: 200, + Label: "Attachement and quick replies", + MsgText: "Hello World", + MsgAttachments: []string{"image/jpeg:https://foo.bar/image.jpg"}, + MsgQuickReplies: []string{"hello", "world"}, + MsgURN: "discord:694634743521607802", + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/discord/rp/send": { + httpx.NewMockResponse(200, nil, []byte(``)), + }, + }, ExpectedRequests: []ExpectedRequest{ { Path: "/discord/rp/send", Body: `{"id":"10","text":"Hello World","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":["https://foo.bar/image.jpg"],"quick_replies":["hello","world"]}`, }, }, - SendPrep: setSendURL, }, -} - -// setSendURL takes care of setting the send_url to our test server host -func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.MsgOut) { - // this is actually a path, which we'll combine with the test server URL - sendURL := c.StringConfigForKey("send_path", "/discord/rp/send") - sendURL, _ = utils.AddURLPath(s.URL, sendURL) - c.(*test.MockChannel).SetConfig(courier.ConfigSendURL, sendURL) + { + Label: "Error Sending", + MsgText: "Error Sending", + MsgURN: "discord:694634743521607802", + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/discord/rp/send": { + httpx.NewMockResponse(400, nil, []byte(``)), + }, + }, + ExpectedRequests: []ExpectedRequest{ + { + Path: "/discord/rp/send", + Body: `{"id":"10","text":"Error Sending","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":[],"quick_replies":null}`, + }, + }, + ExpectedError: courier.ErrResponseStatus, + }, + { + Label: "Connection Error", + MsgText: "Error", + MsgURN: "discord:694634743521607802", + MockResponses: map[string][]*httpx.MockResponse{ + "http://example.com/discord/rp/send": { + httpx.NewMockResponse(500, nil, []byte(``)), + }, + }, + ExpectedRequests: []ExpectedRequest{ + { + Path: "/discord/rp/send", + Body: `{"id":"10","text":"Error","to":"694634743521607802","channel":"bac782c2-7aeb-4389-92f5-97887744f573","attachments":[],"quick_replies":null}`, + }, + }, + ExpectedError: courier.ErrConnectionFailed, + }, } func TestOutgoing(t *testing.T) { diff --git a/handlers/dmark/handler.go b/handlers/dmark/handler.go index eebebb1a6..dbe4cd69b 100644 --- a/handlers/dmark/handler.go +++ b/handlers/dmark/handler.go @@ -106,23 +106,16 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w } func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.SendResult, clog *courier.ChannelLog) error { - // TODO convert functionality from legacy method below - return nil -} - -func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *courier.ChannelLog) (courier.StatusUpdate, error) { // get our authentication token auth := msg.Channel().StringConfigForKey(courier.ConfigAuthToken, "") if auth == "" { - return nil, fmt.Errorf("no authorization token set for DK channel") + return courier.ErrChannelConfig } - callbackDomain := msg.Channel().CallbackDomain(h.Server().Config().Domain) dlrURL := fmt.Sprintf("https://%s%s%s/status?id=%s&status=%%s", callbackDomain, "/c/dk/", msg.Channel().UUID(), msg.ID().String()) - status := h.Backend().NewStatusUpdate(msg.Channel(), msg.ID(), courier.MsgStatusErrored, clog) parts := handlers.SplitMsgByChannel(msg.Channel(), msg.Text(), maxMsgLength) - for i, part := range parts { + for _, part := range parts { form := url.Values{ "sender": []string{strings.TrimLeft(msg.Channel().Address(), "+")}, "receiver": []string{strings.TrimLeft(msg.URN().Path(), "+")}, @@ -132,32 +125,27 @@ func (h *handler) SendLegacy(ctx context.Context, msg courier.MsgOut, clog *cour req, err := http.NewRequest(http.MethodPost, sendURL, strings.NewReader(form.Encode())) if err != nil { - return nil, err + return err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", fmt.Sprintf("Token %s", auth)) resp, respBody, err := h.RequestHTTP(req, clog) - if err != nil || resp.StatusCode/100 != 2 { - return status, nil + if err != nil || resp.StatusCode/100 == 5 { + return courier.ErrConnectionFailed + } else if resp.StatusCode/100 != 2 { + return courier.ErrResponseStatus } // grab the external id externalID, err := jsonparser.GetString(respBody, "sms_id") if err != nil { - clog.Error(courier.ErrorResponseValueMissing("sms_id")) - return status, nil + return courier.ErrFailedWithReason("", "response missing sms_id") } - // if this is our first message, record the external id - if i == 0 { - status.SetExternalID(externalID) - } - - // this was wired successfully - status.SetStatus(courier.MsgStatusWired) + res.AddExternalID(externalID) } - return status, nil + return nil } diff --git a/handlers/dmark/handler_test.go b/handlers/dmark/handler_test.go index ef51b15a1..b57eb10fd 100644 --- a/handlers/dmark/handler_test.go +++ b/handlers/dmark/handler_test.go @@ -1,13 +1,14 @@ package dmark import ( - "net/http/httptest" + "net/url" "testing" "time" "github.com/nyaruka/courier" . "github.com/nyaruka/courier/handlers" "github.com/nyaruka/courier/test" + "github.com/nyaruka/gocommon/httpx" ) var testChannels = []courier.Channel{ @@ -90,46 +91,66 @@ func BenchmarkHandler(b *testing.B) { RunChannelBenchmarks(b, testChannels, newHandler(), testCases) } -// setSendURL takes care of setting the sendURL to call -func setSendURL(s *httptest.Server, h courier.ChannelHandler, c courier.Channel, m courier.MsgOut) { - sendURL = s.URL -} - var defaultSendTestCases = []OutgoingTestCase{ { - Label: "Plain Send", - MsgText: "Simple Message ☺", - MsgURN: "tel:+250788383383", - ExpectedExtIDs: []string{"6b1c15d3-cba2-46f7-9a25-78265e58057d"}, - MockResponseBody: `{ "type": "MT", "sms_id": "6b1c15d3-cba2-46f7-9a25-78265e58057d" }`, - MockResponseStatus: 200, - ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, - ExpectedPostParams: map[string]string{"text": "Simple Message ☺", "receiver": "250788383383", "sender": "2020", "dlr_url": "https://localhost/c/dk/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%s"}, - ExpectedMsgStatus: "W", - SendPrep: setSendURL, + Label: "Plain Send", + MsgText: "Simple Message ☺", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://smsapi1.dmarkmobile.com/sms/": { + httpx.NewMockResponse(200, nil, []byte(`{ "type": "MT", "sms_id": "6b1c15d3-cba2-46f7-9a25-78265e58057d" }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{"Authorization": "Token Authy"}, + Form: url.Values{ + "text": {"Simple Message ☺"}, + "receiver": {"250788383383"}, + "sender": {"2020"}, + "dlr_url": {"https://localhost/c/dk/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%s"}, + }, + }}, + ExpectedExtIDs: []string{"6b1c15d3-cba2-46f7-9a25-78265e58057d"}, }, { - Label: "Invalid Body", - MsgText: "Error Message", - MsgURN: "tel:+250788383383", - MockResponseBody: `{ "error": "failed" }`, - MockResponseStatus: 200, - ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, - ExpectedPostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, - ExpectedMsgStatus: "E", - ExpectedLogErrors: []*courier.ChannelError{courier.ErrorResponseValueMissing("sms_id")}, - SendPrep: setSendURL, + Label: "Invalid Body", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://smsapi1.dmarkmobile.com/sms/": { + httpx.NewMockResponse(200, nil, []byte(`{ "error": "failed" }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{"Authorization": "Token Authy"}, + Form: url.Values{ + "text": {"Error Message"}, + "receiver": {"250788383383"}, + "sender": {"2020"}, + "dlr_url": {"https://localhost/c/dk/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%s"}, + }, + }}, + ExpectedError: courier.ErrFailedWithReason("", "response missing sms_id"), }, { - Label: "Error Sending", - MsgText: "Error Message", - MsgURN: "tel:+250788383383", - MockResponseBody: `{ "error": "failed" }`, - MockResponseStatus: 401, - ExpectedHeaders: map[string]string{"Authorization": "Token Authy"}, - ExpectedPostParams: map[string]string{"text": "Error Message", "receiver": "250788383383", "sender": "2020"}, - ExpectedMsgStatus: "E", - SendPrep: setSendURL, + Label: "Error Sending", + MsgText: "Error Message", + MsgURN: "tel:+250788383383", + MockResponses: map[string][]*httpx.MockResponse{ + "https://smsapi1.dmarkmobile.com/sms/": { + httpx.NewMockResponse(401, nil, []byte(`{ "error": "failed" }`)), + }, + }, + ExpectedRequests: []ExpectedRequest{{ + Headers: map[string]string{"Authorization": "Token Authy"}, + Form: url.Values{ + "text": {"Error Message"}, + "receiver": {"250788383383"}, + "sender": {"2020"}, + "dlr_url": {"https://localhost/c/dk/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?id=10&status=%s"}, + }, + }}, + ExpectedError: courier.ErrResponseStatus, }, }