Skip to content

Commit

Permalink
Added adapter for Conversant Media (#708)
Browse files Browse the repository at this point in the history
* Added adapter for Conversant along with tests

* Updated version

* Set xhr.withCredentials to true

* Added test for Conversant request headers

* Removed unnecessary stub

* Added bid object to bid response submission
  • Loading branch information
msahagu2 authored and Nate Cozi committed Nov 2, 2016
1 parent 94fffc8 commit 92b785f
Show file tree
Hide file tree
Showing 3 changed files with 484 additions and 0 deletions.
1 change: 1 addition & 0 deletions adapters.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"aol",
"appnexus",
"appnexusAst",
"conversant",
"getintent",
"hiromedia",
"indexExchange",
Expand Down
223 changes: 223 additions & 0 deletions src/adapters/conversant.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
'use strict';
var VERSION = '2.0.1',
CONSTANTS = require('../constants.json'),
utils = require('../utils.js'),
bidfactory = require('../bidfactory.js'),
bidmanager = require('../bidmanager.js'),
adloader = require('../adloader');

/**
* Adapter for requesting bids from Conversant
*/
var ConversantAdapter = function () {
var w = window,
n = navigator;

// production endpoint
var conversantUrl = '//media.msg.dotomi.com/s2s/header?callback=$$PREBID_GLOBAL$$.conversantResponse';

// SSAPI returns JSONP with window.pbjs.conversantResponse as the cb
var appendScript = function (code) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.className = 'cnvr-response';

try {
script.appendChild(document.createTextNode(code));
document.getElementsByTagName('head')[0].appendChild(script);
} catch (e) {
script.text = code;
document.getElementsByTagName('head')[0].appendChild(script);
}
};

var httpPOSTAsync = function (url, data) {
var xmlHttp = new w.XMLHttpRequest();

xmlHttp.onload = function () {
appendScript(xmlHttp.responseText);
};
xmlHttp.open('POST', url, true); // true for asynchronous
xmlHttp.withCredentials = true;
xmlHttp.send(data);
};

var getDNT = function () {
return n.doNotTrack === '1' || w.doNotTrack === '1' || n.msDoNotTrack === '1' || n.doNotTrack === 'yes';
};

var getDevice = function () {
return {
h: screen.height,
w: screen.width,
dnt: getDNT() ? 1 : 0,
language: n.language.split('-')[0],
make: n.vendor ? n.vendor : '',
ua: n.userAgent
};
};

var callBids = function (params) {
var conversantBids = params.bids || [];
requestBids(conversantBids);
};

var requestBids = function (bidReqs) {
// build bid request object
var page = location.pathname + location.search + location.hash,
siteId = '',
conversantImps = [],
conversantBidReqs,
secure = 0;

//build impression array for conversant
utils._each(bidReqs, function (bid) {
var bidfloor = utils.getBidIdParamater('bidloor', bid.params),
sizeArrayLength = bid.sizes.length,
adW = 0,
adH = 0,
imp;

secure = utils.getBidIdParamater('secure', bid.params) ? 1 : secure;
siteId = utils.getBidIdParamater('site_id', bid.params);

if (sizeArrayLength === 2 && typeof bid.sizes[0] === 'number' && typeof bid.sizes[1] === 'number') {
adW = bid.sizes[0];
adH = bid.sizes[1];
} else {
adW = bid.sizes[0][0];
adH = bid.sizes[0][1];
}

imp = {
id: bid.bidId,
banner: {
w: adW,
h: adH
},
secure: secure,
bidfloor: bidfloor ? bidfloor : 0,
displaymanager: 'Prebid.js',
displaymanagerver: VERSION
};

conversantImps.push(imp);
});

conversantBidReqs = {
'id': utils.getUniqueIdentifierStr(),
'imp': conversantImps,

'site': {
'id': siteId,
'mobile': document.querySelector('meta[name="viewport"][content*="width=device-width"]') !== null ? 1 : 0,
'page': page
},

'device': getDevice(),
'at': 1
};

var url = secure ? 'https:' + conversantUrl : location.protocol + conversantUrl;
httpPOSTAsync(url, JSON.stringify(conversantBidReqs));
};

var addEmptyBidResponses = function (placementsWithBidsBack) {
var allConversantBidRequests = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'conversant');

if (allConversantBidRequests && allConversantBidRequests.bids){
utils._each(allConversantBidRequests.bids, function (conversantBid) {
if (!utils.contains(placementsWithBidsBack, conversantBid.placementCode)) {
// Add a no-bid response for this placement.
var bid = bidfactory.createBid(2, conversantBid);
bid.bidderCode = 'conversant';
bidmanager.addBidResponse(conversantBid.placementCode, bid);
}
});
}
};

var parseSeatbid = function (bidResponse) {
var placementsWithBidsBack = [];
utils._each(bidResponse.bid, function (conversantBid) {
var responseCPM,
placementCode = '',
id = conversantBid.impid,
bid = {},
responseAd,
responseNurl,
sizeArrayLength;

// Bid request we sent Conversant
var bidRequested = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'conversant').bids.find(bid => bid.bidId === id);

if (bidRequested) {
placementCode = bidRequested.placementCode;
bidRequested.status = CONSTANTS.STATUS.GOOD;
responseCPM = parseFloat(conversantBid.price);

if (responseCPM !== 0.0) {
conversantBid.placementCode = placementCode;
placementsWithBidsBack.push(placementCode);
conversantBid.size = bidRequested.sizes;
responseAd = conversantBid.adm || '';
responseNurl = conversantBid.nurl || '';

// Our bid!
bid = bidfactory.createBid(1, bidRequested);
bid.creative_id = conversantBid.id || '';
bid.bidderCode = 'conversant';

bid.cpm = responseCPM;

// Track impression image onto returned html
bid.ad = responseAd + '<img src=\"' + responseNurl + '\" />';

sizeArrayLength = bidRequested.sizes.length;
if (sizeArrayLength === 2 && typeof bidRequested.sizes[0] === 'number' && typeof bidRequested.sizes[1] === 'number') {
bid.width = bidRequested.sizes[0];
bid.height = bidRequested.sizes[1];
} else {
bid.width = bidRequested.sizes[0][0];
bid.height = bidRequested.sizes[0][1];
}

bidmanager.addBidResponse(placementCode, bid);
}
}
});
addEmptyBidResponses(placementsWithBidsBack);
};

// Register our callback to the global object:
$$PREBID_GLOBAL$$.conversantResponse = function (conversantResponseObj, path) {
// valid object?
if (conversantResponseObj && conversantResponseObj.id) {
if (conversantResponseObj.seatbid && conversantResponseObj.seatbid.length > 0 && conversantResponseObj.seatbid[0].bid && conversantResponseObj.seatbid[0].bid.length > 0) {
utils._each(conversantResponseObj.seatbid, parseSeatbid);
} else {
//no response data for any placements
addEmptyBidResponses([]);
}
} else {
//no response data for any placements
addEmptyBidResponses([]);
}
// for debugging purposes
if (path){
adloader.loadScript(path, function () {
var allConversantBidRequests = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'conversant');

if ($$PREBID_GLOBAL$$.conversantDebugResponse){
$$PREBID_GLOBAL$$.conversantDebugResponse(allConversantBidRequests);
}
});
}
}; // conversantResponse

return {
callBids: callBids
};
};

module.exports = ConversantAdapter;
Loading

0 comments on commit 92b785f

Please sign in to comment.