From e3c749f25b68bf59a4a17d04e9d695c8cda97b80 Mon Sep 17 00:00:00 2001 From: Zac Carlin Date: Wed, 8 Mar 2023 16:54:43 -0500 Subject: [PATCH 1/6] Add intentIq Id to trinity request. --- modules/sonobiBidAdapter.js | 92 +++++++++++++++++++++- test/spec/modules/sonobiBidAdapter_spec.js | 8 ++ 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index 87358705cb5..9291a8b8b74 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -4,6 +4,7 @@ import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; import { userSync } from '../src/userSync.js'; +import { bidderSettings } from '../src/bidderSettings.js'; const BIDDER_CODE = 'sonobi'; const STR_ENDPOINT = 'https://apex.go.sonobi.com/trinity.json'; const PAGEVIEW_ID = generateUUID(); @@ -49,6 +50,7 @@ export const spec = { return true; }, + /** * Make a server request from the list of BidRequests. * @@ -93,7 +95,7 @@ export const spec = { 'lib_name': 'prebid', 'lib_v': '$prebid.version$', 'us': 0, - + 'iqid': bidderSettings.get(BIDDER_CODE, 'storageAllowed') ? (loadOrCreateFirstPartyData()).pcid : null, }; const fpd = bidderRequest.ortb2; @@ -388,6 +390,94 @@ export function _getPlatform(context = window) { } return 'desktop'; } +/** + * Check for local storage + * Generate a UUID for the user if one does not exist in local storage + * Store the UUID in local storage for future use + * @return {object} firstPartyData - Data object containing first party information + */ +function loadOrCreateFirstPartyData() { + var localStorageEnabled; + // var wasDebugCheck = false; + // var isDebugMode = false; + var FIRST_PARTY_KEY = '_iiq_fdata'; + // var isDebug = function () { + // if (!wasDebugCheck) { + // if (hasLocalStorage()) { + // var dbgValue = readData('_iiq_debug_level'); + // if (dbgValue !== null) { + // isDebugMode = true; + // } + // } + // wasDebugCheck = true; + // } + // return isDebugMode; + // }; + var logger = function (msg) { + // if (isDebug()) { console.log('IIQ ' + '%c' + msg, 'color: yellow ; background-color: blue; border-radius: 3px'); } + }; + var tryParse = function (data) { + try { + return JSON.parse(data); + } catch (err) { + logger(err); + } + return null; + }; + var readData = function (key) { + try { + if (hasLocalStorage()) { + return window.localStorage.getItem(key); + } + } catch (error) { + logger(error); + } + return null; + }; + var hasLocalStorage = function () { + if (typeof localStorageEnabled != 'undefined') { return localStorageEnabled; } else { + try { + localStorageEnabled = !!window.localStorage; + return localStorageEnabled; + } catch (e) { + localStorageEnabled = false; + logger('Local storage api disabled'); + } + } + return false; + }; + var generateGUID = function () { + var d = new Date().getTime(); + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16); + }); + }; + var storeData = function (key, value) { + try { + if (typeof key === 'string' && key.startsWith('_iiq_fdata')) { + logger('IntentIQ: storing data: key=' + key + ' value=' + value); + if (value && hasLocalStorage()) { + window.localStorage.setItem(key, value); + } + } + } catch (error) { + logger(error); + } + }; + var firstPartyData = tryParse(readData(FIRST_PARTY_KEY)); + if (!firstPartyData || !firstPartyData.pcid) { + logger('Generetaing new key.'); + var firstPartyId = generateGUID(); + firstPartyData = { pcid: firstPartyId, pcidDate: Date.now() }; + } else if (firstPartyData && !firstPartyData.pcidDate) { + logger('Key retreived. Adding timestamp.'); + firstPartyData.pcidDate = Date.now(); + } + storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData)); + return firstPartyData; +}; function newRenderer(adUnitCode, bid, rendererOptions = {}) { const renderer = Renderer.install({ diff --git a/test/spec/modules/sonobiBidAdapter_spec.js b/test/spec/modules/sonobiBidAdapter_spec.js index 56ed4d5196e..8cb00ebb2bc 100644 --- a/test/spec/modules/sonobiBidAdapter_spec.js +++ b/test/spec/modules/sonobiBidAdapter_spec.js @@ -238,6 +238,13 @@ describe('SonobiBidAdapter', function () { }); describe('.buildRequests', function () { + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + sonobi: { + storageAllowed: true + } + }; + }); let sandbox; beforeEach(function () { sinon.stub(userSync, 'canBidderRegisterSync'); @@ -398,6 +405,7 @@ describe('SonobiBidAdapter', function () { expect(bidRequests.data.ref).not.to.be.empty expect(bidRequests.data.s).not.to.be.empty expect(bidRequests.data.pv).to.equal(bidRequestsPageViewID.data.pv) + expect(bidRequests.data.iqid).to.match(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/) expect(bidRequests.data.hfa).to.not.exist expect(bidRequests.bidderRequests).to.eql(bidRequest); expect(bidRequests.data.ref).to.equal('overrides_top_window_location'); From 8e5bded7235f67c20d58a4420fb8a71005304f70 Mon Sep 17 00:00:00 2001 From: Zac Carlin Date: Wed, 8 Mar 2023 17:12:15 -0500 Subject: [PATCH 2/6] Minimized function to needed components. --- modules/sonobiBidAdapter.js | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index 9291a8b8b74..b70aea50a15 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -398,39 +398,18 @@ export function _getPlatform(context = window) { */ function loadOrCreateFirstPartyData() { var localStorageEnabled; - // var wasDebugCheck = false; - // var isDebugMode = false; + var FIRST_PARTY_KEY = '_iiq_fdata'; - // var isDebug = function () { - // if (!wasDebugCheck) { - // if (hasLocalStorage()) { - // var dbgValue = readData('_iiq_debug_level'); - // if (dbgValue !== null) { - // isDebugMode = true; - // } - // } - // wasDebugCheck = true; - // } - // return isDebugMode; - // }; - var logger = function (msg) { - // if (isDebug()) { console.log('IIQ ' + '%c' + msg, 'color: yellow ; background-color: blue; border-radius: 3px'); } - }; var tryParse = function (data) { try { return JSON.parse(data); } catch (err) { - logger(err); + return null; } - return null; }; var readData = function (key) { - try { - if (hasLocalStorage()) { - return window.localStorage.getItem(key); - } - } catch (error) { - logger(error); + if (hasLocalStorage()) { + return window.localStorage.getItem(key); } return null; }; @@ -441,7 +420,6 @@ function loadOrCreateFirstPartyData() { return localStorageEnabled; } catch (e) { localStorageEnabled = false; - logger('Local storage api disabled'); } } return false; @@ -457,22 +435,19 @@ function loadOrCreateFirstPartyData() { var storeData = function (key, value) { try { if (typeof key === 'string' && key.startsWith('_iiq_fdata')) { - logger('IntentIQ: storing data: key=' + key + ' value=' + value); if (value && hasLocalStorage()) { window.localStorage.setItem(key, value); } } } catch (error) { - logger(error); + } }; var firstPartyData = tryParse(readData(FIRST_PARTY_KEY)); if (!firstPartyData || !firstPartyData.pcid) { - logger('Generetaing new key.'); var firstPartyId = generateGUID(); firstPartyData = { pcid: firstPartyId, pcidDate: Date.now() }; } else if (firstPartyData && !firstPartyData.pcidDate) { - logger('Key retreived. Adding timestamp.'); firstPartyData.pcidDate = Date.now(); } storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData)); From cc004ba0426c31fdf7ee58de4c0a23c3f32da255 Mon Sep 17 00:00:00 2001 From: Zac Carlin Date: Thu, 9 Mar 2023 15:27:21 -0500 Subject: [PATCH 3/6] Added return statemen. --- modules/sonobiBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index b70aea50a15..e2a9722868b 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -440,7 +440,7 @@ function loadOrCreateFirstPartyData() { } } } catch (error) { - + return; } }; var firstPartyData = tryParse(readData(FIRST_PARTY_KEY)); From 8a17e2c6e92a22e225cfcbb90865bb14e7521337 Mon Sep 17 00:00:00 2001 From: Zac Carlin Date: Thu, 9 Mar 2023 16:06:01 -0500 Subject: [PATCH 4/6] Fixed return statement linter rule. --- modules/sonobiBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index e2a9722868b..b70aea50a15 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -440,7 +440,7 @@ function loadOrCreateFirstPartyData() { } } } catch (error) { - return; + } }; var firstPartyData = tryParse(readData(FIRST_PARTY_KEY)); From 8b720dd429b9e3ed01268841809012e6eac5a4f8 Mon Sep 17 00:00:00 2001 From: Zac Carlin Date: Wed, 22 Mar 2023 13:40:23 -0400 Subject: [PATCH 5/6] Changes suggested in PR review. --- modules/sonobiBidAdapter.js | 8 +++----- test/spec/modules/sonobiBidAdapter_spec.js | 4 ++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index b70aea50a15..46b8346873a 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -434,13 +434,11 @@ function loadOrCreateFirstPartyData() { }; var storeData = function (key, value) { try { - if (typeof key === 'string' && key.startsWith('_iiq_fdata')) { - if (value && hasLocalStorage()) { - window.localStorage.setItem(key, value); - } + if (hasLocalStorage()) { + window.localStorage.setItem(key, value); } } catch (error) { - + return null; } }; var firstPartyData = tryParse(readData(FIRST_PARTY_KEY)); diff --git a/test/spec/modules/sonobiBidAdapter_spec.js b/test/spec/modules/sonobiBidAdapter_spec.js index 8cb00ebb2bc..792ec8f7983 100644 --- a/test/spec/modules/sonobiBidAdapter_spec.js +++ b/test/spec/modules/sonobiBidAdapter_spec.js @@ -396,6 +396,10 @@ describe('SonobiBidAdapter', function () { expect(bidRequests.data.coppa).to.equal(0); }); + it('should have storageAllowed set to true', function () { + expect($$PREBID_GLOBAL$$.bidderSettings.sonobi.storageAllowed).to.be.true; + }); + it('should return a properly formatted request', function () { const bidRequests = spec.buildRequests(bidRequest, bidderRequests) const bidRequestsPageViewID = spec.buildRequests(bidRequest, bidderRequests) From bc1c2bbd352766720ca9b042d5d4e215b7ed9955 Mon Sep 17 00:00:00 2001 From: Zac Carlin Date: Thu, 23 Mar 2023 16:32:45 -0400 Subject: [PATCH 6/6] Added date to trinity request. Updated tests. --- modules/sonobiBidAdapter.js | 2 +- test/spec/modules/sonobiBidAdapter_spec.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index 46b8346873a..6760a3c18ab 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -95,7 +95,7 @@ export const spec = { 'lib_name': 'prebid', 'lib_v': '$prebid.version$', 'us': 0, - 'iqid': bidderSettings.get(BIDDER_CODE, 'storageAllowed') ? (loadOrCreateFirstPartyData()).pcid : null, + 'iqid': bidderSettings.get(BIDDER_CODE, 'storageAllowed') ? JSON.stringify(loadOrCreateFirstPartyData()) : null, }; const fpd = bidderRequest.ortb2; diff --git a/test/spec/modules/sonobiBidAdapter_spec.js b/test/spec/modules/sonobiBidAdapter_spec.js index 792ec8f7983..b9bd0dc4d9f 100644 --- a/test/spec/modules/sonobiBidAdapter_spec.js +++ b/test/spec/modules/sonobiBidAdapter_spec.js @@ -409,7 +409,8 @@ describe('SonobiBidAdapter', function () { expect(bidRequests.data.ref).not.to.be.empty expect(bidRequests.data.s).not.to.be.empty expect(bidRequests.data.pv).to.equal(bidRequestsPageViewID.data.pv) - expect(bidRequests.data.iqid).to.match(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/) + expect(JSON.parse(bidRequests.data.iqid).pcid).to.match(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/) + expect(JSON.parse(bidRequests.data.iqid).pcidDate).to.match(/^[0-9]{13}$/) expect(bidRequests.data.hfa).to.not.exist expect(bidRequests.bidderRequests).to.eql(bidRequest); expect(bidRequests.data.ref).to.equal('overrides_top_window_location');