Skip to content

Commit

Permalink
Multiple modules: automatically fill in PPID for DFP video URLs (#8365)
Browse files Browse the repository at this point in the history
  • Loading branch information
dgirardi authored May 12, 2022
1 parent 737ef37 commit e47b908
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 16 deletions.
8 changes: 8 additions & 0 deletions modules/dfpAdServerVideo.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { auctionManager } from '../src/auctionManager.js';
import { gdprDataHandler, uspDataHandler } from '../src/adapterManager.js';
import * as events from '../src/events.js';
import CONSTANTS from '../src/constants.json';
import {getPPID} from '../src/adserver.js';

/**
* @typedef {Object} DfpVideoParams
Expand Down Expand Up @@ -118,6 +119,13 @@ export function buildDfpVideoUrl(options) {
const uspConsent = uspDataHandler.getConsentData();
if (uspConsent) { queryParams.us_privacy = uspConsent; }

if (!queryParams.ppid) {
const ppid = getPPID();
if (ppid != null) {
queryParams.ppid = ppid;
}
}

return buildUrl(Object.assign({
protocol: 'https',
host: 'securepubads.g.doubleclick.net',
Expand Down
40 changes: 24 additions & 16 deletions modules/userId/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ import {
timestamp,
isEmpty
} from '../../src/utils.js';
import {getPPID as coreGetPPID} from '../../src/adserver.js';

const MODULE_NAME = 'User ID';
const COOKIE = 'cookie';
Expand Down Expand Up @@ -650,6 +651,19 @@ function idSystemInitializer({delay = delayFor} = {}) {

let initIdSystem;

function getPPID() {
// 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) {
return ppidValue;
} else {
logWarn(`User ID - Googletag Publisher Provided ID for ${ppidSource} is not between 32 and 150 characters - ${ppidValue}`);
}
}
}

/**
* Hook is executed before adapters, but after consentManagement. Consent data is requied because
* this module requires GDPR consent with Purpose #1 to save data locally.
Expand All @@ -666,23 +680,16 @@ export function requestBidsHook(fn, reqBidsConfigObj, {delay = delayFor} = {}) {
]).then(() => {
// 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);
});
}
const ppid = getPPID();
if (ppid) {
if (isGptPubadsDefined()) {
window.googletag.pubads().setPublisherProvidedId(ppid);
} else {
logWarn(`User ID - Googletag Publisher Provided ID for ${ppidSource} is not between 32 and 150 characters - ${ppidValue}`);
window.googletag = window.googletag || {};
window.googletag.cmd = window.googletag.cmd || [];
window.googletag.cmd.push(function() {
window.googletag.pubads().setPublisherProvidedId(ppid);
});
}
}

Expand Down Expand Up @@ -980,6 +987,7 @@ function updateSubmodules() {
if (!addedUserIdHook && submodules.length) {
// priority value 40 will load after consentManagement with a priority of 50
getGlobal().requestBids.before(requestBidsHook, 40);
coreGetPPID.after((next) => next(getPPID()));
logInfo(`${MODULE_NAME} - usersync config updated for ${submodules.length} submodules: `, submodules.map(a => a.submodule.name));
addedUserIdHook = true;
}
Expand Down
7 changes: 7 additions & 0 deletions src/adserver.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { formatQS } from './utils.js';
import { targeting } from './targeting.js';
import {hook} from './hook.js';

// Adserver parent class
const AdServer = function(attr) {
Expand All @@ -11,6 +12,7 @@ const AdServer = function(attr) {
};

// DFP ad server
// TODO: this seems to be unused?
export function dfpAdserver(options, urlComponents) {
var adserver = new AdServer(options);
adserver.urlComponents = urlComponents;
Expand Down Expand Up @@ -53,3 +55,8 @@ export function dfpAdserver(options, urlComponents) {

return adserver;
};

/**
* return the GAM PPID, if available (eid for the userID configured with `userSync.ppidSource`)
*/
export const getPPID = hook('sync', () => undefined);
45 changes: 45 additions & 0 deletions test/spec/modules/dfpAdServerVideo_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { auctionManager } from 'src/auctionManager.js';
import { gdprDataHandler, uspDataHandler } from 'src/adapterManager.js';
import * as adpod from 'modules/adpod.js';
import { server } from 'test/mocks/xhr.js';
import * as adServer from 'src/adserver.js';
import {deepClone} from 'src/utils.js';
import {hook} from '../../../src/hook.js';

const bid = {
videoCacheKey: 'abc',
Expand All @@ -20,6 +23,10 @@ const bid = {
};

describe('The DFP video support module', function () {
before(() => {
hook.ready();
});

it('should make a legal request URL when given the required params', function () {
const url = parse(buildDfpVideoUrl({
adUnit: adUnit,
Expand Down Expand Up @@ -226,6 +233,44 @@ describe('The DFP video support module', function () {
gdprDataHandlerStub.restore();
});

describe('GAM PPID', () => {
let ppid;
let getPPIDStub;
beforeEach(() => {
getPPIDStub = sinon.stub(adServer, 'getPPID').callsFake(() => ppid);
});
afterEach(() => {
getPPIDStub.restore();
});

Object.entries({
'params': {params: {'iu': 'mock/unit'}},
'url': {url: 'https://video.adserver.mock/', params: {'iu': 'mock/unit'}}
}).forEach(([t, opts]) => {
describe(`when using ${t}`, () => {
function buildUrlAndGetParams() {
const url = parse(buildDfpVideoUrl(Object.assign({
adUnit: adUnit,
bid: deepClone(bid),
}, opts)));
return utils.parseQS(url.query);
}

it('should be included if available', () => {
ppid = 'mockPPID';
const q = buildUrlAndGetParams();
expect(q.ppid).to.equal('mockPPID');
});

it('should not be included if not available', () => {
ppid = undefined;
const q = buildUrlAndGetParams();
expect(q.hasOwnProperty('ppid')).to.be.false;
})
})
})
})

describe('special targeting unit test', function () {
const allTargetingData = {
'hb_format': 'video',
Expand Down
18 changes: 18 additions & 0 deletions test/spec/modules/userId_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import * as mockGpt from '../integration/faker/googletag.js';
import 'src/prebid.js';
import {hook} from '../../../src/hook.js';
import {mockGdprConsent} from '../../helpers/consentData.js';
import {getPPID} from '../../../src/adserver.js';

let assert = require('chai').assert;
let expect = require('chai').expect;
Expand Down Expand Up @@ -445,6 +446,23 @@ describe('User ID', function () {
});
});

it('should make PPID available to core', () => {
init(config);
setSubmoduleRegistry([sharedIdSystemSubmodule]);
const id = 'thishastobelongerthan32characters';
config.setConfig({
userSync: {
ppid: 'pubcid.org',
userIds: [
{ name: 'pubCommonId', value: {'pubcid': id} },
]
}
});
return getGlobal().refreshUserIds().then(() => {
expect(getPPID()).to.eql(id);
})
});

describe('refreshing before init is complete', () => {
const MOCK_ID = {'MOCKID': '1111'};
let mockIdCallback;
Expand Down

0 comments on commit e47b908

Please sign in to comment.