Skip to content

Commit

Permalink
Upgrade Quantcast adapter for Prebid 1.0 (#1753)
Browse files Browse the repository at this point in the history
* Add v1.0 adapter skeleton

* Fix a typo in variable name declaration

* Change spec dependencies

* Add new describes for test

* Move URL detechtion inside buildRequests method

* Add necessary cases

* Clean test cases

* Export Quantcast adapter constants

* Implemenent test cases

* Fix wrong ports number

* Correct test cases

* Make string with single quote

* Remove unused statements

* Revert "Remove unused statements"

This reverts commit 459ca31.

* Remove unused statements

* Change string to single quote

* Fix sizes type

* Fix the sizes propty name typo in the spec

* Remove unused method, key value and comments

* Update the spec

* Change code using single quote

* Update the first argument for interpretResponse method and its spec

* Handle undefined Server Response

* Add required params from the server response
  • Loading branch information
Xinyang Li authored and matthewlane committed Oct 26, 2017
1 parent c5d1ecf commit 51ffb4e
Show file tree
Hide file tree
Showing 3 changed files with 347 additions and 294 deletions.
255 changes: 146 additions & 109 deletions modules/quantcastBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,128 +1,165 @@
const utils = require('src/utils.js');
const bidfactory = require('src/bidfactory.js');
const bidmanager = require('src/bidmanager.js');
const ajax = require('src/ajax.js');
const CONSTANTS = require('src/constants.json');
const adaptermanager = require('src/adaptermanager');
const QUANTCAST_CALLBACK_URL = 'http://global.qc.rtb.quantserve.com:8080/qchb';

var QuantcastAdapter = function QuantcastAdapter() {
const BIDDER_CODE = 'quantcast';

const DEFAULT_BID_FLOOR = 0.0000000001;
let bidRequests = {};

let returnEmptyBid = function(bidId) {
var bidRequested = utils.getBidRequest(bidId);
if (!utils.isEmpty(bidRequested)) {
let bid = bidfactory.createBid(CONSTANTS.STATUS.NO_BID, bidRequested);
bid.bidderCode = BIDDER_CODE;
bidmanager.addBidResponse(bidRequested.placementCode, bid);
import * as utils from 'src/utils';
import { registerBidder } from 'src/adapters/bidderFactory';

const BIDDER_CODE = 'quantcast';
const DEFAULT_BID_FLOOR = 0.0000000001;

export const QUANTCAST_CALLBACK_URL = 'global.qc.rtb.quantserve.com';
export const QUANTCAST_CALLBACK_URL_TEST = 's2s-canary.quantserve.com';
export const QUANTCAST_NET_REVENUE = true;
export const QUANTCAST_TEST_PUBLISHER = 'test-publisher';
export const QUANTCAST_TTL = 4;

/**
* The documentation for Prebid.js Adapter 1.0 can be found at link below,
* http://prebid.org/dev-docs/bidder-adapter-1.html
*/
export const spec = {
code: BIDDER_CODE,

/**
* Verify the `AdUnits.bids` response with `true` for valid request and `false`
* for invalid request.
*
* @param {object} bid
* @return boolean `true` is this is a valid bid, and `false` otherwise
*/
isBidRequestValid(bid) {
if (!bid) {
return false;
}
};

// expose the callback to the global object:
$$PREBID_GLOBAL$$.handleQuantcastCB = function (responseText) {
if (utils.isEmpty(responseText)) {
return;
}
let response = null;
try {
response = JSON.parse(responseText);
} catch (e) {
// Malformed JSON
utils.logError("Malformed JSON received from server - can't do anything here");
return;
}

if (response === null || !response.hasOwnProperty('bids') || utils.isEmpty(response.bids)) {
utils.logError("Sub-optimal JSON received from server - can't do anything here");
return;
if (bid.mediaType === 'video') {
return false;
}

for (let i = 0; i < response.bids.length; i++) {
let seatbid = response.bids[i];
let key = seatbid.placementCode;
var request = bidRequests[key];
if (request === null || request === undefined) {
return returnEmptyBid(seatbid.placementCode);
}
// This line is required since this is the field
// that bidfactory.createBid looks for
request.bidId = request.imp[0].placementCode;
let responseBid = bidfactory.createBid(CONSTANTS.STATUS.GOOD, request);

responseBid.cpm = seatbid.cpm;
responseBid.ad = seatbid.ad;
responseBid.height = seatbid.height;
responseBid.width = seatbid.width;
responseBid.bidderCode = response.bidderCode;
responseBid.requestId = request.requestId;
responseBid.bidderCode = BIDDER_CODE;

bidmanager.addBidResponse(request.bidId, responseBid);
return true;
},

/**
* Make a server request when the page asks Prebid.js for bids from a list of
* `BidRequests`.
*
* @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be send to Quantcast server
* @return ServerRequest information describing the request to the server.
*/
buildRequests(bidRequests) {
const bids = bidRequests || [];

const referrer = utils.getTopWindowUrl();
const loc = utils.getTopWindowLocation();
const domain = loc.hostname;

let publisherTagURL;
let publisherTagURLTest;

// Switch the callback URL to Quantcast Canary Endpoint for testing purpose
// `//` is not used because we have different port setting at our end
switch (window.location.protocol) {
case 'https:':
publisherTagURL = `https://${QUANTCAST_CALLBACK_URL}:8443/qchb`;
publisherTagURLTest = `https://${QUANTCAST_CALLBACK_URL_TEST}:8443/qchb`;
break;
default:
publisherTagURL = `http://${QUANTCAST_CALLBACK_URL}:8080/qchb`;
publisherTagURLTest = `http://${QUANTCAST_CALLBACK_URL_TEST}:8080/qchb`;
}
};

function callBids(params) {
let bids = params.bids || [];
if (bids.length === 0) {
return;
}

let referrer = utils.getTopWindowUrl();
let loc = utils.getTopWindowLocation();
let domain = loc.hostname;
let publisherId = 0;
const bidRequestsList = bids.map(bid => {
const bidSizes = [];

publisherId = '' + bids[0].params.publisherId;
utils._each(bids, function(bid) {
let key = bid.placementCode;
var bidSizes = [];
utils._each(bid.sizes, function (size) {
bid.sizes.forEach(size => {
bidSizes.push({
'width': size[0],
'height': size[1]
width: size[0],
height: size[1]
});
});

bidRequests[key] = bidRequests[key] || {
'publisherId': publisherId,
'requestId': bid.bidId,
'bidId': bid.bidId,
'site': {
'page': loc.href,
'referrer': referrer,
'domain': domain,
// Request Data Format can be found at https://wiki.corp.qc/display/adinf/QCX
const requestData = {
publisherId: bid.params.publisherId,
requestId: bid.bidId,
imp: [
{
banner: {
battr: bid.params.battr,
sizes: bidSizes
},
placementCode: bid.placementCode,
bidFloor: bid.params.bidFloor || DEFAULT_BID_FLOOR
}
],
site: {
page: loc.href,
referrer,
domain
},
'imp': [{

'banner': {
'battr': bid.params.battr,
'sizes': bidSizes,
},
'placementCode': bid.placementCode,
'bidFloor': bid.params.bidFloor || DEFAULT_BID_FLOOR,
}]
bidId: bid.bidId
};
});

utils._each(bidRequests, function (bidRequest) {
ajax.ajax(QUANTCAST_CALLBACK_URL, $$PREBID_GLOBAL$$.handleQuantcastCB, JSON.stringify(bidRequest), {
const data = JSON.stringify(requestData);

const url =
bid.params.publisherId === QUANTCAST_TEST_PUBLISHER
? publisherTagURLTest
: publisherTagURL;

return {
data,
method: 'POST',
withCredentials: true
});
url
};
});
}

// Export the `callBids` function, so that Prebid.js can execute
// this function when the page asks to send out bid requests.
return {
callBids: callBids,
QUANTCAST_CALLBACK_URL: QUANTCAST_CALLBACK_URL
};
};
return bidRequestsList;
},

/**
* Function get called when the browser has received the response from Quantcast server.
* The function parse the response and create a `bidResponse` object containing one/more bids.
* Returns an empty array if no valid bids
*
* Response Data Format can be found at https://wiki.corp.qc/display/adinf/QCX
*
* @param {*} serverResponse A successful response from Quantcast server.
* @return {Bid[]} An array of bids which were nested inside the server.
*
*/
interpretResponse(serverResponse) {
if (serverResponse === undefined) {
utils.logError('Server Response is undefined');
return [];
}

const response = serverResponse['body'];

if (
response === undefined ||
!response.hasOwnProperty('bids') ||
utils.isEmpty(response.bids)
) {
utils.logError('Sub-optimal JSON received from Quantcast server');
return [];
}

adaptermanager.registerBidAdapter(new QuantcastAdapter(), 'quantcast');
const bidResponsesList = response.bids.map(bid => {
const { ad, cpm, width, height, creativeId, currency } = bid;

return {
requestId: response.requestId,
cpm,
width,
height,
ad,
ttl: QUANTCAST_TTL,
creativeId,
netRevenue: QUANTCAST_NET_REVENUE,
currency
};
});

return bidResponsesList;
}
};

module.exports = QuantcastAdapter;
registerBidder(spec);
31 changes: 31 additions & 0 deletions modules/quantcastBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Overview

```
Module Name: Quantcast Bidder Adapter
Module Type: Bidder Adapter
Maintainer: xli@quantcast.com
```

# Description

Module that connects to Quantcast demand sources to fetch bids.

# Test Parameters

```js
const adUnits = [{
code: 'banner',
sizes: [
[300, 250]
],
bids: [
{
bidder: 'quantcast',
params: {
publisherId: 'test-publisher', // REQUIRED - Publisher ID provided by Quantcast
battr: [1, 2] // OPTIONAL - Array of blocked creative attributes as per OpenRTB Spec List 5.3
}
}
]
}];
```
Loading

0 comments on commit 51ffb4e

Please sign in to comment.