-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
66a5390
commit 25ceedc
Showing
8 changed files
with
2,955 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
const { getMappingConfig } = require('../../util'); | ||
const BASE_URL = 'https://api.bluecore.com/api/track/mobile/v1'; | ||
|
||
const CONFIG_CATEGORIES = { | ||
IDENTIFY: { | ||
name: 'bluecoreIdentifyConfig', | ||
type: 'identify', | ||
}, | ||
TRACK: { | ||
name: 'bluecoreTrackConfig', | ||
type: 'track', | ||
}, | ||
}; | ||
|
||
const EVENT_NAME_MAPPING = { | ||
'Product Viewed': 'viewed_product', | ||
'Product Added': 'add_to_cart', | ||
'Order Completed': 'purchase', | ||
'Products Searched': 'search', | ||
'Product Added to Wishlist': 'wishlist', | ||
'Checkout Step Viewed': 'checkout', | ||
'Product Removed': 'remove_from_cart', | ||
'Subscribe Interest': 'subscribe_interest', | ||
'Unsubscribe Interest': 'unsubscribe_interest', | ||
Identify: 'identify', | ||
}; | ||
|
||
const BLUECORE_IDENTIFY_EXCLUSION = [ | ||
'event', | ||
'phone', | ||
'phoneNumber', | ||
'phone_number', | ||
'firstName', | ||
'firstname', | ||
'first_name', | ||
'lastName', | ||
'lastname', | ||
'last_name', | ||
'gender', | ||
]; | ||
|
||
const MAPPING_CONFIG = getMappingConfig(CONFIG_CATEGORIES, __dirname); | ||
module.exports = { | ||
CONFIG_CATEGORIES, | ||
MAPPING_CONFIG, | ||
EVENT_NAME_MAPPING, | ||
BLUECORE_IDENTIFY_EXCLUSION, | ||
BASE_URL, | ||
}; |
49 changes: 49 additions & 0 deletions
49
src/v0/destinations/bluecore/data/bluecoreIdentifyConfig.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
[ | ||
{ | ||
"destKey": "properties.distinct_id", | ||
"sourceKeys": ["userId", "anonymousId", "email"], | ||
"required": true | ||
}, | ||
{ | ||
"destKey": "properties.custormer.name", | ||
"sourceKeys": "name", | ||
"required": false, | ||
"sourceFromGenericMap": true | ||
}, | ||
{ | ||
"destKey": "properties.custormer.age", | ||
"sourceKeys": "age", | ||
"required": false | ||
}, | ||
{ | ||
"destKey": "event", | ||
"sourceKeys": "event", | ||
"required": false | ||
}, | ||
{ | ||
"destKey": "properties.custormer.sex", | ||
"sourceKeys": "sex", | ||
"required": false | ||
}, | ||
{ | ||
"destKey": "properties.custormer.address", | ||
"sourceKeys": "address", | ||
"required": false | ||
}, | ||
{ | ||
"destKey": "properties.custormer.email", | ||
"sourceKeys": "email", | ||
"required": true, | ||
"sourceFromGenericMap": true | ||
}, | ||
{ | ||
"destKey": "client", | ||
"sourceKeys": "context.app.version", | ||
"required": false | ||
}, | ||
{ | ||
"destKey": "properties.device", | ||
"sourceKeys": "context.device.model", | ||
"required": false | ||
} | ||
] |
43 changes: 43 additions & 0 deletions
43
src/v0/destinations/bluecore/data/bluecoreTrackConfig.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
[ | ||
{ | ||
"destKey": "distinct_id", | ||
"sourceKeys": ["userId", "anonymousId", "email"], | ||
"required": true | ||
}, | ||
{ | ||
"destKey": "customer.name", | ||
"sourceKeys": "name", | ||
"required": false | ||
}, | ||
{ | ||
"destKey": "customer.age", | ||
"sourceKeys": "age", | ||
"required": false | ||
}, | ||
{ | ||
"destKey": "customer.sex", | ||
"sourceKeys": "sex", | ||
"required": false | ||
}, | ||
{ | ||
"destKey": "customer.address", | ||
"sourceKeys": "address", | ||
"required": false | ||
}, | ||
{ | ||
"destKey": "customer.email", | ||
"sourceKeys": "email", | ||
"required": false, | ||
"sourceFromGenericMap": true | ||
}, | ||
{ | ||
"destKey": "client", | ||
"sourceKeys": "context.app.version", | ||
"required": false | ||
}, | ||
{ | ||
"destKey": "device", | ||
"sourceKeys": "context.device.model", | ||
"required": false | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
const eventProcessor = require('./transform'); | ||
|
||
const sampleEvent = { | ||
message: { | ||
type: 'TRACK', | ||
event: 'Product Viewed', | ||
userId: '27340af5c8819', | ||
properties: { | ||
product_id: '622c6f5d5cf86a4c77358033', | ||
sku: '8472-998-0112', | ||
category: 'Games', | ||
name: 'Cones of Dunshire', | ||
brand: 'Wyatt Games', | ||
variant: 'exapansion pack', | ||
price: 49.99, | ||
quantity: 5, | ||
coupon: 'PREORDER15', | ||
currency: 'USD', | ||
position: 1, | ||
url: 'https://www.website.com/product/path', | ||
image_url: 'https://www.website.com/product/path.webp', | ||
}, | ||
}, | ||
destination: { | ||
|
||
}, | ||
}; | ||
|
||
eventProcessor.process(sampleEvent) | ||
.then(response => { | ||
console.log('Response:', response); | ||
}) | ||
.catch(error => { | ||
console.error('Error:', error); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
const { EventType } = require('../../../constants'); | ||
const { | ||
constructPayload, | ||
ErrorMessage, | ||
defaultRequestConfig, | ||
defaultPostRequestConfig, | ||
getValueFromMessage, | ||
isDefinedAndNotNull, | ||
extractCustomFields, | ||
simpleProcessRouterDest, | ||
} = require('../../util'); | ||
|
||
const { | ||
// getActionSource, | ||
// handleProduct, | ||
// handleSearch, | ||
handleProductListViewed, | ||
// handleOrder, | ||
// populateCustomDataBasedOnCategory, | ||
// getCategoryFromEvent, | ||
} = require('./utils'); | ||
|
||
const { JSON_MIME_TYPE } = require('../../util/constant'); | ||
const { | ||
TransformationError, | ||
InstrumentationError, | ||
ConfigurationError, | ||
} = require('../../util/errorTypes'); | ||
|
||
const { | ||
MAPPING_CONFIG, | ||
CONFIG_CATEGORIES, | ||
BASE_URL, | ||
EVENT_NAME_MAPPING, | ||
BLUECORE_IDENTIFY_EXCLUSION, | ||
} = require('./config'); | ||
|
||
function checkValidEventName(str) { | ||
return str.includes('.') || /\d/.test(str) || str.length > 64; | ||
} | ||
|
||
|
||
const trackResponseBuilder = async (message, category, { Config }) => { | ||
console.log('Incoming Message:', message); | ||
console.log('Destination Category:', category); | ||
console.log('Configuration:', Config); | ||
|
||
let event = getValueFromMessage(message, 'event'); | ||
if (!event) { | ||
throw new InstrumentationError('[BLUECORE] property:: event is required for track call'); | ||
} | ||
|
||
if (!Config.eventApiKey) { | ||
throw new ConfigurationError('[BLUECORE] event Api Keys required for Authentication.'); | ||
} | ||
let payload = {}; | ||
console.log('constructed Payload :', payload); | ||
|
||
if (!payload) { | ||
// fail-safety for developer error | ||
throw new TransformationError(ErrorMessage.FailedToConstructPayload); | ||
} | ||
event = event.trim(); | ||
// Check for the event type being 'Product Viewed' | ||
if (event.toLowerCase() === 'product viewed') { | ||
// Utilize handleProductListViewed function | ||
|
||
// console.log('Current Message:', message); | ||
const properties = handleProductListViewed(message, category); | ||
// Add other necessary properties to the payload | ||
properties.distinct_id = '[email protected]'; | ||
properties.token = 'bluestore'; | ||
properties.client = '4.0'; | ||
properties.device = 'mobile/iPad'; | ||
console.log(properties); | ||
|
||
payload = { event : 'viewed_product', properties : properties}; | ||
// payload.event = event.replace(/\s+/g, '_'); | ||
// payload.properties = properties; | ||
// if (checkValidEventName(payload.event)) { | ||
// throw new InstrumentationError( | ||
// "[BLUECORE] Event shouldn't contain period(.), numeric value and contains not more than 64 characters", | ||
// ); | ||
// } | ||
// payload = extractCustomFields(message, payload, ['properties'], []); | ||
|
||
for (const product of properties.products) { | ||
Check failure on line 87 in src/v0/destinations/bluecore/transform.js GitHub Actions / Code Coverage
|
||
console.log("Product Details:"); | ||
console.log(product); | ||
} | ||
|
||
// Build the response object with Bluecore payload | ||
const response = defaultRequestConfig(); | ||
response.endpoint = `${BASE_URL}`; | ||
|
||
response.method = defaultPostRequestConfig.requestMethod; | ||
const basicAuth = Buffer.from(Config.eventApiKey).toString('base64'); | ||
response.headers = { | ||
Authorization: `Basic ${basicAuth}`, | ||
'Content-Type': JSON_MIME_TYPE, | ||
}; | ||
response.body.JSON = payload; | ||
console.log('Transformed Payload:', payload); | ||
return response; | ||
|
||
} | ||
if (isDefinedAndNotNull(EVENT_NAME_MAPPING[event])) { | ||
payload.event = EVENT_NAME_MAPPING[event]; | ||
} | ||
payload.event = payload.event.replace(/\s+/g, '_'); | ||
if (checkValidEventName(payload.event)) { | ||
throw new InstrumentationError( | ||
"[BLUECORE] Event shouldn't contain period(.), numeric value and contains not more than 64 characters", | ||
); | ||
} | ||
payload = extractCustomFields(message, payload, ['properties'], []); | ||
console.log('Transformed Payload:', payload); | ||
|
||
const response = defaultRequestConfig(); | ||
response.endpoint = `${BASE_URL}`; | ||
|
||
response.method = defaultPostRequestConfig.requestMethod; | ||
const basicAuth = Buffer.from(Config.eventApiKey).toString('base64'); | ||
response.headers = { | ||
Authorization: `Basic ${basicAuth}`, | ||
'Content-Type': JSON_MIME_TYPE, | ||
}; | ||
response.body.JSON = payload; | ||
return response; | ||
}; | ||
|
||
const identifyResponseBuilder = async (message, category, { Config }) => { | ||
if (!Config.usersApiKey) { | ||
throw new ConfigurationError('[BLUECORE] User API Key required for Authentication.'); | ||
} | ||
|
||
let payload = constructPayload(message, MAPPING_CONFIG[category.name]); | ||
let event = getValueFromMessage(message, 'event'); | ||
console.log('Payload after constructPayload:', payload); | ||
console.log('Payload properties after constructPayload:', payload.properties); | ||
|
||
if (!payload) { | ||
// fail-safety for developer error | ||
throw new TransformationError(ErrorMessage.FailedToConstructPayload); | ||
} | ||
|
||
payload = extractCustomFields( | ||
message, | ||
payload, | ||
['traits', 'context.traits'], | ||
BLUECORE_IDENTIFY_EXCLUSION, | ||
); | ||
|
||
console.log('Payload after extractCustomFields:', payload); | ||
console.log('Properties after extractCustomFields:', payload.properties); | ||
|
||
|
||
const response = defaultRequestConfig(); | ||
response.endpoint = `${BASE_URL}`; | ||
response.method = defaultPostRequestConfig.requestMethod; | ||
|
||
const basicAuth = Buffer.from(Config.usersApiKey).toString('base64'); | ||
response.headers = { | ||
Authorization: `Basic ${basicAuth}`, | ||
'Content-Type': JSON_MIME_TYPE, | ||
}; | ||
response.body.JSON = payload; | ||
// response.body.JSON.event = event; | ||
|
||
console.log('Final Response before returning:', response); | ||
|
||
return response; | ||
}; | ||
|
||
|
||
const process = async (event) => { | ||
const { message, destination } = event; | ||
console.log('Incoming Event:', event); | ||
console.log('Incoming Destination:', destination); | ||
|
||
if (!message.type) { | ||
throw new InstrumentationError('Message Type is not present. Aborting message.'); | ||
} | ||
|
||
const messageType = message.type.toLowerCase(); | ||
const category = CONFIG_CATEGORIES[message.type.toUpperCase()]; | ||
console.log('Category :', category); | ||
let response; | ||
switch (messageType) { | ||
case EventType.TRACK: | ||
response = await trackResponseBuilder(message, category, destination); | ||
break; | ||
case EventType.IDENTIFY: | ||
response = await identifyResponseBuilder(message, category, destination); | ||
break; | ||
default: | ||
throw new InstrumentationError(`Message type ${messageType} not supported`); | ||
} | ||
// Log the final response before returning it | ||
console.log('Final Response:', response); | ||
|
||
return response; | ||
}; | ||
|
||
const processRouterDest = async (inputs, reqMetadata) => { | ||
const respList = await simpleProcessRouterDest(inputs, process, reqMetadata); | ||
return respList; | ||
}; | ||
|
||
module.exports = { process, processRouterDest }; |
Oops, something went wrong.