diff --git a/src/v1/sources/cordial/config.js b/src/v1/sources/cordial/config.js new file mode 100644 index 0000000000..764c734870 --- /dev/null +++ b/src/v1/sources/cordial/config.js @@ -0,0 +1,6 @@ +const eventsMapping = { + crdl_app_install: 'Application Installed', + crdl_app_open: 'Application Opened', +}; + +module.exports = { eventsMapping }; diff --git a/src/v1/sources/cordial/mapping.json b/src/v1/sources/cordial/mapping.json new file mode 100644 index 0000000000..1ce066e07c --- /dev/null +++ b/src/v1/sources/cordial/mapping.json @@ -0,0 +1,22 @@ +[ + { + "sourceKeys": "event._id", + "destKeys": "properties.event_id" + }, + { + "sourceKeys": "contact._id", + "destKeys": ["context.traits.userId", "userId"] + }, + { + "sourceKeys": ["event.ts", "event.ats"], + "destKeys": ["timestamp", "sentAt", "originalTimestamp"] + }, + { + "sourceKeys": "event.d", + "destKeys": "context.device" + }, + { + "sourceKeys": "contact.channels.email.address", + "destKeys": ["context.traits.email"] + } +] diff --git a/src/v1/sources/cordial/transform.js b/src/v1/sources/cordial/transform.js new file mode 100644 index 0000000000..5548efee70 --- /dev/null +++ b/src/v1/sources/cordial/transform.js @@ -0,0 +1,51 @@ +const Message = require('../../../v0/sources/message'); +const { CommonUtils } = require('../../../util/common'); +const { generateUUID, isDefinedAndNotNull } = require('../../../v0/util'); +const { eventsMapping } = require('./config'); + +const mapping = require('./mapping.json'); + +const processEvent = (inputPaylaod) => { + const message = new Message(`Cordial`); + let eventName = inputPaylaod.event?.a || inputPaylaod.event?.action; + if (eventName in eventsMapping) { + eventName = eventsMapping[eventName]; + } + message.setEventType('track'); + message.setEventName(eventName); + message.setPropertiesV2(inputPaylaod, mapping); + + const externalId = []; + // setting up cordial contact_id to externalId + if (inputPaylaod.contact.cID) { + externalId.push({ + type: 'cordialContactId', + id: inputPaylaod.contact.cID, + }); + } + message.context.externalId = externalId; + + if (!isDefinedAndNotNull(message.userId)) { + message.anonymousId = generateUUID(); + } + // Due to multiple mappings to the same destination path object some are not showing up due to which we are doing the following + message.context.traits = { ...message.context.traits, ...inputPaylaod.contact }; + message.properties = { + ...message.properties, + ...inputPaylaod.event.properties, + ...inputPaylaod.event, + }; + delete message.properties.properties; + delete message.properties.d; + // eslint-disable-next-line no-underscore-dangle + delete message.properties._id; + return message; +}; + +const process = (inputEvent) => { + const { event: events } = inputEvent; + const eventsArray = CommonUtils.toArray(events); + return eventsArray.map(processEvent); +}; + +exports.process = process; diff --git a/test/integrations/sources/cordial/data.ts b/test/integrations/sources/cordial/data.ts new file mode 100644 index 0000000000..acb02e9fbf --- /dev/null +++ b/test/integrations/sources/cordial/data.ts @@ -0,0 +1,628 @@ +import utils from '../../../../src/v0/util'; + +const defaultMockFns = () => { + jest.spyOn(utils, 'generateUUID').mockReturnValue('97fcd7b2-cc24-47d7-b776-057b7b199513'); +}; + +export const data = [ + { + name: 'cordial', + description: 'Simple Single object Input event with normal channel and action', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + contact: { + _id: '6690fe3655e334xx028xxx', + channels: { + email: { + address: 'jondoe@example.com', + subscribeStatus: 'subscribed', + subscribedAt: '2024-07-12T09:58:14+0000', + }, + }, + createdAt: '2024-07-12T09:58:14+0000', + address: { + city: 'San Miego', + }, + first_name: 'John', + last_name: 'Doe', + lastUpdateSource: 'api', + lastModified: '2024-07-12T13:00:49+0000', + cID: '6690fe3655e334xx028xxx', + }, + event: { + _id: '669141857b8cxxx1ba0da2xx', + cID: '6690fe3655e334xx028xxx', + ts: '2024-07-12T14:45:25+00:00', + ats: '2024-07-12T14:45:25+0000', + a: 'browse', + tzo: -7, + rl: 'a', + UID: '4934ee07118197xx3f74d5xxxx7b0076', + time: '2024-07-12T14:45:25+0000', + action: 'browse', + bmID: '', + first: 0, + properties: { + category: 'Shirts', + url: 'http://example.com/shirts', + description: 'A really cool khaki shirt.', + price: 9.99, + title: 'Khaki Shirt', + test_key: 'value', + }, + }, + }, + source: {}, + }, + ], + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + name: 'unknown', + version: 'unknown', + }, + integration: { + name: 'Cordial', + }, + traits: { + userId: '6690fe3655e334xx028xxx', + email: 'jondoe@example.com', + _id: '6690fe3655e334xx028xxx', + channels: { + email: { + address: 'jondoe@example.com', + subscribeStatus: 'subscribed', + subscribedAt: '2024-07-12T09:58:14+0000', + }, + }, + createdAt: '2024-07-12T09:58:14+0000', + address: { + city: 'San Miego', + }, + first_name: 'John', + last_name: 'Doe', + lastUpdateSource: 'api', + lastModified: '2024-07-12T13:00:49+0000', + cID: '6690fe3655e334xx028xxx', + }, + externalId: [{ id: '6690fe3655e334xx028xxx', type: 'cordialContactId' }], + }, + integrations: { + Cordial: false, + }, + type: 'track', + event: 'browse', + originalTimestamp: '2024-07-12T14:45:25+00:00', + properties: { + event_id: '669141857b8cxxx1ba0da2xx', + category: 'Shirts', + url: 'http://example.com/shirts', + description: 'A really cool khaki shirt.', + price: 9.99, + title: 'Khaki Shirt', + test_key: 'value', + cID: '6690fe3655e334xx028xxx', + ts: '2024-07-12T14:45:25+00:00', + ats: '2024-07-12T14:45:25+0000', + a: 'browse', + tzo: -7, + rl: 'a', + UID: '4934ee07118197xx3f74d5xxxx7b0076', + time: '2024-07-12T14:45:25+0000', + action: 'browse', + bmID: '', + first: 0, + }, + userId: '6690fe3655e334xx028xxx', + timestamp: '2024-07-12T14:45:25+00:00', + sentAt: '2024-07-12T14:45:25+00:00', + }, + ], + }, + }, + ], + }, + }, + mockFns: () => { + defaultMockFns(); + }, + }, + { + name: 'cordial', + description: 'Multiple object Input event with batched payload', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: [ + { + contact: { + _id: '633b2fd70a12be027e0b0xxx', + lang_locale: 'EN-US', + channels: { + email: { + address: 'johndoe@example.com', + subscribeStatus: 'none', + }, + }, + createdAt: '2022-10-03T18:54:15+0000', + email_sha256_hash: + 'f959bdf883831ebb96612eb9xxxx1e0c9481780adf5f70xxx862155531bf61df', + first_name: 'john', + last_name: 'doe', + lastUpdateSource: 'cordial', + lastModified: '2024-07-24T07:52:46+0000', + cID: '633b2fd70a12be027e0b0xxx', + }, + event: { + _id: '66a0b2ce5344b55fxxxc5a64', + cID: '633b2fd70a12be027e0b0xxx', + ts: '2024-07-24T07:52:46+00:00', + ats: '2024-07-24T07:52:39+0000', + g: { + countryISO: 'PL', + country: 'Poland', + state: 'MZ', + city: 'Warszawa', + postalCode: '00-686', + geoLoc: { + lat: 52.22744369506836, + lon: 21.009017944335938, + }, + tz: 'Europe/Warsaw', + }, + d: { + type: 'computer', + device: 'Macintosh', + platform: 'OS X', + browser: 'Chrome', + robot: false, + }, + a: 'browse', + UID: '471af949fffe749c2ebfxxx950ea73c', + sp: { + bid: 'cf6de7f1-cce5-40xx-ac9c-7c82a2xxc09e', + }, + tzo: -7, + rl: '6', + time: '2024-07-24T07:52:39+0000', + action: 'browse', + bmID: '', + first: 0, + properties: { + url: 'https://aaff-008.dx.commercecloud.salesforce.com/s/UGG-US/cart', + product_item_group_id: ['1094269'], + product_category: ['allproducts'], + product_name: ['wtp ab'], + product_group: ['women'], + }, + }, + }, + { + contact: { + _id: '633b2fd12312be027e0b0xxx', + lang_locale: 'EN-US', + channels: { + email: { + address: 'johndoe1@example.com', + subscribeStatus: 'none', + }, + }, + createdAt: '2022-10-03T18:54:15+0000', + email_sha256_hash: + 'f95912b883831eab11612eb9xxxx1e0c9481780ad45770xxx862155531bf61df', + first_name: 'john', + last_name: 'doe', + lastUpdateSource: 'cordial', + lastModified: '2024-07-24T07:52:46+0000', + cID: '633b2fd12312be027e0b0xxx', + }, + event: { + _id: '66aku0b2ce527b55fx1xc5a64', + cID: '633b2fd12312be027e0b0xxx', + ts: '2024-07-24T07:52:46+00:00', + ats: '2024-07-24T07:52:39+0000', + g: { + countryISO: 'PL', + country: 'Poland', + state: 'MZ', + city: 'Warszawa', + postalCode: '00-686', + geoLoc: { + lat: 52.22744369506836, + lon: 21.009017944335938, + }, + tz: 'Europe/Warsaw', + }, + d: { + type: 'computer', + device: 'Macintosh', + platform: 'OS X', + browser: 'Chrome', + robot: false, + }, + a: 'browse', + UID: '471af949fffe74sdh382ebfxxx950ea73c', + sp: { + bid: 'cf6de7f1-123ce5-20xx-ac9c-7c82a2xxc09e', + }, + tzo: -7, + rl: '6', + time: '2024-07-24T07:52:39+0000', + action: 'browse', + bmID: '', + first: 0, + properties: { + url: 'https://aaff-008.dx.commercecloud.salesforce.com/s/UGG-US/cart', + product_item_group_id: ['1094269'], + product_category: ['allproducts'], + product_name: ['wtp ab'], + product_group: ['women'], + }, + }, + }, + ], + source: {}, + }, + ], + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + name: 'unknown', + version: 'unknown', + }, + integration: { + name: 'Cordial', + }, + traits: { + userId: '633b2fd70a12be027e0b0xxx', + email: 'johndoe@example.com', + _id: '633b2fd70a12be027e0b0xxx', + lang_locale: 'EN-US', + channels: { + email: { + address: 'johndoe@example.com', + subscribeStatus: 'none', + }, + }, + createdAt: '2022-10-03T18:54:15+0000', + email_sha256_hash: + 'f959bdf883831ebb96612eb9xxxx1e0c9481780adf5f70xxx862155531bf61df', + first_name: 'john', + last_name: 'doe', + lastUpdateSource: 'cordial', + lastModified: '2024-07-24T07:52:46+0000', + cID: '633b2fd70a12be027e0b0xxx', + }, + device: { + type: 'computer', + device: 'Macintosh', + platform: 'OS X', + browser: 'Chrome', + robot: false, + }, + externalId: [{ id: '633b2fd70a12be027e0b0xxx', type: 'cordialContactId' }], + }, + integrations: { + Cordial: false, + }, + type: 'track', + event: 'browse', + properties: { + event_id: '66a0b2ce5344b55fxxxc5a64', + url: 'https://aaff-008.dx.commercecloud.salesforce.com/s/UGG-US/cart', + product_item_group_id: ['1094269'], + product_category: ['allproducts'], + product_name: ['wtp ab'], + product_group: ['women'], + cID: '633b2fd70a12be027e0b0xxx', + ts: '2024-07-24T07:52:46+00:00', + ats: '2024-07-24T07:52:39+0000', + g: { + countryISO: 'PL', + country: 'Poland', + state: 'MZ', + city: 'Warszawa', + postalCode: '00-686', + geoLoc: { + lat: 52.22744369506836, + lon: 21.009017944335938, + }, + tz: 'Europe/Warsaw', + }, + a: 'browse', + UID: '471af949fffe749c2ebfxxx950ea73c', + sp: { + bid: 'cf6de7f1-cce5-40xx-ac9c-7c82a2xxc09e', + }, + tzo: -7, + rl: '6', + time: '2024-07-24T07:52:39+0000', + action: 'browse', + bmID: '', + first: 0, + }, + userId: '633b2fd70a12be027e0b0xxx', + timestamp: '2024-07-24T07:52:46+00:00', + sentAt: '2024-07-24T07:52:46+00:00', + originalTimestamp: '2024-07-24T07:52:46+00:00', + }, + { + context: { + library: { + name: 'unknown', + version: 'unknown', + }, + integration: { + name: 'Cordial', + }, + traits: { + userId: '633b2fd12312be027e0b0xxx', + email: 'johndoe1@example.com', + _id: '633b2fd12312be027e0b0xxx', + lang_locale: 'EN-US', + channels: { + email: { + address: 'johndoe1@example.com', + subscribeStatus: 'none', + }, + }, + createdAt: '2022-10-03T18:54:15+0000', + email_sha256_hash: + 'f95912b883831eab11612eb9xxxx1e0c9481780ad45770xxx862155531bf61df', + first_name: 'john', + last_name: 'doe', + lastUpdateSource: 'cordial', + lastModified: '2024-07-24T07:52:46+0000', + cID: '633b2fd12312be027e0b0xxx', + }, + device: { + type: 'computer', + device: 'Macintosh', + platform: 'OS X', + browser: 'Chrome', + robot: false, + }, + externalId: [{ id: '633b2fd12312be027e0b0xxx', type: 'cordialContactId' }], + }, + integrations: { + Cordial: false, + }, + type: 'track', + event: 'browse', + properties: { + event_id: '66aku0b2ce527b55fx1xc5a64', + url: 'https://aaff-008.dx.commercecloud.salesforce.com/s/UGG-US/cart', + product_item_group_id: ['1094269'], + product_category: ['allproducts'], + product_name: ['wtp ab'], + product_group: ['women'], + cID: '633b2fd12312be027e0b0xxx', + ts: '2024-07-24T07:52:46+00:00', + ats: '2024-07-24T07:52:39+0000', + g: { + countryISO: 'PL', + country: 'Poland', + state: 'MZ', + city: 'Warszawa', + postalCode: '00-686', + geoLoc: { + lat: 52.22744369506836, + lon: 21.009017944335938, + }, + tz: 'Europe/Warsaw', + }, + a: 'browse', + UID: '471af949fffe74sdh382ebfxxx950ea73c', + sp: { + bid: 'cf6de7f1-123ce5-20xx-ac9c-7c82a2xxc09e', + }, + tzo: -7, + rl: '6', + time: '2024-07-24T07:52:39+0000', + action: 'browse', + bmID: '', + first: 0, + }, + userId: '633b2fd12312be027e0b0xxx', + timestamp: '2024-07-24T07:52:46+00:00', + sentAt: '2024-07-24T07:52:46+00:00', + originalTimestamp: '2024-07-24T07:52:46+00:00', + }, + ], + }, + }, + ], + }, + }, + mockFns: () => { + defaultMockFns(); + }, + }, + { + name: 'cordial', + description: 'Simple Single object Input event with no CId', + module: 'source', + version: 'v1', + input: { + request: { + body: [ + { + event: { + contact: { + _id: '6690fe3655e334xx028xx1', + channels: { + email: { + address: 'jondoe@example.com', + subscribeStatus: 'subscribed', + subscribedAt: '2024-07-12T09:58:14+0000', + }, + }, + createdAt: '2024-07-12T09:58:14+0000', + address: { + city: 'San Miego', + }, + first_name: 'John', + last_name: 'Doe', + lastUpdateSource: 'api', + lastModified: '2024-07-12T13:00:49+0000', + }, + event: { + _id: '669141857b8cxxx1ba0da2x1', + ts: '2024-07-12T14:45:25+00:00', + ats: '2024-07-12T14:45:25+0000', + d: { + type: 'computer', + device: false, + platform: false, + browser: false, + robot: true, + }, + a: 'browse', + tzo: -7, + rl: 'a', + UID: '4934ee07197xx3f74d5xxxx7b0076', + time: '2024-07-12T14:45:25+0000', + action: 'browse', + bmID: '', + first: 0, + properties: { + category: 'Shirts', + url: 'http://example.com/shirts', + description: 'A really cool khaki shirt.', + price: 9.99, + title: 'Khaki Shirt', + test_key: 'value', + }, + }, + }, + source: {}, + }, + ], + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, + pathSuffix: '', + }, + output: { + response: { + status: 200, + body: [ + { + output: { + batch: [ + { + context: { + library: { + name: 'unknown', + version: 'unknown', + }, + integration: { + name: 'Cordial', + }, + traits: { + userId: '6690fe3655e334xx028xx1', + email: 'jondoe@example.com', + _id: '6690fe3655e334xx028xx1', + channels: { + email: { + address: 'jondoe@example.com', + subscribeStatus: 'subscribed', + subscribedAt: '2024-07-12T09:58:14+0000', + }, + }, + createdAt: '2024-07-12T09:58:14+0000', + address: { + city: 'San Miego', + }, + first_name: 'John', + last_name: 'Doe', + lastUpdateSource: 'api', + lastModified: '2024-07-12T13:00:49+0000', + }, + device: { + type: 'computer', + device: false, + platform: false, + browser: false, + robot: true, + }, + externalId: [], + }, + integrations: { + Cordial: false, + }, + type: 'track', + event: 'browse', + originalTimestamp: '2024-07-12T14:45:25+00:00', + properties: { + event_id: '669141857b8cxxx1ba0da2x1', + category: 'Shirts', + url: 'http://example.com/shirts', + description: 'A really cool khaki shirt.', + price: 9.99, + title: 'Khaki Shirt', + test_key: 'value', + ts: '2024-07-12T14:45:25+00:00', + ats: '2024-07-12T14:45:25+0000', + a: 'browse', + tzo: -7, + rl: 'a', + UID: '4934ee07197xx3f74d5xxxx7b0076', + time: '2024-07-12T14:45:25+0000', + action: 'browse', + bmID: '', + first: 0, + }, + userId: '6690fe3655e334xx028xx1', + timestamp: '2024-07-12T14:45:25+00:00', + sentAt: '2024-07-12T14:45:25+00:00', + }, + ], + }, + }, + ], + }, + }, + mockFns: () => { + defaultMockFns(); + }, + }, +];