Skip to content

Commit

Permalink
Extended ID permissions supported by bidder (prebid#6276)
Browse files Browse the repository at this point in the history
* User id bidder permission scheme

* styling

* prebidServer support

* -

* fix

* prebidServerBidAdapter take eidPermissions directly from userId module

* -

* unit tests

* -

* -

* update

* -

* -

* changed pbjs_bidders to pbjsBidders

* changed pbjsBidders to bidders
ext.prebid.data.eidPermissions to ext.prebid.data.eidpermissions

* rerun circleci

* rerun circleci

* omitting eidPermission entry if 'bidders' is not configured

* fixed 'calling the PBS adapter without any defined userId modules causes an exception'

* proposal

* rerun circleci

* utils implementation

* comment

* revert import validation

Co-authored-by: myerkovich <[email protected]>
Co-authored-by: Marko Yerkovich <[email protected]>
Co-authored-by: Marko Yerkovich <[email protected]>
  • Loading branch information
4 people authored Feb 17, 2021
1 parent 838ede5 commit 3fd2bb5
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 40 deletions.
1 change: 1 addition & 0 deletions integrationExamples/gpt/userId_example.html
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@
},
{
name: "sharedId",
// bidders: ["rubicon", "sampleBidders"], // to allow this ID for specific bidders
params: {
syncTime: 60 // in seconds, default is 24 hours
},
Expand Down
29 changes: 27 additions & 2 deletions modules/prebidServerBidAdapter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import includes from 'core-js-pure/features/array/includes.js';
import { S2S_VENDORS } from './config.js';
import { ajax } from '../../src/ajax.js';
import find from 'core-js-pure/features/array/find.js';
import { getPrebidInternal } from '../../src/utils.js';

const getConfig = config.getConfig;

Expand All @@ -23,6 +24,8 @@ const DEFAULT_S2S_NETREVENUE = true;

let _s2sConfigs;

let eidPermissions;

/**
* @typedef {Object} AdapterOptions
* @summary s2sConfig parameter that adds arguments to resulting OpenRTB payload that goes to Prebid Server
Expand Down Expand Up @@ -459,7 +462,7 @@ export function resetWurlMap() {
}

const OPEN_RTB_PROTOCOL = {
buildRequest(s2sBidRequest, bidRequests, adUnits, s2sConfig) {
buildRequest(s2sBidRequest, bidRequests, adUnits, s2sConfig, requestedBidders) {
let imps = [];
let aliases = {};
const firstBidRequest = bidRequests[0];
Expand Down Expand Up @@ -704,6 +707,17 @@ const OPEN_RTB_PROTOCOL = {
utils.deepSetValue(request, 'user.ext.eids', bidUserIdAsEids);
}

if (utils.isArray(eidPermissions) && eidPermissions.length > 0) {
if (requestedBidders && utils.isArray(requestedBidders)) {
eidPermissions.forEach(i => {
if (i.bidders) {
i.bidders = i.bidders.filter(bidder => requestedBidders.includes(bidder))
}
});
}
utils.deepSetValue(request, 'ext.prebid.data.eidpermissions', eidPermissions);
}

if (bidRequests) {
if (firstBidRequest.gdprConsent) {
// note - gdprApplies & consentString may be undefined in certain use-cases for consentManagement module
Expand Down Expand Up @@ -962,8 +976,9 @@ export function PrebidServer() {
queueSync(syncBidders, gdprConsent, uspConsent, s2sBidRequest.s2sConfig);
}

const request = OPEN_RTB_PROTOCOL.buildRequest(s2sBidRequest, bidRequests, validAdUnits, s2sBidRequest.s2sConfig);
const request = OPEN_RTB_PROTOCOL.buildRequest(s2sBidRequest, bidRequests, validAdUnits, s2sBidRequest.s2sConfig, requestedBidders);
const requestJson = request && JSON.stringify(request);
utils.logInfo('BidRequest: ' + requestJson);
if (request && requestJson) {
ajax(
s2sBidRequest.s2sConfig.endpoint,
Expand Down Expand Up @@ -1021,4 +1036,14 @@ export function PrebidServer() {
});
}

/**
* Global setter that sets eids permissions for bidders
* This setter is to be used by userId module when included
* @param {array} newEidPermissions
*/
function setEidPermissions(newEidPermissions) {
eidPermissions = newEidPermissions;
}
getPrebidInternal().setEidPermissions = setEidPermissions;

adapterManager.registerBidAdapter(new PrebidServer(), 'prebidServer');
22 changes: 22 additions & 0 deletions modules/userId/eids.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,25 @@ export function createEidsArray(bidRequestUserId) {
}
return eids;
}

/**
* @param {SubmoduleContainer[]} submodules
*/
export function buildEidPermissions(submodules) {
let eidPermissions = [];
submodules.filter(i => utils.isPlainObject(i.idObj) && Object.keys(i.idObj).length)
.forEach(i => {
Object.keys(i.idObj).forEach(key => {
if (utils.deepAccess(i, 'config.bidders') && Array.isArray(i.config.bidders) &&
utils.deepAccess(USER_IDS_CONFIG, key + '.source')) {
eidPermissions.push(
{
source: USER_IDS_CONFIG[key].source,
bidders: i.config.bidders
}
);
}
});
});
return eidPermissions;
}
53 changes: 41 additions & 12 deletions modules/userId/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,9 @@ import { getGlobal } from '../../src/prebidGlobal.js';
import { gdprDataHandler } from '../../src/adapterManager.js';
import CONSTANTS from '../../src/constants.json';
import { module, hook } from '../../src/hook.js';
import { createEidsArray } from './eids.js';
import { createEidsArray, buildEidPermissions } from './eids.js';
import { getCoreStorageManager } from '../../src/storageManager.js';
import {getPrebidInternal} from '../../src/utils.js';

const MODULE_NAME = 'User ID';
const COOKIE = 'cookie';
Expand Down Expand Up @@ -215,6 +216,14 @@ export function setStoredValue(submodule, value) {
}
}

function setPrebidServerEidPermissions(initializedSubmodules) {
let setEidPermissions = getPrebidInternal().setEidPermissions;
if (typeof setEidPermissions === 'function' && utils.isArray(initializedSubmodules)) {
setEidPermissions(buildEidPermissions(initializedSubmodules));
}
}

/**
/**
* @param {SubmoduleStorage} storage
* @param {String|undefined} key optional key of the value
Expand Down Expand Up @@ -434,6 +443,26 @@ function getCombinedSubmoduleIds(submodules) {
return combinedSubmoduleIds;
}

/**
* This function will create a combined object for bidder with allowed subModule Ids
* @param {SubmoduleContainer[]} submodules
* @param {string} bidder
*/
function getCombinedSubmoduleIdsForBidder(submodules, bidder) {
if (!Array.isArray(submodules) || !submodules.length || !bidder) {
return {};
}
return submodules
.filter(i => !i.config.bidders || !utils.isArray(i.config.bidders) || i.config.bidders.includes(bidder))
.filter(i => utils.isPlainObject(i.idObj) && Object.keys(i.idObj).length)
.reduce((carry, i) => {
Object.keys(i.idObj).forEach(key => {
carry[key] = i.idObj[key];
});
return carry;
}, {});
}

/**
* @param {AdUnit[]} adUnits
* @param {SubmoduleContainer[]} submodules
Expand All @@ -442,19 +471,18 @@ function addIdDataToAdUnitBids(adUnits, submodules) {
if ([adUnits].some(i => !Array.isArray(i) || !i.length)) {
return;
}
const combinedSubmoduleIds = getCombinedSubmoduleIds(submodules);
const combinedSubmoduleIdsAsEids = createEidsArray(combinedSubmoduleIds);
if (Object.keys(combinedSubmoduleIds).length) {
adUnits.forEach(adUnit => {
if (adUnit.bids && utils.isArray(adUnit.bids)) {
adUnit.bids.forEach(bid => {
adUnits.forEach(adUnit => {
if (adUnit.bids && utils.isArray(adUnit.bids)) {
adUnit.bids.forEach(bid => {
const combinedSubmoduleIds = getCombinedSubmoduleIdsForBidder(submodules, bid.bidder);
if (Object.keys(combinedSubmoduleIds).length) {
// create a User ID object on the bid,
bid.userId = combinedSubmoduleIds;
bid.userIdAsEids = combinedSubmoduleIdsAsEids;
});
}
});
}
bid.userIdAsEids = createEidsArray(combinedSubmoduleIds);
}
});
}
});
}

/**
Expand All @@ -467,6 +495,7 @@ function initializeSubmodulesAndExecuteCallbacks(continueAuction) {
if (typeof initializedSubmodules === 'undefined') {
initializedSubmodules = initSubmodules(submodules, gdprDataHandler.getConsentData());
if (initializedSubmodules.length) {
setPrebidServerEidPermissions(initializedSubmodules);
// list of submodules that have callbacks that need to be executed
const submodulesWithCallbacks = initializedSubmodules.filter(item => utils.isFn(item.callback));

Expand Down
8 changes: 8 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ export const internal = {
deepEqual
};

let prebidInternal = {}
/**
* Returns object that is used as internal prebid namespace
*/
export function getPrebidInternal() {
return prebidInternal;
}

var uniqueRef = {};
export let bind = function(a, b) { return b; }.bind(null, 1, uniqueRef)() === uniqueRef
? Function.prototype.bind
Expand Down
46 changes: 21 additions & 25 deletions test/spec/modules/prebidServerBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -953,17 +953,15 @@ describe('S2S Adapter', function () {
adapter.callBids(request, BID_REQUESTS, addBidResponse, done, ajax);

const requestBid = JSON.parse(server.requests[0].requestBody);

expect(requestBid.ext).to.deep.equal({
prebid: {
aliases: {
brealtime: 'appnexus'
},
auctiontimestamp: 1510852447530,
targeting: {
includebidderkeys: false,
includewinners: true
}
expect(requestBid.ext).to.haveOwnProperty('prebid');
expect(requestBid.ext.prebid).to.deep.include({
aliases: {
brealtime: 'appnexus'
},
auctiontimestamp: 1510852447530,
targeting: {
includebidderkeys: false,
includewinners: true
}
});
});
Expand All @@ -985,17 +983,15 @@ describe('S2S Adapter', function () {
adapter.callBids(request, BID_REQUESTS, addBidResponse, done, ajax);

const requestBid = JSON.parse(server.requests[0].requestBody);

expect(requestBid.ext).to.deep.equal({
prebid: {
aliases: {
[alias]: 'appnexus'
},
auctiontimestamp: 1510852447530,
targeting: {
includebidderkeys: false,
includewinners: true
}
expect(requestBid.ext).to.haveOwnProperty('prebid');
expect(requestBid.ext.prebid).to.deep.include({
aliases: {
[alias]: 'appnexus'
},
auctiontimestamp: 1510852447530,
targeting: {
includebidderkeys: false,
includewinners: true
}
});
});
Expand Down Expand Up @@ -1376,7 +1372,7 @@ describe('S2S Adapter', function () {

expect(requestBid).to.haveOwnProperty('ext');
expect(requestBid.ext).to.haveOwnProperty('prebid');
expect(requestBid.ext.prebid).to.deep.equal({
expect(requestBid.ext.prebid).to.deep.include({
auctiontimestamp: 1510852447530,
foo: 'bar',
targeting: {
Expand Down Expand Up @@ -1410,7 +1406,7 @@ describe('S2S Adapter', function () {

expect(requestBid).to.haveOwnProperty('ext');
expect(requestBid.ext).to.haveOwnProperty('prebid');
expect(requestBid.ext.prebid).to.deep.equal({
expect(requestBid.ext.prebid).to.deep.include({
auctiontimestamp: 1510852447530,
targeting: {
includewinners: false,
Expand Down Expand Up @@ -1446,7 +1442,7 @@ describe('S2S Adapter', function () {

expect(requestBid).to.haveOwnProperty('ext');
expect(requestBid.ext).to.haveOwnProperty('prebid');
expect(requestBid.ext.prebid).to.deep.equal({
expect(requestBid.ext.prebid).to.deep.include({
auctiontimestamp: 1510852447530,
cache: {
vastxml: 'vastxml-set-though-extPrebid.cache.vastXml'
Expand Down
Loading

0 comments on commit 3fd2bb5

Please sign in to comment.