From 664f2846fd0969cb7f7ca5f2fb40b7b4f886538f Mon Sep 17 00:00:00 2001 From: Robert Ray Martinez III Date: Thu, 18 Nov 2021 09:12:54 -0800 Subject: [PATCH] UserID Module: allow userid to ppid sync (#7681) * sync PPID with googletag * dont need to export * add log warning if not right length --- modules/userId/index.js | 29 +++++++++++++- test/spec/integration/faker/googletag.js | 6 +++ test/spec/modules/userId_spec.js | 51 ++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) diff --git a/modules/userId/index.js b/modules/userId/index.js index b0293a9c26a..42fff2cd16c 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -141,7 +141,7 @@ import { createEidsArray, buildEidPermissions } from './eids.js'; import { getCoreStorageManager } from '../../src/storageManager.js'; import { getPrebidInternal, isPlainObject, logError, isArray, cyrb53Hash, deepAccess, timestamp, delayExecution, logInfo, isFn, - logWarn, isEmptyStr, isNumber + logWarn, isEmptyStr, isNumber, isGptPubadsDefined } from '../../src/utils.js'; import includes from 'core-js-pure/features/array/includes.js'; @@ -184,6 +184,9 @@ export let syncDelay; /** @type {(number|undefined)} */ export let auctionDelay; +/** @type {(string|undefined)} */ +let ppidSource; + /** @param {Submodule[]} submodules */ export function setSubmoduleRegistry(submodules) { submoduleRegistry = submodules; @@ -557,6 +560,26 @@ export function requestBidsHook(fn, reqBidsConfigObj) { initializeSubmodulesAndExecuteCallbacks(function () { // pass available user id data to bid adapters addIdDataToAdUnitBids(reqBidsConfigObj.adUnits || getGlobal().adUnits, initializedSubmodules); + + // userSync.ppid should be one of the 'source' values in getUserIdsAsEids() eg pubcid.org or id5-sync.com + const matchingUserId = ppidSource && (getUserIdsAsEids() || []).find(userID => userID.source === ppidSource); + if (matchingUserId && typeof deepAccess(matchingUserId, 'uids.0.id') === 'string') { + const ppidValue = matchingUserId.uids[0].id.replace(/[\W_]/g, ''); + if (ppidValue.length >= 32 && ppidValue.length <= 150) { + if (isGptPubadsDefined()) { + window.googletag.pubads().setPublisherProvidedId(ppidValue); + } else { + window.googletag = window.googletag || {}; + window.googletag.cmd = window.googletag.cmd || []; + window.googletag.cmd.push(function() { + window.googletag.pubads().setPublisherProvidedId(ppidValue); + }); + } + } else { + logWarn(`User ID - Googletag Publisher Provided ID for ${ppidSource} is not between 32 and 150 characters - ${ppidValue}`); + } + } + // calling fn allows prebid to continue processing fn.call(this, reqBidsConfigObj); }); @@ -817,6 +840,7 @@ export function attachIdSystem(submodule) { * @param {{getConfig:function}} config */ export function init(config) { + ppidSource = undefined; submodules = []; configRegistry = []; addedUserIdHook = false; @@ -839,9 +863,10 @@ export function init(config) { } // listen for config userSyncs to be set - config.getConfig(conf => { + config.getConfig('userSync', conf => { // Note: support for 'usersync' was dropped as part of Prebid.js 4.0 const userSync = conf.userSync; + ppidSource = userSync.ppid; if (userSync && userSync.userIds) { configRegistry = userSync.userIds; syncDelay = isNumber(userSync.syncDelay) ? userSync.syncDelay : DEFAULT_SYNC_DELAY; diff --git a/test/spec/integration/faker/googletag.js b/test/spec/integration/faker/googletag.js index 1d1a7512153..a8676b500a5 100644 --- a/test/spec/integration/faker/googletag.js +++ b/test/spec/integration/faker/googletag.js @@ -51,9 +51,15 @@ export function enable() { window.googletag = { _slots: [], _callbackMap: {}, + _ppid: undefined, + cmd: [], pubads: function () { var self = this; return { + setPublisherProvidedId: function (ppid) { + self._ppid = ppid; + }, + getSlots: function () { return self._slots; }, diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index 0190bceca70..29b5aca630e 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -49,6 +49,7 @@ import {flocIdSubmodule} from 'modules/flocIdSystem.js' import {amxIdSubmodule} from '../../../modules/amxIdSystem.js'; import {akamaiDAPIdSubmodule} from 'modules/akamaiDAPIdSystem.js' import {kinessoIdSubmodule} from 'modules/kinessoIdSystem.js' +import * as mockGpt from '../integration/faker/googletag.js'; let assert = require('chai').assert; let expect = require('chai').expect; @@ -114,15 +115,21 @@ describe('User ID', function () { describe('Decorate Ad Units', function () { beforeEach(function () { + // reset mockGpt so nothing else interferes + mockGpt.disable(); + mockGpt.enable(); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('pubcid_alt', 'altpubcid200000', (new Date(Date.now() + 5000).toUTCString())); sinon.spy(coreStorage, 'setCookie'); + sinon.stub(utils, 'logWarn'); }); afterEach(function () { + mockGpt.enable(); $$PREBID_GLOBAL$$.requestBids.removeAll(); config.resetConfig(); coreStorage.setCookie.restore(); + utils.logWarn.restore(); }); after(function () { @@ -321,6 +328,50 @@ describe('User ID', function () { expect((getGlobal()).getUserIdsAsEids()).to.deep.equal(createEidsArray((getGlobal()).getUserIds())); }); + it('should set googletag ppid correctly', function () { + let adUnits = [getAdUnitMock()]; + setSubmoduleRegistry([amxIdSubmodule, sharedIdSystemSubmodule, identityLinkSubmodule]); + init(config); + + config.setConfig({ + userSync: { + ppid: 'pubcid.org', + userIds: [ + { name: 'amxId', value: {'amxId': 'amx-id-value-amx-id-value-amx-id-value'} }, + { name: 'pubCommonId', value: {'pubcid': 'pubCommon-id-value-pubCommon-id-value'} }, + { name: 'identityLink', value: {'idl_env': 'identityLink-id-value-identityLink-id-value'} }, + ] + } + }); + // before ppid should not be set + expect(window.googletag._ppid).to.equal(undefined); + requestBidsHook(() => {}, {adUnits}); + // ppid should have been set without dashes and stuff + expect(window.googletag._ppid).to.equal('pubCommonidvaluepubCommonidvalue'); + }); + + it('should log a warning if PPID too big or small', function () { + let adUnits = [getAdUnitMock()]; + setSubmoduleRegistry([sharedIdSystemSubmodule]); + init(config); + + config.setConfig({ + userSync: { + ppid: 'pubcid.org', + userIds: [ + { name: 'pubCommonId', value: {'pubcid': 'pubcommonIdValue'} }, + ] + } + }); + // before ppid should not be set + expect(window.googletag._ppid).to.equal(undefined); + requestBidsHook(() => {}, {adUnits}); + // ppid should NOT have been set + expect(window.googletag._ppid).to.equal(undefined); + // a warning should have been emmited + expect(utils.logWarn.args[0][0]).to.exist.and.to.contain('User ID - Googletag Publisher Provided ID for pubcid.org is not between 32 and 150 characters - pubcommonIdValue'); + }); + it('pbjs.refreshUserIds refreshes', function() { let sandbox = sinon.createSandbox();