Skip to content

Commit

Permalink
feat(GARL): support vdm next for GARL (#3835)
Browse files Browse the repository at this point in the history
* feat(GARL): support vdm next for GARL

* feat(GARL): support vdm next for GARL

* feat(GARL): support vdm next for GARL

* chore: updated tests with new structure
  • Loading branch information
sandeepdsvs authored Nov 7, 2024
1 parent 2c22ba7 commit f4b38eb
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ const {
constructPayload,
returnArrayOfSubarrays,
getSuccessRespEvents,
isEventSentByVDMV1Flow,
isEventSentByVDMV2Flow,
} = require('../../util');
const { populateConsentFromConfig } = require('../../util/googleUtils');
const { populateIdentifiers, responseBuilder } = require('./util');
const { populateIdentifiers, responseBuilder, getOperationAudienceId } = require('./util');
const { getErrorResponse, createFinalResponse } = require('../../util/recordUtils');
const { offlineDataJobsMapping, consentConfigMap } = require('./config');

Expand All @@ -19,6 +21,9 @@ const processRecordEventArray = (
destination,
accessToken,
developerToken,
audienceId,
typeOfList,
isHashRequired,
operationType,
) => {
let outputPayloads = {};
Expand All @@ -31,7 +36,12 @@ const processRecordEventArray = (
metadata.push(record.metadata);
});

const userIdentifiersList = populateIdentifiers(fieldsArray, destination);
const userIdentifiersList = populateIdentifiers(
fieldsArray,
destination,
typeOfList,
isHashRequired,
);

const outputPayload = constructPayload(message, offlineDataJobsMapping);
outputPayload.operations = [];
Expand Down Expand Up @@ -68,7 +78,7 @@ const processRecordEventArray = (
Object.values(outputPayloads).forEach((data) => {
const consentObj = populateConsentFromConfig(destination.Config, consentConfigMap);
toSendEvents.push(
responseBuilder(accessToken, developerToken, data, destination, message, consentObj),
responseBuilder(accessToken, developerToken, data, destination, audienceId, consentObj),
);
});

Expand All @@ -77,12 +87,13 @@ const processRecordEventArray = (
return successResponse;
};

async function processRecordInputs(groupedRecordInputs) {
const { destination, message, metadata } = groupedRecordInputs[0];
function preparepayload(events, config) {
const { destination, message, metadata } = events[0];
const accessToken = getAccessToken(metadata, 'access_token');
const developerToken = getValueFromMessage(metadata, 'secret.developer_token');
const { audienceId, typeOfList, isHashRequired } = config;

const groupedRecordsByAction = lodash.groupBy(groupedRecordInputs, (record) =>
const groupedRecordsByAction = lodash.groupBy(events, (record) =>
record.message.action?.toLowerCase(),
);

Expand All @@ -97,6 +108,9 @@ async function processRecordInputs(groupedRecordInputs) {
destination,
accessToken,
developerToken,
audienceId,
typeOfList,
isHashRequired,
'remove',
);
}
Expand All @@ -108,6 +122,9 @@ async function processRecordInputs(groupedRecordInputs) {
destination,
accessToken,
developerToken,
audienceId,
typeOfList,
isHashRequired,
'add',
);
}
Expand All @@ -119,6 +136,9 @@ async function processRecordInputs(groupedRecordInputs) {
destination,
accessToken,
developerToken,
audienceId,
typeOfList,
isHashRequired,
'add',
);
}
Expand All @@ -139,6 +159,45 @@ async function processRecordInputs(groupedRecordInputs) {
return finalResponse;
}

function processRecordInputsV0(groupedRecordInputs) {
const { destination, message } = groupedRecordInputs[0];
const { audienceId, typeOfList, isHashRequired } = destination.Config;

return preparepayload(groupedRecordInputs, {
audienceId: getOperationAudienceId(audienceId, message),
typeOfList,
isHashRequired,
});
}

function processRecordInputsV1(groupedRecordInputs) {
const { connection } = groupedRecordInputs[0];
const { audienceId, typeOfList, isHashRequired } = connection.config.destination;

const events = groupedRecordInputs.map((record) => ({
...record,
message: {
...record.message,
fields: record.message.identifiers,
},
}));

return preparepayload(events, {
audienceId,
typeOfList,
isHashRequired,
});
}

function processRecordInputs(groupedRecordInputs) {
const event = groupedRecordInputs[0];
// First check for rETL flow and second check for ES flow
if (isEventSentByVDMV1Flow(event) || !isEventSentByVDMV2Flow(event)) {
return processRecordInputsV0(groupedRecordInputs);
}
return processRecordInputsV1(groupedRecordInputs);
}

module.exports = {
processRecordInputs,
};
20 changes: 17 additions & 3 deletions src/v0/destinations/google_adwords_remarketing_lists/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const {
const { populateConsentFromConfig } = require('../../util/googleUtils');
const { offlineDataJobsMapping, consentConfigMap } = require('./config');
const { processRecordInputs } = require('./recordTransform');
const { populateIdentifiers, responseBuilder } = require('./util');
const { populateIdentifiers, responseBuilder, getOperationAudienceId } = require('./util');

function extraKeysPresent(dictionary, keyList) {
// eslint-disable-next-line no-restricted-syntax
Expand All @@ -37,12 +37,18 @@ function extraKeysPresent(dictionary, keyList) {
const createPayload = (message, destination) => {
const { listData } = message.properties;
const properties = ['add', 'remove'];
const { typeOfList, isHashRequired } = destination.Config;

let outputPayloads = {};
const typeOfOperation = Object.keys(listData);
typeOfOperation.forEach((key) => {
if (properties.includes(key)) {
const userIdentifiersList = populateIdentifiers(listData[key], destination);
const userIdentifiersList = populateIdentifiers(
listData[key],
destination,
typeOfList,
isHashRequired,
);
if (userIdentifiersList.length === 0) {
logger.info(
`Google_adwords_remarketing_list]:: No attributes are present in the '${key}' property.`,
Expand Down Expand Up @@ -113,8 +119,16 @@ const processEvent = async (metadata, message, destination) => {

Object.values(createdPayload).forEach((data) => {
const consentObj = populateConsentFromConfig(destination.Config, consentConfigMap);
const { audienceId } = destination.Config;
response.push(
responseBuilder(accessToken, developerToken, data, destination, message, consentObj),
responseBuilder(
accessToken,
developerToken,
data,
destination,
getOperationAudienceId(audienceId, message),
consentObj,
),
);
});
return response;
Expand Down
47 changes: 30 additions & 17 deletions src/v0/destinations/google_adwords_remarketing_lists/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,24 @@ const hashEncrypt = (object) => {
});
};

const responseBuilder = (accessToken, developerToken, body, { Config }, message, consentBlock) => {
const responseBuilder = (
accessToken,
developerToken,
body,
{ Config },
audienceId,
consentBlock,
) => {
const payload = body;
const response = defaultRequestConfig();
const filteredCustomerId = removeHyphens(Config.customerId);
response.endpoint = `${BASE_ENDPOINT}/${filteredCustomerId}/offlineUserDataJobs`;
response.body.JSON = removeUndefinedAndNullValues(payload);
let operationAudienceId = Config.audienceId || Config.listId;
const mappedToDestination = get(message, MappedToDestinationKey);
if (!operationAudienceId && mappedToDestination) {
const { objectType } = getDestinationExternalIDInfoForRetl(
message,
'GOOGLE_ADWORDS_REMARKETING_LISTS',
);
operationAudienceId = objectType;
}
if (!isDefinedAndNotNullAndNotEmpty(operationAudienceId)) {
if (!isDefinedAndNotNullAndNotEmpty(audienceId)) {
throw new ConfigurationError('List ID is a mandatory field');
}
response.params = {
listId: operationAudienceId,
listId: audienceId,
customerId: filteredCustomerId,
consent: consentBlock,
};
Expand All @@ -69,14 +67,15 @@ const responseBuilder = (accessToken, developerToken, body, { Config }, message,
* This function helps creates an array with proper mapping for userIdentiFier.
* Logics: Here we are creating an array with all the attributes provided in the add/remove array
* inside listData.
* @param {rudder event message properties listData add} attributeArray
* @param {rudder event destination} Config
* @param {Array} attributeArray rudder event message properties listData add
* @param {object} Config rudder event destination
* @param {string} typeOfList
* @param {boolean} isHashRequired
* @returns
*/
const populateIdentifiers = (attributeArray, { Config }) => {
const populateIdentifiers = (attributeArray, { Config }, typeOfList, isHashRequired) => {
const userIdentifier = [];
const { typeOfList } = Config;
const { isHashRequired, userSchema } = Config;
const { userSchema } = Config;
let attribute;
if (TYPEOFLIST[typeOfList]) {
attribute = TYPEOFLIST[typeOfList];
Expand Down Expand Up @@ -116,7 +115,21 @@ const populateIdentifiers = (attributeArray, { Config }) => {
return userIdentifier;
};

const getOperationAudienceId = (audienceId, message) => {
let operationAudienceId = audienceId;
const mappedToDestination = get(message, MappedToDestinationKey);
if (!operationAudienceId && mappedToDestination) {
const { objectType } = getDestinationExternalIDInfoForRetl(
message,
'GOOGLE_ADWORDS_REMARKETING_LISTS',
);
operationAudienceId = objectType;
}
return operationAudienceId;
};

module.exports = {
populateIdentifiers,
responseBuilder,
getOperationAudienceId,
};
20 changes: 13 additions & 7 deletions src/v0/destinations/google_adwords_remarketing_lists/util.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { populateIdentifiers, responseBuilder } = require('./util');
const { populateIdentifiers, responseBuilder, getOperationAudienceId } = require('./util');
const { API_VERSION } = require('./config');
const accessToken = 'abcd1234';
const developerToken = 'ijkl9101';
Expand Down Expand Up @@ -29,7 +29,7 @@ const body = {
const baseDestination = {
Config: {
rudderAccountId: '258Yea7usSKNpbkIaesL9oJ9iYw',
listId: '7090784486',
audienceId: '7090784486',
customerId: '7693729833',
loginCustomerId: '',
subAccount: false,
Expand Down Expand Up @@ -150,7 +150,7 @@ describe('GARL utils test', () => {
developerToken,
body,
baseDestination,
message,
getOperationAudienceId(baseDestination.Config.audienceId, message),
consentBlock,
);
expect(response).toEqual(expectedResponse);
Expand All @@ -166,7 +166,7 @@ describe('GARL utils test', () => {
developerToken,
body,
destination2,
message,
getOperationAudienceId(baseDestination.Config.audienceId, message),
consentBlock,
);
expect(response).toEqual();
Expand All @@ -178,13 +178,13 @@ describe('GARL utils test', () => {
it('Should throw error if operationAudienceId is not defined', () => {
try {
const destination1 = Object.create(baseDestination);
destination1.Config.listId = '';
destination1.Config.audienceId = '';
const response = responseBuilder(
accessToken,
developerToken,
body,
destination1,
message,
getOperationAudienceId(baseDestination.Config.audienceId, message),
consentBlock,
);
expect(response).toEqual();
Expand All @@ -196,7 +196,13 @@ describe('GARL utils test', () => {

describe('populateIdentifiers function tests', () => {
it('Should hash and return identifiers for a given list of attributes', () => {
const identifier = populateIdentifiers(attributeArray, baseDestination);
const { typeOfList, isHashRequired } = baseDestination.Config;
const identifier = populateIdentifiers(
attributeArray,
baseDestination,
typeOfList,
isHashRequired,
);
expect(identifier).toEqual(hashedArray);
});
});
Expand Down
Loading

0 comments on commit f4b38eb

Please sign in to comment.