From dfd6117fbba521941876bc9681858d4a6d32b0bf Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:13:24 +0530 Subject: [PATCH 1/3] feat: onboard fullstory cloud mode (#2536) * feat: onboard fullstory cloud mode * test: add more tests for identify --- .../destinations/fullstory/procWorkflow.yaml | 104 +++++ test/__tests__/data/fullstory.json | 354 ++++++++++++++++++ test/__tests__/fullstory-cdk.test.ts | 32 ++ 3 files changed, 490 insertions(+) create mode 100644 src/cdk/v2/destinations/fullstory/procWorkflow.yaml create mode 100644 test/__tests__/data/fullstory.json create mode 100644 test/__tests__/fullstory-cdk.test.ts diff --git a/src/cdk/v2/destinations/fullstory/procWorkflow.yaml b/src/cdk/v2/destinations/fullstory/procWorkflow.yaml new file mode 100644 index 0000000000..50ac2a8163 --- /dev/null +++ b/src/cdk/v2/destinations/fullstory/procWorkflow.yaml @@ -0,0 +1,104 @@ +bindings: + - name: EventType + path: ../../../../constants + - path: ../../bindings/jsontemplate + exportAll: true + - name: removeUndefinedAndNullValues + path: ../../../../v0/util + +steps: + - name: validateInput + template: | + $.assert(.message.type, "message Type is not present. Aborting message."); + $.assert(.message.type in {{$.EventType.([.TRACK, .IDENTIFY])}}, + "message type " + .message.type + " is not supported"); + - name: prepareContext + template: | + $.context.messageType = .message.type.toLowerCase(); + $.context.payload = {}; + $.context.finalHeaders = { + "authorization": "Basic " + .destination.Config.apiKey, + "content-type": "application/json" + }; + - name: identifyPayload + condition: $.context.messageType == "identify" + template: | + $.context.endpoint = "https://api.fullstory.com/v2/users"; + $.context.payload.properties = .message.traits ?? .message.context.traits; + $.context.payload.uid = .message.userId; + $.context.payload.email = .message.context.traits.email; + $.context.payload.display_name = .message.context.traits.name; + + - name: trackPayload + condition: $.context.messageType == "track" + template: | + $.context.endpoint = "https://api.fullstory.com/v2/events"; + $.context.payload.name = .message.event; + $.context.payload.properties = .message.properties; + $.context.payload.timestamp = .message.originalTimestamp; + $.context.payload.context = {}; + + - name: validateEventName + condition: $.context.messageType == "track" + template: | + $.assert(.message.event, "event is required for track call") + + - name: mapContextFieldsForTrack + condition: $.context.messageType == "track" + template: | + $.context.payload.context.browser = { + "url": .message.context.page.url, + "user_agent": .message.context.userAgent, + "initial_referrer": .message.context.page.initial_referrer, + }; + $.context.payload.context.mobile = { + "app_name": .message.context.app.name, + "app_version": .message.context.app.version, + }; + $.context.payload.context.device = { + "manufacturer": .message.context.device.manufacturer, + "model": .message.context.device.model, + }; + $.context.payload.context.location = { + "ip_address": .message.context.ip, + "latitude": .message.properties.latitude, + "longitude": .message.properties.longitude, + "city": .message.properties.city, + "region": .message.properties.region, + "country": .message.properties.country, + }; + + - name: mapIdsForTrack + condition: $.context.messageType == "track" + template: | + $.context.payload.session = { + "id": .message.properties.sessionId, + "use_most_recent": .message.properties.useMostRecent, + }; + $.context.payload.user = { + "id": .message.properties.userId ?? .message.userId, + } + + - name: cleanPayload + template: | + $.context.payload = $.removeUndefinedAndNullValues($.context.payload); + - name: buildResponseForProcessTransformation + template: | + $.context.payload.({ + "body": { + "JSON": ., + "JSON_ARRAY": {}, + "XML": {}, + "FORM": {} + }, + "version": "1", + "type": "REST", + "method": "POST", + "endpoint": $.context.endpoint, + "headers": $.context.finalHeaders, + "params": {}, + "files": {} + }) + + + diff --git a/test/__tests__/data/fullstory.json b/test/__tests__/data/fullstory.json new file mode 100644 index 0000000000..b6e462005b --- /dev/null +++ b/test/__tests__/data/fullstory.json @@ -0,0 +1,354 @@ +[ + { + "description": "Complete track event", + "input": { + "message": { + "anonymousId": "78c53c15-32a1-4b65-adac-bec2d7bb8fab", + "channel": "web", + "context": { + "app": { + "name": "RSPM", + "version": "1.9.0" + }, + "campaign": { + "name": "sales campaign", + "source": "google", + "medium": "medium", + "term": "event data", + "content": "Make sense of the modern data stack" + }, + "ip": "192.0.2.0", + "library": { + "name": "RudderLabs JavaScript SDK", + "version": "2.9.1" + }, + "locale": "en-US", + "device": { + "manufacturer": "Nokia", + "model": "N2023" + }, + "page": { + "path": "/best-seller/1", + "initial_referrer": "https://www.google.com/search", + "initial_referring_domain": "google.com", + "referrer": "https://www.google.com/search?q=estore+bestseller", + "referring_domain": "google.com", + "search": "estore bestseller", + "title": "The best sellers offered by EStore", + "url": "https://www.estore.com/best-seller/1" + }, + "screen": { + "density": 420, + "height": 1794, + "width": 1080, + "innerHeight": 200, + "innerWidth": 100 + }, + "userAgent": "Dalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)" + }, + "event": "Product Reviewed", + "integrations": { + "All": true + }, + "messageId": "1578564113557-af022c68-429e-4af4-b99b-2b9174056383", + "properties": { + "userId": "u001", + "sessionId": "s001", + "review_id": "review_id_1", + "product_id": "product_id_1", + "rating": 5.0, + "review_body": "Sample Review Body", + "latitude": 44.56, + "longitude": 54.46, + "region": "Atlas", + "city": "NY", + "country": "USA" + }, + "originalTimestamp": "2020-01-09T10:01:53.558Z", + "type": "track", + "sentAt": "2020-01-09T10:02:03.257Z" + }, + "destination": { + "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", + "Name": "Fullstory", + "DestinationDefinition": { + "Config": { + "cdkV2Enabled": true + } + }, + "Config": { + "apiKey": "dummyfullstoryAPIKey" + }, + "Enabled": true, + "Transformations": [] + }, + "metadata": { + "sourceType": "fddf", + "destinationType": "fdf", + "k8_namespace": "fdfd" + } + }, + "output": { + "body": { + "JSON": { + "name": "Product Reviewed", + "properties": { + "userId": "u001", + "sessionId": "s001", + "review_id": "review_id_1", + "product_id": "product_id_1", + "rating": 5, + "review_body": "Sample Review Body", + "latitude": 44.56, + "longitude": 54.46, + "region": "Atlas", + "city": "NY", + "country": "USA" + }, + "timestamp": "2020-01-09T10:01:53.558Z", + "context": { + "browser": { + "url": "https://www.estore.com/best-seller/1", + "user_agent": "Dalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)", + "initial_referrer": "https://www.google.com/search" + }, + "mobile": { + "app_name": "RSPM", + "app_version": "1.9.0" + }, + "device": { + "manufacturer": "Nokia", + "model": "N2023" + }, + "location": { + "ip_address": "192.0.2.0", + "latitude": 44.56, + "longitude": 54.46, + "city": "NY", + "region": "Atlas", + "country": "USA" + } + }, + "session": { + "id": "s001" + }, + "user": { + "id": "u001" + } + }, + "JSON_ARRAY": {}, + "XML": {}, + "FORM": {} + }, + "method": "POST", + "params": {}, + "version": "1", + "type": "REST", + "endpoint": "https://api.fullstory.com/v2/events", + "headers": { + "authorization": "Basic dummyfullstoryAPIKey", + "content-type": "application/json" + }, + "files": {} + } + }, + { + "description": "Missing event name", + "input": { + "message": { + "channel": "web", + "context": { + "device": { + "manufacturer": "Nokia", + "model": "N2023" + }, + "userAgent": "Dalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)" + }, + "integrations": { + "All": true + }, + "properties": { + "userId": "u001", + "latitude": 44.56, + "longitude": 54.46, + "region": "Atlas", + "city": "NY", + "country": "USA" + }, + "originalTimestamp": "2020-01-09T10:01:53.558Z", + "type": "track", + "sentAt": "2020-01-09T10:02:03.257Z" + }, + "destination": { + "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", + "Name": "Fullstory", + "DestinationDefinition": { + "Config": { + "cdkV2Enabled": true + } + }, + "Config": { + "apiKey": "dummyfullstoryAPIKey" + }, + "Enabled": true, + "Transformations": [] + }, + "metadata": { + "sourceType": "fddf", + "destinationType": "fdf", + "k8_namespace": "fdfd" + } + }, + "output": { + "error": "event is required for track call: Workflow: procWorkflow, Step: validateEventName, ChildStep: undefined, OriginalError: event is required for track call" + } + }, + { + "description": "Complete identify event", + "input": { + "message": { + "userId": "dummy-user001", + "channel": "web", + "context": { + "traits": { + "company": "Initech", + "address": { + "country": "USA", + "state": "CA", + "street": "101 dummy street" + }, + "email": "dummyuser@domain.com", + "name": "dummy user", + "phone": "099-999-9999" + }, + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" + }, + "integrations": { + "All": true + }, + "originalTimestamp": "2020-01-27T12:20:55.301Z", + "receivedAt": "2020-01-27T17:50:58.657+05:30", + "request_ip": "14.98.244.60", + "sentAt": "2020-01-27T12:20:56.849Z", + "timestamp": "2020-01-27T17:50:57.109+05:30", + "type": "identify" + }, + "destination": { + "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", + "Name": "Fullstory", + "DestinationDefinition": { + "Config": { + "cdkV2Enabled": true + } + }, + "Config": { + "apiKey": "fullstoryAPIKey" + }, + "Enabled": true, + "Transformations": [] + }, + "metadata": { + "sourceType": "fddf", + "destinationType": "fdf", + "k8_namespace": "fdfd" + } + }, + "output": { + "body": { + "JSON": { + "properties": { + "company": "Initech", + "address": { + "country": "USA", + "state": "CA", + "street": "101 dummy street" + }, + "email": "dummyuser@domain.com", + "name": "dummy user", + "phone": "099-999-9999" + }, + "uid": "dummy-user001", + "email": "dummyuser@domain.com", + "display_name": "dummy user" + }, + "JSON_ARRAY": {}, + "XML": {}, + "FORM": {} + }, + "version": "1", + "type": "REST", + "method": "POST", + "endpoint": "https://api.fullstory.com/v2/users", + "headers": { + "authorization": "Basic fullstoryAPIKey", + "content-type": "application/json" + }, + "params": {}, + "files": {} + } + }, + { + "description": "Identify event with needed traits", + "input": { + "message": { + "userId": "dummy-user001", + "channel": "web", + "context": { + "traits": { + "email": "dummyuser@domain.com", + "name": "dummy user", + "phone": "099-999-9999" + } + }, + "timestamp": "2020-01-27T17:50:57.109+05:30", + "type": "identify" + }, + "destination": { + "ID": "1pYpzzvcn7AQ2W9GGIAZSsN6Mfq", + "Name": "Fullstory", + "DestinationDefinition": { + "Config": { + "cdkV2Enabled": true + } + }, + "Config": { + "apiKey": "fullstoryAPIKey" + }, + "Enabled": true, + "Transformations": [] + }, + "metadata": { + "sourceType": "fddf", + "destinationType": "fdf", + "k8_namespace": "fdfd" + } + }, + "output": { + "body": { + "JSON": { + "properties": { + "email": "dummyuser@domain.com", + "name": "dummy user", + "phone": "099-999-9999" + }, + "uid": "dummy-user001", + "email": "dummyuser@domain.com", + "display_name": "dummy user" + }, + "JSON_ARRAY": {}, + "XML": {}, + "FORM": {} + }, + "version": "1", + "type": "REST", + "method": "POST", + "endpoint": "https://api.fullstory.com/v2/users", + "headers": { + "authorization": "Basic fullstoryAPIKey", + "content-type": "application/json" + }, + "params": {}, + "files": {} + } + } +] diff --git a/test/__tests__/fullstory-cdk.test.ts b/test/__tests__/fullstory-cdk.test.ts new file mode 100644 index 0000000000..f7e0491aac --- /dev/null +++ b/test/__tests__/fullstory-cdk.test.ts @@ -0,0 +1,32 @@ +import fs from 'fs'; +import path from 'path'; +import { processCdkV2Workflow } from '../../src/cdk/v2/handler'; +import tags from '../../src/v0/util/tags'; + +const integration = 'fullstory'; +const destName = 'Fullstory'; + +// Processor Test files +const testDataFile = fs.readFileSync(path.resolve(__dirname, `./data/${integration}.json`), { + encoding: 'utf8', +}); +const testData = JSON.parse(testDataFile); + +describe(`${destName} Tests`, () => { + describe('Processor Tests', () => { + testData.forEach((dataPoint, index) => { + it(`${destName} - payload: ${index}`, async () => { + try { + const output = await processCdkV2Workflow( + integration, + dataPoint.input, + tags.FEATURES.PROCESSOR, + ); + expect(output).toEqual(dataPoint.output); + } catch (error: any) { + expect(error.message).toEqual(dataPoint.output.error); + } + }); + }); + }); +}); From 2b38e2c6a5d3556112c7bf2d0aff516a46acfeb8 Mon Sep 17 00:00:00 2001 From: Anant Jain <62471433+anantjain45823@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:57:12 +0530 Subject: [PATCH 2/3] Revert "fix(INT-339): marketo response handler to handle static list removed and skipped statuses" (#2619) Revert "fix(INT-339): marketo response handler to handle static list removed and skipped statuses (#2606)" This reverts commit e3fed49d2725a6c60409db00cfda2a997da78e71. --- src/v0/destinations/marketo/util.js | 77 ++++++++----------- .../marketo_static_list/proxy_response.json | 34 +------- .../data/marketo_static_list_proxy_input.json | 20 ----- .../marketo_static_list_proxy_output.json | 67 ++++------------ 4 files changed, 52 insertions(+), 146 deletions(-) diff --git a/src/v0/destinations/marketo/util.js b/src/v0/destinations/marketo/util.js index 1da9dc0f7e..ab39aafc15 100644 --- a/src/v0/destinations/marketo/util.js +++ b/src/v0/destinations/marketo/util.js @@ -19,8 +19,6 @@ const tags = require('../../util/tags'); * https://developers.marketo.com/rest-api/error-codes/ */ -const ERROR_CODE_TO_PASS = ['1015']; - const MARKETO_RETRYABLE_CODES = ['601', '602', '604', '611']; const MARKETO_ABORTABLE_CODES = [ '600', @@ -36,28 +34,29 @@ const MARKETO_ABORTABLE_CODES = [ ]; const MARKETO_THROTTLED_CODES = ['502', '606', '607', '608', '615']; -// Keeping here for reference const RECORD_LEVEL_ABORTBALE_ERRORS = [ -// '1001', -// '1002', -// '1003', -// '1004', -// '1005', -// '1006', -// '1007', -// '1008', -// '1011', -// '1013', -// '1014', -// '1016', -// '1017', -// '1018', -// '1021', -// '1026', -// '1027', -// '1028', -// '1036', -// '1049', -// ]; +const RECORD_LEVEL_ABORTBALE_ERRORS = [ + '1001', + '1002', + '1003', + '1004', + '1005', + '1006', + '1007', + '1008', + '1011', + '1013', + '1014', + '1015', + '1016', + '1017', + '1018', + '1021', + '1026', + '1027', + '1028', + '1036', + '1049', +]; const { DESTINATION } = require('./config'); const logger = require('../../../logger'); @@ -87,7 +86,7 @@ const marketoApplicationErrorHandler = (marketoResponse, sourceMessage, destinat }; /** * this function checks the status of individual responses and throws error if any - * response status does not match the expected status + * response ststus does not match the expected status * doc1: https://developers.marketo.com/rest-api/lead-database/custom-objects/#create_and_update * doc2: https://developers.marketo.com/rest-api/lead-database/#create_and_update * Structure of marketoResponse: { @@ -123,27 +122,17 @@ const marketoApplicationErrorHandler = (marketoResponse, sourceMessage, destinat const nestedResponseHandler = (marketoResponse, sourceMessage) => { const checkStatus = (res) => { const { status } = res; - const allowedStatus = ['updated', 'added', 'removed', 'created']; - if ( - status && - !allowedStatus.includes(status) - // we need to check the case where the id are not in list - ) { + if (status && status !== 'updated' && status !== 'created' && status !== 'added') { const { reasons } = res; let statusCode = 400; - if (reasons) { - const errorCodesFromDest = reasons.map((reason) => reason.code); - const filteredErrorCode = errorCodesFromDest.find( - (errorCode) => !ERROR_CODE_TO_PASS.includes(errorCode), - ); - if (!filteredErrorCode) { - return; - } - if (MARKETO_THROTTLED_CODES.includes(filteredErrorCode.code)) { - statusCode = 429; - } else if (MARKETO_RETRYABLE_CODES.includes(filteredErrorCode.code)) { - statusCode = 500; - } + if (reasons && RECORD_LEVEL_ABORTBALE_ERRORS.includes(reasons[0].code)) { + statusCode = 400; + } else if (reasons && MARKETO_ABORTABLE_CODES.includes(reasons[0].code)) { + statusCode = 400; + } else if (reasons && MARKETO_THROTTLED_CODES.includes(reasons[0].code)) { + statusCode = 429; + } else if (reasons && MARKETO_RETRYABLE_CODES.includes(reasons[0].code)) { + statusCode = 500; } throw new InstrumentationError( `Request failed during: ${sourceMessage}, error: ${JSON.stringify(reasons)}`, diff --git a/test/__mocks__/data/marketo_static_list/proxy_response.json b/test/__mocks__/data/marketo_static_list/proxy_response.json index 2a58d99da2..5c00ced941 100644 --- a/test/__mocks__/data/marketo_static_list/proxy_response.json +++ b/test/__mocks__/data/marketo_static_list/proxy_response.json @@ -1,31 +1,4 @@ { - "https://marketo_acct_id_success.mktorest.com/rest/v1/lists/1234/leads.json?id=110&id=111&id=112": { - "data": { - "requestId": "b6d1#18a8d2c10e7", - "result": [ - { - "id": 110, - "status": "skipped", - "reasons": [ - { - "code": "1015", - "message": "Lead not in list" - } - ] - }, - { - "id": 111, - "status": "removed" - }, - { - "id": 112, - "status": "removed" - } - ], - "success": true - }, - "status": 200 - }, "https://marketo_acct_id_success.mktorest.com/rest/v1/lists/1234/leads.json?id=1&id=2&id=3": { "data": { "requestId": "68d8#1846058ee27", @@ -87,13 +60,14 @@ "status": "skipped", "reasons": [ { - "code": "1015", - "message": "Lead not in list" + "code": "1004", + "message": "Lead not found" } ] }, + "success": true }, "status": 200 } -} \ No newline at end of file +} diff --git a/test/__tests__/data/marketo_static_list_proxy_input.json b/test/__tests__/data/marketo_static_list_proxy_input.json index 6f84e7416d..85142d68d7 100644 --- a/test/__tests__/data/marketo_static_list_proxy_input.json +++ b/test/__tests__/data/marketo_static_list_proxy_input.json @@ -1,24 +1,4 @@ [ - { - "type": "REST", - "endpoint": "https://marketo_acct_id_success.mktorest.com/rest/v1/lists/1234/leads.json?id=110&id=111&id=112", - "method": "POST", - "userId": "", - "headers": { - "Authorization": "Bearer Incorrect_token", - "Content-Type": "application/json" - }, - "body": { - "FORM": {}, - "JSON": {}, - "JSON_ARRAY": {}, - "XML": {} - }, - "files": {}, - "params": { - "destination": "marketo_static_list" - } - }, { "type": "REST", "endpoint": "https://marketo_acct_id_success.mktorest.com/rest/v1/lists/1234/leads.json?id=1&id=2&id=3", diff --git a/test/__tests__/data/marketo_static_list_proxy_output.json b/test/__tests__/data/marketo_static_list_proxy_output.json index 8ac482b5be..2dfbee0e8e 100644 --- a/test/__tests__/data/marketo_static_list_proxy_output.json +++ b/test/__tests__/data/marketo_static_list_proxy_output.json @@ -1,37 +1,4 @@ [ - { - "output": { - "message": "Request Processed Successfully", - "destinationResponse": { - "response": { - "requestId": "b6d1#18a8d2c10e7", - "result": [ - { - "id": 110, - "status": "skipped", - "reasons": [ - { - "code": "1015", - "message": "Lead not in list" - } - ] - }, - { - "id": 111, - "status": "removed" - }, - { - "id": 112, - "status": "removed" - } - ], - "success": true - }, - "status": 200 - }, - "status": 200 - } - }, { "output": { "status": 500, @@ -105,25 +72,21 @@ }, { "output": { - "status": 200, - "message": "Request Processed Successfully", - "destinationResponse": { - "response": { - "requestId": "12d3c#1846057dce2", - "result": { - "id": 5, - "status": "skipped", - "reasons": [ - { - "code": "1015", - "message": "Lead not in list" - } - ] - }, - "success": true - }, - "status": 200 - } + "destinationResponse": "", + "message": "Request failed during: during Marketo Static List Response Handling, error: [{\"code\":\"1004\",\"message\":\"Lead not found\"}]", + "statTags": { + "destType": "MARKETO_STATIC_LIST", + "errorCategory": "dataValidation", + "destinationId": "Non-determininable", + "workspaceId": "Non-determininable", + "errorType": "instrumentation", + "feature": "dataDelivery", + "implementation": "native", + "destinationId": "Non-determininable", + "workspaceId": "Non-determininable", + "module": "destination" + }, + "status": 400 } } ] \ No newline at end of file From 0f3b39e64f50cec54a5fcd59e0da298092ca0f22 Mon Sep 17 00:00:00 2001 From: Anant Jain <62471433+anantjain45823@users.noreply.github.com> Date: Fri, 15 Sep 2023 15:17:47 +0530 Subject: [PATCH 3/3] fix(INT-568): slack send event to event specific channel based on channel webhook (#2563) * fix: slack send event to event specific channel * small fixes * incorporated legacy method * added test cases and small fixes * fixed payload for modern webhooks for not sending app details * feat:added blacklisted event option --- src/v0/destinations/slack/transform.js | 173 +++-- src/v0/destinations/slack/util.js | 6 +- test/__tests__/data/slack_input.json | 887 ++++++++++++++++++++++--- test/__tests__/data/slack_output.json | 105 ++- test/__tests__/slack.test.js | 2 +- 5 files changed, 1014 insertions(+), 159 deletions(-) diff --git a/src/v0/destinations/slack/transform.js b/src/v0/destinations/slack/transform.js index ee58b63dff..b56ebfbc48 100644 --- a/src/v0/destinations/slack/transform.js +++ b/src/v0/destinations/slack/transform.js @@ -16,25 +16,38 @@ const { defaultRequestConfig, getFieldValueFromMessage, simpleProcessRouterDest, + isDefinedAndNotNull, } = require('../../util'); const { InstrumentationError, ConfigurationError } = require('../../util/errorTypes'); // build the response to be sent to backend, url encoded header is required as slack accepts payload in this format // add the username and image for Rudder // image currently served from prod CDN -const buildResponse = (payloadJSON, message, destination) => { - const endpoint = destination.Config.webhookUrl; +const buildResponse = ( + payloadJSON, + message, + destination, + channelWebhook = null, + sendAppNameAndIcon = true, +) => { + const endpoint = channelWebhook || destination.Config.webhookUrl; const response = defaultRequestConfig(); response.endpoint = endpoint; response.method = defaultPostRequestConfig.requestMethod; response.headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; response.userId = message.userId ? message.userId : message.anonymousId; + const payload = + sendAppNameAndIcon === true + ? JSON.stringify({ + ...payloadJSON, + username: SLACK_USER_NAME, + icon_url: SLACK_RUDDER_IMAGE_URL, + }) + : JSON.stringify({ + ...payloadJSON, + }); response.body.FORM = { - payload: JSON.stringify({ - ...payloadJSON, - username: SLACK_USER_NAME, - icon_url: SLACK_RUDDER_IMAGE_URL, - }), + payload, }; response.statusCode = 200; logger.debug(response); @@ -42,21 +55,15 @@ const buildResponse = (payloadJSON, message, destination) => { }; const processIdentify = (message, destination) => { - // debug(JSON.stringify(destination)); const identifyTemplateConfig = destination.Config.identifyTemplate; const traitsList = getWhiteListedTraits(destination); const defaultIdentifyTemplate = 'Identified {{name}}'; logger.debug('defaulTraitsList:: ', traitsList); const uName = getName(message); - // required traitlist ?? - /* if (!traitsList || traitsList.length == 0) { - throw Error("traits list in config not present"); - } */ - const template = Handlebars.compile( (identifyTemplateConfig - ? identifyTemplateConfig.trim().length === 0 + ? identifyTemplateConfig.trim()?.length === 0 ? undefined : identifyTemplateConfig : undefined) || @@ -69,7 +76,7 @@ const processIdentify = (message, destination) => { logger.debug( 'identifyTemplateConfig: ', (identifyTemplateConfig - ? identifyTemplateConfig.trim().length === 0 + ? identifyTemplateConfig.trim()?.length === 0 ? undefined : identifyTemplateConfig : undefined) || @@ -95,18 +102,40 @@ const processIdentify = (message, destination) => { return buildResponse({ text: resultText }, message, destination); }; -function buildChannelList(channelListToSendThisEvent, eventChannelConfig, eventName) { - eventChannelConfig.forEach((channelConfig) => { - const configEventName = channelConfig.eventName - ? channelConfig.eventName.trim().length > 0 - ? channelConfig.eventName - : undefined - : undefined; - const configEventChannel = channelConfig.eventChannel - ? channelConfig.eventChannel.trim().length > 0 - ? channelConfig.eventChannel - : undefined - : undefined; +const isEventNameMatchesRegex = (eventName, regex) => eventName.match(regex)?.length > 0; + +const getChannelForEventName = (eventChannelSettings, eventName) => { + for (const channelConfig of eventChannelSettings) { + const configEventName = + channelConfig?.eventName?.trim()?.length > 0 ? channelConfig.eventName : null; + const channelWebhook = + channelConfig?.eventChannelWebhook?.length > 0 ? channelConfig.eventChannelWebhook : null; + + if (configEventName && isDefinedAndNotNull(channelWebhook)) { + if (channelConfig.eventRegex) { + logger.debug('regex: ', `${configEventName} trying to match with ${eventName}`); + logger.debug( + 'match:: ', + configEventName, + eventName, + eventName.match(new RegExp(configEventName, 'g')), + ); + if (isEventNameMatchesRegex(eventName, new RegExp(configEventName, 'g'))) { + return channelWebhook; + } + } else if (channelConfig.eventName === eventName) { + return channelWebhook; + } + } + } + return null; +}; +const getChannelNameForEvent = (eventChannelSettings, eventName) => { + for (const channelConfig of eventChannelSettings) { + const configEventName = + channelConfig?.eventName?.trim()?.length > 0 ? channelConfig.eventName : null; + const configEventChannel = + channelConfig?.eventChannel?.trim()?.length > 0 ? channelConfig.eventChannel : null; if (configEventName && configEventChannel) { if (channelConfig.eventRegex) { logger.debug('regex: ', `${configEventName} trying to match with ${eventName}`); @@ -116,37 +145,29 @@ function buildChannelList(channelListToSendThisEvent, eventChannelConfig, eventN eventName, eventName.match(new RegExp(configEventName, 'g')), ); - if ( - eventName.match(new RegExp(configEventName, 'g')) && - eventName.match(new RegExp(configEventName, 'g')).length > 0 - ) { - channelListToSendThisEvent.add(configEventChannel); + if (isEventNameMatchesRegex(eventName, new RegExp(configEventName, 'g'))) { + return configEventChannel; } } else if (configEventName === eventName) { - channelListToSendThisEvent.add(configEventChannel); + return configEventChannel; } } - }); -} + } + return null; +}; -function buildtemplateList(templateListForThisEvent, eventTemplateConfig, eventName) { - eventTemplateConfig.forEach((templateConfig) => { - const configEventName = templateConfig.eventName - ? templateConfig.eventName.trim().length > 0 - ? templateConfig.eventName - : undefined - : undefined; +const buildtemplateList = (templateListForThisEvent, eventTemplateSettings, eventName) => { + eventTemplateSettings.forEach((templateConfig) => { + const configEventName = + templateConfig?.eventName?.trim()?.length > 0 ? templateConfig.eventName : undefined; const configEventTemplate = templateConfig.eventTemplate - ? templateConfig.eventTemplate.trim().length > 0 + ? templateConfig.eventTemplate.trim()?.length > 0 ? templateConfig.eventTemplate : undefined : undefined; if (configEventName && configEventTemplate) { if (templateConfig.eventRegex) { - if ( - eventName.match(new RegExp(configEventName, 'g')) && - eventName.match(new RegExp(configEventName, 'g')).length > 0 - ) { + if (isEventNameMatchesRegex(eventName, new RegExp(configEventName, 'g'))) { templateListForThisEvent.add(configEventTemplate); } } else if (configEventName === eventName) { @@ -154,32 +175,47 @@ function buildtemplateList(templateListForThisEvent, eventTemplateConfig, eventN } } }); -} +}; const processTrack = (message, destination) => { // logger.debug(JSON.stringify(destination)); - const eventChannelConfig = destination.Config.eventChannelSettings; - const eventTemplateConfig = destination.Config.eventTemplateSettings; + const { Config } = destination; + const { eventChannelSettings, eventTemplateSettings, incomingWebhooksType, blacklistedEvents } = + Config; + const eventName = message.event; - if (!message.event) { + if (!eventName) { throw new InstrumentationError('Event name is required'); } - const eventName = message.event; - const channelListToSendThisEvent = new Set(); + if (blacklistedEvents?.length > 0) { + const blackListedEvents = blacklistedEvents.map((item) => item.eventName); + if (blackListedEvents.includes(eventName)) { + throw new ConfigurationError('Event is blacklisted. Please check configuration.'); + } + } + const templateListForThisEvent = new Set(); const traitsList = getWhiteListedTraits(destination); - // Add global context to regex always - // build the channel list and templatelist for the event, pick the first in case of multiple - // using set to filter out - // document this behaviour + /* Add global context to regex always + * build the channel list and template list for the event, pick the first in case of multiple + * using set to filter out + * document this behaviour + */ - // building channel list - buildChannelList(channelListToSendThisEvent, eventChannelConfig, eventName); - const channelListArray = Array.from(channelListToSendThisEvent); + // getting specific channel for event if available + + let channelWebhook; + let channelName; + if (incomingWebhooksType && incomingWebhooksType === 'modern') { + channelWebhook = getChannelForEventName(eventChannelSettings, eventName); + } else { + // default + channelName = getChannelNameForEvent(eventChannelSettings, eventName); + } // building templatelist - buildtemplateList(templateListForThisEvent, eventTemplateConfig, eventName); + buildtemplateList(templateListForThisEvent, eventTemplateSettings, eventName); const templateListArray = Array.from(templateListForThisEvent); logger.debug( @@ -187,8 +223,6 @@ const processTrack = (message, destination) => { templateListArray, templateListArray.length > 0 ? templateListArray[0] : undefined, ); - logger.debug('channelListToSendThisEvent: ', channelListArray); - // track event default handlebar expression const defaultTemplate = '{{name}} did {{event}}'; const template = templateListArray @@ -219,9 +253,16 @@ const processTrack = (message, destination) => { } catch (err) { throw new ConfigurationError(`Something is wrong with the event template: '${template}'`); } - - if (channelListArray && channelListArray.length > 0) { - return buildResponse({ channel: channelListArray[0], text: resultText }, message, destination); + if (incomingWebhooksType === 'modern' && channelWebhook) { + return buildResponse({ text: resultText }, message, destination, channelWebhook, false); + } + if (channelName) { + return buildResponse( + { channel: channelName, text: resultText }, + message, + destination, + channelWebhook, + ); } return buildResponse({ text: resultText }, message, destination); }; diff --git a/src/v0/destinations/slack/util.js b/src/v0/destinations/slack/util.js index b327d1d867..658ffe4d37 100644 --- a/src/v0/destinations/slack/util.js +++ b/src/v0/destinations/slack/util.js @@ -72,8 +72,10 @@ const stringifyJSON = (json, whiteListedTraits) => { return output; }; -// build default identify template -// if whitelisted traits are present build on it else build the entire traits object +/* build default identify template + * if whitelisted traits are present build on it + * else build the entire traits object + */ const buildDefaultTraitTemplate = (traitsList, traits, template) => { let generatedStringFromTemplate = template; // build template with whitelisted traits diff --git a/test/__tests__/data/slack_input.json b/test/__tests__/data/slack_input.json index 4e6195a37d..9b1ec52664 100644 --- a/test/__tests__/data/slack_input.json +++ b/test/__tests__/data/slack_input.json @@ -7,17 +7,130 @@ "ID": "1ZQUiJVMlmF7lfsdfXg7KXQnlLV", "Name": "SLACK", "DisplayName": "Slack", - "Config": { "excludeKeys": [], "includeKeys": [] } + "Config": { + "excludeKeys": [], + "includeKeys": [] + } }, "Config": { "eventChannelSettings": [ { - "eventChannel": "#slack_integration", + "eventChannelWebhook": "https://hooks.slack.com/services/example/test/demo", "eventName": "is", "eventRegex": true + } + ], + "eventTemplateSettings": [ + { + "eventName": "is", + "eventRegex": true, + "eventTemplate": "{{name}} performed {{event}} with {{properties.key1}} {{properties.key2}}" + }, + { + "eventName": "", + "eventRegex": false, + "eventTemplate": "" + } + ], + "webhookUrl": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", + "whitelistedTraitsSettings": [ + { + "trait": "hiji" }, - { "eventChannel": "", "eventName": "", "eventRegex": false }, - { "eventChannel": "", "eventName": "", "eventRegex": false } + { + "trait": "" + } + ] + }, + "Enabled": true, + "Transformations": [], + "IsProcessorEnabled": true + }, + "message": { + "anonymousId": "4de817fb-7f8e-4e23-b9be-f6736dbda20f", + "channel": "web", + "context": { + "app": { + "build": "1.0.0", + "name": "RudderLabs JavaScript SDK", + "namespace": "com.rudderlabs.javascript", + "version": "1.1.1-rc.1" + }, + "library": { + "name": "RudderLabs JavaScript SDK", + "version": "1.1.1-rc.1" + }, + "locale": "en-US", + "os": { + "name": "", + "version": "" + }, + "page": { + "path": "/tests/html/script-test.html", + "referrer": "http://localhost:1111/tests/html/", + "search": "", + "title": "", + "url": "http://localhost:1111/tests/html/script-test.html" + }, + "screen": { + "density": 1.7999999523162842 + }, + "traits": { + "country": "India", + "email": "name@domain.com", + "hiji": "hulala", + "name": "my-name" + }, + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" + }, + "integrations": { + "All": true + }, + "messageId": "9ecc0183-89ed-48bd-87eb-b2d8e1ca6780", + "originalTimestamp": "2020-03-23T03:46:30.916Z", + "properties": { + "path": "/tests/html/script-test.html", + "referrer": "http://localhost:1111/tests/html/", + "search": "", + "title": "", + "url": "http://localhost:1111/tests/html/script-test.html" + }, + "receivedAt": "2020-03-23T09:16:31.041+05:30", + "request_ip": "[::1]:52056", + "sentAt": "2020-03-23T03:46:30.916Z", + "timestamp": "2020-03-23T09:16:31.041+05:30", + "type": "identify", + "userId": "12345" + }, + "metadata": { + "anonymousId": "4de817fb-7f8e-4e23-b9be-f6736dbda20f", + "destinationId": "1ZQVSU9SXNg6KYgZALaqjAO3PIL", + "destinationType": "SLACK", + "jobId": 126, + "messageId": "9ecc0183-89ed-48bd-87eb-b2d8e1ca6780", + "sourceId": "1YhwKyDcKstudlGxkeN5p2wgsrp" + } + }, + { + "destination": { + "ID": "1ZQVSU9SXNg6KYgZALaqjAO3PIL", + "Name": "test-slack", + "DestinationDefinition": { + "ID": "1ZQUiJVMlmF7lfsdfXg7KXQnlLV", + "Name": "SLACK", + "DisplayName": "Slack", + "Config": { + "excludeKeys": [], + "includeKeys": [] + } + }, + "Config": { + "eventChannelSettings": [ + { + "eventChannelWebhook": "https://hooks.slack.com/services/example/test/demo", + "eventName": "is", + "eventRegex": true + } ], "eventTemplateSettings": [ { @@ -25,11 +138,27 @@ "eventRegex": true, "eventTemplate": "{{name}} performed {{event}} with {{properties.key1}} {{properties.key2}}" }, - { "eventName": "", "eventRegex": false, "eventTemplate": "" } + { + "eventName": "", + "eventRegex": false, + "eventTemplate": "" + } ], "identifyTemplate": "identified {{name}} with {{traits}}", "webhookUrl": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", - "whitelistedTraitsSettings": [{ "trait": "hiji" }, { "trait": "" }] + "whitelistedTraitsSettings": [ + { + "trait": "hiji" + }, + { + "trait": "" + } + ], + "blacklistedEvents": [ + { + "eventName": "black_event" + } + ] }, "Enabled": true, "Transformations": [], @@ -50,7 +179,10 @@ "version": "1.1.1-rc.1" }, "locale": "en-US", - "os": { "name": "", "version": "" }, + "os": { + "name": "", + "version": "" + }, "page": { "path": "/tests/html/script-test.html", "referrer": "http://localhost:1111/tests/html/", @@ -58,7 +190,9 @@ "title": "", "url": "http://localhost:1111/tests/html/script-test.html" }, - "screen": { "density": 1.7999999523162842 }, + "screen": { + "density": 1.7999999523162842 + }, "traits": { "country": "India", "email": "name@domain.com", @@ -67,7 +201,9 @@ }, "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" }, - "integrations": { "All": true }, + "integrations": { + "All": true + }, "messageId": "9ecc0183-89ed-48bd-87eb-b2d8e1ca6780", "originalTimestamp": "2020-03-23T03:46:30.916Z", "properties": { @@ -101,17 +237,18 @@ "ID": "1ZQUiJVMlmF7lfsdfXg7KXQnlLV", "Name": "SLACK", "DisplayName": "Slack", - "Config": { "excludeKeys": [], "includeKeys": [] } + "Config": { + "excludeKeys": [], + "includeKeys": [] + } }, "Config": { "eventChannelSettings": [ { - "eventChannel": "#slack_integration", + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/example", "eventName": "is", "eventRegex": true - }, - { "eventChannel": "", "eventName": "", "eventRegex": false }, - { "eventChannel": "", "eventName": "", "eventRegex": false } + } ], "eventTemplateSettings": [ { @@ -119,11 +256,22 @@ "eventRegex": true, "eventTemplate": "{{name}} performed {{event}} with {{properties.key1}} {{properties.key2}}" }, - { "eventName": "", "eventRegex": false, "eventTemplate": "" } + { + "eventName": "", + "eventRegex": false, + "eventTemplate": "" + } ], "identifyTemplate": "identified {{name}} with {{traits}}", "webhookUrl": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", - "whitelistedTraitsSettings": [{ "trait": "hiji" }, { "trait": "" }] + "whitelistedTraitsSettings": [ + { + "trait": "hiji" + }, + { + "trait": "" + } + ] }, "Enabled": true, "Transformations": [], @@ -144,7 +292,10 @@ "version": "1.1.1-rc.1" }, "locale": "en-US", - "os": { "name": "", "version": "" }, + "os": { + "name": "", + "version": "" + }, "page": { "path": "", "referrer": "", @@ -152,7 +303,389 @@ "title": "", "url": "" }, - "screen": { "density": 1.7999999523162842 }, + "screen": { + "density": 1.7999999523162842 + }, + "traits": { + "country": "India", + "email": "name@domain.com", + "hiji": "hulala", + "name": "my-name" + }, + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" + }, + "traits": { + "country": "USA", + "email": "test@domain.com", + "hiji": "hulala-1", + "name": "my-name-1" + }, + "integrations": { + "All": true + }, + "messageId": "4aaecff2-a513-4bbf-9824-c471f4ac9777", + "originalTimestamp": "2020-03-23T03:41:46.122Z", + "receivedAt": "2020-03-23T09:11:46.244+05:30", + "request_ip": "[::1]:52055", + "sentAt": "2020-03-23T03:41:46.123Z", + "timestamp": "2020-03-23T09:11:46.243+05:30", + "type": "identify", + "userId": "12345" + }, + "metadata": { + "anonymousId": "12345", + "destinationId": "1ZQVSU9SXNg6KYgZALaqjAO3PIL", + "destinationType": "SLACK", + "jobId": 123, + "messageId": "4aaecff2-a513-4bbf-9824-c471f4ac9777", + "sourceId": "1YhwKyDcKstudlGxkeN5p2wgsrp" + } + }, + { + "destination": { + "ID": "1ZQVSU9SXNg6KYgZALaqjAO3PIL", + "Name": "test-slack", + "DestinationDefinition": { + "ID": "1ZQUiJVMlmF7lfsdfXg7KXQnlLV", + "Name": "SLACK", + "DisplayName": "Slack", + "Config": { + "excludeKeys": [], + "includeKeys": [] + } + }, + "Config": { + "incomingWebhooksType": "modern", + "eventChannelSettings": [ + { + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/demo", + "eventName": "is", + "eventRegex": true + }, + { + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/example+1", + "eventName": "is", + "eventRegex": true + } + ], + "eventTemplateSettings": [ + { + "eventName": "is", + "eventRegex": true, + "eventTemplate": "{{name}} performed {{event}} with {{properties.key1}} {{properties.key2}} and traits {{traitsList.hiji}}" + }, + { + "eventName": "", + "eventRegex": false, + "eventTemplate": "" + } + ], + "identifyTemplate": "identified {{name}} with {{traits}}", + "webhookUrl": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", + "whitelistedTraitsSettings": [ + { + "trait": "hiji" + }, + { + "trait": "" + } + ], + "blacklistedEvents": [ + { + "eventName": "black_event" + } + ] + }, + "Enabled": true, + "Transformations": [], + "IsProcessorEnabled": true + }, + "message": { + "anonymousId": "00000000000000000000000000", + "channel": "web", + "context": { + "app": { + "build": "1.0.0", + "name": "RudderLabs JavaScript SDK", + "namespace": "com.rudderlabs.javascript", + "version": "1.1.1-rc.1" + }, + "ip": "0.0.0.0", + "library": { + "name": "RudderLabs JavaScript SDK", + "version": "1.1.1-rc.1" + }, + "locale": "en-US", + "os": { + "name": "", + "version": "" + }, + "page": { + "path": "/tests/html/script-test.html", + "referrer": "http://localhost:1111/tests/html/", + "search": "", + "title": "", + "url": "http://localhost:1111/tests/html/script-test.html" + }, + "screen": { + "density": 1.7999999523162842 + }, + "traits": { + "country": "India", + "email": "name@domain.com", + "hiji": "hulala", + "name": "my-name" + }, + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" + }, + "event": "test_isent1", + "integrations": { + "All": true + }, + "messageId": "78102118-56ac-4c5a-a495-8cd7c8f71cc2", + "originalTimestamp": "2020-03-23T03:46:30.921Z", + "properties": { + "currency": "USD", + "key1": "test_val1", + "key2": "test_val2", + "revenue": 30, + "user_actual_id": 12345 + }, + "receivedAt": "2020-03-23T09:16:31.064+05:30", + "request_ip": "[::1]:52057", + "sentAt": "2020-03-23T03:46:30.921Z", + "timestamp": "2020-03-23T09:16:31.064+05:30", + "type": "track", + "userId": "12345" + }, + "metadata": { + "anonymousId": "00000000000000000000000000", + "destinationId": "1ZQVSU9SXNg6KYgZALaqjAO3PIL", + "destinationType": "SLACK", + "jobId": 128, + "messageId": "78102118-56ac-4c5a-a495-8cd7c8f71cc2", + "sourceId": "1YhwKyDcKstudlGxkeN5p2wgsrp" + } + }, + { + "destination": { + "ID": "1ZQVSU9SXNg6KYgZALaqjAO3PIL", + "Name": "test-slack", + "DestinationDefinition": { + "ID": "1ZQUiJVMlmF7lfsdfXg7KXQnlLV", + "Name": "SLACK", + "DisplayName": "Slack", + "Config": { + "excludeKeys": [], + "includeKeys": [] + } + }, + "Config": { + "incomingWebhooksType": "modern", + "eventChannelSettings": [ + { + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/example", + "eventName": "is", + "eventChannel": "example_channel", + "eventRegex": true + }, + { + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/example+1", + "eventName": "is", + "eventChannel": "example_channel", + "eventRegex": true + } + ], + "eventTemplateSettings": [ + { + "eventName": "is", + "eventRegex": true, + "eventTemplate": "{{name}} performed {{event}} with {{properties.key1}} {{properties.key2}}" + }, + { + "eventName": "", + "eventRegex": false, + "eventTemplate": "" + } + ], + "identifyTemplate": "identified {{name}} with {{traits}}", + "webhookUrl": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", + "whitelistedTraitsSettings": [ + { + "trait": "hiji" + }, + { + "trait": "" + } + ], + "blacklistedEvents": [ + { + "eventName": "black_event" + } + ] + }, + "Enabled": true, + "Transformations": [], + "IsProcessorEnabled": true + }, + "message": { + "anonymousId": "00000000000000000000000000", + "channel": "web", + "context": { + "app": { + "build": "1.0.0", + "name": "RudderLabs JavaScript SDK", + "namespace": "com.rudderlabs.javascript", + "version": "1.1.1-rc.1" + }, + "ip": "0.0.0.0", + "library": { + "name": "RudderLabs JavaScript SDK", + "version": "1.1.1-rc.1" + }, + "locale": "en-US", + "os": { + "name": "", + "version": "" + }, + "page": { + "path": "/tests/html/script-test.html", + "referrer": "http://localhost:1111/tests/html/", + "search": "", + "title": "", + "url": "http://localhost:1111/tests/html/script-test.html" + }, + "screen": { + "density": 1.7999999523162842 + }, + "traits": { + "country": "India", + "email": "name@domain.com", + "hiji": "hulala", + "name": "my-name" + }, + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" + }, + "event": "test_eventing_testis", + "integrations": { + "All": true + }, + "messageId": "8b8d5937-09bc-49dc-a35e-8cd6370575f8", + "originalTimestamp": "2020-03-23T03:46:30.922Z", + "properties": { + "currency": "USD", + "key1": "test_val1", + "key2": "test_val2", + "revenue": 30, + "user_actual_id": 12345 + }, + "receivedAt": "2020-03-23T09:16:31.064+05:30", + "request_ip": "[::1]:52054", + "sentAt": "2020-03-23T03:46:30.923Z", + "timestamp": "2020-03-23T09:16:31.063+05:30", + "type": "track", + "userId": "12345" + }, + "metadata": { + "anonymousId": "00000000000000000000000000", + "destinationId": "1ZQVSU9SXNg6KYgZALaqjAO3PIL", + "destinationType": "SLACK", + "jobId": 129, + "messageId": "8b8d5937-09bc-49dc-a35e-8cd6370575f8", + "sourceId": "1YhwKyDcKstudlGxkeN5p2wgsrp" + } + }, + { + "destination": { + "ID": "1ZQVSU9SXNg6KYgZALaqjAO3PIL", + "Name": "test-slack", + "DestinationDefinition": { + "ID": "1ZQUiJVMlmF7lfsdfXg7KXQnlLV", + "Name": "SLACK", + "DisplayName": "Slack", + "Config": { + "excludeKeys": [], + "includeKeys": [] + } + }, + "Config": { + "incomingWebhooksType": "modern", + "eventChannelSettings": [ + { + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/example", + "eventName": "test_eventing_test", + "eventChannel": "example_channel", + "eventRegex": false + }, + { + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/example+1", + "eventName": "", + "eventChannel": "example_channel", + "eventRegex": true + } + ], + "eventTemplateSettings": [ + { + "eventName": "is", + "eventRegex": true, + "eventTemplate": "{{name}} performed {{event}} with {{properties.key1}} {{properties.key2}}" + }, + { + "eventName": "", + "eventRegex": false, + "eventTemplate": "" + } + ], + "identifyTemplate": "identified {{name}} with {{traits}}", + "webhookUrl": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", + "whitelistedTraitsSettings": [ + { + "trait": "hiji" + }, + { + "trait": "" + } + ], + "blacklistedEvents": [ + { + "eventName": "black_event" + } + ] + }, + "Enabled": true, + "Transformations": [], + "IsProcessorEnabled": true + }, + "message": { + "anonymousId": "00000000000000000000000000", + "channel": "web", + "context": { + "app": { + "build": "1.0.0", + "name": "RudderLabs JavaScript SDK", + "namespace": "com.rudderlabs.javascript", + "version": "1.1.1-rc.1" + }, + "ip": "0.0.0.0", + "library": { + "name": "RudderLabs JavaScript SDK", + "version": "1.1.1-rc.1" + }, + "locale": "en-US", + "os": { + "name": "", + "version": "" + }, + "page": { + "path": "/tests/html/script-test.html", + "referrer": "http://localhost:1111/tests/html/", + "search": "", + "title": "", + "url": "http://localhost:1111/tests/html/script-test.html" + }, + "screen": { + "density": 1.7999999523162842 + }, "traits": { "country": "India", "email": "name@domain.com", @@ -161,28 +694,32 @@ }, "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" }, - "traits": { - "country": "USA", - "email": "test@domain.com", - "hiji": "hulala-1", - "name": "my-name-1" + "event": "test_eventing_test", + "integrations": { + "All": true }, - "integrations": { "All": true }, - "messageId": "4aaecff2-a513-4bbf-9824-c471f4ac9777", - "originalTimestamp": "2020-03-23T03:41:46.122Z", - "receivedAt": "2020-03-23T09:11:46.244+05:30", - "request_ip": "[::1]:52055", - "sentAt": "2020-03-23T03:41:46.123Z", - "timestamp": "2020-03-23T09:11:46.243+05:30", - "type": "identify", + "messageId": "8b8d5937-09bc-49dc-a35e-8cd6370575f8", + "originalTimestamp": "2020-03-23T03:46:30.922Z", + "properties": { + "currency": "USD", + "key1": "test_val1", + "key2": "test_val2", + "revenue": 30, + "user_actual_id": 12345 + }, + "receivedAt": "2020-03-23T09:16:31.064+05:30", + "request_ip": "[::1]:52054", + "sentAt": "2020-03-23T03:46:30.923Z", + "timestamp": "2020-03-23T09:16:31.063+05:30", + "type": "track", "userId": "12345" }, "metadata": { - "anonymousId": "12345", + "anonymousId": "00000000000000000000000000", "destinationId": "1ZQVSU9SXNg6KYgZALaqjAO3PIL", "destinationType": "SLACK", - "jobId": 123, - "messageId": "4aaecff2-a513-4bbf-9824-c471f4ac9777", + "jobId": 129, + "messageId": "8b8d5937-09bc-49dc-a35e-8cd6370575f8", "sourceId": "1YhwKyDcKstudlGxkeN5p2wgsrp" } }, @@ -194,17 +731,24 @@ "ID": "1ZQUiJVMlmF7lfsdfXg7KXQnlLV", "Name": "SLACK", "DisplayName": "Slack", - "Config": { "excludeKeys": [], "includeKeys": [] } + "Config": { + "excludeKeys": [], + "includeKeys": [] + } }, "Config": { + "incomingWebhooksType": "legacy", "eventChannelSettings": [ { - "eventChannel": "#slack_integration", + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/demo", "eventName": "is", "eventRegex": true }, - { "eventChannel": "", "eventName": "", "eventRegex": false }, - { "eventChannel": "", "eventName": "", "eventRegex": false } + { + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/example+1", + "eventName": "is", + "eventRegex": true + } ], "eventTemplateSettings": [ { @@ -212,11 +756,27 @@ "eventRegex": true, "eventTemplate": "{{name}} performed {{event}} with {{properties.key1}} {{properties.key2}} and traits {{traitsList.hiji}}" }, - { "eventName": "", "eventRegex": false, "eventTemplate": "" } + { + "eventName": "", + "eventRegex": false, + "eventTemplate": "" + } ], "identifyTemplate": "identified {{name}} with {{traits}}", "webhookUrl": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", - "whitelistedTraitsSettings": [{ "trait": "hiji" }, { "trait": "" }] + "whitelistedTraitsSettings": [ + { + "trait": "hiji" + }, + { + "trait": "" + } + ], + "blacklistedEvents": [ + { + "eventName": "black_event" + } + ] }, "Enabled": true, "Transformations": [], @@ -238,7 +798,10 @@ "version": "1.1.1-rc.1" }, "locale": "en-US", - "os": { "name": "", "version": "" }, + "os": { + "name": "", + "version": "" + }, "page": { "path": "/tests/html/script-test.html", "referrer": "http://localhost:1111/tests/html/", @@ -246,7 +809,9 @@ "title": "", "url": "http://localhost:1111/tests/html/script-test.html" }, - "screen": { "density": 1.7999999523162842 }, + "screen": { + "density": 1.7999999523162842 + }, "traits": { "country": "India", "email": "name@domain.com", @@ -256,7 +821,9 @@ "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" }, "event": "test_isent1", - "integrations": { "All": true }, + "integrations": { + "All": true + }, "messageId": "78102118-56ac-4c5a-a495-8cd7c8f71cc2", "originalTimestamp": "2020-03-23T03:46:30.921Z", "properties": { @@ -290,17 +857,25 @@ "ID": "1ZQUiJVMlmF7lfsdfXg7KXQnlLV", "Name": "SLACK", "DisplayName": "Slack", - "Config": { "excludeKeys": [], "includeKeys": [] } + "Config": { + "excludeKeys": [], + "includeKeys": [] + } }, "Config": { + "incomingWebhooksType": "legacy", "eventChannelSettings": [ { - "eventChannel": "#slack_integration", + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/example", "eventName": "is", "eventRegex": true }, - { "eventChannel": "", "eventName": "", "eventRegex": false }, - { "eventChannel": "", "eventName": "", "eventRegex": false } + { + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/example+1", + "eventChannel": "example-of-legacy", + "eventName": "is", + "eventRegex": true + } ], "eventTemplateSettings": [ { @@ -308,11 +883,27 @@ "eventRegex": true, "eventTemplate": "{{name}} performed {{event}} with {{properties.key1}} {{properties.key2}}" }, - { "eventName": "", "eventRegex": false, "eventTemplate": "" } + { + "eventName": "", + "eventRegex": false, + "eventTemplate": "" + } ], "identifyTemplate": "identified {{name}} with {{traits}}", "webhookUrl": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", - "whitelistedTraitsSettings": [{ "trait": "hiji" }, { "trait": "" }] + "whitelistedTraitsSettings": [ + { + "trait": "hiji" + }, + { + "trait": "" + } + ], + "blacklistedEvents": [ + { + "eventName": "black_event" + } + ] }, "Enabled": true, "Transformations": [], @@ -334,7 +925,10 @@ "version": "1.1.1-rc.1" }, "locale": "en-US", - "os": { "name": "", "version": "" }, + "os": { + "name": "", + "version": "" + }, "page": { "path": "/tests/html/script-test.html", "referrer": "http://localhost:1111/tests/html/", @@ -342,7 +936,9 @@ "title": "", "url": "http://localhost:1111/tests/html/script-test.html" }, - "screen": { "density": 1.7999999523162842 }, + "screen": { + "density": 1.7999999523162842 + }, "traits": { "country": "India", "email": "name@domain.com", @@ -352,7 +948,9 @@ "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" }, "event": "test_eventing_testis", - "integrations": { "All": true }, + "integrations": { + "All": true + }, "messageId": "8b8d5937-09bc-49dc-a35e-8cd6370575f8", "originalTimestamp": "2020-03-23T03:46:30.922Z", "properties": { @@ -394,19 +992,9 @@ "Config": { "eventChannelSettings": [ { - "eventChannel": "#slack_integration", + "eventChannelWebhook": "https://hooks.slack.com/services/example/test/demo", "eventName": "is", "eventRegex": true - }, - { - "eventChannel": "", - "eventName": "", - "eventRegex": false - }, - { - "eventChannel": "", - "eventName": "", - "eventRegex": false } ], "eventTemplateSettings": [ @@ -510,17 +1098,18 @@ "ID": "1ZQUiJVMlmF7lfsdfXg7KXQnlLV", "Name": "SLACK", "DisplayName": "Slack", - "Config": { "excludeKeys": [], "includeKeys": [] } + "Config": { + "excludeKeys": [], + "includeKeys": [] + } }, "Config": { "eventChannelSettings": [ { - "eventChannel": "#slack_integration", + "eventChannelWebhook": "https://hooks.slack.com/services/example/test/demo", "eventName": "is", "eventRegex": true - }, - { "eventChannel": "", "eventName": "", "eventRegex": false }, - { "eventChannel": "", "eventName": "", "eventRegex": false } + } ], "eventTemplateSettings": [ { @@ -528,11 +1117,22 @@ "eventRegex": true, "eventTemplate": "{{name}} performed {{event}} with {{properties.key1}} {{properties.key2}}" }, - { "eventName": "", "eventRegex": false, "eventTemplate": "" } + { + "eventName": "", + "eventRegex": false, + "eventTemplate": "" + } ], "identifyTemplate": "identified {{name}} with {{traits}}", "webhookUrl": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", - "whitelistedTraitsSettings": [{ "trait": "hiji" }, { "trait": "" }] + "whitelistedTraitsSettings": [ + { + "trait": "hiji" + }, + { + "trait": "" + } + ] }, "Enabled": true, "Transformations": [], @@ -554,7 +1154,10 @@ "version": "1.1.1-rc.1" }, "locale": "en-US", - "os": { "name": "", "version": "" }, + "os": { + "name": "", + "version": "" + }, "page": { "path": "/tests/html/script-test.html", "referrer": "http://localhost:1111/tests/html/", @@ -562,7 +1165,9 @@ "title": "", "url": "http://localhost:1111/tests/html/script-test.html" }, - "screen": { "density": 1.7999999523162842 }, + "screen": { + "density": 1.7999999523162842 + }, "traits": { "country": "India", "email": "name@domain.com", @@ -571,7 +1176,9 @@ }, "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" }, - "integrations": { "All": true }, + "integrations": { + "All": true + }, "messageId": "8b8d5937-09bc-49dc-a35e-8cd6370575f8", "originalTimestamp": "2020-03-23T03:46:30.922Z", "properties": { @@ -605,17 +1212,18 @@ "ID": "1ZQUiJVMlmF7lfsdfXg7KXQnlLV", "Name": "SLACK", "DisplayName": "Slack", - "Config": { "excludeKeys": [], "includeKeys": [] } + "Config": { + "excludeKeys": [], + "includeKeys": [] + } }, "Config": { "eventChannelSettings": [ { - "eventChannel": "#slack_integration", + "eventChannelWebhook": "https://hooks.slack.com/services/example/test/demo", "eventName": "is", "eventRegex": true - }, - { "eventChannel": "", "eventName": "", "eventRegex": false }, - { "eventChannel": "", "eventName": "", "eventRegex": false } + } ], "eventTemplateSettings": [ { @@ -623,11 +1231,22 @@ "eventRegex": true, "eventTemplate": "{{name}} performed {{event}} with {{properties. key1}} {{properties.key2}} and traits {{traitsList.hiji}}" }, - { "eventName": "", "eventRegex": false, "eventTemplate": "" } + { + "eventName": "", + "eventRegex": false, + "eventTemplate": "" + } ], "identifyTemplate": "identified {{name}} with {{traits}}", "webhookUrl": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", - "whitelistedTraitsSettings": [{ "trait": "hiji" }, { "trait": "" }] + "whitelistedTraitsSettings": [ + { + "trait": "hiji" + }, + { + "trait": "" + } + ] }, "Enabled": true, "Transformations": [], @@ -649,7 +1268,10 @@ "version": "1.1.1-rc.1" }, "locale": "en-US", - "os": { "name": "", "version": "" }, + "os": { + "name": "", + "version": "" + }, "page": { "path": "/tests/html/script-test.html", "referrer": "http://localhost:1111/tests/html/", @@ -657,7 +1279,9 @@ "title": "", "url": "http://localhost:1111/tests/html/script-test.html" }, - "screen": { "density": 1.7999999523162842 }, + "screen": { + "density": 1.7999999523162842 + }, "traits": { "country": "India", "email": "name@domain.com", @@ -667,7 +1291,9 @@ "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" }, "event": "test_isent1", - "integrations": { "All": true }, + "integrations": { + "All": true + }, "messageId": "78102118-56ac-4c5a-a495-8cd7c8f71cc2", "originalTimestamp": "2020-03-23T03:46:30.921Z", "properties": { @@ -692,5 +1318,98 @@ "messageId": "78102118-56ac-4c5a-a495-8cd7c8f71cc2", "sourceId": "1YhwKyDcKstudlGxkeN5p2wgsrp" } + }, + { + "destination": { + "ID": "1ZQVSU9SXNg6KYgZALaqjAO3PIL", + "Name": "test-slack", + "DestinationDefinition": { + "ID": "1ZQUiJVMlmF7lfsdfXg7KXQnlLV", + "Name": "SLACK", + "DisplayName": "Slack", + "Config": { + "excludeKeys": [], + "includeKeys": [] + } + }, + "Config": { + "incomingWebhooksType": "legacy", + "eventChannelSettings": [ + { + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/example", + "eventName": "is", + "eventRegex": true + }, + { + "eventChannelWebhook": "https://hooks.slack.com/services/id1/id2/example+1", + "eventChannel": "example-of-legacy", + "eventName": "is", + "eventRegex": true + } + ], + "eventTemplateSettings": [ + { + "eventName": "is", + "eventRegex": true, + "eventTemplate": "{{name}} performed {{event}} with {{properties.key1}} {{properties.key2}}" + }, + { + "eventName": "", + "eventRegex": false, + "eventTemplate": "" + } + ], + "identifyTemplate": "identified {{name}} with {{traits}}", + "webhookUrl": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", + "whitelistedTraitsSettings": [ + { + "trait": "hiji" + }, + { + "trait": "" + } + ], + "blacklistedEvents": [ + { + "eventName": "black_event" + } + ] + }, + "Enabled": true, + "Transformations": [], + "IsProcessorEnabled": true + }, + "message": { + "anonymousId": "00000000000000000000000000", + "channel": "web", + "context": {}, + "event": "black_event", + "integrations": { + "All": true + }, + "messageId": "8b8d5937-09bc-49dc-a35e-8cd6370575f8", + "originalTimestamp": "2020-03-23T03:46:30.922Z", + "properties": { + "currency": "USD", + "key1": "test_val1", + "key2": "test_val2", + "revenue": 30, + "user_actual_id": 12345 + }, + "receivedAt": "2020-03-23T09:16:31.064+05:30", + "request_ip": "[::1]:52054", + "sentAt": "2020-03-23T03:46:30.923Z", + "timestamp": "2020-03-23T09:16:31.063+05:30", + "type": "track", + "userId": "12345" + }, + "metadata": { + "anonymousId": "00000000000000000000000000", + "destinationId": "1ZQVSU9SXNg6KYgZALaqjAO3PIL", + "destinationType": "SLACK", + "jobId": 129, + "messageId": "8b8d5937-09bc-49dc-a35e-8cd6370575f8", + "sourceId": "1YhwKyDcKstudlGxkeN5p2wgsrp" + } } -] +] \ No newline at end of file diff --git a/test/__tests__/data/slack_output.json b/test/__tests__/data/slack_output.json index 5c8495c757..853daf7801 100644 --- a/test/__tests__/data/slack_output.json +++ b/test/__tests__/data/slack_output.json @@ -1,4 +1,25 @@ [ + { + "version": "1", + "type": "REST", + "method": "POST", + "endpoint": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "params": {}, + "body": { + "JSON": {}, + "XML": {}, + "JSON_ARRAY": {}, + "FORM": { + "payload": "{\"text\":\"Identified my-namehiji: hulala \",\"username\":\"RudderStack\",\"icon_url\":\"https://cdn.rudderlabs.com/rudderstack.png\"}" + } + }, + "files": {}, + "userId": "12345", + "statusCode": 200 + }, { "error": "Event type page is not supported" }, @@ -7,7 +28,9 @@ "type": "REST", "method": "POST", "endpoint": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", - "headers": { "Content-Type": "application/x-www-form-urlencoded" }, + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, "params": {}, "body": { "JSON": {}, @@ -21,19 +44,84 @@ "userId": "12345", "statusCode": 200 }, + { + "version": "1", + "type": "REST", + "method": "POST", + "endpoint": "https://hooks.slack.com/services/id1/id2/demo", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "params": {}, + "body": { + "JSON": {}, + "XML": {}, + "JSON_ARRAY": {}, + "FORM": { + "payload": "{\"text\":\"my-name performed test_isent1 with test_val1 test_val2 and traits hulala\"}" + } + }, + "files": {}, + "userId": "12345", + "statusCode": 200 + }, + { + "version": "1", + "type": "REST", + "method": "POST", + "endpoint": "https://hooks.slack.com/services/id1/id2/example", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "params": {}, + "body": { + "JSON": {}, + "XML": {}, + "JSON_ARRAY": {}, + "FORM": { + "payload": "{\"text\":\"my-name performed test_eventing_testis with test_val1 test_val2\"}" + } + }, + "files": {}, + "userId": "12345", + "statusCode": 200 + }, + { + "version": "1", + "type": "REST", + "method": "POST", + "endpoint": "https://hooks.slack.com/services/id1/id2/example", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "params": {}, + "body": { + "JSON": {}, + "XML": {}, + "JSON_ARRAY": {}, + "FORM": { + "payload": "{\"text\":\"my-name did test_eventing_test\"}" + } + }, + "files": {}, + "userId": "12345", + "statusCode": 200 + }, { "version": "1", "type": "REST", "method": "POST", "endpoint": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", - "headers": { "Content-Type": "application/x-www-form-urlencoded" }, + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, "params": {}, "body": { "JSON": {}, "XML": {}, "JSON_ARRAY": {}, "FORM": { - "payload": "{\"channel\":\"#slack_integration\",\"text\":\"my-name performed test_isent1 with test_val1 test_val2 and traits hulala\",\"username\":\"RudderStack\",\"icon_url\":\"https://cdn.rudderlabs.com/rudderstack.png\"}" + "payload": "{\"text\":\"my-name performed test_isent1 with test_val1 test_val2 and traits hulala\",\"username\":\"RudderStack\",\"icon_url\":\"https://cdn.rudderlabs.com/rudderstack.png\"}" } }, "files": {}, @@ -45,14 +133,16 @@ "type": "REST", "method": "POST", "endpoint": "https://hooks.slack.com/services/THZM86VSS/BV9HZ2UN6/demo", - "headers": { "Content-Type": "application/x-www-form-urlencoded" }, + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, "params": {}, "body": { "JSON": {}, "XML": {}, "JSON_ARRAY": {}, "FORM": { - "payload": "{\"channel\":\"#slack_integration\",\"text\":\"my-name performed test_eventing_testis with test_val1 test_val2\",\"username\":\"RudderStack\",\"icon_url\":\"https://cdn.rudderlabs.com/rudderstack.png\"}" + "payload": "{\"channel\":\"example-of-legacy\",\"text\":\"my-name performed test_eventing_testis with test_val1 test_val2\",\"username\":\"RudderStack\",\"icon_url\":\"https://cdn.rudderlabs.com/rudderstack.png\"}" } }, "files": {}, @@ -67,5 +157,8 @@ }, { "error": "Something is wrong with the event template: '{{name}} performed {{event}} with {{properties. key1}} {{properties.key2}} and traits {{traitsList.hiji}}'" + }, + { + "error": "Event is blacklisted. Please check configuration." } -] +] \ No newline at end of file diff --git a/test/__tests__/slack.test.js b/test/__tests__/slack.test.js index c2b5b91ede..eec0f4054f 100644 --- a/test/__tests__/slack.test.js +++ b/test/__tests__/slack.test.js @@ -29,7 +29,7 @@ const inputRouterData = JSON.parse(inputRouterDataFile); const expectedRouterData = JSON.parse(outputRouterDataFile); inputData.forEach((input, index) => { - test(`${name} Tests - payload: %{index}`, () => { + test(`${name} Tests - payload: ${index}`, () => { try { const output = transformer.process(input); expect(output).toEqual([expectedData[index]]);