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

Blue Billywig bid adapter update #5584

Merged
merged 5 commits into from
Sep 4, 2020
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
189 changes: 84 additions & 105 deletions modules/bluebillywigBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as utils from '../src/utils.js';
import find from 'core-js-pure/features/array/find.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { VIDEO } from '../src/mediaTypes.js';
import { config } from '../src/config.js';
Expand All @@ -17,7 +18,10 @@ const BB_CONSTANTS = {
DEFAULT_TTL: 300,
DEFAULT_WIDTH: 768,
DEFAULT_HEIGHT: 432,
DEFAULT_NET_REVENUE: true
DEFAULT_NET_REVENUE: true,
VIDEO_PARAMS: ['mimes', 'minduration', 'maxduration', 'protocols', 'w', 'h', 'startdelay', 'placement', 'linearity', 'skip', 'skipmin',
'skipafter', 'sequence', 'battr', 'maxextended', 'minbitrate', 'maxbitrate', 'boxingallowed', 'playbackmethod', 'playbackend', 'delivery', 'pos', 'companionad',
'api', 'companiontype', 'ext']
};

// Aliasing
Expand All @@ -26,8 +30,6 @@ const getConfig = config.getConfig;
// Helper Functions
export const BB_HELPERS = {
addSiteAppDevice: function(request, pageUrl) {
if (!request) return;

if (typeof getConfig('app') === 'object') request.app = getConfig('app');
else {
request.site = {};
Expand All @@ -41,32 +43,22 @@ export const BB_HELPERS = {
if (!request.device.h) request.device.h = window.innerHeight;
},
addSchain: function(request, validBidRequests) {
if (!request) return;

const schain = utils.deepAccess(validBidRequests, '0.schain');
if (schain) request.source.ext = { schain: schain };
},
addCurrency: function(request) {
if (!request) return;

const adServerCur = getConfig('currency.adServerCurrency');
if (adServerCur && typeof adServerCur === 'string') request.cur = [adServerCur];
else if (Array.isArray(adServerCur) && adServerCur.length) request.cur = [adServerCur[0]];
},
addUserIds: function(request, validBidRequests) {
if (!request) return;

const bidUserId = utils.deepAccess(validBidRequests, '0.userId');
const eids = createEidsArray(bidUserId);

if (eids.length) {
utils.deepSetValue(request, 'user.ext.eids', eids);
}
},
addDigiTrust: function(request, bidRequests) {
const digiTrust = BB_HELPERS.getDigiTrustParams(bidRequests && bidRequests[0]);
if (digiTrust) utils.deepSetValue(request, 'user.ext.digitrust', digiTrust);
},
substituteUrl: function (url, publication, renderer) {
return url.replace('$$URL_START', (DEV_MODE) ? 'https://dev.' : 'https://').replace('$$PUBLICATION', publication).replace('$$RENDERER', renderer);
},
Expand All @@ -79,41 +71,59 @@ export const BB_HELPERS = {
getRendererUrl: function(publication, renderer) {
return BB_HELPERS.substituteUrl(BB_CONSTANTS.RENDERER_URL, publication, renderer);
},
getDigiTrustParams: function(bidRequest) {
const digiTrustId = BB_HELPERS.getDigiTrustId(bidRequest);
transformVideoParams: function(videoParams, videoParamsExt) {
videoParams = utils.deepClone(videoParams);

if (!digiTrustId || (digiTrustId.privacy && digiTrustId.privacy.optout)) return null;
return {
id: digiTrustId.id,
keyv: digiTrustId.keyv
}
},
getDigiTrustId: function(bidRequest) {
const bidRequestDigiTrust = utils.deepAccess(bidRequest, 'userId.digitrustid.data');
if (bidRequestDigiTrust) return bidRequestDigiTrust;
let playerSize = videoParams.playerSize || [BB_CONSTANTS.DEFAULT_WIDTH, BB_CONSTANTS.DEFAULT_HEIGHT];
if (Array.isArray(playerSize[0])) playerSize = playerSize[0];

videoParams.w = playerSize[0];
videoParams.h = playerSize[1];
videoParams.placement = 3;

if (videoParamsExt) videoParams = Object.assign(videoParams, videoParamsExt);

const videoParamsProperties = Object.keys(videoParams);

const digiTrustUser = getConfig('digiTrustId');
return (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || null;
videoParamsProperties.forEach(property => {
if (BB_CONSTANTS.VIDEO_PARAMS.indexOf(property) === -1) delete videoParams[property];
});

return videoParams;
},
transformRTBToPrebidProps: function(bid, serverResponse) {
bid.cpm = bid.price; delete bid.price;
bid.bidId = bid.impid;
bid.requestId = bid.impid; delete bid.impid;
bid.width = bid.w || BB_CONSTANTS.DEFAULT_WIDTH;
bid.height = bid.h || BB_CONSTANTS.DEFAULT_HEIGHT;
const bidObject = {
cpm: bid.price,
currency: serverResponse.cur,
netRevenue: BB_CONSTANTS.DEFAULT_NET_REVENUE,
bidId: bid.impid,
requestId: bid.impid,
creativeId: bid.crid,
mediaType: VIDEO,
width: bid.w || BB_CONSTANTS.DEFAULT_WIDTH,
height: bid.h || BB_CONSTANTS.DEFAULT_HEIGHT,
ttl: BB_CONSTANTS.DEFAULT_TTL
};

const extPrebidTargeting = utils.deepAccess(bid, 'ext.prebid.targeting');
const extPrebidCache = utils.deepAccess(bid, 'ext.prebid.cache');

if (extPrebidCache && typeof extPrebidCache.vastXml === 'object' && extPrebidCache.vastXml.cacheId && extPrebidCache.vastXml.url) {
bidObject.videoCacheKey = extPrebidCache.vastXml.cacheId;
bidObject.vastUrl = extPrebidCache.vastXml.url;
} else if (extPrebidTargeting && extPrebidTargeting.hb_uuid && extPrebidTargeting.hb_cache_host && extPrebidTargeting.hb_cache_path) {
bidObject.videoCacheKey = extPrebidTargeting.hb_uuid;
bidObject.vastUrl = `https://${extPrebidTargeting.hb_cache_host}${extPrebidTargeting.hb_cache_path}?uuid=${extPrebidTargeting.hb_uuid}`;
}
if (bid.adm) {
bid.ad = bid.adm;
bid.vastXml = bid.adm;
delete bid.adm;
bidObject.ad = bid.adm;
bidObject.vastXml = bid.adm;
}
if (bid.nurl && !bid.adm) { // ad markup is on win notice url, and adm is ommited according to OpenRTB 2.5
bid.vastUrl = bid.nurl;
delete bid.nurl;
if (!bidObject.vastUrl && bid.nurl && !bid.adm) { // ad markup is on win notice url, and adm is ommited according to OpenRTB 2.5
bidObject.vastUrl = bid.nurl;
}
bid.netRevenue = BB_CONSTANTS.DEFAULT_NET_REVENUE;
bid.creativeId = bid.crid; delete bid.crid;
bid.currency = serverResponse.cur;
bid.ttl = BB_CONSTANTS.DEFAULT_TTL;

return bidObject;
},
};

Expand All @@ -132,18 +142,14 @@ const BB_RENDERER = {
return;
}

const rendererId = BB_RENDERER.getRendererId(bid.publicationName, bid.rendererCode);
if (!(window.bluebillywig && window.bluebillywig.renderers)) {
utils.logWarn(`${BB_CONSTANTS.BIDDER_CODE}: renderer code failed to initialize...`);
return;
}

const rendererId = BB_RENDERER.getRendererId(bid.publicationName, bid.rendererCode);
const ele = document.getElementById(bid.adUnitCode); // NB convention

let renderer;

for (let rendererIndex = 0; rendererIndex < window.bluebillywig.renderers.length; rendererIndex++) {
if (window.bluebillywig.renderers[rendererIndex]._id === rendererId) {
renderer = window.bluebillywig.renderers[rendererIndex];
break;
}
}
const renderer = find(window.bluebillywig.renderers, r => r._id === rendererId);

if (renderer) renderer.bootstrap(config, ele);
else utils.logWarn(`${BB_CONSTANTS.BIDDER_CODE}: Couldn't find a renderer with ${rendererId}`);
Expand Down Expand Up @@ -212,9 +218,8 @@ export const spec = {
utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: connections is not of type array. Rejecting bid: `, bid);
return false;
} else {
for (let connectionIndex = 0; connectionIndex < bid.params.connections.length; connectionIndex++) {
const connection = bid.params.connections[connectionIndex];
if (!bid.params.hasOwnProperty(connection)) {
for (let i = 0; i < bid.params.connections.length; i++) {
if (!bid.params.hasOwnProperty(bid.params.connections[i])) {
utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: connection specified in params.connections, but not configured in params. Rejecting bid: `, bid);
return false;
}
Expand All @@ -225,6 +230,11 @@ export const spec = {
return false;
}

if (bid.params.hasOwnProperty('video') && (bid.params.video === null || typeof bid.params.video !== 'object')) {
utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: params.video must be of type object. Rejecting bid: `, bid);
return false;
}

if (bid.hasOwnProperty('mediaTypes') && bid.mediaTypes.hasOwnProperty(VIDEO)) {
if (!bid.mediaTypes[VIDEO].hasOwnProperty('context')) {
utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no context specified in bid. Rejecting bid: `, bid);
Expand All @@ -245,20 +255,21 @@ export const spec = {
buildRequests(validBidRequests, bidderRequest) {
const imps = [];

for (let validBidRequestIndex = 0; validBidRequestIndex < validBidRequests.length; validBidRequestIndex++) {
const validBidRequest = validBidRequests[validBidRequestIndex];
const _this = this;
validBidRequests.forEach(validBidRequest => {
if (!this.syncStore.publicationName) this.syncStore.publicationName = validBidRequest.params.publicationName;
if (!this.syncStore.accountId) this.syncStore.accountId = validBidRequest.params.accountId;

const ext = validBidRequest.params.connections.reduce(function(extBuilder, connection) {
const ext = validBidRequest.params.connections.reduce((extBuilder, connection) => {
extBuilder[connection] = validBidRequest.params[connection];

if (_this.syncStore.bidders.indexOf(connection) === -1) _this.syncStore.bidders.push(connection);
if (this.syncStore.bidders.indexOf(connection) === -1) this.syncStore.bidders.push(connection);

return extBuilder;
}, {});

imps.push({ id: validBidRequest.bidId, ext, secure: window.location.protocol === 'https' ? 1 : 0, video: utils.deepAccess(validBidRequest, 'mediaTypes.video') });
}
const videoParams = BB_HELPERS.transformVideoParams(utils.deepAccess(validBidRequest, 'mediaTypes.video'), utils.deepAccess(validBidRequest, 'params.video'));
imps.push({ id: validBidRequest.bidId, ext, secure: window.location.protocol === 'https' ? 1 : 0, video: videoParams });
});

const request = {
id: bidderRequest.auctionId,
Expand Down Expand Up @@ -293,7 +304,6 @@ export const spec = {
BB_HELPERS.addSchain(request, validBidRequests);
BB_HELPERS.addCurrency(request);
BB_HELPERS.addUserIds(request, validBidRequests);
BB_HELPERS.addDigiTrust(request, validBidRequests);

return {
method: 'POST',
Expand All @@ -311,74 +321,43 @@ export const spec = {

const bids = [];

for (let seatbidIndex = 0; seatbidIndex < serverResponse.seatbid.length; seatbidIndex++) {
const seatbid = serverResponse.seatbid[seatbidIndex];
if (!seatbid.bid || !Array.isArray(seatbid.bid)) continue;
for (let bidIndex = 0; bidIndex < seatbid.bid.length; bidIndex++) {
const bid = seatbid.bid[bidIndex];
BB_HELPERS.transformRTBToPrebidProps(bid, serverResponse);

let bidParams;
for (let bidderRequestBidsIndex = 0; bidderRequestBidsIndex < request.bidderRequest.bids.length; bidderRequestBidsIndex++) {
if (request.bidderRequest.bids[bidderRequestBidsIndex].bidId === bid.bidId) {
bidParams = request.bidderRequest.bids[bidderRequestBidsIndex].params;
}
}
serverResponse.seatbid.forEach(seatbid => {
if (!seatbid.bid || !Array.isArray(seatbid.bid)) return;
seatbid.bid.forEach(bid => {
bid = BB_HELPERS.transformRTBToPrebidProps(bid, serverResponse);

if (bidParams) {
bid.publicationName = bidParams.publicationName;
bid.rendererCode = bidParams.rendererCode;
bid.accountId = bidParams.accountId;
}
const bidParams = find(request.bidderRequest.bids, bidderRequestBid => bidderRequestBid.bidId === bid.bidId).params;
bid.publicationName = bidParams.publicationName;
bid.rendererCode = bidParams.rendererCode;
bid.accountId = bidParams.accountId;

const rendererUrl = BB_HELPERS.getRendererUrl(bid.publicationName, bid.rendererCode);

bid.renderer = BB_RENDERER.newRenderer(rendererUrl, bid.adUnitCode);

bids.push(bid);
}
}
});
});

return bids;
},
getUserSyncs(syncOptions, serverResponses, gdpr) {
if (!serverResponses || !serverResponses.length) return [];
if (!syncOptions.iframeEnabled) return [];

const queryString = [];
let accountId;
let publication;

const serverResponse = serverResponses[0];
if (!serverResponse.body || !serverResponse.body.seatbid) return [];

for (let seatbidIndex = 0; seatbidIndex < serverResponse.body.seatbid.length; seatbidIndex++) {
const seatbid = serverResponse.body.seatbid[seatbidIndex];
for (let bidIndex = 0; bidIndex < seatbid.bid.length; bidIndex++) {
const bid = seatbid.bid[bidIndex];
accountId = bid.accountId || null;
publication = bid.publicationName || null;

if (publication && accountId) break;
}
if (publication && accountId) break;
}

if (!publication || !accountId) return [];

if (gdpr.gdprApplies) queryString.push(`gdpr=${gdpr.gdprApplies ? 1 : 0}`);
if (gdpr.gdprApplies && gdpr.consentString) queryString.push(`gdpr_consent=${gdpr.consentString}`);

if (this.syncStore.uspConsent) queryString.push(`usp_consent=${this.syncStore.uspConsent}`);

queryString.push(`accountId=${accountId}`);
queryString.push(`accountId=${this.syncStore.accountId}`);
queryString.push(`bidders=${btoa(JSON.stringify(this.syncStore.bidders))}`);
queryString.push(`cb=${Date.now()}-${Math.random().toString().replace('.', '')}`);

if (DEV_MODE) queryString.push('bbpbs_debug=true');

// NB syncUrl by default starts with ?pub=$$PUBLICATION
const syncUrl = `${BB_HELPERS.getSyncUrl(publication)}&${queryString.join('&')}`;
const syncUrl = `${BB_HELPERS.getSyncUrl(this.syncStore.publicationName)}&${queryString.join('&')}`;

return [{
type: 'iframe',
Expand Down
Loading