From 4682ae39963d09e38179280a7edbce92bb7b4114 Mon Sep 17 00:00:00 2001 From: Jaimin Panchal Date: Tue, 7 Aug 2018 14:31:16 -0400 Subject: [PATCH] prebidServerBidAdapter cleanup (#2844) * prebidServerBidAdapter cleanup * move module * wip * remove commented code --- modules/appnexusBidAdapter.js | 24 +++ modules/audienceNetworkBidAdapter.js | 17 +- modules/conversantBidAdapter.js | 14 ++ modules/ixBidAdapter.js | 12 ++ modules/openxBidAdapter.js | 6 + modules/prebidServerBidAdapter/config.js | 19 +++ .../index.js} | 156 +++--------------- modules/pubmaticBidAdapter.js | 13 ++ modules/pulsepointBidAdapter.js | 8 +- modules/rubiconBidAdapter.js | 13 ++ src/adapters/bidderFactory.js | 2 + src/utils.js | 35 ++++ .../modules/prebidServerBidAdapter_spec.js | 2 +- 13 files changed, 185 insertions(+), 136 deletions(-) create mode 100644 modules/prebidServerBidAdapter/config.js rename modules/{prebidServerBidAdapter.js => prebidServerBidAdapter/index.js} (84%) diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index ab9a13404e5..d5cb3ac2800 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -129,6 +129,30 @@ export const spec = { url: '//acdn.adnxs.com/ib/static/usersync/v3/async_usersync.html' }]; } + }, + + transformBidParams: function(params, isOpenRtb) { + params = utils.convertTypes({ + 'member': 'string', + 'invCode': 'string', + 'placementId': 'number', + 'keywords': utils.transformBidderParamKeywords + }, params); + + if (isOpenRtb) { + params.use_pmt_rule = (typeof params.usePaymentRule === 'boolean') ? params.usePaymentRule : false; + if (params.usePaymentRule) { delete params.usePaymentRule; } + + Object.keys(params).forEach(paramKey => { + let convertedKey = utils.convertCamelToUnderscore(paramKey); + if (convertedKey !== paramKey) { + params[convertedKey] = params[paramKey]; + delete params[paramKey]; + } + }); + } + + return params; } } diff --git a/modules/audienceNetworkBidAdapter.js b/modules/audienceNetworkBidAdapter.js index 5e9053dfc40..12810a960c1 100644 --- a/modules/audienceNetworkBidAdapter.js +++ b/modules/audienceNetworkBidAdapter.js @@ -4,7 +4,7 @@ import { registerBidder } from 'src/adapters/bidderFactory'; import { config } from 'src/config'; import { formatQS } from 'src/url'; -import { generateUUID, getTopWindowUrl, isSafariBrowser } from 'src/utils'; +import { generateUUID, getTopWindowUrl, isSafariBrowser, convertTypes } from 'src/utils'; import findIndex from 'core-js/library/fn/array/find-index'; import includes from 'core-js/library/fn/array/includes'; @@ -242,12 +242,25 @@ const interpretResponse = ({ body }, { adformats, requestIds, sizes }) => { }); }; +/** + * Covert bid param types for S2S + * @param {Object} params bid params + * @param {Boolean} isOpenRtb boolean to check openrtb2 protocol + * @return {Object} params bid params + */ +const transformBidParams = (params, isOpenRtb) => { + return convertTypes({ + 'placementId': 'string' + }, params); +} + export const spec = { code, supportedMediaTypes, isBidRequestValid, buildRequests, - interpretResponse + interpretResponse, + transformBidParams }; registerBidder(spec); diff --git a/modules/conversantBidAdapter.js b/modules/conversantBidAdapter.js index b5171b6c9ad..aae892f4eed 100644 --- a/modules/conversantBidAdapter.js +++ b/modules/conversantBidAdapter.js @@ -196,6 +196,20 @@ export const spec = { } return bidResponses; + }, + + /** + * Covert bid param types for S2S + * @param {Object} params bid params + * @param {Boolean} isOpenRtb boolean to check openrtb2 protocol + * @return {Object} params bid params + */ + transformBidParams: function(params, isOpenRtb) { + return utils.convertTypes({ + 'site_id': 'string', + 'secure': 'number', + 'mobile': 'number' + }, params); } }; diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 0778917efb1..c09a35e4d67 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -305,6 +305,18 @@ export const spec = { } return bids; + }, + + /** + * Covert bid param types for S2S + * @param {Object} params bid params + * @param {Boolean} isOpenRtb boolean to check openrtb2 protocol + * @return {Object} params bid params + */ + transformBidParams: function(params, isOpenRtb) { + return utils.convertTypes({ + 'siteID': 'number' + }, params); } }; diff --git a/modules/openxBidAdapter.js b/modules/openxBidAdapter.js index cd5bcef36ad..6a79681484e 100644 --- a/modules/openxBidAdapter.js +++ b/modules/openxBidAdapter.js @@ -63,6 +63,12 @@ export const spec = { url: url }]; } + }, + transformBidParams: function(params, isOpenRtb) { + return utils.convertTypes({ + 'unit': 'string', + 'customFloor': 'number' + }, params); } }; diff --git a/modules/prebidServerBidAdapter/config.js b/modules/prebidServerBidAdapter/config.js new file mode 100644 index 00000000000..a2b0b6bec77 --- /dev/null +++ b/modules/prebidServerBidAdapter/config.js @@ -0,0 +1,19 @@ +// accountId and bidders params are not included here, should be configured by end-user +export const S2S_VENDORS = { + 'appnexus': { + adapter: 'prebidServer', + cookieSet: false, + enabled: true, + endpoint: '//prebid.adnxs.com/pbs/v1/openrtb2/auction', + syncEndpoint: '//prebid.adnxs.com/pbs/v1/cookie_sync', + timeout: 1000 + }, + 'rubicon': { + adapter: 'prebidServer', + cookieSet: false, + enabled: true, + endpoint: '//prebid-server.rubiconproject.com/auction', + syncEndpoint: '//prebid-server.rubiconproject.com/cookie_sync', + timeout: 500 + } +} diff --git a/modules/prebidServerBidAdapter.js b/modules/prebidServerBidAdapter/index.js similarity index 84% rename from modules/prebidServerBidAdapter.js rename to modules/prebidServerBidAdapter/index.js index 28d7dcb54c4..47c1bfa80db 100644 --- a/modules/prebidServerBidAdapter.js +++ b/modules/prebidServerBidAdapter/index.js @@ -10,6 +10,7 @@ import { VIDEO } from 'src/mediaTypes'; import { isValid } from 'src/adapters/bidderFactory'; import events from 'src/events'; import includes from 'core-js/library/fn/array/includes'; +import { S2S_VENDORS } from './config.js'; const getConfig = config.getConfig; @@ -32,26 +33,6 @@ config.setDefaults({ 's2sConfig': s2sDefaultConfig }); -// accountId and bidders params are not included here, should be configured by end-user -const availVendorDefaults = { - 'appnexus': { - adapter: 'prebidServer', - cookieSet: false, - enabled: true, - endpoint: '//prebid.adnxs.com/pbs/v1/openrtb2/auction', - syncEndpoint: '//prebid.adnxs.com/pbs/v1/cookie_sync', - timeout: 1000 - }, - 'rubicon': { - adapter: 'prebidServer', - cookieSet: false, - enabled: true, - endpoint: '//prebid-server.rubiconproject.com/auction', - syncEndpoint: '//prebid-server.rubiconproject.com/cookie_sync', - timeout: 500 - } -}; - /** * Set config for server to server header bidding * @typedef {Object} options - required @@ -69,13 +50,12 @@ function setS2sConfig(options) { if (options.defaultVendor) { let vendor = options.defaultVendor; let optionKeys = Object.keys(options); - - if (availVendorDefaults.hasOwnProperty(vendor)) { + if (S2S_VENDORS[vendor]) { // vendor keys will be set if either: the key was not specified by user // or if the user did not set their own distinct value (ie using the system default) to override the vendor - Object.keys(availVendorDefaults[vendor]).forEach(function(vendorKey) { + Object.keys(S2S_VENDORS[vendor]).forEach((vendorKey) => { if (s2sDefaultConfig[vendorKey] === options[vendorKey] || !includes(optionKeys, vendorKey)) { - options[vendorKey] = availVendorDefaults[vendor][vendorKey]; + options[vendorKey] = S2S_VENDORS[vendor][vendorKey]; } }); } else { @@ -184,93 +164,6 @@ function doClientSideSyncs(bidders) { }); } -/** - * Try to convert a value to a type. - * If it can't be done, the value will be returned. - * - * @param {string} typeToConvert The target type. e.g. "string", "number", etc. - * @param {*} value The value to be converted into typeToConvert. - */ -function tryConvertType(typeToConvert, value) { - if (typeToConvert === 'string') { - return value && value.toString(); - } else if (typeToConvert === 'number') { - return Number(value); - } else { - return value; - } -} - -const tryConvertString = tryConvertType.bind(null, 'string'); -const tryConvertNumber = tryConvertType.bind(null, 'number'); - -const paramTypes = { - 'appnexus': { - 'member': tryConvertString, - 'invCode': tryConvertString, - 'placementId': tryConvertNumber, - 'keywords': utils.transformBidderParamKeywords - }, - 'rubicon': { - 'accountId': tryConvertNumber, - 'siteId': tryConvertNumber, - 'zoneId': tryConvertNumber - }, - 'indexExchange': { - 'siteID': tryConvertNumber - }, - 'audienceNetwork': { - 'placementId': tryConvertString - }, - 'pubmatic': { - 'publisherId': tryConvertString, - 'adSlot': tryConvertString - }, - 'districtm': { - 'member': tryConvertString, - 'invCode': tryConvertString, - 'placementId': tryConvertNumber - }, - 'pulsepoint': { - 'cf': tryConvertString, - 'cp': tryConvertNumber, - 'ct': tryConvertNumber - }, - 'conversant': { - 'site_id': tryConvertString, - 'secure': tryConvertNumber, - 'mobile': tryConvertNumber - }, - 'openx': { - 'unit': tryConvertString, - 'customFloor': tryConvertNumber - }, -}; - -/* - * Modify an adunit's bidder parameters to match the expected parameter types - */ -function convertTypes(adUnits) { - adUnits.forEach(adUnit => { - adUnit.bids.forEach(bid => { - // aliases use the base bidder's paramTypes - const bidder = adaptermanager.aliasRegistry[bid.bidder] || bid.bidder; - const types = paramTypes[bidder] || []; - - Object.keys(types).forEach(key => { - if (bid.params[key]) { - bid.params[key] = types[key](bid.params[key]); - - // don't send invalid values - if (isNaN(bid.params[key])) { - delete bid.params.key; - } - } - }); - }); - }); -} - function _getDigiTrustQueryParams() { function getDigiTrustId() { let digiTrustUser = window.DigiTrust && (config.getConfig('digiTrustId') || window.DigiTrust.getUser({member: 'T9QSFKPDN9'})); @@ -327,6 +220,15 @@ function transformHeightWidth(adUnit) { const LEGACY_PROTOCOL = { buildRequest(s2sBidRequest, bidRequests, adUnits) { + adUnits.forEach(adUnit => { + adUnit.bids.forEach(bid => { + const adapter = adaptermanager.bidderRegistry[bid.bidder]; + if (adapter && adapter.getSpec().transformBidParams) { + bid.params = adapter.getSpec().transformBidParams(bid.params, isOpenRtb()); + } + }); + }); + // pbs expects an ad_unit.video attribute if the imp is video adUnits.forEach(adUnit => { adUnit.sizes = transformHeightWidth(adUnit); @@ -504,19 +406,9 @@ const OPEN_RTB_PROTOCOL = { // get bidder params in form { : {...params} } const ext = adUnit.bids.reduce((acc, bid) => { - // TODO: move this bidder specific out to a more ideal location (submodule?); https://github.com/prebid/Prebid.js/issues/2420 - // convert all AppNexus keys to underscore format for pbs - if (bid.bidder === 'appnexus') { - bid.params.use_pmt_rule = (typeof bid.params.usePaymentRule === 'boolean') ? bid.params.usePaymentRule : false; - if (bid.params.usePaymentRule) { delete bid.params.usePaymentRule; } - - Object.keys(bid.params).forEach(paramKey => { - let convertedKey = utils.convertCamelToUnderscore(paramKey); - if (convertedKey !== paramKey) { - bid.params[convertedKey] = bid.params[paramKey]; - delete bid.params[paramKey]; - } - }); + const adapter = adaptermanager.bidderRegistry[bid.bidder]; + if (adapter && adapter.getSpec().transformBidParams) { + bid.params = adapter.getSpec().transformBidParams(bid.params, isOpenRtb()); } acc[bid.bidder] = bid.params; return acc; @@ -643,6 +535,13 @@ const OPEN_RTB_PROTOCOL = { } }; +const isOpenRtb = () => { + const OPEN_RTB_PATH = '/openrtb2/'; + + const endpoint = (_s2sConfig && _s2sConfig.endpoint) || ''; + return ~endpoint.indexOf(OPEN_RTB_PATH); +} + /* * Returns the required protocol adapter to communicate with the configured * endpoint. The adapter is an object containing `buildRequest` and @@ -656,12 +555,7 @@ const OPEN_RTB_PROTOCOL = { * const bids = protocol().interpretResponse(response, bidRequests, requestedBidders); */ const protocolAdapter = () => { - const OPEN_RTB_PATH = '/openrtb2/'; - - const endpoint = (_s2sConfig && _s2sConfig.endpoint) || ''; - const isOpenRtb = ~endpoint.indexOf(OPEN_RTB_PATH); - - return isOpenRtb ? OPEN_RTB_PROTOCOL : LEGACY_PROTOCOL; + return isOpenRtb() ? OPEN_RTB_PROTOCOL : LEGACY_PROTOCOL; }; /** @@ -674,8 +568,6 @@ export function PrebidServer() { baseAdapter.callBids = function(s2sBidRequest, bidRequests, addBidResponse, done, ajax) { const adUnits = utils.deepClone(s2sBidRequest.ad_units); - convertTypes(adUnits); - // at this point ad units should have a size array either directly or mapped so filter for that const adUnitsWithSizes = adUnits.filter(unit => unit.sizes && unit.sizes.length); diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 95e639b6843..8b5a766e48b 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -494,6 +494,19 @@ export const spec = { } else { utils.logWarn('PubMatic: Please enable iframe based user sync.'); } + }, + + /** + * Covert bid param types for S2S + * @param {Object} params bid params + * @param {Boolean} isOpenRtb boolean to check openrtb2 protocol + * @return {Object} params bid params + */ + transformBidParams: function(params, isOpenRtb) { + return utils.convertTypes({ + 'publisherId': 'string', + 'adSlot': 'string' + }, params); } }; diff --git a/modules/pulsepointBidAdapter.js b/modules/pulsepointBidAdapter.js index 94733ad7805..7a05253e339 100644 --- a/modules/pulsepointBidAdapter.js +++ b/modules/pulsepointBidAdapter.js @@ -66,8 +66,14 @@ export const spec = { url: '//bh.contextweb.com/visitormatch/prebid' }]; } + }, + transformBidParams: function(params, isOpenRtb) { + return utils.convertTypes({ + 'cf': 'string', + 'cp': 'number', + 'ct': 'number' + }, params); } - }; /** diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js index e77b247a349..83c3c69cf15 100644 --- a/modules/rubiconBidAdapter.js +++ b/modules/rubiconBidAdapter.js @@ -476,6 +476,19 @@ export const spec = { url: SYNC_ENDPOINT + params }; } + }, + /** + * Covert bid param types for S2S + * @param {Object} params bid params + * @param {Boolean} isOpenRtb boolean to check openrtb2 protocol + * @return {Object} params bid params + */ + transformBidParams: function(params, isOpenRtb) { + return utils.convertTypes({ + 'accountId': 'number', + 'siteId': 'number', + 'zoneId': 'number' + }, params); } }; diff --git a/src/adapters/bidderFactory.js b/src/adapters/bidderFactory.js index 8e359d98259..b7574f24c08 100644 --- a/src/adapters/bidderFactory.js +++ b/src/adapters/bidderFactory.js @@ -53,6 +53,8 @@ import { logWarn, logError, parseQueryStringParameters, delayExecution, parseSiz * from the server, determine which user syncs should occur. The argument array will contain every element * which has been sent through to interpretResponse. The order of syncs in this array matters. The most * important ones should come first, since publishers may limit how many are dropped on their page. + * @property {function(object): object} transformBidParams Updates bid params before creating bid request + }} */ /** diff --git a/src/utils.js b/src/utils.js index 7845e1e9bb0..ac7f035d652 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1091,3 +1091,38 @@ export function transformBidderParamKeywords(keywords, paramName = 'keywords') { return arrs; } + +/** + * Try to convert a value to a type. + * If it can't be done, the value will be returned. + * + * @param {string} typeToConvert The target type. e.g. "string", "number", etc. + * @param {*} value The value to be converted into typeToConvert. + */ +function tryConvertType(typeToConvert, value) { + if (typeToConvert === 'string') { + return value && value.toString(); + } else if (typeToConvert === 'number') { + return Number(value); + } else { + return value; + } +} + +export function convertTypes(types, params) { + Object.keys(types).forEach(key => { + if (params[key]) { + if (exports.isFn(types[key])) { + params[key] = types[key](params[key]); + } else { + params[key] = tryConvertType(types[key], params[key]); + } + + // don't send invalid values + if (isNaN(params[key])) { + delete params.key; + } + } + }); + return params; +} diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index cd2022bcab7..f3cc150ab6e 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { PrebidServer as Adapter, resetSyncedStatus } from 'modules/prebidServerBidAdapter'; +import { PrebidServer as Adapter, resetSyncedStatus } from 'modules/prebidServerBidAdapter/index.js'; import adapterManager from 'src/adaptermanager'; import * as utils from 'src/utils'; import cookie from 'src/cookie';