Skip to content

Commit

Permalink
Pubgears Header Bidding Adapter (#953)
Browse files Browse the repository at this point in the history
* adapters/pubgears: initial commit of adapter, unit tests

* adapters/pubgears: new specs

* adapaters.json: added pubgears

* 😎 style fixes

* pubgears: support for non-array `sizes` bids

* pubgears: use `placementCode`, not `adUnitCode`

* pubgears style changes

* pubgears: remove vertical white-space

* pubgears: use utils.replaceInToken instead of own

also add unit test to insure tokens in creative template are expanded
correctly

* rename test ... ahem ...

* pubgears: send $0 bid as status code 2
  • Loading branch information
Walexander authored and Nate Cozi committed May 2, 2017
1 parent 7fde081 commit c17c483
Show file tree
Hide file tree
Showing 3 changed files with 450 additions and 0 deletions.
1 change: 1 addition & 0 deletions adapters.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"openx",
"piximedia",
"pubmatic",
"pubgears",
"pulsepoint",
"pulsepointLite",
"rhythmone",
Expand Down
151 changes: 151 additions & 0 deletions src/adapters/pubgears.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
var bidfactory = require('../bidfactory.js');
var bidmanager = require('../bidmanager.js');
var consts = require('../constants.json');
var utils = require('../utils.js');
var d = document;
var SCRIPT = 'script';
var PARAMS = 'params';
var SIZES = 'sizes';
var SIZE = 'size';
var CPM = 'cpm';
var AD = 'ad';
var WIDTH = 'width';
var HEIGHT = 'height';
var PUB_ZONE = 'pub_zone';
var GROSS_PRICE = 'gross_price';
var RESOURCE = 'resource';
var DETAIL = 'detail';
var BIDDER_CODE_RESPONSE_KEY = 'bidderCode';
var BIDDER_CODE = 'pubgears';
var SCRIPT_ID = 'pg-header-tag';
var ATTRIBUTE_PREFIX = 'data-bsm-';
var SLOT_LIST_ATTRIBUTE = 'slot-list';
var PUBLISHER_ATTRIBUTE = 'pub';
var FLAG_ATTRIBUTE = 'flag';
var PLACEMENT_CODE = 'placementCode';
var BID_ID = 'bidId';
var PUBLISHER_PARAM = 'publisherName';
var PUB_ZONE_PARAM = 'pubZone';
var BID_RECEIVED_EVENT_NAME = 'onBidResponse';
var SLOT_READY_EVENT_NAME = 'onResourceComplete';
var CREATIVE_TEMPLATE = decodeURIComponent("%3Cscript%3E%0A(function(define)%7B%0Adefine(function(a)%7B%0A%09var%20id%3D%20%22pg-ad-%22%20%2B%20Math.floor(Math.random()%20*%201e10)%2C%20d%3D%20document%0A%09d.write(\'%3Cdiv%20id%3D%22\'%2Bid%2B\'%22%3E%3C%2Fdiv%3E\')%0A%09a.push(%7B%0A%09%09pub%3A%20\'%25%25PUBLISHER_NAME%25%25\'%2C%0A%09%09pub_zone%3A%20\'%25%25PUB_ZONE%25%25\'%2C%0A%09%09sizes%3A%20%5B\'%25%25SIZE%25%25\'%5D%2C%0A%09%09flag%3A%20true%2C%0A%09%09container%3A%20d.getElementById(id)%2C%0A%09%7D)%3B%0A%7D)%7D)(function(f)%7Bvar%20key%3D\'uber_imps\'%2Ca%3Dthis%5Bkey%5D%3Dthis%5Bkey%5D%7C%7C%5B%5D%3Bf(a)%3B%7D)%3B%0A%3C%2Fscript%3E%0A%3Cscript%20src%3D%22%2F%2Fc.pubgears.com%2Ftags%2Fb%22%3E%3C%2Fscript%3E%0A");
var TAG_URL = '//c.pubgears.com/tags/h';
var publisher = '';

module.exports = PubGearsAdapter;

function PubGearsAdapter() {
var proxy = null;
var pendingSlots = {};
var initialized = false;

this.callBids = callBids;

function callBids(params) {
var bids = params[consts.JSON_MAPPING.PL_BIDS];
var slots = bids.map(getSlotFromBidParam) ;
if(slots.length <= 0)
return;
publisher = bids[0][PARAMS][PUBLISHER_PARAM];

bids.forEach(function(bid) {

var name = getSlotFromBidParam(bid);
pendingSlots[ name ] = bid;
});

proxy = proxy || getScript(SCRIPT_ID) || makeScript(slots, publisher, SCRIPT_ID, TAG_URL);
if(!initialized)
registerEventListeners(proxy);
initialized = true;
}
function loadScript(script) {
var anchor = (function(scripts) {
return scripts[ scripts.length - 1 ];
})(d.getElementsByTagName(SCRIPT));

return anchor.parentNode.insertBefore(script, anchor);
}
function getSlotFromBidParam(bid) {
var size = getSize(bid);
var params = bid[PARAMS];
var slotName = params[PUB_ZONE_PARAM];
return [ slotName, size ].join('@');
}
function getSlotFromResource(resource) {
var size = resource[SIZE];
var key = [ resource[PUB_ZONE], size ].join('@');
return key;
}
function getSize(bid) {
var sizes = bid[SIZES];
var size = Array.isArray(sizes[0]) ? sizes[0] : sizes;
return size.join('x');
}
function makeScript(slots, publisher, id, url) {
var script = d.createElement(SCRIPT);
script.src = url;
script.id = id ;
script.setAttribute(ATTRIBUTE_PREFIX + SLOT_LIST_ATTRIBUTE, slots.join(' '));
script.setAttribute(ATTRIBUTE_PREFIX + FLAG_ATTRIBUTE, 'true');
script.setAttribute(ATTRIBUTE_PREFIX + PUBLISHER_ATTRIBUTE, publisher);

return loadScript(script);
}
function getScript(id) {
return d.getElementById(id);
}
function registerEventListeners(script) {
script.addEventListener(BID_RECEIVED_EVENT_NAME, onBid, true);
script.addEventListener(SLOT_READY_EVENT_NAME, onComplete, true);
}
function onBid(event) {
var data = event[DETAIL];
var slotKey = getSlotFromResource(data[RESOURCE]);
var bidRequest = pendingSlots[slotKey];
var adUnitCode = bidRequest[PLACEMENT_CODE];
var bid = null;

if(bidRequest) {
bid = buildResponse(data, bidRequest);
bidmanager.addBidResponse(adUnitCode, bid);
utils.logMessage('adding bid respoonse to "' + adUnitCode + '" for bid request "' + bidRequest[BID_ID] + '"');
}else {
utils.logError('Cannot get placement id for slot "' + slotKey + '"');
}
}
function buildResponse(eventData, bidRequest) {
var resource = eventData[RESOURCE];
var dims = resource[SIZE].split('x');
var price = Number(eventData[GROSS_PRICE]);
var status = isNaN(price) || price <= 0 ? 2 : 1;

var response = bidfactory.createBid(status, bidRequest);
response[BIDDER_CODE_RESPONSE_KEY] = BIDDER_CODE;

if(status !== 1)
return response;

response[AD] = getCreative(resource);

response[CPM] = price / 1e3 ;
response[WIDTH] = dims[0];
response[HEIGHT] = dims[1];
return response;
}
function getCreative(resource) {
var token = '%%';
var creative = CREATIVE_TEMPLATE;
var replacementValues = {
publisher_name: publisher,
pub_zone: resource[PUB_ZONE],
size: resource[SIZE]
};
return utils.replaceTokenInString(creative, replacementValues, token);
}
function onComplete(event) {
var data = event[DETAIL];
var slotKey = getSlotFromResource(data[RESOURCE]);
delete pendingSlots[slotKey];
}
}
Loading

0 comments on commit c17c483

Please sign in to comment.