diff --git a/handlers/external/external.go b/handlers/external/external.go index 0ec48d03c..e4b486d3e 100644 --- a/handlers/external/external.go +++ b/handlers/external/external.go @@ -13,6 +13,7 @@ import ( "time" "github.com/antchfx/xmlquery" + "github.com/buger/jsonparser" "github.com/nyaruka/courier" "github.com/nyaruka/courier/handlers" "github.com/nyaruka/gocommon/gsm7" @@ -28,6 +29,8 @@ const ( configFromXPath = "from_xpath" configTextXPath = "text_xpath" + configMOBody = "mo_body_content_type" + configMOFromField = "mo_from_field" configMOTextField = "mo_text_field" configMODateField = "mo_date_field" @@ -148,6 +151,8 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w fromXPath := channel.StringConfigForKey(configFromXPath, "") textXPath := channel.StringConfigForKey(configTextXPath, "") + moBody := channel.StringConfigForKey(configMOBody, "") + if fromXPath != "" && textXPath != "" { // we are reading from an XML body, pull out our fields body, err := io.ReadAll(io.LimitReader(r.Body, 100000)) @@ -168,6 +173,24 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w from = fromNode.InnerText() text = textNode.InnerText() + } else if moBody == "json" { + // we are reading from an JSON body, pull out our fields + body, err := io.ReadAll(io.LimitReader(r.Body, 100000)) + defer r.Body.Close() + if err != nil { + return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("unable to read request body: %s", err)) + } + + from, err = jsonparser.GetString(body, channel.StringConfigForKey(configMOFromField, "from")) + if err != nil { + return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("unable to find field 'from' in request body: %s", err)) + } + + text, err = jsonparser.GetString(body, channel.StringConfigForKey(configMOTextField, "text")) + if err != nil { + return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("unable to find field 'text' in request body: %s", err)) + } + dateString, _ = jsonparser.GetString(body, channel.StringConfigForKey(configMODateField, "date")) } else { // parse our form contentType := r.Header.Get("Content-Type") diff --git a/handlers/external/external_test.go b/handlers/external/external_test.go index 12146607c..712ae563d 100644 --- a/handlers/external/external_test.go +++ b/handlers/external/external_test.go @@ -43,6 +43,7 @@ var handleTestCases = []ChannelHandleTestCase{ ExpectedMsgText: Sp("Join"), ExpectedURN: "tel:+2349067554729", }, + { Label: "Receive Valid Post multipart form", URL: receiveURL, @@ -264,11 +265,48 @@ var customTestCases = []ChannelHandleTestCase{ }, } +var MOJSONChannels = []courier.Channel{ + test.NewMockChannel("8eb23e93-5ecb-45ba-b726-3b064e0c56ab", "EX", "2020", "US", + map[string]interface{}{ + configMOFromField: "from_number", + configMOTextField: "messageText", + configMOBody: "json", + }, + ), +} + +var MOJSONTextCases = []ChannelHandleTestCase{ + { + Label: "Receive Valid Post JSON body", + URL: receiveURL, + Data: `{"from_number":"2349067554729", "messageText": "Join"}`, + ExpectedRespStatus: 200, + ExpectedBodyContains: "Accepted", + ExpectedMsgText: Sp("Join"), + ExpectedURN: "tel:+2349067554729", + }, + { + Label: "Receive missing field JSON body", + URL: receiveURL, + Data: `{"old":"2349067554729", "new": "Join"}`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unable to find field 'from' in request body", + }, + { + Label: "Receive invalid Post JSON body", + URL: receiveURL, + Data: `not_valid`, + ExpectedRespStatus: 400, + ExpectedBodyContains: "unable to find field 'from' in request body", + }, +} + func TestHandler(t *testing.T) { RunChannelTestCases(t, testChannels, newHandler(), handleTestCases) RunChannelTestCases(t, testSOAPReceiveChannels, newHandler(), handleSOAPReceiveTestCases) RunChannelTestCases(t, gmChannels, newHandler(), gmTestCases) RunChannelTestCases(t, customChannels, newHandler(), customTestCases) + RunChannelTestCases(t, MOJSONChannels, newHandler(), MOJSONTextCases) } func BenchmarkHandler(b *testing.B) {