Skip to content

Commit

Permalink
New Adapter ZEDO (prebid#2872)
Browse files Browse the repository at this point in the history
* initial commit

* updated contact and tag details

* changes ti support the renderers

* changes to pass dimId

* fixed names of internal mapping

* added comment

* added gdpr param to request and other fixes
  • Loading branch information
skazedo authored and AdSpacesDevelopers committed Jan 30, 2019
1 parent 46cff2a commit 25e64bf
Show file tree
Hide file tree
Showing 4 changed files with 510 additions and 0 deletions.
7 changes: 7 additions & 0 deletions integrationExamples/gpt/pbjs_example_gpt.html
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,13 @@
pubId: 50357, //REQUIRED
host: 'dsp-staging.adkernel.com' //OPTIONAL
}
},
{
bidder: 'zedo',
params: {
channelCode: 2264002816, //REQUIRED
dimId: 9 //REQUIRED
}
}
]
}, {
Expand Down
205 changes: 205 additions & 0 deletions modules/zedoBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import * as utils from 'src/utils';
import { registerBidder } from 'src/adapters/bidderFactory';
import { BANNER, VIDEO } from 'src/mediaTypes';
import find from 'core-js/library/fn/array/find';

const BIDDER_CODE = 'zedo';
const URL = '//z2.zedo.com/asw/fmb.json';
const SECURE_URL = '//z2.zedo.com/asw/fmb.json';
const DIM_TYPE = {
'7': 'display',
'9': 'display',
'14': 'display',
'70': 'SBR',
'83': 'CurtainRaiser',
'85': 'Inarticle',
'86': 'pswipeup',
'88': 'Inview',
// '85': 'pre-mid-post-roll',
};

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

/**
* Determines whether or not the given bid request is valid.
*
* @param {object} bid The bid to validate.
* @return boolean True if this is a valid bid, and false otherwise.
*/
isBidRequestValid: function (bid) {
return !!(bid.params && bid.params.channelCode && bid.params.dimId);
},

/**
* Make a server request from the list of BidRequests.
*
* @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be sent to the Server.
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function (bidRequests, bidderRequest) {
let data = {
placements: []
};
bidRequests.map(bidRequest => {
let channelCode = parseInt(bidRequest.params.channelCode);
let network = parseInt(channelCode / 1000000);
let channel = channelCode % 1000000;
let dim = getSizes(bidRequest.sizes);
let placement = {
id: bidRequest.bidId,
network: network,
channel: channel,
width: dim[0],
height: dim[1],
dimension: bidRequest.params.dimId,
version: '$prebid.version$',
keyword: '',
transactionId: bidRequest.transactionId
}
if (bidderRequest && bidderRequest.gdprConsent) {
if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') {
data.gdpr = Number(bidderRequest.gdprConsent.gdprApplies);
}
data.gdpr_consent = bidderRequest.gdprConsent.consentString;
}
let dimType = DIM_TYPE[String(bidRequest.params.dimId)]
if (dimType) {
placement['renderers'] = [{
'name': dimType
}]
} else { // default to display
placement['renderers'] = [{
'name': 'display'
}]
}
data['placements'].push(placement);
});
let reqUrl = utils.getTopWindowLocation().protocol === 'http:' ? URL : SECURE_URL;
return {
method: 'GET',
url: reqUrl,
data: 'g=' + JSON.stringify(data)
}
},

/**
* Unpack the response from the server into a list of bids.
*
* @param {*} serverResponse A successful response from the server.
* @return {Bid[]} An array of bids which were nested inside the server.
*/
interpretResponse: function (serverResponse, request) {
serverResponse = serverResponse.body;
const bids = [];
if (!serverResponse || serverResponse.error) {
let errorMessage = `in response for ${request.bidderCode} adapter`;
if (serverResponse && serverResponse.error) { errorMessage += `: ${serverResponse.error}`; }
utils.logError(errorMessage);
return bids;
}

if (serverResponse.ad) {
serverResponse.ad.forEach(ad => {
const creativeBid = getCreative(ad);
if (creativeBid) {
if (parseInt(creativeBid.cpm) !== 0) {
const bid = newBid(ad, creativeBid, request);
bid.mediaType = parseMediaType(creativeBid);
bids.push(bid);
}
}
});
}
return bids;
},

getUserSyncs: function (syncOptions, responses, gdprConsent) {
if (syncOptions.iframeEnabled) {
let url = utils.getTopWindowLocation().protocol === 'http:' ? 'http://d3.zedo.com/rs/us/fcs.html' : 'https://tt3.zedo.com/rs/us/fcs.html';
if (gdprConsent && typeof gdprConsent.consentString === 'string') {
// add 'gdpr' only if 'gdprApplies' is defined
if (typeof gdprConsent.gdprApplies === 'boolean') {
url += `?gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`;
} else {
url += `?gdpr_consent=${gdprConsent.consentString}`;
}
}
return [{
type: 'iframe',
url: url
}];
}
}
};

function getCreative(ad) {
return ad && ad.creatives && ad.creatives.length && find(ad.creatives, creative => creative.adId);
}
/**
* Unpack the Server's Bid into a Prebid-compatible one.
* @param serverBid
* @param rtbBid
* @param bidderRequest
* @return Bid
*/
function newBid(serverBid, creativeBid, bidderRequest) {
const bid = {
requestId: serverBid.slotId,
creativeId: creativeBid.adId,
dealId: 99999999,
currency: 'USD',
netRevenue: true,
ttl: 300
};

if (creativeBid.creativeDetails.type === 'VAST') {
Object.assign(bid, {
width: creativeBid.width,
height: creativeBid.height,
vastXml: creativeBid.creativeDetails.adContent,
cpm: (parseInt(creativeBid.cpm) * 0.65) / 1000000,
ttl: 3600
});
} else {
Object.assign(bid, {
width: creativeBid.width,
height: creativeBid.height,
cpm: (parseInt(creativeBid.cpm) * 0.6) / 1000000,
ad: creativeBid.creativeDetails.adContent
});
}

return bid;
}
/* Turn bid request sizes into compatible format */
function getSizes(requestSizes) {
let width = 0;
let height = 0;
if (utils.isArray(requestSizes) && requestSizes.length === 2 &&
!utils.isArray(requestSizes[0])) {
width = parseInt(requestSizes[0], 10);
height = parseInt(requestSizes[1], 10);
} else if (typeof requestSizes === 'object') {
for (let i = 0; i < requestSizes.length; i++) {
let size = requestSizes[i];
width = parseInt(size[0], 10);
height = parseInt(size[1], 10);
break;
}
}
return [width, height];
}

function parseMediaType(creativeBid) {
const adType = creativeBid.creativeDetails.type;
if (adType === 'VAST') {
return VIDEO;
} else {
return BANNER;
}
}

registerBidder(spec);
30 changes: 30 additions & 0 deletions modules/zedoBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Overview

Module Name: ZEDO Bidder Adapter
Module Type: Bidder Adapter
Maintainer: prebidsupport@zedo.com

# Description

Module that connects to ZEDO's demand sources.

For video integration, ZEDO returns content as vastXML and requires the publisher to define the cache url in config passed to Prebid for it to be valid in the auction

# Test Parameters
```
var adUnits = [
{
code: 'banner-ad-div',
sizes: [[300, 250], [728, 90]],
bids: [
{
bidder: 'zedo',
params: {
code: 2264004118
dimId: 9
}
}
]
}
];
```
Loading

0 comments on commit 25e64bf

Please sign in to comment.