From 08b1a373b638bf5cbb5219dec0dd812f7552b98b Mon Sep 17 00:00:00 2001 From: Mo Mustafa Date: Mon, 7 Oct 2024 16:37:22 -0700 Subject: [PATCH 1/2] fix: send default and update consent payloads on kit init --- src/common.js | 36 ++++++++++++++++++++++++ src/consent.js | 6 ---- src/event-handler.js | 31 +++------------------ src/initialization.js | 21 ++++++++------ test/tests.js | 64 +++++++++++++++++++++++++++++++------------ 5 files changed, 99 insertions(+), 59 deletions(-) diff --git a/src/common.js b/src/common.js index 8c8d772..e7f2dd8 100644 --- a/src/common.js +++ b/src/common.js @@ -53,6 +53,42 @@ Common.prototype.sendGtagConsent = function (type, payload) { gtag('consent', type, payload); }; +Common.prototype.getEventConsentState = function (eventConsentState) { + return eventConsentState && eventConsentState.getGDPRConsentState + ? eventConsentState.getGDPRConsentState() + : {}; +}; + +Common.prototype.maybeSendConsentUpdateToGoogle = function (consentState) { + // If consent payload is empty, + // we never sent an initial default consent state + // so we shouldn't send an update. + if ( + this.consentPayloadAsString && + this.consentMappings && + !this.isEmpty(consentState) + ) { + var updatedConsentPayload = + this.consentHandler.generateConsentStatePayloadFromMappings( + consentState, + this.consentMappings + ); + + var eventConsentAsString = JSON.stringify(updatedConsentPayload); + + if (eventConsentAsString !== this.consentPayloadAsString) { + this.sendGtagConsent('update', updatedConsentPayload); + this.consentPayloadAsString = eventConsentAsString; + } + } +}; + +Common.prototype.sendDefaultConsentPayloadToGoogle = function (consentPayload) { + this.consentPayloadAsString = JSON.stringify(consentPayload); + + this.sendGtagConsent('default', consentPayload); +}; + Common.prototype.cloneObject = function (obj) { return JSON.parse(JSON.stringify(obj)); }; diff --git a/src/consent.js b/src/consent.js index b1ae5f2..388be5b 100644 --- a/src/consent.js +++ b/src/consent.js @@ -46,12 +46,6 @@ ConsentHandler.prototype.getUserConsentState = function () { return userConsentState; }; -ConsentHandler.prototype.getEventConsentState = function (eventConsentState) { - return eventConsentState && eventConsentState.getGDPRConsentState - ? eventConsentState.getGDPRConsentState() - : {}; -}; - ConsentHandler.prototype.getConsentSettings = function () { var consentSettings = {}; diff --git a/src/event-handler.js b/src/event-handler.js index b3b1ab0..cf7058e 100644 --- a/src/event-handler.js +++ b/src/event-handler.js @@ -10,34 +10,11 @@ function EventHandler(common) { this.common = common || {}; } -EventHandler.prototype.maybeSendConsentUpdateToGoogle = function (event) { - // If consent payload is empty, - // we never sent an initial default consent state - // so we shouldn't send an update. - if (this.common.consentPayloadAsString && this.common.consentMappings) { - var eventConsentState = this.common.consentHandler.getEventConsentState( - event.ConsentState - ); - - if (!this.common.isEmpty(eventConsentState)) { - var updatedConsentPayload = - this.common.consentHandler.generateConsentStatePayloadFromMappings( - eventConsentState, - this.common.consentMappings - ); - - var eventConsentAsString = JSON.stringify(updatedConsentPayload); - - if (eventConsentAsString !== this.common.consentPayloadAsString) { - this.common.sendGtagConsent('update', updatedConsentPayload); - this.common.consentPayloadAsString = eventConsentAsString; - } - } - } -}; - EventHandler.prototype.logEvent = function (event) { - this.maybeSendConsentUpdateToGoogle(event); + var eventConsentState = this.common.getEventConsentState( + event.ConsentState + ); + this.common.maybeSendConsentUpdateToGoogle(eventConsentState); var gtagProperties = {}; this.common.setCustomVariables(event, gtagProperties); diff --git a/src/initialization.js b/src/initialization.js index 4285a43..1bfbfa8 100644 --- a/src/initialization.js +++ b/src/initialization.js @@ -45,20 +45,25 @@ var initialization = { common.consentPayloadDefaults = common.consentHandler.getConsentSettings(); - var initialConsentState = common.consentHandler.getUserConsentState(); - var defaultConsentPayload = + var defaultConsentPayload = common.cloneObject( + common.consentPayloadDefaults + ); + var updatedConsentState = common.consentHandler.getUserConsentState(); + var updatedDefaultConsentPayload = common.consentHandler.generateConsentStatePayloadFromMappings( - initialConsentState, + updatedConsentState, common.consentMappings ); - + if (!common.isEmpty(defaultConsentPayload)) { - common.consentPayloadAsString = JSON.stringify( - defaultConsentPayload + common.sendDefaultConsentPayloadToGoogle(defaultConsentPayload); + } else if (!common.isEmpty(updatedDefaultConsentPayload)) { + common.sendDefaultConsentPayloadToGoogle( + updatedDefaultConsentPayload ); - - common.sendGtagConsent('default', defaultConsentPayload); } + + common.maybeSendConsentUpdateToGoogle(updatedConsentState); }, }; diff --git a/test/tests.js b/test/tests.js index 5e10073..2aed06d 100644 --- a/test/tests.js +++ b/test/tests.js @@ -567,7 +567,7 @@ describe('DoubleClick', function () { done(); }); - it('should merge Consent Setting Defaults with User Consent State to construct a Default Consent State', (done) => { + it('should construct a Default Consent State Payload from Default Settings and construct an Update Consent State Payload from Mappings', (done) => { mParticle.forwarder.init( { conversionId: 'AW-123123123', @@ -584,9 +584,20 @@ describe('DoubleClick', function () { true ); - var expectedDataLayer = [ + var expectedDataLayer1 = [ 'consent', 'default', + { + ad_personalization: 'granted', // From Consent Settings + ad_user_data: 'granted', // From Consent Settings + ad_storage: 'granted', // From Consent Settings + analytics_storage: 'granted', // From Consent Settings + }, + ]; + + var expectedDataLayer2 = [ + 'consent', + 'update', { ad_personalization: 'denied', // From User Consent State ad_user_data: 'denied', // From User Consent State @@ -597,10 +608,13 @@ describe('DoubleClick', function () { // Initial elements of Data Layer are setup for gtag. // Consent state should be on the bottom - window.dataLayer.length.should.eql(4); + window.dataLayer.length.should.eql(5); window.dataLayer[3][0].should.equal('consent'); window.dataLayer[3][1].should.equal('default'); - window.dataLayer[3][2].should.deepEqual(expectedDataLayer[2]); + window.dataLayer[3][2].should.deepEqual(expectedDataLayer1[2]); + window.dataLayer[4][0].should.equal('consent'); + window.dataLayer[4][1].should.equal('update'); + window.dataLayer[4][2].should.deepEqual(expectedDataLayer2[2]); done(); }); @@ -820,7 +834,18 @@ describe('DoubleClick', function () { true ); - var expectedDataLayerBefore = [ + var expectedDataLayerBefore1 = [ + 'consent', + 'default', + { + ad_personalization: 'granted', // From Consent Settings + ad_user_data: 'granted', // From Consent Settings + ad_storage: 'granted', // From Consent Settings + analytics_storage: 'granted', // From Consent Settings + }, + ]; + + var expectedDataLayerBefore2 = [ 'consent', 'update', { @@ -833,10 +858,13 @@ describe('DoubleClick', function () { // Initial elements of Data Layer are setup for gtag. // Consent state should be on the bottom - window.dataLayer.length.should.eql(4); + window.dataLayer.length.should.eql(5); window.dataLayer[3][0].should.equal('consent'); window.dataLayer[3][1].should.equal('default'); - window.dataLayer[3][2].should.deepEqual(expectedDataLayerBefore[2]); + window.dataLayer[3][2].should.deepEqual(expectedDataLayerBefore1[2]); + window.dataLayer[4][0].should.equal('consent'); + window.dataLayer[4][1].should.equal('update'); + window.dataLayer[4][2].should.deepEqual(expectedDataLayerBefore2[2]); mParticle.forwarder.process({ EventName: 'Test Event', @@ -889,11 +917,11 @@ describe('DoubleClick', function () { // Initial elements of Data Layer are setup for gtag. // Consent Default is index 3 - // Consent Update is index 4 - window.dataLayer.length.should.eql(5); - window.dataLayer[4][0].should.equal('consent'); - window.dataLayer[4][1].should.equal('update'); - window.dataLayer[4][2].should.deepEqual(expectedDataLayerAfter[2]); + // Consent Update is index 5 + window.dataLayer.length.should.eql(6); + window.dataLayer[5][0].should.equal('consent'); + window.dataLayer[5][1].should.equal('update'); + window.dataLayer[5][2].should.deepEqual(expectedDataLayerAfter[2]); mParticle.forwarder.process({ EventName: 'Test Event', @@ -962,12 +990,12 @@ describe('DoubleClick', function () { ]; // Initial elements of Data Layer are setup for gtag. // Consent Default is index 3 - // Consent Update is index 4 - // Consent Update #2 is index 5 - window.dataLayer.length.should.eql(6); - window.dataLayer[5][0].should.equal('consent'); - window.dataLayer[5][1].should.equal('update'); - window.dataLayer[5][2].should.deepEqual(expectedDataLayerFinal[2]); + // Consent Update is index 5 + // Consent Update #2 is index 6 + window.dataLayer.length.should.eql(7); + window.dataLayer[6][0].should.equal('consent'); + window.dataLayer[6][1].should.equal('update'); + window.dataLayer[6][2].should.deepEqual(expectedDataLayerFinal[2]); done(); }); From 946caeb055d685251743ce95b3fc525ed914e98b Mon Sep 17 00:00:00 2001 From: Mo Mustafa Date: Tue, 8 Oct 2024 12:02:58 -0700 Subject: [PATCH 2/2] fix: send default and update consent payloads on kit init --- src/initialization.js | 3 +++ test/tests.js | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/initialization.js b/src/initialization.js index 1bfbfa8..2f322b1 100644 --- a/src/initialization.js +++ b/src/initialization.js @@ -55,8 +55,11 @@ var initialization = { common.consentMappings ); + // If a default consent payload exists (as selected in the mParticle UI), set it as the default if (!common.isEmpty(defaultConsentPayload)) { common.sendDefaultConsentPayloadToGoogle(defaultConsentPayload); + // If a default consent payload does not exist, but the user currently has updated their consent, + // send that as the default because a default must be sent } else if (!common.isEmpty(updatedDefaultConsentPayload)) { common.sendDefaultConsentPayloadToGoogle( updatedDefaultConsentPayload diff --git a/test/tests.js b/test/tests.js index 2aed06d..1d4a510 100644 --- a/test/tests.js +++ b/test/tests.js @@ -857,7 +857,8 @@ describe('DoubleClick', function () { ]; // Initial elements of Data Layer are setup for gtag. - // Consent state should be on the bottom + // Default Consent payload from default settings should be index 3 + // Update Consent payload from mappings should be on the bottom (index 4) window.dataLayer.length.should.eql(5); window.dataLayer[3][0].should.equal('consent'); window.dataLayer[3][1].should.equal('default'); @@ -917,7 +918,8 @@ describe('DoubleClick', function () { // Initial elements of Data Layer are setup for gtag. // Consent Default is index 3 - // Consent Update is index 5 + // Initial Consent Update from mappings is index 4 + // Consent Update #2 is index 5 window.dataLayer.length.should.eql(6); window.dataLayer[5][0].should.equal('consent'); window.dataLayer[5][1].should.equal('update'); @@ -990,8 +992,9 @@ describe('DoubleClick', function () { ]; // Initial elements of Data Layer are setup for gtag. // Consent Default is index 3 - // Consent Update is index 5 - // Consent Update #2 is index 6 + // Initial Consent Update from mappings is index 4 + // Consent Update #2 is index 5 + // Consent Update #3 is index 6 window.dataLayer.length.should.eql(7); window.dataLayer[6][0].should.equal('consent'); window.dataLayer[6][1].should.equal('update');