Skip to content

Commit

Permalink
event updates
Browse files Browse the repository at this point in the history
  • Loading branch information
idettman committed May 22, 2020
1 parent 67a1b1e commit fcdcd0c
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 12 deletions.
90 changes: 79 additions & 11 deletions modules/prebidServerBidAdapter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,10 +366,43 @@ let nativeEventTrackerMethodMap = {
*/
let bidIdMap = {};
let nativeAssetCache = {}; // store processed native params to preserve

/**
* map wurl to auction id and adId for use in the BID_WON event
*/
let wurlMap = {};

/**
* @param {string} auctionId the id representing the auction
* @param {string} adId generated value set to bidObject.adId by bidderFactory Bid()
* @param {string} wurl events.winurl passed from prebidServer as wurl
*/
function addWurl(auctionId, adId, wurl) {
wurlMap[`${auctionId}${adId}`] = wurl;
}

/**
* @param {string} auctionId the id representing the auction
* @param {string} adId generated value set to bidObject.adId by bidderFactory Bid()
* @param {string} wurl events.winurl passed from prebidServer as wurl
*/
function removeWurl(auctionId, adId) {
wurlMap[`${auctionId}${adId}`] = undefined;
}
/**
* @param {string} auctionId the id representing the auction
* @param {string} adId generated value set to bidObject.adId by bidderFactory Bid()
* @return {(string|undefined)} events.winurl which was passed as wurl
*/
function getWurl(auctionId, adId) {
return wurlMap[`${auctionId}${adId}`];
}

const OPEN_RTB_PROTOCOL = {
buildRequest(s2sBidRequest, bidRequests, adUnits) {
let imps = [];
let aliases = {};
const firstBidRequest = bidRequests[0];

// transform ad unit into array of OpenRTB impression objects
adUnits.forEach(adUnit => {
Expand Down Expand Up @@ -515,14 +548,14 @@ const OPEN_RTB_PROTOCOL = {
* @type {(string|undefined)}
*/
const pbAdSlot = utils.deepAccess(adUnit, 'fpd.context.pbAdSlot');
if (typeof pbAdSlot === 'string' && pbAdSlot) {
if (typeof pbAdSlot === 'string' && !utils.isEmptyStr(pbAdSlot)) {
utils.deepSetValue(imp, 'ext.context.data.adslot', pbAdSlot);
}

Object.assign(imp, mediaTypes);

// if storedAuctionResponse has been set, pass SRID
const storedAuctionResponseBid = find(bidRequests[0].bids, bid => (bid.adUnitCode === adUnit.code && bid.storedAuctionResponse));
const storedAuctionResponseBid = find(firstBidRequest.bids, bid => (bid.adUnitCode === adUnit.code && bid.storedAuctionResponse));
if (storedAuctionResponseBid) {
utils.deepSetValue(imp, 'ext.prebid.storedauctionresponse.id', storedAuctionResponseBid.storedAuctionResponse.toString());
}
Expand All @@ -544,6 +577,8 @@ const OPEN_RTB_PROTOCOL = {
test: getConfig('debug') ? 1 : 0,
ext: {
prebid: {
// set ext.prebid.auctiontimestamp with the auction timestamp. Data type is long integer.
auctiontimestamp: firstBidRequest.auctionStart,
targeting: {
// includewinners is always true for openrtb
includewinners: true,
Expand Down Expand Up @@ -571,9 +606,9 @@ const OPEN_RTB_PROTOCOL = {
request.cur = [adServerCur[0]];
}

_appendSiteAppDevice(request, bidRequests[0].refererInfo.referer);
_appendSiteAppDevice(request, firstBidRequest.refererInfo.referer);

const digiTrust = _getDigiTrustQueryParams(bidRequests && bidRequests[0]);
const digiTrust = _getDigiTrustQueryParams(firstBidRequest);
if (digiTrust) {
utils.deepSetValue(request, 'user.ext.digitrust', digiTrust);
}
Expand All @@ -596,19 +631,19 @@ const OPEN_RTB_PROTOCOL = {
}

if (bidRequests) {
if (bidRequests[0].gdprConsent) {
if (firstBidRequest.gdprConsent) {
// note - gdprApplies & consentString may be undefined in certain use-cases for consentManagement module
let gdprApplies;
if (typeof bidRequests[0].gdprConsent.gdprApplies === 'boolean') {
gdprApplies = bidRequests[0].gdprConsent.gdprApplies ? 1 : 0;
if (typeof firstBidRequest.gdprConsent.gdprApplies === 'boolean') {
gdprApplies = firstBidRequest.gdprConsent.gdprApplies ? 1 : 0;
}
utils.deepSetValue(request, 'regs.ext.gdpr', gdprApplies);
utils.deepSetValue(request, 'user.ext.consent', bidRequests[0].gdprConsent.consentString);
utils.deepSetValue(request, 'user.ext.consent', firstBidRequest.gdprConsent.consentString);
}

// US Privacy (CCPA) support
if (bidRequests[0].uspConsent) {
utils.deepSetValue(request, 'regs.ext.us_privacy', bidRequests[0].uspConsent);
if (firstBidRequest.uspConsent) {
utils.deepSetValue(request, 'regs.ext.us_privacy', firstBidRequest.uspConsent);
}
}

Expand Down Expand Up @@ -658,10 +693,26 @@ const OPEN_RTB_PROTOCOL = {
bidRequest.serverResponseTimeMs = serverResponseTimeMs;
}

const extPrebidTargeting = utils.deepAccess(bid, 'ext.prebid.targeting');
// Look for seatbid[].bid[].ext.prebid.bidid and place it in the bidResponse object for use in analytics adapters as 'pbsBidId'
const bidId = utils.deepAccess(bid, 'ext.prebid.bidid');
if (typeof bidId === 'string' && !utils.isEmptyStr(bidId)) {
bidObject.pbsBidId = bidId;
}

// store wurl by auctionId and adId so it can be access from the BID_WON event handler
if (typeof bid.wurl === 'string' && !utils.isEmptyStr(bid.wurl)) {
addWurl(bidRequest.auctionId, bidObject.adId, bid.wurl);
}

let extPrebidTargeting = utils.deepAccess(bid, 'ext.prebid.targeting');

// If ext.prebid.targeting exists, add it as a property value named 'adserverTargeting'
if (extPrebidTargeting && typeof extPrebidTargeting === 'object') {
// If wurl exists, remove hb_winurl and hb_bidid targeting attributes
if (bid.wurl) {
extPrebidTargeting = utils.getDefinedParams(extPrebidTargeting, Object.keys(extPrebidTargeting)
.filter(i => (i.indexOf('hb_winurl') === -1 && i.indexOf('hb_bidid') === -1)));
}
bidObject.adserverTargeting = extPrebidTargeting;
}

Expand Down Expand Up @@ -773,6 +824,20 @@ const OPEN_RTB_PROTOCOL = {
}
};

/**
* BID_WON event to request the wurl
* @param {Bid} args the winning bid object
*/
function bidWonHandler(args) {
const wurl = getWurl(args.auctionId, args.adId);
if (typeof wurl === 'string' && !utils.isEmptyStr(wurl)) {
// can remove array item after calling the wurl
removeWurl(args.auctionId, args.adId);
utils.logMessage(`Invoking image pixel for wurl on BID_WIN: "${wurl}"`);
utils.triggerPixel(wurl);
}
}

/**
* Bidder adapter for Prebid Server
*/
Expand Down Expand Up @@ -856,6 +921,9 @@ export function PrebidServer() {
doClientSideSyncs(requestedBidders);
}

// Listen for bid won to call wurl
events.on(EVENTS.BID_WON, bidWonHandler);

return Object.assign(this, {
callBids: baseAdapter.callBids,
setBidderCode: baseAdapter.setBidderCode,
Expand Down
2 changes: 1 addition & 1 deletion modules/rubiconAnalyticsAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ function sendMessage(auctionId, bidWonId) {
function formatBid(bid) {
return utils.pick(bid, [
'bidder',
'bidId', bidId => utils.deepAccess(bid, 'bidResponse.seatBidId') || bidId,
'bidId', bidId => utils.deepAccess(bid, 'bidResponse.pbsBidId') || utils.deepAccess(bid, 'bidResponse.seatBidId') || bidId,
'status',
'error',
'source', (source, bid) => {
Expand Down
3 changes: 3 additions & 0 deletions modules/rubiconBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,9 @@ export const spec = {
utils.deepSetValue(data.imp[0], 'ext.prebid.storedauctionresponse.id', bidRequest.storedAuctionResponse.toString());
}

// set ext.prebid.auctiontimestamp using auction time
utils.deepSetValue(data.imp[0], 'ext.prebid.auctiontimestamp', bidderRequest.auctionStart);

return {
method: 'POST',
url: VIDEO_ENDPOINT,
Expand Down
129 changes: 129 additions & 0 deletions test/spec/modules/prebidServerBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ const RESPONSE_OPENRTB = {
'adm': '<script src="http://lax1-ib.adnxs.com/ab?e=wqT_3QKgB6CgAwAAAwDWAAUBCJ7kvtMFEPft7JnIuImSdBj87IDv8q21rXcqNgkAAAECCOA_EQEHNAAA4D8ZAAAAgOtR4D8hERIAKREJADERG6Aw8ub8BDi-B0C-B0gCUNbLkw5Y4YBIYABokUB48NIEgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAsABA8gBAtABCdgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNTE3MjY5NTM0KTt1ZigncicsIDI5NjgxMTEwLDIeAPCckgKBAiFqRHF3RUFpNjBJY0VFTmJMa3c0WUFDRGhnRWd3QURnQVFBUkl2Z2RROHViOEJGZ0FZUF9fX184UGFBQndBWGdCZ0FFQmlBRUJrQUVCbUFFQm9BRUJxQUVEc0FFQXVRRXBpNGlEQUFEZ1A4RUJLWXVJZ3dBQTREX0pBVkx3MU5mdl9lMF8yUUVBQUFBQUFBRHdQLUFCQVBVQgUPKEpnQ0FLQUNBTFVDBRAETDAJCPBUTUFDQWNnQ0FkQUNBZGdDQWVBQ0FPZ0NBUGdDQUlBREFaQURBSmdEQWFnRHV0Q0hCTG9ERVdSbFptRjFiSFFqVEVGWU1Ub3pPRFk1mgI5IS1ndndfUTYEAfCENFlCSUlBUW9BRG9SWkdWbVlYVnNkQ05NUVZneE9qTTROamsu2ALoB-ACx9MB6gJHaHR0cDovL3ByZWJpZC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2dwdC9hcHBuZXh1cy10ZXN0Lmh0bWzyAhAKBkFEVl9JRBIGNCXTHPICEQoGQ1BHARM4BzE5Nzc5MzPyAhAKBUNQBRPwljg1MTM1OTSAAwGIAwGQAwCYAxSgAwGqAwDAA6wCyAMA2AMA4AMA6AMA-AMDgAQAkgQJL29wZW5ydGIymAQAogQMMjE2LjU1LjQ3Ljk0qAQAsgQMCAAQABgAIAAwADgAuAQAwAQAyAQA0gQRZGVmYXVsdCNMQVgxOjM4NjnaBAIIAeAEAPAE1suTDogFAZgFAKAF______8BA7ABqgUkYzdkY2YxNGYtZjliYS00Yzc3LWEzYjQtMjdmNmRmMzkwNjdmwAUAyQVpLhTwP9IFCQkJDFAAANgFAeAFAfAFAfoFBAgAEACQBgA.&s=f4dc8b6fa65845d08f0a87c145e12cb7d6288c2a&referrer=http%3A%2F%2Fprebid.localhost%3A9999%2FintegrationExamples%2Fgpt%2Fappnexus-test.html&pp=${AUCTION_PRICE}"></script>',
'adid': '29681110',
'adomain': ['appnexus.com'],
'wurl': 'http://wurl.org?id=333',
'iurl': 'http://lax1-ib.adnxs.com/cr?id=2968111',
'cid': '958',
'crid': '2968111',
Expand Down Expand Up @@ -304,6 +305,7 @@ const RESPONSE_OPENRTB_VIDEO = {
ext: {
prebid: {
type: 'video',
bidid: '654321'
},
bidder: {
appnexus: {
Expand Down Expand Up @@ -955,6 +957,7 @@ describe('S2S Adapter', function () {
aliases: {
brealtime: 'appnexus'
},
auctiontimestamp: 1510852447530,
targeting: {
includebidderkeys: false,
includewinners: true
Expand Down Expand Up @@ -989,6 +992,7 @@ describe('S2S Adapter', function () {
aliases: {
[alias]: 'appnexus'
},
auctiontimestamp: 1510852447530,
targeting: {
includebidderkeys: false,
includewinners: true
Expand Down Expand Up @@ -1240,6 +1244,7 @@ describe('S2S Adapter', function () {
expect(requestBid).to.haveOwnProperty('ext');
expect(requestBid.ext).to.haveOwnProperty('prebid');
expect(requestBid.ext.prebid).to.deep.equal({
auctiontimestamp: 1510852447530,
foo: 'bar',
targeting: {
includewinners: true,
Expand Down Expand Up @@ -1271,6 +1276,7 @@ describe('S2S Adapter', function () {
expect(requestBid).to.haveOwnProperty('ext');
expect(requestBid.ext).to.haveOwnProperty('prebid');
expect(requestBid.ext.prebid).to.deep.equal({
auctiontimestamp: 1510852447530,
targeting: {
includewinners: false,
includebidderkeys: true
Expand Down Expand Up @@ -1304,6 +1310,7 @@ describe('S2S Adapter', function () {
expect(requestBid).to.haveOwnProperty('ext');
expect(requestBid.ext).to.haveOwnProperty('prebid');
expect(requestBid.ext.prebid).to.deep.equal({
auctiontimestamp: 1510852447530,
cache: {
vastxml: 'vastxml-set-though-extPrebid.cache.vastXml'
},
Expand Down Expand Up @@ -1768,6 +1775,76 @@ describe('S2S Adapter', function () {
expect(response).to.have.property('vastUrl', 'https://prebid-cache.net/cache?uuid=a5ad3993');
});

it('handles response cache from ext.prebid.targeting with wurl', function () {
const s2sConfig = Object.assign({}, CONFIG, {
endpoint: 'https://prebidserverurl/openrtb2/auction?querystring=param'
});
config.setConfig({ s2sConfig });
const cacheResponse = utils.deepClone(RESPONSE_OPENRTB_VIDEO);
cacheResponse.seatbid.forEach(item => {
item.bid[0].wurl = 'https://wurl.com?a=1&b=2';
item.bid[0].ext.prebid.targeting = {
hb_uuid: 'a5ad3993',
hb_cache_host: 'prebid-cache.net',
hb_cache_path: '/cache'
}
});
server.respondWith(JSON.stringify(cacheResponse));
adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax);
server.respond();

sinon.assert.calledOnce(addBidResponse);
const response = addBidResponse.firstCall.args[1];
expect(response).to.have.property('pbsBidId', '654321');
});

it('handles response cache from ext.prebid.targeting with wurl and removes invalid targeting', function () {
const s2sConfig = Object.assign({}, CONFIG, {
endpoint: 'https://prebidserverurl/openrtb2/auction?querystring=param'
});
config.setConfig({ s2sConfig });
const cacheResponse = utils.deepClone(RESPONSE_OPENRTB_VIDEO);
cacheResponse.seatbid.forEach(item => {
item.bid[0].wurl = 'https://wurl.com?a=1&b=2';
item.bid[0].ext.prebid.targeting = {
hb_uuid: 'a5ad3993',
hb_cache_host: 'prebid-cache.net',
hb_cache_path: '/cache',
hb_winurl: 'https://hbwinurl.com?a=1&b=2',
hb_bidid: '1234567890',
}
});
server.respondWith(JSON.stringify(cacheResponse));
adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax);
server.respond();

sinon.assert.calledOnce(addBidResponse);
const response = addBidResponse.firstCall.args[1];

expect(response.adserverTargeting).to.deep.equal({
hb_uuid: 'a5ad3993',
hb_cache_host: 'prebid-cache.net',
hb_cache_path: '/cache'
});
});

it('add request property pbsBidId with ext.prebid.bidid value', function () {
const s2sConfig = Object.assign({}, CONFIG, {
endpoint: 'https://prebidserverurl/openrtb2/auction?querystring=param'
});
config.setConfig({ s2sConfig });
const cacheResponse = utils.deepClone(RESPONSE_OPENRTB_VIDEO);

server.respondWith(JSON.stringify(cacheResponse));
adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax);
server.respond();

sinon.assert.calledOnce(addBidResponse);
const response = addBidResponse.firstCall.args[1];

expect(response).to.have.property('pbsBidId', '654321');
});

it('handles OpenRTB native responses', function () {
sinon.stub(utils, 'getBidRequest').returns({
adUnitCode: 'div-gpt-ad-1460505748561-0',
Expand Down Expand Up @@ -1796,6 +1873,58 @@ describe('S2S Adapter', function () {
});
});

describe('bid won events', function () {
let server;
let logWarnSpy;
let getUniqueIdentifierStrStub;

beforeEach(function () {
server = sinon.fakeServer.create();
sinon.stub(utils, 'triggerPixel');
sinon.stub(utils, 'insertUserSyncIframe');
sinon.stub(utils, 'logError');
logWarnSpy = sinon.spy(utils, 'logWarn');
getUniqueIdentifierStrStub = sinon.stub(utils, 'getUniqueIdentifierStr').callsFake(() => '101010101010');
});

afterEach(function () {
server.restore();
utils.triggerPixel.restore();
utils.insertUserSyncIframe.restore();
utils.logError.restore();
logWarnSpy.restore();
getUniqueIdentifierStrStub.restore();
});

it('should call triggerPixel on bid won event when wurl is defined', function () {
const s2sConfig = Object.assign({}, CONFIG, {
endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'
});
config.setConfig({ s2sConfig });

const clonedResponse = utils.deepClone(RESPONSE_OPENRTB);
const bid = clonedResponse.seatbid[0].bid[0];
bid.wurl = 'https://wurl.org';
server.respondWith(JSON.stringify(clonedResponse));
adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax);
server.respond();

events.emit(CONSTANTS.EVENTS.BID_WON, {
auctionId: '173afb6d132ba3',
adId: '101010101010'
});

sinon.assert.calledOnce(addBidResponse);

const response = addBidResponse.firstCall.args[1];
expect(response).to.have.property('bidderCode', 'appnexus');
expect(response).to.have.property('requestId', '123');

expect(utils.triggerPixel.called).to.be.true;
expect(utils.triggerPixel.getCall(0).args[0]).to.include('https://wurl.org');
});
})

describe('s2sConfig', function () {
let logErrorSpy;

Expand Down
1 change: 1 addition & 0 deletions test/spec/modules/rubiconBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1461,6 +1461,7 @@ describe('the rubicon adapter', function () {
expect(post.site.content.language).to.equal('en');
expect(imp.ext.rubicon.video.skip).to.equal(1);
expect(imp.ext.rubicon.video.skipafter).to.equal(15);
expect(imp.ext.prebid.auctiontimestamp).to.equal(1472239426000);
expect(post.user.ext.consent).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A==');
expect(post.user.ext.eids[0].source).to.equal('liveintent.com');
expect(post.user.ext.eids[0].uids[0].id).to.equal('0000-1111-2222-3333');
Expand Down

0 comments on commit fcdcd0c

Please sign in to comment.