Skip to content

Commit fc09080

Browse files
authored
fix: refactor code and add validation for values (#3971)
* fix: refactor code and add validation for values * chore: update updateConversion conditions to mutually exclusive
1 parent 6ec3d55 commit fc09080

File tree

6 files changed

+163
-25
lines changed

6 files changed

+163
-25
lines changed

src/v0/destinations/google_adwords_offline_conversions/data/TrackAddStoreConversionsConfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
],
1818
"required": true,
1919
"metadata": {
20-
"type": "toNumber"
20+
"type": "toNumber",
21+
"regex": "^([1-9]\\d*(\\.\\d+)?|0\\.\\d+)$"
2122
}
2223
},
2324
{

src/v0/destinations/google_adwords_offline_conversions/transform.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ const {
1818
getClickConversionPayloadAndEndpoint,
1919
getConsentsDataFromIntegrationObj,
2020
getCallConversionPayload,
21-
updateConversion,
2221
} = require('./utils');
2322
const helper = require('./helper');
2423

@@ -49,9 +48,6 @@ const getConversions = (message, metadata, { Config }, event, conversionType) =>
4948
filteredCustomerId,
5049
eventLevelConsentsData,
5150
);
52-
convertedPayload.payload.conversions[0] = updateConversion(
53-
convertedPayload.payload.conversions[0],
54-
);
5551
payload = convertedPayload.payload;
5652
endpoint = convertedPayload.endpoint;
5753
} else if (conversionType === 'store') {

src/v0/destinations/google_adwords_offline_conversions/utils.js

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,24 @@ const populateUserIdentifier = ({ email, phone, properties, payload, UserIdentif
346346
}
347347
return copiedPayload;
348348
};
349+
350+
/**
351+
* remove redundant ids
352+
* @param {*} conversionCopy
353+
*/
354+
const updateConversion = (conversion) => {
355+
const conversionCopy = cloneDeep(conversion);
356+
if (conversionCopy.gclid) {
357+
delete conversionCopy.wbraid;
358+
delete conversionCopy.gbraid;
359+
} else if (conversionCopy.wbraid && conversionCopy.gbraid) {
360+
throw new InstrumentationError(`You can't use both wbraid and gbraid.`);
361+
} else if (conversionCopy.wbraid || conversionCopy.gbraid) {
362+
delete conversionCopy.userIdentifiers;
363+
}
364+
return conversionCopy;
365+
};
366+
349367
const getClickConversionPayloadAndEndpoint = (
350368
message,
351369
Config,
@@ -423,6 +441,7 @@ const getClickConversionPayloadAndEndpoint = (
423441
const consentObject = finaliseConsent(consentConfigMap, eventLevelConsent, Config);
424442
// here conversions[0] is expected to be present there are some mandatory properties mapped in the mapping json.
425443
set(payload, 'conversions[0].consent', consentObject);
444+
payload.conversions[0] = updateConversion(payload.conversions[0]);
426445
return { payload, endpoint };
427446
};
428447

@@ -431,25 +450,6 @@ const getConsentsDataFromIntegrationObj = (message) => {
431450
return integrationObj?.consents || {};
432451
};
433452

434-
/**
435-
* remove redundant ids
436-
* @param {*} conversionCopy
437-
*/
438-
const updateConversion = (conversion) => {
439-
const conversionCopy = cloneDeep(conversion);
440-
if (conversionCopy.gclid) {
441-
delete conversionCopy.wbraid;
442-
delete conversionCopy.gbraid;
443-
}
444-
if (conversionCopy.wbraid && conversionCopy.gbraid) {
445-
throw new InstrumentationError(`You can't use both wbraid and gbraid.`);
446-
}
447-
if (conversionCopy.wbraid || conversionCopy.gbraid) {
448-
delete conversionCopy.userIdentifiers;
449-
}
450-
return conversionCopy;
451-
};
452-
453453
module.exports = {
454454
validateDestinationConfig,
455455
generateItemListFromProducts,

src/v0/util/index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,7 @@ const handleMetadataForValue = (value, metadata, destKey, integrationsObj = null
971971
validateTimestamp,
972972
allowedKeyCheck,
973973
toArray,
974+
regex,
974975
} = metadata;
975976

976977
// if value is null and defaultValue is supplied - use that
@@ -1044,7 +1045,14 @@ const handleMetadataForValue = (value, metadata, destKey, integrationsObj = null
10441045
}
10451046
return [formattedVal];
10461047
}
1047-
1048+
if (regex) {
1049+
const regexPattern = new RegExp(regex);
1050+
if (!regexPattern.test(formattedVal)) {
1051+
throw new InstrumentationError(
1052+
`The value '${formattedVal}' does not match the regex pattern, ${regex}`,
1053+
);
1054+
}
1055+
}
10481056
return formattedVal;
10491057
};
10501058

@@ -2489,4 +2497,5 @@ module.exports = {
24892497
removeEmptyKey,
24902498
isAxiosError,
24912499
convertToUuid,
2500+
handleMetadataForValue,
24922501
};

src/v0/util/index.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,3 +1049,27 @@ describe('convertToUuid', () => {
10491049
expect(result).toBe('672ca00c-37f4-5d71-b8c3-6ae0848080ec');
10501050
});
10511051
});
1052+
1053+
describe('', () => {
1054+
it('should return original value when regex pattern is invalid', () => {
1055+
const value = 'test value';
1056+
const metadata = {
1057+
regex: `\\b(?!1000\\b)\\d{4,}\\b`,
1058+
};
1059+
try {
1060+
const result = utilities.handleMetadataForValue(value, metadata);
1061+
} catch (e) {
1062+
expect(e.message).toBe(
1063+
`The value 'test value' does not match the regex pattern, \\b(?!1000\\b)\\d{4,}\\b`,
1064+
);
1065+
}
1066+
});
1067+
it('should return true when the regex matches', () => {
1068+
const value = 1003;
1069+
const metadata = {
1070+
regex: `\\b(?!1000\\b)\\d{4,}\\b`,
1071+
};
1072+
const res = utilities.handleMetadataForValue(value, metadata);
1073+
expect(res).toBe(1003);
1074+
});
1075+
});

test/integrations/destinations/google_adwords_offline_conversions/processor/data.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5929,4 +5929,112 @@ export const data = [
59295929
},
59305930
mockFns: timestampMock,
59315931
},
5932+
{
5933+
name: 'google_adwords_offline_conversions',
5934+
description: 'Test 29 : store conversion which has value less than 0, should throw error',
5935+
feature: 'processor',
5936+
module: 'destination',
5937+
version: 'v0',
5938+
input: {
5939+
request: {
5940+
body: [
5941+
{
5942+
message: {
5943+
channel: 'web',
5944+
context: {
5945+
traits: {},
5946+
},
5947+
event: 'Product Clicked',
5948+
type: 'track',
5949+
messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71',
5950+
anonymousId: '00000000000000000000000000',
5951+
userId: '12345',
5952+
properties: {
5953+
item_id: 'item id',
5954+
merchant_id: 'merchant id',
5955+
currency: 'INR',
5956+
revenue: '0',
5957+
store_code: 'store code',
5958+
gclid: 'gclid',
5959+
conversionDateTime: '2019-10-14T11:15:18.299Z',
5960+
product_id: '123445',
5961+
quantity: 123,
5962+
},
5963+
integrations: {
5964+
google_adwords_offline_conversion: {
5965+
consent: {
5966+
adUserdata: 'UNSPECIFIED',
5967+
adPersonalization: 'GRANTED',
5968+
},
5969+
},
5970+
},
5971+
name: 'ApplicationLoaded',
5972+
sentAt: '2019-10-14T11:15:53.296Z',
5973+
},
5974+
metadata: {
5975+
secret: {
5976+
access_token: 'abcd1234',
5977+
refresh_token: 'efgh5678',
5978+
developer_token: 'ijkl91011',
5979+
},
5980+
},
5981+
destination: {
5982+
Config: {
5983+
isCustomerAllowed: false,
5984+
customerId: '111-222-3333',
5985+
subAccount: true,
5986+
loginCustomerId: 'login-customer-id',
5987+
userDataConsent: 'GRANTED',
5988+
personalizationConsent: 'DENIED',
5989+
eventsToOfflineConversionsTypeMapping: [
5990+
{
5991+
from: 'Product Clicked',
5992+
to: 'store',
5993+
},
5994+
],
5995+
eventsToConversionsNamesMapping: [
5996+
{
5997+
from: 'Product Clicked',
5998+
to: 'Sign-up - click',
5999+
},
6000+
],
6001+
hashUserIdentifier: true,
6002+
defaultUserIdentifier: 'phone',
6003+
validateOnly: false,
6004+
rudderAccountId: '2EOknn1JNH7WK1MfNkgr4t3u4fGYKkRK',
6005+
},
6006+
},
6007+
},
6008+
],
6009+
},
6010+
},
6011+
output: {
6012+
response: {
6013+
status: 200,
6014+
body: [
6015+
{
6016+
error:
6017+
"The value '0' does not match the regex pattern, ^([1-9]\\d*(\\.\\d+)?|0\\.\\d+)$",
6018+
metadata: {
6019+
secret: {
6020+
access_token: 'abcd1234',
6021+
developer_token: 'ijkl91011',
6022+
refresh_token: 'efgh5678',
6023+
},
6024+
},
6025+
statTags: {
6026+
destType: 'GOOGLE_ADWORDS_OFFLINE_CONVERSIONS',
6027+
errorCategory: 'dataValidation',
6028+
errorType: 'instrumentation',
6029+
feature: 'processor',
6030+
implementation: 'native',
6031+
module: 'destination',
6032+
},
6033+
statusCode: 400,
6034+
},
6035+
],
6036+
},
6037+
},
6038+
mockFns: timestampMock,
6039+
},
59326040
];

0 commit comments

Comments
 (0)