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

adding PAF userId and RTD modules. test paf bid adapter #46

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions modules/.submodules.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"netIdSystem",
"nextrollIdSystem",
"novatiqIdSystem",
"pafIdSystem",
"parrableIdSystem",
"pubProvidedIdSystem",
"publinkIdSystem",
Expand Down Expand Up @@ -60,6 +61,7 @@
"jwplayerRtdProvider",
"medianetRtdProvider",
"optimeraRtdProvider",
"pafRtdProvider",
"permutiveRtdProvider",
"reconciliationRtdProvider",
"sirdataRtdProvider",
Expand Down
366 changes: 366 additions & 0 deletions modules/openxRtbBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,366 @@
import {config} from '../src/config.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
import * as utils from '../src/utils.js';
import {BANNER, VIDEO} from '../src/mediaTypes.js';
import {includes} from '../src/polyfill.js';

const bidderConfig = 'hb_pb_ortb';
const bidderVersion = '1.0';
const VIDEO_TARGETING = ['startdelay', 'mimes', 'minduration', 'maxduration',
'startdelay', 'skippable', 'playbackmethod', 'api', 'protocols', 'boxingallowed',
'linearity', 'delivery', 'protocol', 'placement', 'minbitrate', 'maxbitrate', 'ext'];
export const REQUEST_URL = 'https://rtb.openx.net/openrtbb/prebidjs';
export const SYNC_URL = 'https://u.openx.net/w/1.0/pd';
export const DEFAULT_PH = '2d1251ae-7f3a-47cf-bd2a-2f288854a0ba';
export const spec = {
code: 'openx2',
supportedMediaTypes: [BANNER, VIDEO],
isBidRequestValid,
buildRequests,
interpretResponse,
getUserSyncs,
transformBidParams
};

registerBidder(spec);

function transformBidParams(params, isOpenRtb) {
return utils.convertTypes({
'unit': 'string',
'customFloor': 'number'
}, params);
}

function isBidRequestValid(bidRequest) {
const hasDelDomainOrPlatform = bidRequest.params.delDomain ||
bidRequest.params.platform;

if (utils.deepAccess(bidRequest, 'mediaTypes.banner') &&
hasDelDomainOrPlatform) {
return !!bidRequest.params.unit ||
utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes.length') > 0;
}

return !!(bidRequest.params.unit && hasDelDomainOrPlatform);
}

function buildRequests(bids, bidderRequest) {
let videoBids = bids.filter(bid => isVideoBid(bid));
let bannerBids = bids.filter(bid => isBannerBid(bid));
let requests = bannerBids.length ? [createBannerRequest(bannerBids, bidderRequest)] : [];
videoBids.forEach(bid => {
requests.push(createVideoRequest(bid, bidderRequest));
});
return requests;
}

function createBannerRequest(bids, bidderRequest) {
let data = getBaseRequest(bids[0], bidderRequest);
data.imp = bids.map(bid => {
const floor = getFloor(bid, BANNER);
let imp = {
id: bid.bidId,
tagid: bid.params.unit,
banner: {
format: toFormat(bid.mediaTypes.banner.sizes),
topframe: utils.inIframe() ? 0 : 1
},
ext: {divid: bid.adUnitCode}
};
enrichImp(imp, bid, floor);
return imp;
});
return {
method: 'POST',
url: REQUEST_URL,
data: data
}
}

function toFormat(sizes) {
return sizes.map((s) => {
return { w: s[0], h: s[1] };
});
}

function enrichImp(imp, bid, floor) {
if (bid.params.customParams) {
utils.deepSetValue(imp, 'ext.customParams', bid.params.customParams);
}
if (floor > 0) {
imp.bidfloor = floor;
imp.bidfloorcur = 'USD';
} else if (bid.params.customFloor) {
imp.bidfloor = bid.params.customFloor;
}
if (bid.ortb2Imp && bid.ortb2Imp.ext && bid.ortb2Imp.ext.data) {
imp.ext.data = bid.ortb2Imp.ext.data;
}
}

function enrichFloc(req, bid) {
if (bid.userId && bid.userId.flocId) {
const flocObject = {
id: 'chrome',
segment: [{
id: 'floc',
value: bid.userId.flocId.id.toString(),
ext: {
ver: bid.userId.flocId.version
}
}]
}
if (!req.user) {
req.user = {};
}
if (!req.user.data) {
req.user.data = [];
}
req.user.data.push(flocObject);
}
}

function createVideoRequest(bid, bidderRequest) {
let width;
let height;
const videoMediaType = utils.deepAccess(bid, `mediaTypes.video`);
const playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize');
const context = utils.deepAccess(bid, 'mediaTypes.video.context');
const floor = getFloor(bid, VIDEO);

// normalize config for video size
if (utils.isArray(bid.sizes) && bid.sizes.length === 2 && !utils.isArray(bid.sizes[0])) {
width = parseInt(bid.sizes[0], 10);
height = parseInt(bid.sizes[1], 10);
} else if (utils.isArray(bid.sizes) && utils.isArray(bid.sizes[0]) && bid.sizes[0].length === 2) {
width = parseInt(bid.sizes[0][0], 10);
height = parseInt(bid.sizes[0][1], 10);
} else if (utils.isArray(playerSize) && playerSize.length === 2) {
width = parseInt(playerSize[0], 10);
height = parseInt(playerSize[1], 10);
}

let data = getBaseRequest(bid, bidderRequest);
data.imp = [{
id: bid.bidId,
tagid: bid.params.unit,
video: {
w: width,
h: height,
topframe: utils.inIframe() ? 0 : 1
},
ext: {divid: bid.adUnitCode}
}];

enrichImp(data.imp[0], bid, floor);

if (context) {
if (context === 'instream') {
data.imp[0].video.placement = 1;
} else if (context === 'outstream') {
data.imp[0].video.placement = 4;
}
}

let videoParams = bid.params.video || bid.params.openrtb || {};
if (utils.isArray(videoParams.imp)) {
videoParams = videoParams[0].video;
}

Object.keys(videoParams)
.filter(param => includes(VIDEO_TARGETING, param))
.forEach(param => data.imp[0].video[param] = videoParams[param]);
Object.keys(videoMediaType)
.filter(param => includes(VIDEO_TARGETING, param))
.forEach(param => data.imp[0].video[param] = videoMediaType[param]);

return {
method: 'POST',
url: REQUEST_URL,
data: data
}
}

function getBaseRequest(bid, bidderRequest) {
let req = {
id: bidderRequest.auctionId,
cur: [config.getConfig('currency.adServerCurrency') || 'USD'],
at: 1,
tmax: config.getConfig('bidderTimeout'),
site: {
page: config.getConfig('pageUrl') || bidderRequest.refererInfo.referer
},
regs: {
coppa: (config.getConfig('coppa') === true || bid.params.coppa) ? 1 : 0,
},
device: {
dnt: (utils.getDNT() || bid.params.doNotTrack) ? 1 : 0,
h: screen.height,
w: screen.width,
ua: window.navigator.userAgent,
language: window.navigator.language.split('-').shift()
},
ext: {
bc: bid.params.bc || `${bidderConfig}_${bidderVersion}`,
frontier_flags: {is_filtered: true}
}
};

if (bid.params.platform) {
utils.deepSetValue(req, 'ext.platform', bid.params.platform);
}
if (bid.params.delDomain) {
utils.deepSetValue(req, 'ext.delDomain', bid.params.delDomain);
}
if (bid.params.test) {
req.test = 1
}
if (bidderRequest.gdprConsent) {
if (bidderRequest.gdprConsent.gdprApplies !== undefined) {
utils.deepSetValue(req, 'regs.ext.gdpr', bidderRequest.gdprConsent.gdprApplies === true ? 1 : 0);
}
if (bidderRequest.gdprConsent.consentString !== undefined) {
utils.deepSetValue(req, 'user.ext.consent', bidderRequest.gdprConsent.consentString);
}
if (bidderRequest.gdprConsent.addtlConsent !== undefined) {
utils.deepSetValue(req, 'user.ext.ConsentedProvidersSettings.consented_providers', bidderRequest.gdprConsent.addtlConsent);
}
}
if (bidderRequest.uspConsent) {
utils.deepSetValue(req, 'regs.ext.us_privacy', bidderRequest.uspConsent);
}
if (bid.schain) {
utils.deepSetValue(req, 'source.ext.schain', bid.schain);
}
if (bid.userIdAsEids) {
utils.deepSetValue(req, 'user.ext.eids', bid.userIdAsEids);
}
const commonFpd = config.getConfig('ortb2') || {};
if (commonFpd.site) {
utils.mergeDeep(req, {site: commonFpd.site});
}
if (commonFpd.user) {
utils.mergeDeep(req, {user: commonFpd.user});
}
enrichFloc(req, bid)
return req;
}

function isVideoBid(bid) {
return utils.deepAccess(bid, 'mediaTypes.video');
}

function isBannerBid(bid) {
return utils.deepAccess(bid, 'mediaTypes.banner') || !isVideoBid(bid);
}

function getFloor(bid, mediaType) {
let floor = 0;

if (typeof bid.getFloor === 'function') {
const floorInfo = bid.getFloor({
currency: 'USD',
mediaType: mediaType,
size: '*'
});

if (typeof floorInfo === 'object' &&
floorInfo.currency === 'USD' &&
!isNaN(parseFloat(floorInfo.floor))) {
floor = Math.max(floor, parseFloat(floorInfo.floor));
}
}

return floor;
}

function interpretResponse(resp, req) {
// pass these from request to the responses for use in userSync
if (req.data.ext) {
if (req.data.ext.delDomain) {
utils.deepSetValue(resp, 'body.ext.delDomain', req.data.ext.delDomain);
}
if (req.data.ext.platform) {
utils.deepSetValue(resp, 'body.ext.platform', req.data.ext.platform);
}
}

const respBody = resp.body;
if ('nbr' in respBody) {
return [];
}

let bids = [];
respBody.seatbid.forEach(seatbid => {
bids = [...bids, ...seatbid.bid.map(bid => {
let response = {
requestId: bid.impid,
cpm: bid.price,
width: bid.w,
height: bid.h,
creativeId: bid.crid,
dealId: bid.dealid,
currency: respBody.cur || 'USD',
netRevenue: true,
ttl: 300,
mediaType: 'banner' in req.data.imp[0] ? BANNER : VIDEO,
meta: { advertiserDomains: bid.adomain }
};

if (response.mediaType === VIDEO) {
if (bid.nurl) {
response.vastUrl = bid.nurl;
} else {
response.vastXml = bid.adm;
}
} else {
response.ad = bid.adm;
}

if (bid.ext) {
response.meta.networkId = bid.ext.dsp_id;
response.meta.advertiserId = bid.ext.buyer_id;
response.meta.brandId = bid.ext.brand_id;
}
return response
})];
});

return bids;
}

/**
* @param syncOptions
* @param responses
* @param gdprConsent
* @param uspConsent
* @return {{type: (string), url: (*|string)}[]}
*/
function getUserSyncs(syncOptions, responses, gdprConsent, uspConsent) {
if (syncOptions.iframeEnabled || syncOptions.pixelEnabled) {
let pixelType = syncOptions.iframeEnabled ? 'iframe' : 'image';
let queryParamStrings = [];
let syncUrl = SYNC_URL;
if (gdprConsent) {
queryParamStrings.push('gdpr=' + (gdprConsent.gdprApplies ? 1 : 0));
queryParamStrings.push('gdpr_consent=' + encodeURIComponent(gdprConsent.consentString || ''));
}
if (uspConsent) {
queryParamStrings.push('us_privacy=' + encodeURIComponent(uspConsent));
}
if (responses.length > 0 && responses[0].body && responses[0].body.ext) {
const ext = responses[0].body.ext;
if (ext.delDomain) {
syncUrl = `https://${ext.delDomain}/w/1.0/pd`
} else if (ext.platform) {
queryParamStrings.push('ph=' + ext.platform)
}
} else {
queryParamStrings.push('ph=' + DEFAULT_PH)
}
return [{
type: pixelType,
url: `${syncUrl}${queryParamStrings.length > 0 ? '?' + queryParamStrings.join('&') : ''}`
}];
}
}
Loading