diff --git a/src/cdk/v2/destinations/lytics/config.ts b/src/cdk/v2/destinations/lytics/config.ts new file mode 100644 index 0000000000..6756834caa --- /dev/null +++ b/src/cdk/v2/destinations/lytics/config.ts @@ -0,0 +1,9 @@ +import { getMappingConfig } from '../../../../v0/util'; + +const CONFIG_CATEGORIES = { + CUSTOMER_PROPERTIES_CONFIG: { name: 'LYTICSIdentifyConfig' }, +}; + +const MAPPING_CONFIG = getMappingConfig(CONFIG_CATEGORIES, __dirname); +export const CUSTOMER_PROPERTIES_CONFIG = + MAPPING_CONFIG[CONFIG_CATEGORIES.CUSTOMER_PROPERTIES_CONFIG.name]; diff --git a/src/cdk/v2/destinations/lytics/data/LYTICSIdentifyConfig.json b/src/cdk/v2/destinations/lytics/data/LYTICSIdentifyConfig.json new file mode 100644 index 0000000000..c1996d34f7 --- /dev/null +++ b/src/cdk/v2/destinations/lytics/data/LYTICSIdentifyConfig.json @@ -0,0 +1,25 @@ +[ + { + "destKey": "user_id", + "sourceKeys": "userIdOnly", + "sourceFromGenericMap": true, + "required": false + }, + { + "destKey": "anonymous_id", + "sourceKeys": "anonymousId", + "required": false + }, + { + "destKey": "first_name", + "sourceKeys": "firstName", + "sourceFromGenericMap": true, + "required": false + }, + { + "destKey": "last_name", + "sourceKeys": "lastName", + "sourceFromGenericMap": true, + "required": false + } +] diff --git a/src/cdk/v2/destinations/lytics/procWorkflow.yaml b/src/cdk/v2/destinations/lytics/procWorkflow.yaml index 2622146221..834493e79c 100644 --- a/src/cdk/v2/destinations/lytics/procWorkflow.yaml +++ b/src/cdk/v2/destinations/lytics/procWorkflow.yaml @@ -5,9 +5,12 @@ bindings: path: ../../../../v0/util - name: removeUndefinedAndNullValues path: ../../../../v0/util + - name: constructPayload + path: ../../../../v0/util - path: ../../bindings/jsontemplate - name: defaultRequestConfig path: ../../../../v0/util + - path: ./config steps: - name: validateInput @@ -24,20 +27,19 @@ steps: condition: $.context.messageType === {{$.EventType.IDENTIFY}} template: | const flattenTraits = $.flattenJson(.message.traits ?? .message.context.traits); - $.context.payload = .message.({ + const payload = $.constructPayload(.message, $.CUSTOMER_PROPERTIES_CONFIG); + $.context.payload = { ...flattenTraits, - first_name: {{{{$.getGenericPaths("firstName")}}}}, - last_name: {{{{$.getGenericPaths("lastName")}}}}, - user_id: {{{{$.getGenericPaths("userId")}}}} - }) + ...payload, + } else: name: payloadForOthers template: | const flattenProperties = $.flattenJson(.message.properties); + const customerPropertiesInfo = $.constructPayload(.message, $.CUSTOMER_PROPERTIES_CONFIG); $.context.payload = .message.({ ...flattenProperties, - first_name: .properties.firstName ?? .properties.firstname, - last_name: .properties.lastName ?? .properties.lastname + ...customerPropertiesInfo }) - name: trackPayload condition: $.context.messageType === {{$.EventType.TRACK}} diff --git a/src/v0/destinations/lytics/config.js b/src/v0/destinations/lytics/config.js deleted file mode 100644 index c7843eda46..0000000000 --- a/src/v0/destinations/lytics/config.js +++ /dev/null @@ -1,27 +0,0 @@ -const { getMappingConfig } = require('../../util'); - -const ENDPOINT = 'https://api.lytics.io/collect/json'; -const CONFIG_CATEGORIES = { - IDENTIFY: { - name: 'LYTICSIdentifyConfig', - }, - PAGESCREEN: { - name: 'LYTICSPageScreenConfig', - }, - TRACK: { - name: 'LYTICSTrackConfig', - }, -}; - -const forFirstName = ['firstname', 'firstName']; -const forLastName = ['lastname', 'lastName']; - -const MAPPING_CONFIG = getMappingConfig(CONFIG_CATEGORIES, __dirname); - -module.exports = { - ENDPOINT, - MAPPING_CONFIG, - CONFIG_CATEGORIES, - forFirstName, - forLastName, -}; diff --git a/src/v0/destinations/lytics/data/LYTICSIdentifyConfig.json b/src/v0/destinations/lytics/data/LYTICSIdentifyConfig.json deleted file mode 100644 index d9765490e3..0000000000 --- a/src/v0/destinations/lytics/data/LYTICSIdentifyConfig.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "destKey": "user_id", - "sourceKeys": [ - "userId", - "traits.userId", - "traits.id", - "context.traits.userId", - "context.traits.id", - "anonymousId" - ], - "required": false - }, - { - "destKey": "", - "sourceKeys": ["traits", "context.traits"], - "required": false - } -] diff --git a/src/v0/destinations/lytics/data/LYTICSPageScreenConfig.json b/src/v0/destinations/lytics/data/LYTICSPageScreenConfig.json deleted file mode 100644 index f925dbc5bd..0000000000 --- a/src/v0/destinations/lytics/data/LYTICSPageScreenConfig.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "destKey": "event", - "sourceKeys": "name", - "required": false - }, - { - "destKey": "", - "sourceKeys": "properties", - "required": false - } -] diff --git a/src/v0/destinations/lytics/data/LYTICSTrackConfig.json b/src/v0/destinations/lytics/data/LYTICSTrackConfig.json deleted file mode 100644 index 5de09eb10b..0000000000 --- a/src/v0/destinations/lytics/data/LYTICSTrackConfig.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "destKey": "_e", - "sourceKeys": "event", - "required": false - }, - { - "destKey": "", - "sourceKeys": "properties", - "required": false - } -] diff --git a/src/v0/destinations/lytics/transform.js b/src/v0/destinations/lytics/transform.js deleted file mode 100644 index c3a971adba..0000000000 --- a/src/v0/destinations/lytics/transform.js +++ /dev/null @@ -1,77 +0,0 @@ -const { InstrumentationError } = require('@rudderstack/integrations-lib'); -const { EventType } = require('../../../constants'); -const { - CONFIG_CATEGORIES, - MAPPING_CONFIG, - ENDPOINT, - forFirstName, - forLastName, -} = require('./config'); -const { - constructPayload, - defaultPostRequestConfig, - removeUndefinedAndNullValues, - defaultRequestConfig, - flattenJson, - simpleProcessRouterDest, -} = require('../../util'); -const { JSON_MIME_TYPE } = require('../../util/constant'); - -const responseBuilderSimple = (message, category, destination) => { - const payload = constructPayload(message, MAPPING_CONFIG[category.name]); - const response = defaultRequestConfig(); - const { stream, apiKey } = destination.Config; - response.endpoint = `${ENDPOINT}/${stream}?access_token=${apiKey}`; - response.method = defaultPostRequestConfig.requestMethod; - const flattenedPayload = removeUndefinedAndNullValues(flattenJson(payload)); - forFirstName.forEach((key) => { - if (flattenedPayload[key]) { - flattenedPayload.first_name = flattenedPayload[key]; - delete flattenedPayload[key]; - } - }); - forLastName.forEach((key) => { - if (flattenedPayload[key]) { - flattenedPayload.last_name = flattenedPayload[key]; - delete flattenedPayload[key]; - } - }); - response.body.JSON = flattenedPayload; - response.headers = { - 'Content-Type': JSON_MIME_TYPE, - }; - return response; -}; - -const processEvent = (message, destination) => { - if (!message.type) { - throw new InstrumentationError('Event type is required'); - } - const messageType = message.type; - let category; - switch (messageType.toLowerCase()) { - case EventType.IDENTIFY: - category = CONFIG_CATEGORIES.IDENTIFY; - break; - case EventType.PAGE: - case EventType.SCREEN: - category = CONFIG_CATEGORIES.PAGESCREEN; - break; - case EventType.TRACK: - category = CONFIG_CATEGORIES.TRACK; - break; - default: - throw new InstrumentationError(`Event type ${messageType} is not supported`); - } - // build the response - return responseBuilderSimple(message, category, destination); -}; - -const process = (event) => processEvent(event.message, event.destination); - -const processRouterDest = async (inputs, reqMetadata) => { - const respList = await simpleProcessRouterDest(inputs, process, reqMetadata); - return respList; -}; - -module.exports = { process, processRouterDest }; diff --git a/test/integrations/destinations/lytics/processor/data.ts b/test/integrations/destinations/lytics/processor/data.ts index 344eecc3cd..dd5511140a 100644 --- a/test/integrations/destinations/lytics/processor/data.ts +++ b/test/integrations/destinations/lytics/processor/data.ts @@ -143,6 +143,7 @@ export const data = [ body: { JSON: { _e: 'Order Completed', + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', checkout_id: 'what is checkout id here??', coupon: 'APPARELSALE', currency: 'GBP', @@ -190,6 +191,7 @@ export const data = [ 'products[2].url': 'https://www.example.com/product/offer-t-shirt', 'products[2].value': 12.99, 'products[2].variant': 'Black', + user_id: 'rudder123', revenue: 31.98, shipping: 4, value: 31.98, @@ -293,6 +295,7 @@ export const data = [ params: {}, body: { JSON: { + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', user_id: 'rudder123', 'company.id': 'abc123', createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', @@ -407,6 +410,7 @@ export const data = [ params: {}, body: { JSON: { + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', user_id: 'rudder123', 'company.id': 'abc123', createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', @@ -514,6 +518,7 @@ export const data = [ params: {}, body: { JSON: { + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', user_id: 'rudder123', 'company.id': 'abc123', createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', @@ -626,6 +631,7 @@ export const data = [ email: 'rudderTest@gmail.com', name: 'Rudder Test', plan: 'Enterprise', + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', }, XML: {}, JSON_ARRAY: {}, @@ -732,6 +738,7 @@ export const data = [ email: 'rudderTest@gmail.com', name: 'Rudder Test', plan: 'Enterprise', + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', }, XML: {}, JSON_ARRAY: {}, @@ -1116,6 +1123,7 @@ export const data = [ revenue: 31.98, shipping: 4, value: 31.98, + user_id: 'rudder123', }, XML: {}, JSON_ARRAY: {}, @@ -1209,11 +1217,13 @@ export const data = [ body: { JSON: { event: 'ApplicationLoaded', + anonymous_id: '00000000000000000000000000', path: '', referrer: '', search: '', title: '', url: '', + user_id: '12345', }, XML: {}, JSON_ARRAY: {}, @@ -1307,11 +1317,13 @@ export const data = [ body: { JSON: { event: 'ApplicationLoaded', + anonymous_id: '00000000000000000000000000', path: '', referrer: '', search: '', title: '', url: '', + user_id: '12345', }, XML: {}, JSON_ARRAY: {}, @@ -1414,6 +1426,7 @@ export const data = [ params: {}, body: { JSON: { + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', user_id: 'rudder123', 'company.id': 'abc123', createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', @@ -1440,4 +1453,113 @@ export const data = [ }, }, }, + { + name: 'lytics', + description: 'Test 11: user_id is mapped to userIdOnly', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + anonymousId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.1.6', + }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.1.6' }, + locale: 'en-GB', + os: { name: '', version: '' }, + page: { + path: '/testing/script-test.html', + referrer: '', + search: '', + title: '', + url: 'http://localhost:3243/testing/script-test.html', + }, + screen: { density: 2 }, + traits: { + company: { id: 'abc123' }, + createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', + email: 'rudderTest@gmail.com', + name: 'Rudder Test', + plan: 'Enterprise', + firstName: 'Rudderstack', + lastname: 'Test', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36', + }, + integrations: { All: true }, + messageId: 'e108eb05-f6cd-4624-ba8c-568f2e2b3f92', + originalTimestamp: '2020-10-16T08:26:14.938Z', + receivedAt: '2020-10-16T13:56:14.945+05:30', + request_ip: '[::1]', + sentAt: '2020-10-16T08:26:14.939Z', + timestamp: '2020-10-16T13:56:14.944+05:30', + type: 'identify', + }, + destination: { + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + Config: { apiKey: 'dummyApiKey', stream: 'default' }, + Enabled: true, + Transformations: [], + IsProcessorEnabled: true, + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + method: 'POST', + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.lytics.io/collect/json/default?access_token=dummyApiKey', + headers: { 'Content-Type': 'application/json' }, + params: {}, + body: { + JSON: { + anonymous_id: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + 'company.id': 'abc123', + createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', + email: 'rudderTest@gmail.com', + name: 'Rudder Test', + plan: 'Enterprise', + first_name: 'Rudderstack', + last_name: 'Test', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + }, ]; diff --git a/test/integrations/destinations/lytics/router/data.ts b/test/integrations/destinations/lytics/router/data.ts deleted file mode 100644 index e5d9adae5c..0000000000 --- a/test/integrations/destinations/lytics/router/data.ts +++ /dev/null @@ -1,299 +0,0 @@ -export const data = [ - { - name: 'lytics', - description: 'Test 0', - feature: 'router', - module: 'destination', - version: 'v0', - input: { - request: { - body: { - input: [ - { - message: { - anonymousId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.1.6', - }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.1.6' }, - locale: 'en-GB', - os: { name: '', version: '' }, - page: { - path: '/testing/script-test.html', - referrer: '', - search: '', - title: '', - url: 'http://localhost:3243/testing/script-test.html', - }, - screen: { density: 2 }, - traits: { - company: { id: 'abc123' }, - createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', - email: 'rudderTest@gmail.com', - name: 'Rudder Test', - plan: 'Enterprise', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36', - }, - event: 'Order Completed', - integrations: { All: true }, - messageId: 'a0adfab9-baf7-4e09-a2ce-bbe2844c324a', - timestamp: '2020-10-16T08:10:12.782Z', - properties: { - checkout_id: 'what is checkout id here??', - coupon: 'APPARELSALE', - currency: 'GBP', - order_id: 'transactionId', - products: [ - { - brand: '', - category: 'Merch', - currency: 'GBP', - image_url: 'https://www.example.com/product/bacon-jam.jpg', - name: 'Food/Drink', - position: 1, - price: 3, - product_id: 'product-bacon-jam', - quantity: 2, - sku: 'sku-1', - typeOfProduct: 'Food', - url: 'https://www.example.com/product/bacon-jam', - value: 6, - variant: 'Extra topped', - }, - { - brand: 'Levis', - category: 'Merch', - currency: 'GBP', - image_url: 'https://www.example.com/product/t-shirt.jpg', - name: 'T-Shirt', - position: 2, - price: 12.99, - product_id: 'product-t-shirt', - quantity: 1, - sku: 'sku-2', - typeOfProduct: 'Shirt', - url: 'https://www.example.com/product/t-shirt', - value: 12.99, - variant: 'White', - }, - { - brand: 'Levis', - category: 'Merch', - coupon: 'APPARELSALE', - currency: 'GBP', - image_url: 'https://www.example.com/product/offer-t-shirt.jpg', - name: 'T-Shirt-on-offer', - position: 1, - price: 12.99, - product_id: 'offer-t-shirt', - quantity: 1, - sku: 'sku-3', - typeOfProduct: 'Shirt', - url: 'https://www.example.com/product/offer-t-shirt', - value: 12.99, - variant: 'Black', - }, - ], - revenue: 31.98, - shipping: 4, - value: 31.98, - }, - receivedAt: '2020-10-16T13:40:12.792+05:30', - request_ip: '[::1]', - sentAt: '2020-10-16T08:10:12.783Z', - type: 'track', - userId: 'rudder123', - }, - metadata: { jobId: 1, userId: 'u1' }, - destination: { - Config: { apiKey: 'dummyApiKey', stream: 'default' }, - Enabled: true, - Transformations: [], - IsProcessorEnabled: true, - }, - }, - { - message: { - anonymousId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.1.6', - }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.1.6' }, - locale: 'en-GB', - os: { name: '', version: '' }, - page: { - path: '/testing/script-test.html', - referrer: '', - search: '', - title: '', - url: 'http://localhost:3243/testing/script-test.html', - }, - screen: { density: 2 }, - traits: { - company: { id: 'abc123' }, - createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', - email: 'rudderTest@gmail.com', - name: 'Rudder Test', - plan: 'Enterprise', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36', - }, - integrations: { All: true }, - messageId: 'e108eb05-f6cd-4624-ba8c-568f2e2b3f92', - originalTimestamp: '2020-10-16T08:26:14.938Z', - receivedAt: '2020-10-16T13:56:14.945+05:30', - request_ip: '[::1]', - sentAt: '2020-10-16T08:26:14.939Z', - timestamp: '2020-10-16T13:56:14.944+05:30', - type: 'identify', - userId: 'rudder123', - }, - metadata: { jobId: 2, userId: 'u1' }, - destination: { - Config: { apiKey: 'dummyApiKey', stream: 'default' }, - Enabled: true, - Transformations: [], - IsProcessorEnabled: true, - }, - }, - ], - destType: 'lytics', - }, - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: { - output: [ - { - batchedRequest: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://api.lytics.io/collect/json/default?access_token=dummyApiKey', - headers: { 'Content-Type': 'application/json' }, - params: {}, - body: { - JSON: { - _e: 'Order Completed', - checkout_id: 'what is checkout id here??', - coupon: 'APPARELSALE', - currency: 'GBP', - order_id: 'transactionId', - 'products[0].brand': '', - 'products[0].category': 'Merch', - 'products[0].currency': 'GBP', - 'products[0].image_url': 'https://www.example.com/product/bacon-jam.jpg', - 'products[0].name': 'Food/Drink', - 'products[0].position': 1, - 'products[0].price': 3, - 'products[0].product_id': 'product-bacon-jam', - 'products[0].quantity': 2, - 'products[0].sku': 'sku-1', - 'products[0].typeOfProduct': 'Food', - 'products[0].url': 'https://www.example.com/product/bacon-jam', - 'products[0].value': 6, - 'products[0].variant': 'Extra topped', - 'products[1].brand': 'Levis', - 'products[1].category': 'Merch', - 'products[1].currency': 'GBP', - 'products[1].image_url': 'https://www.example.com/product/t-shirt.jpg', - 'products[1].name': 'T-Shirt', - 'products[1].position': 2, - 'products[1].price': 12.99, - 'products[1].product_id': 'product-t-shirt', - 'products[1].quantity': 1, - 'products[1].sku': 'sku-2', - 'products[1].typeOfProduct': 'Shirt', - 'products[1].url': 'https://www.example.com/product/t-shirt', - 'products[1].value': 12.99, - 'products[1].variant': 'White', - 'products[2].brand': 'Levis', - 'products[2].category': 'Merch', - 'products[2].coupon': 'APPARELSALE', - 'products[2].currency': 'GBP', - 'products[2].image_url': 'https://www.example.com/product/offer-t-shirt.jpg', - 'products[2].name': 'T-Shirt-on-offer', - 'products[2].position': 1, - 'products[2].price': 12.99, - 'products[2].product_id': 'offer-t-shirt', - 'products[2].quantity': 1, - 'products[2].sku': 'sku-3', - 'products[2].typeOfProduct': 'Shirt', - 'products[2].url': 'https://www.example.com/product/offer-t-shirt', - 'products[2].value': 12.99, - 'products[2].variant': 'Black', - revenue: 31.98, - shipping: 4, - value: 31.98, - }, - XML: {}, - JSON_ARRAY: {}, - FORM: {}, - }, - files: {}, - }, - metadata: [{ jobId: 1, userId: 'u1' }], - batched: false, - statusCode: 200, - destination: { - Config: { apiKey: 'dummyApiKey', stream: 'default' }, - Enabled: true, - Transformations: [], - IsProcessorEnabled: true, - }, - }, - { - batchedRequest: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://api.lytics.io/collect/json/default?access_token=dummyApiKey', - headers: { 'Content-Type': 'application/json' }, - params: {}, - body: { - JSON: { - user_id: 'rudder123', - 'company.id': 'abc123', - createdAt: 'Thu Mar 24 2016 17:46:45 GMT+0000 (UTC)', - email: 'rudderTest@gmail.com', - name: 'Rudder Test', - plan: 'Enterprise', - }, - XML: {}, - JSON_ARRAY: {}, - FORM: {}, - }, - files: {}, - }, - metadata: [{ jobId: 2, userId: 'u1' }], - batched: false, - statusCode: 200, - destination: { - Config: { apiKey: 'dummyApiKey', stream: 'default' }, - Enabled: true, - Transformations: [], - IsProcessorEnabled: true, - }, - }, - ], - }, - }, - }, - }, -];