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

Auction module updated to support currency/hook #1733

Merged
merged 18 commits into from
Nov 6, 2017
Merged
Show file tree
Hide file tree
Changes from all 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
170 changes: 85 additions & 85 deletions integrationExamples/gpt/hello_world.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,91 +12,91 @@
-->

<html>
<head>
<script>
var PREBID_TIMEOUT = 700;

var adUnits = [{
code: 'div-gpt-ad-1460505748561-0',
sizes: [[300, 250], [300,600]],

// Replace this object to test a new Adapter!
bids: [{
bidder: 'appnexus',
params: {
placementId: '10433394'
}
}]

}];

var pbjs = pbjs || {};
pbjs.que = pbjs.que || [];

</script>

<script type="text/javascript" src="../../build/dev/prebid.js" async></script>
<script>
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
googletag.cmd.push(function() {
googletag.pubads().disableInitialLoad();
});

pbjs.que.push(function() {
pbjs.addAdUnits(adUnits);
pbjs.requestBids({
bidsBackHandler: sendAdserverRequest
});
});

function sendAdserverRequest() {
if (pbjs.adserverRequestSent) return;
pbjs.adserverRequestSent = true;
<head>
<script>
var PREBID_TIMEOUT = 700;

var adUnits = [{
code: 'div-gpt-ad-1460505748561-0',
sizes: [[300, 250], [300,600]],

// Replace this object to test a new Adapter!
bids: [{
bidder: 'appnexusAst',
params: {
placementId: '10433394'
}
}]

}];

var pbjs = pbjs || {};
pbjs.que = pbjs.que || [];

</script>

<script type="text/javascript" src="../../build/dev/prebid.js" async></script>
<script>
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
googletag.cmd.push(function() {
pbjs.que.push(function() {
pbjs.setTargetingForGPTAsync();
googletag.pubads().refresh();
googletag.pubads().disableInitialLoad();
});

pbjs.que.push(function() {
pbjs.addAdUnits(adUnits);
pbjs.requestBids({
bidsBackHandler: sendAdserverRequest
});
});
}

setTimeout(function() {
sendAdserverRequest();
}, PREBID_TIMEOUT);

</script>

<script>
(function () {
var gads = document.createElement('script');
gads.async = true;
gads.type = 'text/javascript';
var useSSL = 'https:' == document.location.protocol;
gads.src = (useSSL ? 'https:' : 'http:') +
'//www.googletagservices.com/tag/js/gpt.js';
var node = document.getElementsByTagName('script')[0];
node.parentNode.insertBefore(gads, node);
})();
</script>

<script>
googletag.cmd.push(function () {
googletag.defineSlot('/19968336/header-bid-tag-0', [[300, 250], [300, 600]], 'div-gpt-ad-1460505748561-0').addService(googletag.pubads());

googletag.pubads().enableSingleRequest();
googletag.enableServices();
});
</script>
</head>

<body>
<h2>Prebid.js Test</h2>
<h5>Div-1</h5>
<div id='div-gpt-ad-1460505748561-0'>
<script type='text/javascript'>
googletag.cmd.push(function() { googletag.display('div-gpt-ad-1460505748561-0'); });
</script>
</div>
</body>
</html>

function sendAdserverRequest() {
if (pbjs.adserverRequestSent) return;
pbjs.adserverRequestSent = true;
googletag.cmd.push(function() {
pbjs.que.push(function() {
pbjs.setTargetingForGPTAsync();
googletag.pubads().refresh();
});
});
}

setTimeout(function() {
sendAdserverRequest();
}, PREBID_TIMEOUT);

</script>

<script>
(function () {
var gads = document.createElement('script');
gads.async = true;
gads.type = 'text/javascript';
var useSSL = 'https:' == document.location.protocol;
gads.src = (useSSL ? 'https:' : 'http:') +
'//www.googletagservices.com/tag/js/gpt.js';
var node = document.getElementsByTagName('script')[0];
node.parentNode.insertBefore(gads, node);
})();
</script>

<script>
googletag.cmd.push(function () {
googletag.defineSlot('/19968336/header-bid-tag-0', [[300, 250], [300, 600]], 'div-gpt-ad-1460505748561-0').addService(googletag.pubads());

googletag.pubads().enableSingleRequest();
googletag.enableServices();
});
</script>
</head>

<body>
<h2>Prebid.js Test</h2>
<h5>Div-1</h5>
<div id='div-gpt-ad-1460505748561-0'>
<script type='text/javascript'>
googletag.cmd.push(function() { googletag.display('div-gpt-ad-1460505748561-0'); });
</script>
</div>
</body>
</html>
59 changes: 33 additions & 26 deletions modules/currency.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { STATUS } from 'src/constants';
import { ajax } from 'src/ajax';
import * as utils from 'src/utils';
import { config } from 'src/config';
import { hooks } from 'src/hook.js';

const DEFAULT_CURRENCY_RATE_URL = 'http://currency.prebid.org/latest.json';
const CURRENCY_RATE_PRECISION = 4;
Expand Down Expand Up @@ -77,6 +78,10 @@ function initCurrency(url) {
conversionCache = {};
currencySupportEnabled = true;

utils.logInfo('Installing addBidResponse decorator for currency module', arguments);

hooks['addBidResponse'].addHook(addBidResponseHook, 100);

if (!currencyRates.conversions) {
ajax(url, function (response) {
try {
Expand All @@ -92,6 +97,10 @@ function initCurrency(url) {
}

function resetCurrency() {
utils.logInfo('Uninstalling addBidResponse decorator for currency module', arguments);

hooks['addBidResponse'].removeHook(addBidResponseHook, 100);

adServerCurrency = 'USD';
conversionCache = {};
currencySupportEnabled = false;
Expand All @@ -100,37 +109,35 @@ function resetCurrency() {
bidderCurrencyDefault = {};
}

export function addBidResponseDecorator(fn) {
return function(adUnitCode, bid) {
if (!bid) {
return fn.apply(this, arguments); // if no bid, call original and let it display warnings
}
export function addBidResponseHook(adUnitCode, bid, fn) {
if (!bid) {
return fn.apply(this, arguments); // if no bid, call original and let it display warnings
}

let bidder = bid.bidderCode || bid.bidder;
if (bidderCurrencyDefault[bidder]) {
let currencyDefault = bidderCurrencyDefault[bidder];
if (bid.currency && currencyDefault !== bid.currency) {
utils.logWarn(`Currency default '${bidder}: ${currencyDefault}' ignored. adapter specified '${bid.currency}'`);
} else {
bid.currency = currencyDefault;
}
let bidder = bid.bidderCode || bid.bidder;
if (bidderCurrencyDefault[bidder]) {
let currencyDefault = bidderCurrencyDefault[bidder];
if (bid.currency && currencyDefault !== bid.currency) {
utils.logWarn(`Currency default '${bidder}: ${currencyDefault}' ignored. adapter specified '${bid.currency}'`);
} else {
bid.currency = currencyDefault;
}
}

// default to USD if currency not set
if (!bid.currency) {
utils.logWarn('Currency not specified on bid. Defaulted to "USD"');
bid.currency = 'USD';
}
// default to USD if currency not set
if (!bid.currency) {
utils.logWarn('Currency not specified on bid. Defaulted to "USD"');
bid.currency = 'USD';
}

// execute immediately if the bid is already in the desired currency
if (bid.currency === adServerCurrency) {
return fn.apply(this, arguments);
}
// execute immediately if the bid is already in the desired currency
if (bid.currency === adServerCurrency) {
return fn.apply(this, arguments);
}

bidResponseQueue.push(wrapFunction(fn, this, arguments));
if (!currencySupportEnabled || currencyRatesLoaded) {
processBidResponseQueue();
}
bidResponseQueue.push(wrapFunction(fn, this, arguments));
if (!currencySupportEnabled || currencyRatesLoaded) {
processBidResponseQueue();
}
}

Expand Down
89 changes: 74 additions & 15 deletions src/adapters/bidderFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { config } from 'src/config';
import bidfactory from 'src/bidfactory';
import { STATUS } from 'src/constants';
import { userSync } from 'src/userSync';
import { nativeBidIsValid } from 'src/native';
import { isValidVideoBid } from 'src/video';

import { logWarn, logError, parseQueryStringParameters, delayExecution } from 'src/utils';
import { logWarn, logError, parseQueryStringParameters, delayExecution, parseSizesInput, getBidderRequest } from 'src/utils';

/**
* This file aims to support Adapters during the Prebid 0.x -> 1.x transition.
Expand Down Expand Up @@ -160,7 +162,9 @@ export function newBidder(spec) {
const adUnitCodesHandled = {};
function addBidWithCode(adUnitCode, bid) {
adUnitCodesHandled[adUnitCode] = true;
addBidResponse(adUnitCode, bid);
if (isValid(adUnitCode, bid, [bidderRequest])) {
addBidResponse(adUnitCode, bid);
}
}

// After all the responses have come back, call done() and
Expand Down Expand Up @@ -279,17 +283,12 @@ export function newBidder(spec) {
onResponse();

function addBidUsingRequestMap(bid) {
// In Prebid 1.0 all the validation logic from bidmanager will move here, as of now we are only validating new params so that adapters dont miss adding them.
if (hasValidKeys(bid)) {
const bidRequest = bidRequestMap[bid.requestId];
if (bidRequest) {
const prebidBid = Object.assign(bidfactory.createBid(STATUS.GOOD, bidRequest), bid);
addBidWithCode(bidRequest.adUnitCode, prebidBid);
} else {
logWarn(`Bidder ${spec.code} made bid for unknown request ID: ${bid.requestId}. Ignoring.`);
}
const bidRequest = bidRequestMap[bid.requestId];
if (bidRequest) {
const prebidBid = Object.assign(bidfactory.createBid(STATUS.GOOD, bidRequest), bid);
addBidWithCode(bidRequest.adUnitCode, prebidBid);
} else {
logError(`Bidder ${spec.code} is missing required params. Check http://prebid.org/dev-docs/bidder-adapter-1.html for list of params.`);
logWarn(`Bidder ${spec.code} made bid for unknown request ID: ${bid.requestId}. Ignoring.`);
}
}

Expand Down Expand Up @@ -318,8 +317,68 @@ export function newBidder(spec) {
return true;
}

function hasValidKeys(bid) {
let bidKeys = Object.keys(bid);
return COMMON_BID_RESPONSE_KEYS.every(key => bidKeys.includes(key));
// Validate the arguments sent to us by the adapter. If this returns false, the bid should be totally ignored.
function isValid(adUnitCode, bid, bidRequests) {
function hasValidKeys() {
let bidKeys = Object.keys(bid);
return COMMON_BID_RESPONSE_KEYS.every(key => bidKeys.includes(key));
}

function errorMessage(msg) {
return `Invalid bid from ${bid.bidderCode}. Ignoring bid: ${msg}`;
}

if (!adUnitCode) {
logWarn('No adUnitCode was supplied to addBidResponse.');
return false;
}

if (!bid) {
logWarn(`Some adapter tried to add an undefined bid for ${adUnitCode}.`);
return false;
}

if (!hasValidKeys()) {
logError(errorMessage(`Bidder ${bid.bidderCode} is missing required params. Check http://prebid.org/dev-docs/bidder-adapter-1.html for list of params.`));
return false;
}

if (bid.mediaType === 'native' && !nativeBidIsValid(bid, bidRequests)) {
logError(errorMessage('Native bid missing some required properties.'));
return false;
}
if (bid.mediaType === 'video' && !isValidVideoBid(bid, bidRequests)) {
logError(errorMessage(`Video bid does not have required vastUrl or renderer property`));
return false;
}
if (bid.mediaType === 'banner' && !validBidSize(adUnitCode, bid, bidRequests)) {
logError(errorMessage(`Banner bids require a width and height`));
return false;
}

return true;
}

// check that the bid has a width and height set
function validBidSize(adUnitCode, bid, bidRequests) {
if ((bid.width || bid.width === 0) && (bid.height || bid.height === 0)) {
return true;
}

const adUnit = getBidderRequest(bidRequests, bid.bidderCode, adUnitCode);

const sizes = adUnit && adUnit.bids && adUnit.bids[0] && adUnit.bids[0].sizes;
const parsedSizes = parseSizesInput(sizes);

// if a banner impression has one valid size, we assign that size to any bid
// response that does not explicitly set width or height
if (parsedSizes.length === 1) {
const [ width, height ] = parsedSizes[0].split('x');
bid.width = width;
bid.height = height;
return true;
}

return false;
}
}
Loading