Skip to content

Commit

Permalink
Add native support to RTBHouseAdapter (#3189)
Browse files Browse the repository at this point in the history
* Refactor rtbhouseBidAdapter and spec

* Add native support to RTB House adapter
  • Loading branch information
Kamoris authored and idettman committed Oct 19, 2018
1 parent 6879fea commit b8eb55c
Show file tree
Hide file tree
Showing 3 changed files with 592 additions and 120 deletions.
351 changes: 270 additions & 81 deletions modules/rtbhouseBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,40 @@
import * as utils from 'src/utils';
import { BANNER } from 'src/mediaTypes';
import { BANNER, NATIVE } from 'src/mediaTypes';
import { registerBidder } from 'src/adapters/bidderFactory';
import includes from 'core-js/library/fn/array/includes';

const BIDDER_CODE = 'rtbhouse';
const REGIONS = ['prebid-eu', 'prebid-us', 'prebid-asia'];
const ENDPOINT_URL = 'creativecdn.com/bidder/prebid/bids';
const DEFAULT_CURRENCY_ARR = ['USD']; // NOTE - USD is the only supported currency right now; Hardcoded for bids
const TTL = 55;

/**
* Helpers
*/

function buildEndpointUrl(region) {
return 'https://' + region + '.' + ENDPOINT_URL;
}

/**
* Produces an OpenRTBImpression from a slot config.
*/
function mapImpression(slot) {
return {
id: slot.bidId,
banner: mapBanner(slot),
tagid: slot.adUnitCode.toString(),
};
}

/**
* Produces an OpenRTB Banner object for the slot given.
*/
function mapBanner(slot) {
return {
w: slot.sizes[0][0],
h: slot.sizes[0][1],
format: mapSizes(slot.sizes)
};
}

/**
* Produce openRTB banner.format object
*/
function mapSizes(slotSizes) {
const format = [];
slotSizes.forEach(elem => {
format.push({
w: elem[0],
h: elem[1]
});
});
return format;
}

/**
* Produces an OpenRTB site object.
*/
function mapSite(validRequest) {
const pubId = validRequest && validRequest.length > 0 ? validRequest[0].params.publisherId : 'unknown';
return {
publisher: {
id: pubId.toString(),
// Codes defined by OpenRTB Native Ads 1.1 specification
export const OPENRTB = {
NATIVE: {
IMAGE_TYPE: {
ICON: 1,
MAIN: 3,
},
ASSET_ID: {
TITLE: 1,
IMAGE: 2,
ICON: 3,
BODY: 4,
SPONSORED: 5,
CTA: 6
},
DATA_ASSET_TYPE: {
SPONSORED: 1,
DESC: 2,
CTA_TEXT: 12,
},
page: utils.getTopWindowUrl(),
name: utils.getOrigin()
}
}
};

export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER],
supportedMediaTypes: [BANNER, NATIVE],

isBidRequestValid: function (bid) {
return !!(includes(REGIONS, bid.params.region) && bid.params.publisherId);
Expand All @@ -87,39 +53,262 @@ export const spec = {
const gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0;
request.regs = {ext: {gdpr: gdpr}};
request.user = {ext: {consent: consentStr}};
};
}

return {
method: 'POST',
url: buildEndpointUrl(validBidRequests[0].params.region),
url: 'https://' + validBidRequests[0].params.region + '.' + ENDPOINT_URL,
data: JSON.stringify(request)
};
},
interpretResponse: function (serverResponse, originalRequest) {
serverResponse = serverResponse.body;
const bids = [];

if (utils.isArray(serverResponse)) {
serverResponse.forEach(serverBid => {
if (serverBid.price !== 0) {
const bid = {
requestId: serverBid.impid,
mediaType: BANNER,
cpm: serverBid.price,
creativeId: serverBid.adid,
ad: serverBid.adm,
width: serverBid.w,
height: serverBid.h,
ttl: 55,
netRevenue: true,
currency: 'USD'
};
bids.push(bid);
}
});
const responseBody = serverResponse.body;
if (!utils.isArray(responseBody)) {
return [];
}

const bids = [];
responseBody.forEach(serverBid => {
if (serverBid.price === 0) {
return;
}
// try...catch would be risky cause JSON.parse throws SyntaxError
if (serverBid.adm.indexOf('{') === 0) {
bids.push(interpretNativeBid(serverBid));
} else {
bids.push(interpretBannerBid(serverBid));
}
});
return bids;
}
};

registerBidder(spec);

/**
* @param {object} slot Ad Unit Params by Prebid
* @returns {object} Imp by OpenRTB 2.5 §3.2.4
*/
function mapImpression(slot) {
return {
id: slot.bidId,
banner: mapBanner(slot),
native: mapNative(slot),
tagid: slot.adUnitCode.toString()
};
}

/**
* @param {object} slot Ad Unit Params by Prebid
* @returns {object} Banner by OpenRTB 2.5 §3.2.6
*/
function mapBanner(slot) {
if (slot.mediaType === 'banner' ||
utils.deepAccess(slot, 'mediaTypes.banner') ||
(!slot.mediaType && !slot.mediaTypes)) {
return {
w: slot.sizes[0][0],
h: slot.sizes[0][1],
format: slot.sizes.map(size => ({
w: size[0],
h: size[1]
}))
};
}
}

/**
* @param {object} slot Ad Unit Params by Prebid
* @returns {object} Site by OpenRTB 2.5 §3.2.13
*/
function mapSite(slot) {
const pubId = slot && slot.length > 0
? slot[0].params.publisherId
: 'unknown';
return {
publisher: {
id: pubId.toString(),
},
page: utils.getTopWindowUrl(),
name: utils.getOrigin()
}
}

/**
* @param {object} slot Ad Unit Params by Prebid
* @returns {object} Request by OpenRTB Native Ads 1.1 §4
*/
function mapNative(slot) {
if (slot.mediaType === 'native' || utils.deepAccess(slot, 'mediaTypes.native')) {
return {
request: {
assets: mapNativeAssets(slot)
},
ver: '1.1'
}
}
}

/**
* @param {object} slot Slot config by Prebid
* @returns {array} Request Assets by OpenRTB Native Ads 1.1 §4.2
*/
function mapNativeAssets(slot) {
const params = slot.nativeParams || utils.deepAccess(slot, 'mediaTypes.native');
const assets = [];
if (params.title) {
assets.push({
id: OPENRTB.NATIVE.ASSET_ID.TITLE,
required: params.title.required ? 1 : 0,
title: {
len: params.title.len || 25
}
})
}
if (params.image) {
assets.push({
id: OPENRTB.NATIVE.ASSET_ID.IMAGE,
required: params.image.required ? 1 : 0,
img: mapNativeImage(params.image, OPENRTB.NATIVE.IMAGE_TYPE.MAIN)
})
}
if (params.icon) {
assets.push({
id: OPENRTB.NATIVE.ASSET_ID.ICON,
required: params.icon.required ? 1 : 0,
img: mapNativeImage(params.icon, OPENRTB.NATIVE.IMAGE_TYPE.ICON)
})
}
if (params.sponsoredBy) {
assets.push({
id: OPENRTB.NATIVE.ASSET_ID.SPONSORED,
required: params.sponsoredBy.required ? 1 : 0,
data: {
type: OPENRTB.NATIVE.DATA_ASSET_TYPE.SPONSORED,
len: params.sponsoredBy.len
}
})
}
if (params.body) {
assets.push({
id: OPENRTB.NATIVE.ASSET_ID.BODY,
required: params.body.request ? 1 : 0,
data: {
type: OPENRTB.NATIVE.DATA_ASSET_TYPE.DESC,
len: params.body.len
}
})
}
if (params.cta) {
assets.push({
id: OPENRTB.NATIVE.ASSET_ID.CTA,
required: params.cta.required ? 1 : 0,
data: {
type: OPENRTB.NATIVE.DATA_ASSET_TYPE.CTA_TEXT,
len: params.cta.len
}
})
}
return assets;
}

/**
* @param {object} image Prebid native.image/icon
* @param {int} type Image or icon code
* @returns {object} Request Image by OpenRTB Native Ads 1.1 §4.4
*/
function mapNativeImage(image, type) {
const img = {type: type};
if (image.aspect_ratios) {
const ratio = image.aspect_ratios[0];
const minWidth = ratio.min_width || 100;
img.wmin = minWidth;
img.hmin = (minWidth / ratio.ratio_width * ratio.ratio_height);
}
if (image.sizes) {
const size = Array.isArray(image.sizes[0]) ? image.sizes[0] : image.sizes;
img.w = size[0];
img.h = size[1];
}
return img
}

/**
* @param {object} serverBid Bid by OpenRTB 2.5 §4.2.3
* @returns {object} Prebid banner bidObject
*/
function interpretBannerBid(serverBid) {
return {
requestId: serverBid.impid,
mediaType: BANNER,
cpm: serverBid.price,
creativeId: serverBid.adid,
ad: serverBid.adm,
width: serverBid.w,
height: serverBid.h,
ttl: TTL,
netRevenue: true,
currency: 'USD'
}
}

/**
* @param {object} serverBid Bid by OpenRTB 2.5 §4.2.3
* @returns {object} Prebid native bidObject
*/
function interpretNativeBid(serverBid) {
return {
requestId: serverBid.impid,
mediaType: NATIVE,
cpm: serverBid.price,
creativeId: serverBid.adid,
width: 1,
height: 1,
ttl: TTL,
netRevenue: true,
currency: 'USD',
native: interpretNativeAd(serverBid.adm),
}
}

/**
* @param {string} adm JSON-encoded Request by OpenRTB Native Ads 1.1 §4.1
* @returns {object} Prebid bidObject.native
*/
function interpretNativeAd(adm) {
const native = JSON.parse(adm).native;
const result = {
clickUrl: encodeURIComponent(native.link.url),
impressionTrackers: native.imptrackers
};
native.assets.forEach(asset => {
switch (asset.id) {
case OPENRTB.NATIVE.ASSET_ID.TITLE:
result.title = asset.title.text;
break;
case OPENRTB.NATIVE.ASSET_ID.IMAGE:
result.image = {
url: encodeURIComponent(asset.img.url),
width: asset.img.w,
height: asset.img.h
};
break;
case OPENRTB.NATIVE.ASSET_ID.ICON:
result.icon = {
url: encodeURIComponent(asset.img.url),
width: asset.img.w,
height: asset.img.h
};
break;
case OPENRTB.NATIVE.ASSET_ID.BODY:
result.body = asset.data.value;
break;
case OPENRTB.NATIVE.ASSET_ID.SPONSORED:
result.sponsoredBy = asset.data.value;
break;
case OPENRTB.NATIVE.ASSET_ID.CTA:
result.cta = asset.data.value;
break;
}
});
return result;
}
Loading

0 comments on commit b8eb55c

Please sign in to comment.