Skip to content

Commit

Permalink
Merge pull request prebid#12 from PubMatic-OpenWrap/S2S
Browse files Browse the repository at this point in the history
Done QA on feature branch S2S. Merging for Nightly release.
  • Loading branch information
PubMatic-OpenWrap committed Jan 19, 2018
2 parents e741527 + 83daa24 commit 1516602
Show file tree
Hide file tree
Showing 12 changed files with 648 additions and 23 deletions.
13 changes: 7 additions & 6 deletions modules.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
[
"appnexusBidAdapter",
"appnexusBidAdapter",
"sekindoUMBidAdapter",
"pulsepointBidAdapter",
"audienceNetworkBidAdapter",
"openxBidAdapter",
"pulsepointBidAdapter",
"audienceNetworkBidAdapter",
"openxBidAdapter",
"rubiconBidAdapter",
"sovrnBidAdapter",
"pubmaticBidAdapter"
]
"pubmaticBidAdapter",
"pubmaticServerBidAdapter"
]
2 changes: 1 addition & 1 deletion modules/appnexusBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ AppNexusAdapter = function AppNexusAdapter() {
let usePaymentRule = utils.getBidIdParameter('usePaymentRule', bid.params);
var jptCall = '//ib.adnxs.com/jpt?';

jptCall = utils.tryAppendQueryString(jptCall, 'callback', preBidNameSpace+'.handleAnCB');
jptCall = utils.tryAppendQueryString(jptCall, 'callback', preBidNameSpace + '.handleAnCB');
jptCall = utils.tryAppendQueryString(jptCall, 'callback_uid', callbackId);
jptCall = utils.tryAppendQueryString(jptCall, 'psa', '0');
jptCall = utils.tryAppendQueryString(jptCall, 'id', placementId);
Expand Down
2 changes: 1 addition & 1 deletion modules/indexExchangeBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ var IndexExchangeAdapter = function IndexExchangeAdapter() {
}

var usingSizeSpecificSiteID = false;
// Check for size defined in bidder params
// Check for size defined in bidder params
if (bid.params.size && utils.isArray(bid.params.size)) {
if (!(bid.sizes[j][0] == bid.params.size[0] && bid.sizes[j][1] == bid.params.size[1])) {
passOnBid(bid.placementCode);
Expand Down
312 changes: 312 additions & 0 deletions modules/pubmaticServerBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
import * as utils from 'src/utils';
import { registerBidder } from 'src/adapters/bidderFactory';
const constants = require('src/constants.json');

const BIDDER_CODE = 'pubmaticServer';
const ENDPOINT = '//ow.pubmatic.com/openrtb/2.4/';
const CURRENCY = 'USD';
const AUCTION_TYPE = 1; // PubMaticServer just picking highest bidding bid from the partners configured
const UNDEFINED = undefined;
const IFRAME = 'iframe';
const IMAGE = 'image';
const REDIRECT = 'redirect';
const DEFAULT_VERSION_ID = '0';

const CUSTOM_PARAMS = {
'kadpageurl': '', // Custom page url
'gender': '', // User gender
'yob': '', // User year of birth
'lat': '', // User location - Latitude
'lon': '', // User Location - Longitude
'wiid': '', // OpenWrap Wrapper Impression ID
'profId': '', // OpenWrap Legacy: Profile ID
'verId': '', // OpenWrap Legacy: version ID
'divId': '' // OpenWrap new
};

function logNonStringParam(paramName, paramValue) {
utils.logWarn('PubMaticServer: Ignoring param : ' + paramName + ' with value : ' + paramValue + ', expects string-value, found ' + typeof paramValue);
}

function _parseSlotParam(paramName, paramValue) {
if (!utils.isStr(paramValue)) {
paramValue && logNonStringParam(paramName, paramValue);
return UNDEFINED;
}

paramValue = paramValue.trim();

switch (paramName) {
case 'pmzoneid':
return paramValue.split(',').slice(0, 50).map(id => id.trim()).join();
case 'kadfloor':
return parseFloat(paramValue) || UNDEFINED;
case 'lat':
return parseFloat(paramValue) || UNDEFINED;
case 'lon':
return parseFloat(paramValue) || UNDEFINED;
case 'yob':
return parseInt(paramValue) || UNDEFINED;
case 'gender':
default:
return paramValue;
}
}

function _initConf() {
var conf = {};
conf.pageURL = utils.getTopWindowUrl().trim();
conf.refURL = utils.getTopWindowReferrer().trim();
return conf;
}

function _handleCustomParams(params, conf) {
// istanbul ignore else
if (!conf.kadpageurl) {
conf.kadpageurl = conf.pageURL;
}

var key, value, entry;
for (key in CUSTOM_PARAMS) {
// istanbul ignore else
if (CUSTOM_PARAMS.hasOwnProperty(key)) {
value = params[key];
// istanbul ignore else
if (value) {
entry = CUSTOM_PARAMS[key];
if (utils.isA(entry, 'Object')) {
// will be used in future when we want to process a custom param before using
// 'keyname': {f: function() {}}
value = entry.f(value, conf);
}

if (utils.isStr(value)) {
conf[key] = value;
} else {
logNonStringParam(key, CUSTOM_PARAMS[key]);
}
}
}
}
return conf;
}

function _createOrtbTemplate(conf) {
return {
id: '' + new Date().getTime(),
at: AUCTION_TYPE,
cur: [CURRENCY],
imp: [],
site: {
page: conf.pageURL,
ref: conf.refURL,
publisher: {}
},
device: {
ua: navigator.userAgent,
js: 1,
dnt: (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0,
h: screen.height,
w: screen.width,
language: navigator.language
},
user: {},
ext: {}
};
}

function _createImpressionObject(bid, conf) {
return {
id: bid.bidId,
tagid: bid.params.adUnitId,
bidfloor: _parseSlotParam('kadfloor', bid.params.kadfloor),
secure: window.location.protocol === 'https:' ? 1 : 0,
banner: {
pos: 0,
topframe: utils.inIframe() ? 0 : 1,
format: (function() {
let arr = [];
for (let i = 0, l = bid.sizes.length; i < l; i++) {
arr.push({
w: bid.sizes[i][0],
h: bid.sizes[i][1]
});
}
return arr;
})()
},
ext: {
pmZoneId: _parseSlotParam('pmzoneid', bid.params.pmzoneid),
div: bid.params.divId
}
};
}

function mandatoryParamCheck(paramName, paramValue) {
if (!utils.isStr(paramValue)) {
utils.logWarn(BIDDER_CODE + ': ' + paramName + ' is mandatory and it should be a string, , found ' + typeof paramValue);
return false;
}
return true;
}

export const spec = {
code: BIDDER_CODE,

/**
* Determines whether or not the given bid request is valid. Valid bid request must have placementId and hbid
*
* @param {BidRequest} bid The bid params to validate.
* @return boolean True if this is a valid bid, and false otherwise.
*/
isBidRequestValid: bid => {
if (bid && bid.params) {
return mandatoryParamCheck('publisherId', bid.params.publisherId) &&
mandatoryParamCheck('adUnitId', bid.params.adUnitId) &&
mandatoryParamCheck('divId', bid.params.divId) &&
mandatoryParamCheck('adUnitIndex', bid.params.adUnitIndex);
}
return false;
},

/**
* Make a server request from the list of BidRequests.
*
* @param {validBidRequests[]} - an array of bids
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: validBidRequests => {
let conf = _initConf();
let payload = _createOrtbTemplate(conf);

if (utils.isEmpty(validBidRequests)) {
utils.logWarn('No Valid Bid Request found for given adUnits');
return;
}

validBidRequests.forEach(bid => {
conf.pubId = conf.pubId || bid.params.publisherId;
conf = _handleCustomParams(bid.params, conf);
conf.transactionId = bid.transactionId;
payload.imp.push(_createImpressionObject(bid, conf));
});

payload.site.publisher.id = conf.pubId.trim();
payload.ext.dm = {
rs: 1,
pubId: conf.pubId,
wp: 'pbjs',
wv: constants.REPO_AND_VERSION,
transactionId: conf.transactionId,
profileid: conf.profId || UNDEFINED,
versionid: conf.verId || DEFAULT_VERSION_ID,
wiid: conf.wiid || UNDEFINED
};
payload.user = {
gender: _parseSlotParam('gender', conf.gender),
yob: _parseSlotParam('yob', conf.yob),
geo: {
lat: _parseSlotParam('lat', conf.lat),
lon: _parseSlotParam('lon', conf.lon)
}
};
payload.device.geo = payload.user.geo;
payload.site.page = conf.kadpageurl || payload.site.page;
payload.site.domain = utils.getTopWindowHostName();
return {
method: 'POST',
url: ENDPOINT,
data: JSON.stringify(payload)
};
},

/**
* Unpack the response from the server into a list of bids.
*
* @param {*} response A successful response from the server.
* @return {Bid[]} An array of bids which were nested inside the server.
*/
interpretResponse: (response, request) => {
const bidResponses = [];
try {
if (response.body && response.body.seatbid) {
// Supporting multiple bid responses for same adSize
const referrer = utils.getTopWindowUrl();
response.body.seatbid.forEach(seatbidder => {
seatbidder.bid &&
seatbidder.bid.forEach(bid => {
if (bid.id !== null && bid.ext.summary) {
bid.ext.summary.forEach((summary, index) => {
if (summary.bidder) {
const firstSummary = index === 0;
const newBid = {
requestId: bid.impid,
bidderCode: BIDDER_CODE,
originalBidder: summary.bidder,
pubmaticServerErrorCode: summary.errorCode,
cpm: (parseFloat(summary.bid) || 0).toFixed(2),
width: summary.width,
height: summary.height,
creativeId: firstSummary ? (bid.crid || bid.id) : bid.id,
dealId: firstSummary ? (bid.dealid || UNDEFINED) : UNDEFINED,
currency: CURRENCY,
netRevenue: true,
ttl: 300,
referrer: referrer,
ad: firstSummary ? bid.adm : ''
};
bidResponses.push(newBid);
}
});
}
});
});
}
} catch (error) {
utils.logError(error);
}
return bidResponses;
},

/**
* Register User Sync.
*/
getUserSyncs: (syncOptions, serverResponses) => {
let serverResponse;
let urls = [];
// Todo: Can fire multiple usersync calls if multiple responses for same adsize found
if (serverResponses.length > 0 && serverResponses[0] && serverResponses[0].body) {
serverResponse = serverResponses[0].body;
}
if (serverResponse && serverResponse.ext && serverResponse.ext.bidderstatus && utils.isArray(serverResponse.ext.bidderstatus)) {
serverResponse.ext.bidderstatus.forEach(bidder => {
if (bidder.usersync && bidder.usersync.url) {
if (bidder.usersync.type === IFRAME) {
if (syncOptions.iframeEnabled) {
urls.push({
type: IFRAME,
url: bidder.usersync.url
});
} else {
utils.logWarn(bidder.bidder + ': Please enable iframe based user sync.');
}
} else if (bidder.usersync.type === IMAGE || bidder.usersync.type === REDIRECT) {
if (syncOptions.pixelEnabled) {
urls.push({
type: IMAGE,
url: bidder.usersync.url
});
} else {
utils.logWarn(bidder.bidder + ': Please enable pixel based user sync.');
}
} else {
utils.logWarn(bidder.bidder + ': Please provide valid user sync type.');
}
}
});
}
return urls;
}
};

registerBidder(spec);
47 changes: 47 additions & 0 deletions modules/pubmaticServerBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Overview

```
Module Name: PubMatic-Server Bid Adapter
Module Type: Bidder Adapter
Maintainer: UOEDev@pubmatic.com
```

# Description

Connects to PubMatic exchange for bids.

PubMaticServer bid adapter supports Banner currently.

# Sample Ad Unit: For Publishers
```
var pbjs = pbjs || {};
pbjs.que.push(function() {
var adUnits = [{
code: 'test-div',
sizes: [
[300, 250],
[728, 90]
],
bids: [{
bidder: 'pubmaticServer',
params: {
publisherId: '301', // required
adSlot: '/15671365/DMDemo@728x90', // required
profileid: '', // required
divId: '', // required
versionid: '', // optional (Default 0)
// openRTB params
lat: '40.712775', // optional
lon: '-74.005973', // optional
yob: '1982', // optional
gender: 'M' // optional
}
}]
}];
});
```
Loading

0 comments on commit 1516602

Please sign in to comment.