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: Add support for Consent State #43

Merged
merged 12 commits into from
Sep 30, 2024
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"before": true,
"beforeEach": true,
"after": true,
"afterEach": true,
"uetq": true,
"UET": true
},
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
"lint:fix": "eslint src/ test/src/ --fix",
"test": "npm run build && npm run build:test && DEBUG=false karma start test/karma.config.js",
"test:debug": "npm run build && npm run build:test && DEBUG=true karma start test/karma.config.js",
"watch": "ENVIRONMENT=production rollup --config rollup.config.js -w"
"watch": "ENVIRONMENT=production rollup --config rollup.config.js -w",
"watch:tests": "ENVIRONMENT=production rollup --config rollup.test.config.js -w"

},
"devDependencies": {
"@semantic-release/changelog": "^5.0.1",
Expand Down
157 changes: 155 additions & 2 deletions src/BingAdsEventForwarder.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,43 @@ var MessageType = {
Commerce: 16,
};

var bingConsentValues = { Denied: 'denied', Granted: 'granted' };
var bingConsentProperties = ['ad_storage'];
var bingToMpConsentSettingsMapping = {
ad_storage: 'defaultAdStorageConsentWeb',
};

var constructor = function() {
var self = this;
var isInitialized = false;
var forwarderSettings = null;
var reportingService = null;

self.consentMappings = [];
self.consentPayloadAsString = '';
self.consentPayloadDefaults = {};

self.name = name;

function initForwarder(settings, service, testMode) {
forwarderSettings = settings;
reportingService = service;

if (forwarderSettings.consentMappingWeb) {
self.consentMappings = parseSettingsString(
forwarderSettings.consentMappingWeb
);
}
self.consentPayloadDefaults = getConsentSettings(forwarderSettings);

var initialConsentPayload = cloneObject(self.consentPayloadDefaults);
var userConsentState = getUserConsentState();

var updatedConsentPayload = generateConsentPayload(
userConsentState,
self.consentMappings
);

try {
if (!testMode) {
(function(window, document, tag, url, queue) {
Expand All @@ -47,14 +72,18 @@ var constructor = function() {
var i;
(window[queue] = window[queue] || []),
(window.uetq = window.uetq || []),
sendConsentDefaultToBing(initialConsentPayload),
(f = function() {
var obj = {
ti: forwarderSettings.tagId,
q: window.uetq,
};
(obj.q = window[queue]),
(window[queue] = new UET(obj)),
window[queue].push('pageLoad');
maybeSendConsentUpdateToBing(
updatedConsentPayload
);
window[queue].push('pageLoad');
}),
(n = document.createElement(tag)),
(n.src = url),
Expand Down Expand Up @@ -128,10 +157,13 @@ var constructor = function() {
"Can't log event on forwarder: " + name + ', not initialized'
);
}

try {
var obj = createUetObject(event, 'pageLoad');

var eventConsentState = getEventConsentState(event.ConsentState);

maybeSendConsentUpdateToBing(eventConsentState);

window.uetq.push(obj);
} catch (e) {
return "Can't log event on forwarder: " + name + ': ' + e;
Expand Down Expand Up @@ -180,10 +212,123 @@ var constructor = function() {
return obj;
}

function getEventConsentState(eventConsentState) {
return eventConsentState && eventConsentState.getGDPRConsentState
? eventConsentState.getGDPRConsentState()
: {};
}

function generateConsentPayload(consentState, mappings) {
if (!mappings) {
return {};
}

var payload = cloneObject(self.consentPayloadDefaults);
if (mappings && mappings.length > 0) {
for (var i = 0; i < mappings.length; i++) {
var mappingEntry = mappings[i];
var mpMappedConsentName = mappingEntry.map.toLowerCase();
var bingMappedConsentName = mappingEntry.value;

if (
consentState[mpMappedConsentName] &&
bingConsentProperties.indexOf(bingMappedConsentName) !== -1
) {
payload[bingMappedConsentName] = consentState[
mpMappedConsentName
].Consented
? bingConsentValues.Granted
: bingConsentValues.Denied;
}
}
}

return payload;
}

function maybeSendConsentUpdateToBing(consentState) {
if (
self.consentPayloadAsString &&
self.consentMappings &&
!isEmpty(consentState)
) {
var updatedConsentPayload = generateConsentPayload(
consentState,
self.consentMappings
);

var eventConsentAsString = JSON.stringify(updatedConsentPayload);

if (eventConsentAsString !== self.consentPayloadAsString) {
window.uetq.push('consent', 'update', updatedConsentPayload);
self.consentPayloadAsString = JSON.stringify(
updatedConsentPayload
);
}
}
}

function sendConsentDefaultToBing(consentPayload) {
self.consentPayloadAsString = JSON.stringify(consentPayload);

window.uetq.push('consent', 'default', consentPayload);
}

this.init = initForwarder;
this.process = processEvent;
};

function getUserConsentState() {
var userConsentState = {};

if (mParticle.Identity && mParticle.Identity.getCurrentUser) {
var currentUser = mParticle.Identity.getCurrentUser();

if (!currentUser) {
return {};
}

var consentState = mParticle.Identity.getCurrentUser().getConsentState();

if (consentState && consentState.getGDPRConsentState) {
userConsentState = consentState.getGDPRConsentState();
}
}

return userConsentState;
}

function getConsentSettings(settings) {
var consentSettings = {};

Object.keys(bingToMpConsentSettingsMapping).forEach(function(
bingConsentKey
) {
var mpConsentSettingKey =
bingToMpConsentSettingsMapping[bingConsentKey];
var bingConsentValuesKey = settings[mpConsentSettingKey];

// Microsoft recommends that for most countries, we should default to 'Granted'
// if a default value is not provided
// https://help.ads.microsoft.com/apex/index/3/en/60119
if (bingConsentValuesKey && mpConsentSettingKey) {
alexs-mparticle marked this conversation as resolved.
Show resolved Hide resolved
consentSettings[bingConsentKey] = bingConsentValues[
bingConsentValuesKey
]
? bingConsentValues[bingConsentValuesKey]
: bingConsentValues.Granted;
} else {
consentSettings[bingConsentKey] = bingConsentValues.Granted;
}
});

return consentSettings;
}

function parseSettingsString(settingsString) {
return JSON.parse(settingsString.replace(/&quot;/g, '"'));
}

function getId() {
return moduleId;
}
Expand Down Expand Up @@ -228,6 +373,14 @@ if (typeof window !== 'undefined') {
}
}

function isEmpty(value) {
return value == null || !(Object.keys(value) || value).length;
}

function cloneObject(obj) {
return JSON.parse(JSON.stringify(obj));
}

module.exports = {
register: register,
};
Loading