Skip to content

Commit

Permalink
Merge branch 'develop' into fb_content_type_fix
Browse files Browse the repository at this point in the history
  • Loading branch information
sandeepdsvs authored Feb 28, 2024
2 parents 060b54c + d619c97 commit 74d7d4b
Show file tree
Hide file tree
Showing 13 changed files with 745 additions and 11 deletions.
1 change: 0 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ See the project's [README](README.md) for further information about working in t
- Include instructions on how to test your changes.
3. Your branch may be merged once all configured checks pass, including:
- A review from appropriate maintainers
4. Along with the PR in transformer raise a PR against [config-generator][config-generator] with the configurations.

## Committing

Expand Down
2 changes: 1 addition & 1 deletion src/cdk/v2/destinations/algolia/procWorkflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ steps:
const filters = $.context.payload.filters;
const objectIDs = $.context.payload.objectIDs;
$.assert(!(filters && objectIDs), "event can't have both objectIds and filters at the same time.");
$.assert(filters || objectIDs, "Either filters or objectIds is required.");
$.assert(filters.length || objectIDs.length, "Either filters or objectIds is required and must be non empty.");
- name: validatePayloadForClickEvent
condition: $.context.payload.eventType === "click"
Expand Down
8 changes: 4 additions & 4 deletions src/v0/destinations/gainsight_px/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ const { getDynamicErrorType } = require('../../../adapters/utils/networkUtils');
const { JSON_MIME_TYPE } = require('../../util/constant');

const handleErrorResponse = (error, customErrMessage, expectedErrStatus, defaultStatus = 400) => {
let destResp;
let errMessage = '';
let errorStatus = defaultStatus;

if (error.response && error.response.data) {
errMessage = error.response.data.externalapierror
? JSON.stringify(error.response.data.externalapierror)
: JSON.stringify(error.response.data);
destResp = error.response?.data?.externalapierror ?? error.response?.data;
errMessage = JSON.stringify(destResp);

errorStatus = error.response.status;

Expand All @@ -26,7 +26,7 @@ const handleErrorResponse = (error, customErrMessage, expectedErrStatus, default
{
[tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(errorStatus),
},
error,
destResp,
);
};

Expand Down
5 changes: 4 additions & 1 deletion src/v0/destinations/hs/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const {
getHashFromArray,
getDestinationExternalIDInfoForRetl,
getValueFromMessage,
isNull,
} = require('../../util');
const {
CONTACT_PROPERTY_MAP_ENDPOINT,
Expand Down Expand Up @@ -223,7 +224,9 @@ const getTransformedJSON = async (message, destination, propertyMap) => {
// lowercase and replace ' ' & '.' with '_'
const hsSupportedKey = formatKey(traitsKey);
if (!rawPayload[traitsKey] && propertyMap[hsSupportedKey]) {
let propValue = traits[traitsKey];
// HS accepts empty string to remove the property from contact
// https://community.hubspot.com/t5/APIs-Integrations/Clearing-values-of-custom-properties-in-Hubspot-contact-using/m-p/409156
let propValue = isNull(traits[traitsKey]) ? '' : traits[traitsKey];
if (propertyMap[hsSupportedKey] === 'date') {
propValue = getUTCMidnightTimeStampValue(propValue);
}
Expand Down
1 change: 1 addition & 0 deletions src/v0/destinations/sfmc/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const ENDPOINTS = {
GET_TOKEN: `auth.marketingcloudapis.com/v2/token`,
CONTACTS: `rest.marketingcloudapis.com/contacts/v1/contacts`,
INSERT_CONTACTS: `rest.marketingcloudapis.com/hub/v1/dataevents/key:`,
EVENT: 'rest.marketingcloudapis.com/interaction/v1/events',
};

const CONFIG_CATEGORIES = {
Expand Down
35 changes: 33 additions & 2 deletions src/v0/destinations/sfmc/transform.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-param-reassign */
/* eslint-disable no-nested-ternary */
const {
NetworkError,
Expand Down Expand Up @@ -188,6 +189,26 @@ const responseBuilderForInsertData = (
return response;
};

// DOC : https://developer.salesforce.com/docs/marketing/marketing-cloud/references/mc_rest_interaction/postEvent.html

const responseBuilderForMessageEvent = (message, subDomain, authToken, hashMapEventDefinition) => {
const contactKey = message.properties.contactId;
delete message.properties.contactId;
const response = defaultRequestConfig();
response.method = defaultPostRequestConfig.requestMethod;
response.endpoint = `https://${subDomain}.${ENDPOINTS.EVENT}`;
response.headers = {
'Content-Type': JSON_MIME_TYPE,
Authorization: `Bearer ${authToken}`,
};
response.body.JSON = {
ContactKey: contactKey,
EventDefinitionKey: hashMapEventDefinition[message.event.toLowerCase()],
Data: { ...message.properties },
};
return response;
};

const responseBuilderSimple = async (message, category, destination) => {
const {
clientId,
Expand All @@ -198,6 +219,7 @@ const responseBuilderSimple = async (message, category, destination) => {
eventToExternalKey,
eventToPrimaryKey,
eventToUUID,
eventToDefinitionMapping,
} = destination.Config;
// map from an event name to an external key of a data extension.
const hashMapExternalKey = getHashFromArray(eventToExternalKey, 'from', 'to');
Expand All @@ -207,6 +229,8 @@ const responseBuilderSimple = async (message, category, destination) => {
const hashMapUUID = getHashFromArray(eventToUUID, 'event', 'uuid');
// token needed for authorization for subsequent calls
const authToken = await getToken(clientId, clientSecret, subDomain);
// map from an event name to an event definition key.
const hashMapEventDefinition = getHashFromArray(eventToDefinitionMapping, 'from', 'to');
// if createOrUpdateContacts is true identify calls for create and update of contacts will not occur.
if (category.type === 'identify' && !createOrUpdateContacts) {
// first call to identify the contact
Expand Down Expand Up @@ -240,10 +264,12 @@ const responseBuilderSimple = async (message, category, destination) => {
if (typeof message.event !== 'string') {
throw new ConfigurationError('Event name must be a string');
}
if (hashMapEventDefinition[message.event.toLowerCase()]) {
return responseBuilderForMessageEvent(message, subDomain, authToken, hashMapEventDefinition);
}
if (!isDefinedAndNotNull(hashMapExternalKey[message.event.toLowerCase()])) {
throw new ConfigurationError('Event not mapped for this track call');
}

return responseBuilderForInsertData(
message,
hashMapExternalKey[message.event.toLowerCase()],
Expand Down Expand Up @@ -293,4 +319,9 @@ const processRouterDest = async (inputs, reqMetadata) => {
return respList;
};

module.exports = { process, processRouterDest, responseBuilderSimple };
module.exports = {
process,
processRouterDest,
responseBuilderSimple,
responseBuilderForMessageEvent,
};
42 changes: 41 additions & 1 deletion src/v0/destinations/sfmc/transform.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { ConfigurationError } = require('@rudderstack/integrations-lib');
const axios = require('axios');
const MockAxiosAdapter = require('axios-mock-adapter');
const { responseBuilderSimple } = require('./transform');
const { responseBuilderSimple, responseBuilderForMessageEvent } = require('./transform');
beforeAll(() => {
const mock = new MockAxiosAdapter(axios);
mock
Expand Down Expand Up @@ -122,4 +122,44 @@ describe('responseBuilderSimple', () => {
expect(response).toHaveProperty('body.JSON');
expect(response).toHaveProperty('headers');
});

it('should build response object with correct details for message event', () => {
const message = {
userId: 'u123',
event: 'testEvent',
properties: {
contactId: '12345',
prop1: 'value1',
prop2: 'value2',
},
};
const subDomain = 'subdomain';
const authToken = 'token';
const hashMapEventDefinition = {
testevent: 'eventDefinitionKey',
};

const response = responseBuilderForMessageEvent(
message,
subDomain,
authToken,
hashMapEventDefinition,
);
expect(response.method).toBe('POST');
expect(response.endpoint).toBe(
'https://subdomain.rest.marketingcloudapis.com/interaction/v1/events',
);
expect(response.headers).toEqual({
'Content-Type': 'application/json',
Authorization: 'Bearer token',
});
expect(response.body.JSON).toEqual({
ContactKey: '12345',
EventDefinitionKey: 'eventDefinitionKey',
Data: {
prop1: 'value1',
prop2: 'value2',
},
});
});
});
2 changes: 2 additions & 0 deletions src/v0/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const removeUndefinedAndNullAndEmptyValues = (obj) =>
lodash.pickBy(obj, isDefinedAndNotNullAndNotEmpty);
const isBlank = (value) => lodash.isEmpty(lodash.toString(value));
const flattenMap = (collection) => lodash.flatMap(collection, (x) => x);
const isNull = (x) => lodash.isNull(x);
// ========================================================================
// GENERIC UTLITY
// ========================================================================
Expand Down Expand Up @@ -2266,6 +2267,7 @@ module.exports = {
isDefinedAndNotNullAndNotEmpty,
isEmpty,
isNotEmpty,
isNull,
isEmptyObject,
isHttpStatusRetryable,
isHttpStatusSuccess,
Expand Down
Loading

0 comments on commit 74d7d4b

Please sign in to comment.