From 0a849736fdc1e38df65b8e008fb6993e20afe314 Mon Sep 17 00:00:00 2001 From: Aparna Hegde Date: Tue, 25 Jun 2019 11:16:09 -0400 Subject: [PATCH 1/3] Removing killswitch behavior for GDPR --- modules/33acrossBidAdapter.js | 26 +++- test/spec/modules/33acrossBidAdapter_spec.js | 147 ++++++++++++++----- 2 files changed, 126 insertions(+), 47 deletions(-) diff --git a/modules/33acrossBidAdapter.js b/modules/33acrossBidAdapter.js index 801a5d564a3..6cec6345f91 100644 --- a/modules/33acrossBidAdapter.js +++ b/modules/33acrossBidAdapter.js @@ -143,14 +143,30 @@ function _createServerRequest(bidRequest, gdprConsent) { } // Sync object will always be of type iframe for TTX -function _createSync(siteId) { +function _createSync({siteId, gdprConsent = {}}) { const ttxSettings = config.getConfig('ttxSettings'); const syncUrl = (ttxSettings && ttxSettings.syncUrl) || SYNC_ENDPOINT; - return { + const {consentString, gdprApplies} = gdprConsent; + + const sync = { type: 'iframe', url: `${syncUrl}&id=${siteId}` + }; + + const gdprMap = { + 'true': 1, + 'false': 0 + }; + + if (typeof gdprApplies === 'boolean') { + const gdpr = gdprMap[gdprApplies.toString()]; + sync.url = `${sync.url}&gdpr=${gdpr}`; } + + sync.url = `${sync.url}&gdpr_consent=${consentString}`; + + return sync; } function _getSize(size) { @@ -310,11 +326,7 @@ function interpretResponse(serverResponse, bidRequest) { // Register one sync per unique guid // NOTE: If gdpr applies do not sync function getUserSyncs(syncOptions, responses, gdprConsent) { - if (gdprConsent && gdprConsent.gdprApplies === true) { - return [] - } else { - return (syncOptions.iframeEnabled) ? adapterState.uniqueSiteIds.map(_createSync) : ([]); - } + return (syncOptions.iframeEnabled) ? adapterState.uniqueSiteIds.map((siteId) => _createSync({gdprConsent, siteId})) : ([]); } export const spec = { diff --git a/test/spec/modules/33acrossBidAdapter_spec.js b/test/spec/modules/33acrossBidAdapter_spec.js index 7e1a8619c63..fb8566bb6b0 100644 --- a/test/spec/modules/33acrossBidAdapter_spec.js +++ b/test/spec/modules/33acrossBidAdapter_spec.js @@ -618,73 +618,140 @@ describe('33acrossBidAdapter:', function () { ]; }); - context('when gdpr does not apply', function() { - let gdprConsent; + context('when iframe is not enabled', function() { + it('returns empty sync array', function() { + const syncOptions = {}; + + spec.buildRequests(bidRequests); + + expect(spec.getUserSyncs(syncOptions)).to.deep.equal([]); + }); + }); + context('when iframe is enabled', function() { + let syncOptions; beforeEach(function() { - gdprConsent = { - gdprApplies: false + syncOptions = { + iframeEnabled: true }; }); - context('when iframe is not enabled', function() { - it('returns empty sync array', function() { - const syncOptions = {}; + context('when there is no gdpr consent data', function() { + it('returns sync urls with undefined consent string as param', function() { + spec.buildRequests(bidRequests); + + const syncResults = spec.getUserSyncs(syncOptions, {}, undefined); + const expectedSyncs = [ + { + type: 'iframe', + url: `${syncs[0].url}&gdpr_consent=undefined` + }, + { + type: 'iframe', + url: `${syncs[1].url}&gdpr_consent=undefined` + } + ] + + expect(syncResults).to.deep.equal(expectedSyncs); + }) + }); + context('when gdpr applies but there is no consent string', function() { + it('returns sync urls with undefined consent string as param and gdpr=1', function() { spec.buildRequests(bidRequests); - expect(spec.getUserSyncs(syncOptions, {}, gdprConsent)).to.deep.equal([]); + const syncResults = spec.getUserSyncs(syncOptions, {}, {gdprApplies: true}); + const expectedSyncs = [ + { + type: 'iframe', + url: `${syncs[0].url}&gdpr=1&gdpr_consent=undefined` + }, + { + type: 'iframe', + url: `${syncs[1].url}&gdpr=1&gdpr_consent=undefined` + } + ]; + + expect(syncResults).to.deep.equal(expectedSyncs); }); }); - context('when iframe is enabled', function() { - it('returns sync array equal to number of unique siteIDs', function() { - const syncOptions = { - iframeEnabled: true - }; - + context('when gdpr applies and there is consent string', function() { + it('returns sync urls with gdpr_consent=consent string as param and gdpr=1', function() { spec.buildRequests(bidRequests); - expect(spec.getUserSyncs(syncOptions, {}, gdprConsent)).to.deep.equal(syncs); + const syncResults = spec.getUserSyncs(syncOptions, {}, {gdprApplies: true, consentString: 'consent123A'}); + const expectedSyncs = [ + { + type: 'iframe', + url: `${syncs[0].url}&gdpr=1&gdpr_consent=consent123A` + }, + { + type: 'iframe', + url: `${syncs[1].url}&gdpr=1&gdpr_consent=consent123A` + } + ]; + + expect(syncResults).to.deep.equal(expectedSyncs); }); }); - }); - - context('when consent data is not defined', function() { - context('when iframe is not enabled', function() { - it('returns empty sync array', function() { - const syncOptions = {}; + context('when gdpr does not apply and there is no consent string', function() { + it('returns sync urls with undefined consent string as param and gdpr=0', function() { spec.buildRequests(bidRequests); - expect(spec.getUserSyncs(syncOptions)).to.deep.equal([]); + const syncResults = spec.getUserSyncs(syncOptions, {}, {gdprApplies: false}); + const expectedSyncs = [ + { + type: 'iframe', + url: `${syncs[0].url}&gdpr=0&gdpr_consent=undefined` + }, + { + type: 'iframe', + url: `${syncs[1].url}&gdpr=0&gdpr_consent=undefined` + } + ]; + expect(syncResults).to.deep.equal(expectedSyncs); }); }); - context('when iframe is enabled', function() { - it('returns sync array equal to number of unique siteIDs', function() { - const syncOptions = { - iframeEnabled: true - }; - + context('when gdpr is unknown and there is consent string', function() { + it('returns sync urls with only consent string as param', function() { spec.buildRequests(bidRequests); - expect(spec.getUserSyncs(syncOptions)).to.deep.equal(syncs); + const syncResults = spec.getUserSyncs(syncOptions, {}, {consentString: 'consent123A'}); + const expectedSyncs = [ + { + type: 'iframe', + url: `${syncs[0].url}&gdpr_consent=consent123A` + }, + { + type: 'iframe', + url: `${syncs[1].url}&gdpr_consent=consent123A` + } + ]; + expect(syncResults).to.deep.equal(expectedSyncs); }); }); - }); - context('when gdpr applies', function() { - it('returns empty sync array', function() { - const syncOptions = {}; - const gdprConsent = { - gdprApplies: true - }; - - spec.buildRequests(bidRequests); + context('when gdpr does not apply and there is consent string (yikes!)', function() { + it('returns sync urls with consent string as param and gdpr=0', function() { + spec.buildRequests(bidRequests); - expect(spec.getUserSyncs(syncOptions, {}, gdprConsent)).to.deep.equal([]); + const syncResults = spec.getUserSyncs(syncOptions, {}, {gdprApplies: false, consentString: 'consent123A'}); + const expectedSyncs = [ + { + type: 'iframe', + url: `${syncs[0].url}&gdpr=0&gdpr_consent=consent123A` + }, + { + type: 'iframe', + url: `${syncs[1].url}&gdpr=0&gdpr_consent=consent123A` + } + ]; + expect(syncResults).to.deep.equal(expectedSyncs); + }); }); - }) + }); }); }); From ecefa15200bfc82103b384a2f0e7a6f74012686b Mon Sep 17 00:00:00 2001 From: Aparna Hegde Date: Tue, 25 Jun 2019 11:27:26 -0400 Subject: [PATCH 2/3] Updated comments to reflect current gdpr logic --- modules/33acrossBidAdapter.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/33acrossBidAdapter.js b/modules/33acrossBidAdapter.js index 6cec6345f91..a7c40bfdeab 100644 --- a/modules/33acrossBidAdapter.js +++ b/modules/33acrossBidAdapter.js @@ -298,8 +298,6 @@ function isBidRequestValid(bid) { // NOTE: With regards to gdrp consent data, // - the server independently infers gdpr applicability therefore, setting the default value to false -// - the server, at this point, also doesn't need the consent string to handle gdpr compliance. So passing -// value whether set or not, for the sake of future dev. function buildRequests(bidRequests, bidderRequest) { const gdprConsent = Object.assign({ consentString: undefined, @@ -323,8 +321,10 @@ function interpretResponse(serverResponse, bidRequest) { return bidResponses; } -// Register one sync per unique guid -// NOTE: If gdpr applies do not sync +// Register one sync per unique guid so long as iframe is enable +// Else no syncs +// For logic on how we handle gdpr data see _createSyncs and module's unit tests +// '33acrossBidAdapter#getUserSyncs' function getUserSyncs(syncOptions, responses, gdprConsent) { return (syncOptions.iframeEnabled) ? adapterState.uniqueSiteIds.map((siteId) => _createSync({gdprConsent, siteId})) : ([]); } From 0a74fd9783bea13138ef599999bbc531e7305f02 Mon Sep 17 00:00:00 2001 From: Aparna Hegde Date: Tue, 25 Jun 2019 22:12:13 -0400 Subject: [PATCH 3/3] URI encode consent string --- modules/33acrossBidAdapter.js | 14 +++----------- test/spec/modules/33acrossBidAdapter_spec.js | 16 ++++++++-------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/modules/33acrossBidAdapter.js b/modules/33acrossBidAdapter.js index a7c40bfdeab..f53bf8b9d17 100644 --- a/modules/33acrossBidAdapter.js +++ b/modules/33acrossBidAdapter.js @@ -64,7 +64,7 @@ function _getAdSlotHTMLElement(adUnitCode) { // Infer the necessary data from valid bid for a minimal ttxRequest and create HTTP request // NOTE: At this point, TTX only accepts request for a single impression -function _createServerRequest(bidRequest, gdprConsent) { +function _createServerRequest(bidRequest, gdprConsent = {}) { const ttxRequest = {}; const params = bidRequest.params; const element = _getAdSlotHTMLElement(bidRequest.adUnitCode); @@ -151,21 +151,13 @@ function _createSync({siteId, gdprConsent = {}}) { const sync = { type: 'iframe', - url: `${syncUrl}&id=${siteId}` - }; - - const gdprMap = { - 'true': 1, - 'false': 0 + url: `${syncUrl}&id=${siteId}&gdpr_consent=${encodeURIComponent(consentString)}` }; if (typeof gdprApplies === 'boolean') { - const gdpr = gdprMap[gdprApplies.toString()]; - sync.url = `${sync.url}&gdpr=${gdpr}`; + sync.url += `&gdpr=${Number(gdprApplies)}`; } - sync.url = `${sync.url}&gdpr_consent=${consentString}`; - return sync; } diff --git a/test/spec/modules/33acrossBidAdapter_spec.js b/test/spec/modules/33acrossBidAdapter_spec.js index fb8566bb6b0..08ea0a863ee 100644 --- a/test/spec/modules/33acrossBidAdapter_spec.js +++ b/test/spec/modules/33acrossBidAdapter_spec.js @@ -664,11 +664,11 @@ describe('33acrossBidAdapter:', function () { const expectedSyncs = [ { type: 'iframe', - url: `${syncs[0].url}&gdpr=1&gdpr_consent=undefined` + url: `${syncs[0].url}&gdpr_consent=undefined&gdpr=1` }, { type: 'iframe', - url: `${syncs[1].url}&gdpr=1&gdpr_consent=undefined` + url: `${syncs[1].url}&gdpr_consent=undefined&gdpr=1` } ]; @@ -684,11 +684,11 @@ describe('33acrossBidAdapter:', function () { const expectedSyncs = [ { type: 'iframe', - url: `${syncs[0].url}&gdpr=1&gdpr_consent=consent123A` + url: `${syncs[0].url}&gdpr_consent=consent123A&gdpr=1` }, { type: 'iframe', - url: `${syncs[1].url}&gdpr=1&gdpr_consent=consent123A` + url: `${syncs[1].url}&gdpr_consent=consent123A&gdpr=1` } ]; @@ -704,11 +704,11 @@ describe('33acrossBidAdapter:', function () { const expectedSyncs = [ { type: 'iframe', - url: `${syncs[0].url}&gdpr=0&gdpr_consent=undefined` + url: `${syncs[0].url}&gdpr_consent=undefined&gdpr=0` }, { type: 'iframe', - url: `${syncs[1].url}&gdpr=0&gdpr_consent=undefined` + url: `${syncs[1].url}&gdpr_consent=undefined&gdpr=0` } ]; expect(syncResults).to.deep.equal(expectedSyncs); @@ -742,11 +742,11 @@ describe('33acrossBidAdapter:', function () { const expectedSyncs = [ { type: 'iframe', - url: `${syncs[0].url}&gdpr=0&gdpr_consent=consent123A` + url: `${syncs[0].url}&gdpr_consent=consent123A&gdpr=0` }, { type: 'iframe', - url: `${syncs[1].url}&gdpr=0&gdpr_consent=consent123A` + url: `${syncs[1].url}&gdpr_consent=consent123A&gdpr=0` } ]; expect(syncResults).to.deep.equal(expectedSyncs);