Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: consent field support for gaoc for API v15 and upgrade the api version from v14 to v16 #3121

Merged
merged 27 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
01167f2
feat: consent field support for GAOC
shrouti1507 Feb 23, 2024
31d3691
fix: clean up of commented code
shrouti1507 Feb 23, 2024
f23127a
fix: clean up the old implementation of GARL to avoid code duplication
shrouti1507 Feb 26, 2024
a0a6885
fix: small edit
shrouti1507 Feb 26, 2024
602f57d
chore: conflict resolved
shrouti1507 Mar 7, 2024
bce1d62
chore: store sales updated, review comments addressed
shrouti1507 Mar 7, 2024
b25d81d
Merge branch 'develop' into feat.consentMode.GAOC
shrouti1507 Mar 7, 2024
3d92ad0
fix: relocating the util and test cases
shrouti1507 Mar 11, 2024
e60117b
fix: refactoring the util
shrouti1507 Mar 11, 2024
f6a30da
Merge branch 'develop' into feat.consentMode.GAOC
shrouti1507 Mar 11, 2024
3d4634e
fix: updating API version to v16
shrouti1507 Mar 11, 2024
e192352
fix: review comments address
shrouti1507 Mar 11, 2024
5d961e8
Update src/v0/destinations/google_adwords_offline_conversions/transfo…
shrouti1507 Mar 11, 2024
a027389
Update src/v0/destinations/google_adwords_offline_conversions/transfo…
shrouti1507 Mar 11, 2024
af7a820
fix: review comments address
shrouti1507 Mar 11, 2024
2be5001
Merge branch 'develop' into feat.consentMode.GAOC
shrouti1507 Mar 11, 2024
76a68ab
Merge branch 'develop' into feat.consentMode.GAOC
shrouti1507 Mar 12, 2024
0f13371
fix: review comments addressed
shrouti1507 Mar 12, 2024
9bae3d4
fix: review comments addressed
shrouti1507 Mar 12, 2024
ad6aea0
fix: utils added
shrouti1507 Mar 12, 2024
3094878
Merge branch 'develop' into feat.consentMode.GAOC
shrouti1507 Mar 12, 2024
05cc867
fix: util function made more pluggable
shrouti1507 Mar 12, 2024
1d99743
Merge branch 'feat.consentMode.GAOC' of github.com:rudderlabs/rudder-…
shrouti1507 Mar 12, 2024
e05e730
fix: conflict resolve
shrouti1507 Mar 13, 2024
b2f4830
Merge branch 'develop' into feat.consentMode.GAOC
shrouti1507 Mar 18, 2024
f3e48c6
chore: add event validation for movable ink destination (#3190)
Gauravudia Mar 18, 2024
b013770
Merge branch 'develop' into feat.consentMode.GAOC
krishna2020 Mar 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/constants/destinationCanonicalNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,18 @@ const DestCanonicalNames = {
'the trade desk',
],
INTERCOM: ['INTERCOM', 'intercom', 'Intercom'],
GOOGLE_ADWORDS_REMARKETING_LISTS: [
'GOOGLE_ADWORDS_REMARKETING_LISTS',
'google_adwords_remarketing_lists',
'Google Adwords Remarketing Lists',
'google adwords remarketing lists',
],
GOOGLE_ADWORDS_OFFLINE_CONVERSIONS: [
'GOOGLE_ADWORDS_OFFLINE_CONVERSIONS',
'google_adwords_offline_conversions',
'Google Adwords Offline Conversions',
'google adwords offline conversions',
],
};

module.exports = { DestHandlerMap, DestCanonicalNames };
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { getMappingConfig } = require('../../util');

const API_VERSION = 'v14';
const API_VERSION = 'v15';

const BASE_ENDPOINT = `https://googleads.googleapis.com/${API_VERSION}/customers/:customerId`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const {
getStoreConversionPayload,
requestBuilder,
getClickConversionPayloadAndEndpoint,
populateConsentForGoogleDestinations,
} = require('./utils');
const helper = require('./helper');

Expand Down Expand Up @@ -59,7 +60,20 @@ const getConversions = (message, metadata, { Config }, event, conversionType) =>
payload = constructPayload(message, trackCallConversionsMapping);
endpoint = CALL_CONVERSION.replace(':customerId', filteredCustomerId);
}

const consentObject = populateConsentForGoogleDestinations(message, conversionType);
if (Object.keys(consentObject)?.length > 0) {
if (payload?.conversions?.length > 0) {
if (conversionType === 'click' || conversionType === 'call') {
shrouti1507 marked this conversation as resolved.
Show resolved Hide resolved
payload.conversions[0].consent = consentObject;
saikumarrs marked this conversation as resolved.
Show resolved Hide resolved
}
} else if (
Object.keys(payload?.addConversionPayload?.operations?.create)?.length > 0 &&
conversionType === 'store'
saikumarrs marked this conversation as resolved.
Show resolved Hide resolved
) {
payload.addConversionPayload.operations.create.consent = consentObject;
}
}

if (conversionType !== 'store') {
// transform originalTimestamp to conversionDateTime format (yyyy-mm-dd hh:mm:ss+|-hh:mm)
// e.g 2019-10-14T11:15:18.299Z -> 2019-10-14 16:10:29+0530
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
isDefinedAndNotNull,
getAuthErrCategoryFromStCode,
getAccessToken,
getIntegrationsObj,
} = require('../../util');
const {
SEARCH_STREAM,
Expand Down Expand Up @@ -65,7 +66,7 @@
feature: 'transformation',
endpointPath: `/googleAds:searchStream`,
requestMethod: 'POST',
module: 'dataDelivery'
module: 'dataDelivery',
});
searchStreamResponse = processAxiosResponse(searchStreamResponse);
if (!isHttpStatusSuccess(searchStreamResponse.status)) {
Expand Down Expand Up @@ -362,6 +363,55 @@
return { payload, endpoint };
};

const GOOGLE_ALLOWED_CONSENT_STATUS = ['UNSPECIFIED', 'UNKNOWN', 'GRANTED', 'DENIED'];
saikumarrs marked this conversation as resolved.
Show resolved Hide resolved

/**
* Populates the consent object based on the provided properties.
*
* @param {object} properties - message.properties containing properties related to consent.
* @returns {object} - An object containing consent information.
* * ref :
* 1) For click conversion :
* a) https://developers.google.com/google-ads/api/rest/reference/rest/v15/customers/uploadClickConversions#ClickConversion
* b) https://developers.google.com/google-ads/api/reference/rpc/v15/ClickConversion#consent
* 2) For Call conversion :
* a) https://developers.google.com/google-ads/api/rest/reference/rest/v15/customers/uploadCallConversions#CallConversion
* b) https://developers.google.com/google-ads/api/reference/rpc/v15/CallConversion#consent
* 3) For Store sales conversion :
* a) https://developers.google.com/google-ads/api/reference/rpc/v15/UserData
* b) https://developers.google.com/google-ads/api/reference/rpc/v15/UserData#consent
*/

const populateConsentForGoogleDestinations = (message) => {
saikumarrs marked this conversation as resolved.
Show resolved Hide resolved
const integrationObj = getIntegrationsObj(message, 'GOOGLE_ADWORDS_OFFLINE_CONVERSIONS') || {};
const consents = integrationObj.consents || {};

// Define a function to process consent based on type
const processConsent = (consentType) => {
if (!consents[consentType]) return 'UNSPECIFIED';
if (GOOGLE_ALLOWED_CONSENT_STATUS.includes(consents[consentType])) {
return consents[consentType];

Check warning on line 393 in src/v0/destinations/google_adwords_offline_conversions/utils.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/google_adwords_offline_conversions/utils.js#L393

Added line #L393 was not covered by tests
}
return 'UNKNOWN';

Check warning on line 395 in src/v0/destinations/google_adwords_offline_conversions/utils.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/google_adwords_offline_conversions/utils.js#L395

Added line #L395 was not covered by tests
saikumarrs marked this conversation as resolved.
Show resolved Hide resolved
};

// Common consent fields to process
const consentFields = {
adUserData: 'adUserData',
adPersonalization: 'adPersonalization',
saikumarrs marked this conversation as resolved.
Show resolved Hide resolved
};

// Construct consentObj based on the common consent fields
const consentObj = Object.keys(consentFields).reduce((obj, consentType) => {
const key = consentFields[consentType];
// eslint-disable-next-line no-param-reassign
obj[key] = processConsent(consentType);
return obj;
}, {});

return consentObj;
};

module.exports = {
validateDestinationConfig,
generateItemListFromProducts,
Expand All @@ -372,4 +422,5 @@
buildAndGetAddress,
getClickConversionPayloadAndEndpoint,
getExisitingUserIdentifier,
populateConsentForGoogleDestinations,
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const {
getClickConversionPayloadAndEndpoint,
buildAndGetAddress,
getExisitingUserIdentifier,
populateConsentForGoogleDestinations,
} = require('./utils');

const getTestMessage = () => {
Expand Down Expand Up @@ -161,7 +162,7 @@ describe('getExisitingUserIdentifier util tests', () => {
describe('getClickConversionPayloadAndEndpoint util tests', () => {
it('getClickConversionPayloadAndEndpoint flow check when default field identifier is present', () => {
let expectedOutput = {
endpoint: 'https://googleads.googleapis.com/v14/customers/9625812972:uploadClickConversions',
endpoint: 'https://googleads.googleapis.com/v15/customers/9625812972:uploadClickConversions',
payload: {
conversions: [
{
Expand All @@ -187,7 +188,7 @@ describe('getClickConversionPayloadAndEndpoint util tests', () => {
delete fittingPayload.traits.email;
delete fittingPayload.properties.email;
let expectedOutput = {
endpoint: 'https://googleads.googleapis.com/v14/customers/9625812972:uploadClickConversions',
endpoint: 'https://googleads.googleapis.com/v15/customers/9625812972:uploadClickConversions',
payload: {
conversions: [
{
Expand Down Expand Up @@ -215,7 +216,7 @@ describe('getClickConversionPayloadAndEndpoint util tests', () => {
delete fittingPayload.traits.phone;
delete fittingPayload.properties.email;
let expectedOutput = {
endpoint: 'https://googleads.googleapis.com/v14/customers/9625812972:uploadClickConversions',
endpoint: 'https://googleads.googleapis.com/v15/customers/9625812972:uploadClickConversions',
payload: {
conversions: [
{
Expand Down Expand Up @@ -251,7 +252,7 @@ describe('getClickConversionPayloadAndEndpoint util tests', () => {
},
];
let expectedOutput = {
endpoint: 'https://googleads.googleapis.com/v14/customers/9625812972:uploadClickConversions',
endpoint: 'https://googleads.googleapis.com/v15/customers/9625812972:uploadClickConversions',
payload: {
conversions: [
{
Expand All @@ -273,3 +274,97 @@ describe('getClickConversionPayloadAndEndpoint util tests', () => {
);
});
});

describe('populateConsentForGoogleDestinations', () => {
saikumarrs marked this conversation as resolved.
Show resolved Hide resolved
// Returns an object with adUserData and adPersonalization properties set to UNSPECIFIED when no consents are provided
it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS : store sales conversion without any mention in integrations object', () => {
saikumarrs marked this conversation as resolved.
Show resolved Hide resolved
const message = {};
const conversionType = 'store';

const result = populateConsentForGoogleDestinations(message, conversionType);

expect(result).toEqual({
adUserData: 'UNSPECIFIED',
adPersonalization: 'UNSPECIFIED',
});
});

// Returns an empty object when the destination name is not recognized
it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS: store sales conversions with integrations object', () => {
const message = {
integrations: {
google_adwords_offline_conversions: {
consents: {
adUserData: 'GRANTED',
adPersonalization: 'DENIED',
},
},
},
};
const conversionType = 'store';

const result = populateConsentForGoogleDestinations(message, conversionType);

expect(result).toEqual({
adPersonalization: 'DENIED',
adUserData: 'GRANTED',
});
});

// Returns an object with adUserData and adPersonalization properties set to the provided consents when they are valid and present in the message properties
it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS: click conversion with integration object of allowed types', () => {
const message = {
integrations: {
google_adwords_offline_conversions: {
consents: {
adUserData: 'GRANTED',
adPersonalization: 'DENIED',
},
},
},
};
const conversionType = 'click';

const result = populateConsentForGoogleDestinations(message, conversionType);

expect(result).toEqual({
adUserData: 'GRANTED',
adPersonalization: 'DENIED',
});
});

// Returns an object with adUserData and adPersonalization properties set to UNSPECIFIED when the provided consents are not valid or not present in the message properties
it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS : click conversion with invalid consent value', () => {
const message = {
integrations: {
google_adwords_offline_conversions: {
consents: {
adUserData: 'GRANTED',
adPersonalization: 'INVALID',
},
},
},
};
const conversionType = 'click';

const result = populateConsentForGoogleDestinations(message, conversionType);

expect(result).toEqual({
adUserData: 'GRANTED',
adPersonalization: 'UNKNOWN',
});
});

// Returns an empty object when the integration object is not present in the message
it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS : call conversion without integrations object consent ', () => {
const message = {};
const conversionType = 'call';

const result = populateConsentForGoogleDestinations(message, conversionType);

expect(result).toEqual({
adUserData: 'UNSPECIFIED',
adPersonalization: 'UNSPECIFIED',
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ const createJob = async (endpoint, headers, method, params) => {
const customerMatchUserListMetadata = {
userList: `customers/${params.customerId}/userLists/${params.listId}`,
};
if (Object.keys(params.consent).length > 0) {
customerMatchUserListMetadata.consent = params.consent;
}
const jobCreatingRequest = {
url: jobCreatingUrl,
data: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ const {
getAccessToken,
} = require('../../util');

const { populateConsentForGoogleDestinations } = require('../../util/googleUtils');

const {
offlineDataJobsMapping,
addressInfoMapping,
Expand Down Expand Up @@ -218,8 +216,7 @@ const processEvent = async (metadata, message, destination) => {
}

Object.values(createdPayload).forEach((data) => {
const consentObj = populateConsentForGoogleDestinations(message.properties);
response.push(responseBuilder(metadata, data, destination, message, consentObj));
response.push(responseBuilder(metadata, data, destination, message));
});
return response;
}
Expand Down
30 changes: 0 additions & 30 deletions src/v0/util/googleUtils/index.js

This file was deleted.

50 changes: 0 additions & 50 deletions src/v0/util/googleUtils/index.test.js

This file was deleted.

Loading
Loading