Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added setTargeting code for custom key-value pairs #3550

Merged
merged 4 commits into from
Feb 22, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
229 changes: 171 additions & 58 deletions modules/ozoneBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import * as utils from '../src/utils';
import { registerBidder } from '../src/adapters/bidderFactory';
import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes';
import { targeting } from '../src/targeting';

const BIDDER_CODE = 'ozone';

const OZONEURI = 'https://elb.the-ozone-project.com/openrtb2/auction';
const OZONECOOKIESYNC = 'https://elb.the-ozone-project.com/static/load-cookie.html';

const OZONEVERSION = '1.4.3';
export const spec = {
code: BIDDER_CODE,

Expand Down Expand Up @@ -70,26 +72,41 @@ export const spec = {
* @returns {*}
*/
interpretResponse(serverResponse, request) {
utils.logInfo('ozone interpretResponse version 2018-12-05 16:46');
utils.logInfo('ozone v' + OZONEVERSION + ' interpretResponse', serverResponse, request);
serverResponse = serverResponse.body || {};
_ozoneInternal.serverResponseId = serverResponse.id; /* this is sent to the ads request as requestId */
if (serverResponse.seatbid) {
if (utils.isArray(serverResponse.seatbid)) {
// check - does the auction ID match the one in the request?
utils.logInfo('checking auction ID: ', _ozoneInternal.auctionId, request.bidderRequest.auctionId);
// serverResponse seems good, let's get the list of bids from the request object:
let arrRequestBids = request.bidderRequest.bids;
// build up a list of winners, one for each bidId in arrBidIds
let arrWinners = [];
for (let i = 0; i < arrRequestBids.length; i++) {
let winner = ozoneGetWinnerForRequestBid(arrRequestBids[i], serverResponse.seatbid);
if (winner !== null) {
let thisBid = arrRequestBids[i];
let ozoneInternalKey = thisBid.bidId;
// let ozoneInternalKey = thisBid.adUnitCode;
let {seat: winningSeat, bid: winningBid} = ozoneGetWinnerForRequestBid(thisBid, serverResponse.seatbid);

utils.logInfo('adding all bids to _ozoneInternal for key: ', ozoneInternalKey);
_ozoneInternal.responses[ozoneInternalKey] = ozoneGetAllBidsForBidId(ozoneInternalKey, serverResponse.seatbid);
_ozoneInternal.winners[ozoneInternalKey] = {'seat': winningSeat, 'bid': winningBid};
if (winningBid !== null) {
const {defaultWidth, defaultHeight} = defaultSize(arrRequestBids[i]);
winner = ozoneAddStandardProperties(winner, defaultWidth, defaultHeight);
arrWinners.push(winner);
winningBid = ozoneAddStandardProperties(winningBid, defaultWidth, defaultHeight);
// utils.logInfo(['adding allBids to winningBid object for key: ', thisBid.bidId]);
// winningBid['allBids'] = ozoneGetAllBidsForBidId(thisBid.bidId, serverResponse.seatbid);
utils.logInfo('winner is', winningBid);
arrWinners.push(winningBid);
utils.logInfo('arrWinners is', arrWinners);
utils.logInfo('_ozoneInternal is', _ozoneInternal);
}
}
let winnersClean = arrWinners.filter(w => {
return (w.bidId); // will be cast to boolean
});
utils.logInfo(['going to return winnersClean:', winnersClean]);
utils.logInfo('going to return winnersClean:', winnersClean);
return winnersClean;
} else {
return [];
Expand All @@ -99,23 +116,16 @@ export const spec = {
}
},
buildRequests(validBidRequests, bidderRequest) {
let ozoneRequest = validBidRequests[0].params;
ozoneRequest['id'] = utils.generateUUID();
ozoneRequest['auctionId'] = bidderRequest['auctionId'];

if (bidderRequest.hasOwnProperty('placementId')) {
bidderRequest.placementId = (bidderRequest.placementId).toString();
}
if (bidderRequest.hasOwnProperty('siteId')) {
bidderRequest.siteId = (bidderRequest.siteId).toString();
}
if (bidderRequest.hasOwnProperty('publisherId')) {
bidderRequest.publisherId = (bidderRequest.publisherId).toString();
}
utils.logInfo('ozone v' + OZONEVERSION + ' validBidRequests', validBidRequests, 'bidderRequest', bidderRequest);
utils.logInfo('buildRequests setting auctionId', bidderRequest.auctionId);
_ozoneInternal.auctionId = bidderRequest.auctionId;
let htmlParams = validBidRequests[0].params; // the html page config params will be included in each element
let ozoneRequest = {}; // we only want to set specific properties on this, not validBidRequests[0].params
// ozoneRequest['id'] = utils.generateUUID();
ozoneRequest['id'] = bidderRequest.auctionId; // Unique ID of the bid request, provided by the exchange.
ozoneRequest['auctionId'] = bidderRequest['auctionId']; // not sure if this should be here?

// if (!ozoneRequest.test) {
delete ozoneRequest.test; // don't allow test to be set in the config - ONLY use $_GET['pbjs_debug']
// }
if (bidderRequest.gdprConsent) {
ozoneRequest.regs = {};
ozoneRequest.regs.ext = {};
Expand All @@ -126,45 +136,90 @@ export const spec = {
}
let tosendtags = validBidRequests.map(ozoneBidRequest => {
var obj = {};
obj.id = ozoneBidRequest.bidId;
obj.tagid = String(ozoneBidRequest.params.ozoneid);
obj.id = ozoneBidRequest.bidId; // this causes a failure if we change it to something else
// obj.id = ozoneBidRequest.adUnitCode; // (eg. 'mpu' or 'leaderboard') A unique identifier for this impression within the context of the bid request (typically, starts with 1 and increments.
obj.tagid = (ozoneBidRequest.params.placementId).toString();
obj.secure = window.location.protocol === 'https:' ? 1 : 0;
obj.banner = {
topframe: 1,
w: ozoneBidRequest.sizes[0][0] || 0,
h: ozoneBidRequest.sizes[0][1] || 0,
format: ozoneBidRequest.sizes.map(s => {
return {w: s[0], h: s[1]};
})
};
if (ozoneBidRequest.params.hasOwnProperty('customData')) {
obj.customData = ozoneBidRequest.params.customData;
// is there a banner (or nothing declared, so banner is the default)?
let arrBannerSizes = [];
/* NOTE - if there is sizes element in the config root then there will be a mediaTypes.banner element automatically generated for us, so this code is deprecated */
if (!ozoneBidRequest.hasOwnProperty('mediaTypes')) {
if (ozoneBidRequest.hasOwnProperty('sizes')) {
utils.logInfo('no mediaTypes detected - will use the sizes array in the config root');
arrBannerSizes = ozoneBidRequest.sizes;
} else {
utils.logInfo('no mediaTypes detected, no sizes array in the config root either. Cannot set sizes for banner type');
}
} else {
if (ozoneBidRequest.mediaTypes.hasOwnProperty(BANNER)) {
arrBannerSizes = ozoneBidRequest.mediaTypes[BANNER].sizes; /* Note - if there is a sizes element in the config root it will be pushed into here */
utils.logInfo('setting banner size from the mediaTypes.banner element: ', arrBannerSizes);
}
// Video integration is not complete yet
if (ozoneBidRequest.mediaTypes.hasOwnProperty(VIDEO)) {
obj.video = ozoneBidRequest.mediaTypes[VIDEO];
utils.logInfo('setting video object from the mediaTypes.video element: ', obj.video);
}
// Native integration is not complete yet
if (ozoneBidRequest.mediaTypes.hasOwnProperty(NATIVE)) {
obj.native = ozoneBidRequest.mediaTypes[NATIVE];
utils.logInfo('setting native object from the mediaTypes.native element: ', obj.native);
}
}
if (ozoneBidRequest.params.hasOwnProperty('ozoneData')) {
obj.ozoneData = ozoneBidRequest.params.ozoneData;
// build the banner request using banner sizes we found in either possible location:
if (arrBannerSizes.length > 0) {
obj.banner = {
topframe: 1,
w: arrBannerSizes[0][0] || 0,
h: arrBannerSizes[0][1] || 0,
format: arrBannerSizes.map(s => {
return {w: s[0], h: s[1]};
})
};
}
if (ozoneBidRequest.params.hasOwnProperty('lotameData')) {
obj.lotameData = ozoneBidRequest.params.lotameData;
if (ozoneBidRequest.params.hasOwnProperty('placementId')) {
obj.placementId = (ozoneBidRequest.params.placementId).toString();
}
if (ozoneBidRequest.params.hasOwnProperty('publisherId')) {
obj.publisherId = (ozoneBidRequest.params.publisherId).toString();
}
if (ozoneBidRequest.params.hasOwnProperty('siteId')) {
obj.siteId = (ozoneBidRequest.params.siteId).toString();
}
obj.ext = {'prebid': {'storedrequest': {'id': (ozoneBidRequest.params.placementId).toString()}}};
// build the imp['ext'] object
obj.ext = {'prebid': {'storedrequest': {'id': (ozoneBidRequest.params.placementId).toString()}}, 'ozone': {}};
obj.ext.ozone.adUnitCode = ozoneBidRequest.adUnitCode; // eg. 'mpu'
obj.ext.ozone.transactionId = ozoneBidRequest.transactionId; // this is the transactionId PER adUnit, common across bidders for this unit
_ozoneInternal.adUnitCodes[obj.id] = ozoneBidRequest.adUnitCode; // we need to map this here as the adUnitCode doesnt come into the response
if (ozoneBidRequest.params.hasOwnProperty('customData')) {
obj.ext.ozone.customData = ozoneBidRequest.params.customData;
}
if (ozoneBidRequest.params.hasOwnProperty('ozoneData')) {
obj.ext.ozone.ozoneData = ozoneBidRequest.params.ozoneData;
}
if (ozoneBidRequest.params.hasOwnProperty('lotameData')) {
obj.ext.ozone.lotameData = ozoneBidRequest.params.lotameData;
}
if (ozoneBidRequest.hasOwnProperty('crumbs') && ozoneBidRequest.crumbs.hasOwnProperty('pubcid')) {
obj.ext.ozone.pubcid = ozoneBidRequest.crumbs.pubcid;
}

return obj;
});
ozoneRequest.imp = tosendtags;
ozoneRequest.site = {'publisher': {'id': ozoneRequest.publisherId}, 'page': document.location.href};
ozoneRequest.source = {'tid': bidderRequest.auctionId}; // RTB 2.5 : tid is Transaction ID that must be common across all participants in this bid request (e.g., potentially multiple exchanges).
ozoneRequest.site = {'publisher': {'id': htmlParams.publisherId}, 'page': document.location.href};
ozoneRequest.test = parseInt(getTestQuerystringValue()); // will be 1 or 0

var ret = {
method: 'POST',
url: OZONEURI,
data: JSON.stringify(ozoneRequest),
bidderRequest: bidderRequest
};
utils.logInfo(['buildRequests going to return', ret]);
utils.logInfo('_ozoneInternal is', _ozoneInternal);
utils.logInfo('buildRequests ozoneRequest for ret = ', ozoneRequest);
utils.logInfo('buildRequests going to return', ret);
return ret;
},

Expand All @@ -181,21 +236,6 @@ export const spec = {
}
}

/**
* Function matchRequest(id: string, BidRequest: object)
* @param id
* @type string
* @param bidRequest
* @type Object
* @returns Object
*
*/
export function matchRequest(id, bidRequest) {
const {bids} = bidRequest.bidderRequest;
const [returnValue] = bids.filter(bid => bid.bidId === id);
return returnValue;
}

export function checkDeepArray(Arr) {
if (Array.isArray(Arr)) {
if (Array.isArray(Arr[0])) {
Expand Down Expand Up @@ -223,19 +263,45 @@ export function defaultSize(thebidObj) {
*/
export function ozoneGetWinnerForRequestBid(requestBid, serverResponseSeatBid) {
let thisBidWinner = null;
let winningSeat = null;
for (let j = 0; j < serverResponseSeatBid.length; j++) {
let theseBids = serverResponseSeatBid[j].bid;
let thisSeat = serverResponseSeatBid[j].seat;
for (let k = 0; k < theseBids.length; k++) {
if (theseBids[k].impid === requestBid.bidId) { // we've found a matching server response bid for this request bid
// if (theseBids[k].impid === requestBid.adUnitCode) { // we've found a matching server response bid for this request bid
if ((thisBidWinner == null) || (thisBidWinner.price < theseBids[k].price)) {
thisBidWinner = theseBids[k];
thisBidWinner.seat = thisSeat; // we need to add this here - it's the name of the winning bidder, not guaranteed to be available in the bid object.
winningSeat = thisSeat;
break;
}
}
}
}
return thisBidWinner;
return {'seat': winningSeat, 'bid': thisBidWinner};
}

/**
* Get a list of all the bids, for this bidId
* @param matchBidId
* @param serverResponseSeatBid
* @returns {} = {ozone:{obj}, appnexus:{obj}, ... }
*/
export function ozoneGetAllBidsForBidId(matchBidId, serverResponseSeatBid) {
utils.logInfo('ozoneGetAllBidsForBidId - starting, with: ', matchBidId, serverResponseSeatBid);
let objBids = {};
for (let j = 0; j < serverResponseSeatBid.length; j++) {
let theseBids = serverResponseSeatBid[j].bid;
let thisSeat = serverResponseSeatBid[j].seat;
for (let k = 0; k < theseBids.length; k++) {
if (theseBids[k].impid === matchBidId) { // we've found a matching server response bid for the request bid we're looking for
utils.logInfo('ozoneGetAllBidsForBidId - found matching bid: ', matchBidId, theseBids[k]);
objBids[thisSeat] = theseBids[k];
}
}
}
utils.logInfo('ozoneGetAllBidsForBidId - going to return: ', objBids);
return objBids;
}

/**
Expand Down Expand Up @@ -274,4 +340,51 @@ export function getTestQuerystringValue() {
return 0;
}

// listeners:
// http://prebid.org/dev-docs/publisher-api-reference.html
// this is called immediately after the standard targeting has been set.
// We will now try to add custom targeting data - auction ID and all losing bidders.
// we will use this instead of having to use in the html page: pbjs.bidderSettings = { ozone: { ... } } - see http://prebid.org/dev-docs/publisher-api-reference.html
pbjs.onEvent('setTargeting', function(arrData) {
utils.logInfo('In the setTargeting event handler. Adding custom k/v to the ad request. _ozoneInternal = ', _ozoneInternal, arrData);
/*
In order to add a custom key/value pair you fundamentally need to do one thing:
Set new targeting for this key by calling setTargeting() on each window.googletag.pubads().getSlots() array.
*/
// iterate over each adUnit in arrData, adding in keys & values we need.
let arrAditionalTargeting = {};
for (let adUnitCode in arrData) {
let thisAdId = arrData[adUnitCode].hb_adid;
if (!_ozoneInternal.responses.hasOwnProperty(thisAdId)) {
// there were no responses for this ad ID
utils.logInfo('There were no responses for adId ' + thisAdId + ' - will not try to set additional oz targeting');
continue;
}
arrAditionalTargeting[adUnitCode] = {};
let ozoneResponse = _ozoneInternal.responses[thisAdId]; /* The key is bidid - always found in responses & matches back to the request. */
Object.keys(ozoneResponse).forEach(function(bidderName, index, ar2) {
arrAditionalTargeting[adUnitCode]['oz_' + bidderName] = bidderName;
arrAditionalTargeting[adUnitCode]['oz_' + bidderName + '_pb'] = String(ozoneResponse[bidderName].price);
arrAditionalTargeting[adUnitCode]['oz_' + bidderName + '_crid'] = String(ozoneResponse[bidderName].crid);
arrAditionalTargeting[adUnitCode]['oz_' + bidderName + '_adv'] = String(ozoneResponse[bidderName].adomain);
arrAditionalTargeting[adUnitCode]['oz_' + bidderName + '_imp_id'] = String(ozoneResponse[bidderName].impid);
});
let objWinner = _ozoneInternal.winners[thisAdId];
arrAditionalTargeting[adUnitCode]['oz_auc_id'] = String(_ozoneInternal.auctionId); /* from request.auctionId */
arrAditionalTargeting[adUnitCode]['oz_winner'] = String(objWinner.seat);
arrAditionalTargeting[adUnitCode]['oz_winner_auc_id'] = String(objWinner.bid.id);
arrAditionalTargeting[adUnitCode]['oz_winner_imp_id'] = String(objWinner.bid.impid);
arrAditionalTargeting[adUnitCode]['oz_response_id'] = String(_ozoneInternal.serverResponseId);
}

utils.logInfo('Going to set additional ad targeting for ozone : ', arrAditionalTargeting);
targeting.setTargetingForGPT(arrAditionalTargeting);

utils.logInfo('ozone setTargeting listener going to finish.');
});

// declare a variable to hold data about the responses & auction ID which we will use in our setTargeting event handler
var _ozoneInternal = { 'responses': {}, 'adUnitCodes': {}, 'winners': {}, 'auctionId': 'not_set', 'serverResponseId': 'not_set' }; // this will hold the response from ozone server call. We use this data to send non-winning bidders to the ad request

registerBidder(spec);
utils.logInfo('ozoneBidAdapter ended');
Loading