Skip to content

Commit

Permalink
Merge branch '3-display-banner-and-video-vast-support-for-rads' into …
Browse files Browse the repository at this point in the history
…'master'

Resolve "Display Banner and video VAST support for RADS"

Closes #3

See merge request osi/prebidjs!4
  • Loading branch information
zav1517 committed Sep 18, 2019
2 parents 2aec8a2 + dafbae2 commit 1031798
Show file tree
Hide file tree
Showing 3 changed files with 397 additions and 0 deletions.
155 changes: 155 additions & 0 deletions modules/radsBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import * as utils from '../src/utils';
import {config} from '../src/config';
import {registerBidder} from '../src/adapters/bidderFactory';
import { BANNER, VIDEO } from '../src/mediaTypes';

const BIDDER_CODE = 'rads';
const ENDPOINT_URL = 'https://rads.recognified.net/md.request.php';
const ENDPOINT_URL_DEV = 'https://dcradn1.online-solution.biz/md.request.php';
const DEFAULT_VAST_FORMAT = 'vast2';

export const spec = {
code: BIDDER_CODE,
aliases: ['rads'],
supportedMediaTypes: [BANNER, VIDEO],
isBidRequestValid: function(bid) {
return !!(bid.params.placement);
},
buildRequests: function(validBidRequests, bidderRequest) {
return validBidRequests.map(bidRequest => {
const params = bidRequest.params;
const videoData = utils.deepAccess(bidRequest, 'mediaTypes.video') || {};
const sizes = utils.parseSizesInput(videoData.playerSize || bidRequest.sizes)[0];
const width = sizes.split('x')[0];
const height = sizes.split('x')[1];
const placementId = params.placement;

const rnd = Math.floor(Math.random() * 99999999999);
const referrer = encodeURIComponent(bidderRequest.refererInfo.referer);
const bidId = bidRequest.bidId;
const isDev = params.devMode || false;

let endpoint = ENDPOINT_URL;
if (isDev) {
endpoint = ENDPOINT_URL_DEV;
}

let payload = {};
if (isVideoRequest(bidRequest)) {
let vastFormat = params.vastFormat || DEFAULT_VAST_FORMAT;
payload = {
rt: vastFormat,
_f: 'prebid_js',
_ps: placementId,
srw: width,
srh: height,
idt: 100,
rnd: rnd,
p: referrer,
bid_id: bidId,
};
} else {
payload = {
rt: 'bid-response',
_f: 'prebid_js',
_ps: placementId,
srw: width,
srh: height,
idt: 100,
rnd: rnd,
p: referrer,
bid_id: bidId,
};
}
prepareExtraParams(params, payload);

return {
method: 'GET',
url: endpoint,
data: objectToQueryString(payload),
}
});
},
interpretResponse: function(serverResponse, bidRequest) {
const bidResponses = [];
const response = serverResponse.body;
const crid = response.crid || 0;
const cpm = response.cpm / 1000000 || 0;
if (cpm !== 0 && crid !== 0) {
const dealId = response.dealid || '';
const currency = response.currency || 'EUR';
const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue;
const bidResponse = {
requestId: response.bid_id,
cpm: cpm,
width: response.width,
height: response.height,
creativeId: crid,
dealId: dealId,
currency: currency,
netRevenue: netRevenue,
ttl: config.getConfig('_bidderTimeout')
};

if (response.vastXml) {
bidResponse.vastXml = response.vastXml;
bidResponse.mediaType = 'video';
} else {
bidResponse.ad = response.adTag;
}

bidResponses.push(bidResponse);
}
return bidResponses;
}
}

function objectToQueryString(obj, prefix) {
let str = [];
let p;
for (p in obj) {
if (obj.hasOwnProperty(p)) {
let k = prefix ? prefix + '[' + p + ']' : p;
let v = obj[p];
str.push((v !== null && typeof v === 'object')
? objectToQueryString(v, k)
: encodeURIComponent(k) + '=' + encodeURIComponent(v));
}
}
return str.join('&');
}

/**
* Check if it's a video bid request
*
* @param {BidRequest} bid - Bid request generated from ad slots
* @returns {boolean} True if it's a video bid
*/
function isVideoRequest(bid) {
return bid.mediaType === 'video' || !!utils.deepAccess(bid, 'mediaTypes.video');
}

function prepareExtraParams(params, payload) {
if (params.pfilter !== undefined) {
payload.pfilter = params.pfilter;
}
if (params.bcat !== undefined) {
payload.bcat = params.bcat;
}
if (params.dvt !== undefined) {
payload.dvt = params.dvt;
}

if (params.latitude !== undefined) {
payload.latitude = params.latitude;
}

if (params.longitude !== undefined) {
payload.longitude = params.longitude;
}
if (params.ip !== undefined) {
payload.i = params.ip;
}
}

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

```
Module Name: RADS Bidder Adapter
Module Type: Bidder Adapter
Maintainer: [email protected]
```

# Description

RADS Bidder Adapter for Prebid.js 1.x

# Test Parameters
```
var adUnits = [
{
code: "test-div",
mediaTypes: {
banner: {
sizes: [[320, 50]]
}
},
bids: [
{
bidder: "rads",
params: {
placement: 101
}
}
]
}
];
```

Required param field is only `placement`.

206 changes: 206 additions & 0 deletions test/spec/modules/radsBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import { expect } from 'chai';
import { spec } from 'modules/radsBidAdapter';
import { newBidder } from 'src/adapters/bidderFactory';

const RADS_ENDPOINT_URL = 'https://rads.recognified.net/md.request.php';

describe('radsAdapter', function () {
const adapter = newBidder(spec);

describe('isBidRequestValid', function () {
let bid = {
'bidder': 'rads',
'params': {
'placement': '6682',
'pfilter': {
'floorprice': 1000000
},
'bcat': 'IAB2,IAB4',
'dvt': 'desktop',
'ip': '1.1.1.1'
},
'sizes': [
[300, 250]
],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
'auctionId': '1d1a030790a475'
};

it('should return true when required params found', function () {
expect(spec.isBidRequestValid(bid)).to.equal(true);
});

it('should return false when required params are not passed', function () {
let bid = Object.assign({}, bid);
delete bid.params;
bid.params = {
'someIncorrectParam': 0
};
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
});

describe('buildRequests', function () {
let bidRequests = [{
'bidder': 'rads',
'params': {
'placement': '6682',
'pfilter': {
'floorprice': 1000000,
'geo': {
'country': 'DE'
}
},
'bcat': 'IAB2,IAB4',
'dvt': 'desktop',
'ip': '1.1.1.1'
},
'sizes': [
[300, 250]
],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
'auctionId': '1d1a030790a475'
}, {
'bidder': 'rads',
'params': {
'placement': '6682',
'pfilter': {
'floorprice': 1000000,
'geo': {
'country': 'DE',
'region': 'DE-BE'
},
},
'bcat': 'IAB2,IAB4',
'dvt': 'desktop'
},
'mediaTypes': {
'video': {
'playerSize': [640, 480],
'context': 'instream'
}
},
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
'auctionId': '1d1a030790a475'
}];

let bidderRequest = {
refererInfo: {
referer: 'some_referrer.net'
}
}

const request = spec.buildRequests(bidRequests, bidderRequest);
it('sends bid request to our endpoint via GET', function () {
expect(request[0].method).to.equal('GET');
let data = request[0].data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid');
expect(data).to.equal('rt=bid-response&_f=prebid_js&_ps=6682&srw=300&srh=250&idt=100&p=some_referrer.net&bid_id=30b31c1838de1e&pfilter%5Bfloorprice%5D=1000000&pfilter%5Bgeo%5D%5Bcountry%5D=DE&bcat=IAB2%2CIAB4&dvt=desktop&i=1.1.1.1');
});

it('sends bid video request to our rads endpoint via GET', function () {
expect(request[1].method).to.equal('GET');
let data = request[1].data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid');
expect(data).to.equal('rt=vast2&_f=prebid_js&_ps=6682&srw=640&srh=480&idt=100&p=some_referrer.net&bid_id=30b31c1838de1e&pfilter%5Bfloorprice%5D=1000000&pfilter%5Bgeo%5D%5Bcountry%5D=DE&pfilter%5Bgeo%5D%5Bregion%5D=DE-BE&bcat=IAB2%2CIAB4&dvt=desktop');
});
});

describe('interpretResponse', function () {
let serverBannerResponse = {
'body': {
'cpm': 5000000,
'crid': 100500,
'width': '300',
'height': '250',
'adTag': '<!-- test creative -->',
'requestId': '220ed41385952a',
'currency': 'EUR',
'ttl': 60,
'netRevenue': true,
'zone': '6682'
}
};
let serverVideoResponse = {
'body': {
'cpm': 5000000,
'crid': 100500,
'width': '300',
'height': '250',
'vastXml': '{"reason":7001,"status":"accepted"}',
'requestId': '220ed41385952a',
'currency': 'EUR',
'ttl': 60,
'netRevenue': true,
'zone': '6682'
}
};

let expectedResponse = [{
requestId: '23beaa6af6cdde',
cpm: 0.5,
width: 0,
height: 0,
creativeId: 100500,
dealId: '',
currency: 'EUR',
netRevenue: true,
ttl: 300,
ad: '<!-- test creative -->'
}, {
requestId: '23beaa6af6cdde',
cpm: 0.5,
width: 0,
height: 0,
creativeId: 100500,
dealId: '',
currency: 'EUR',
netRevenue: true,
ttl: 300,
vastXml: '{"reason":7001,"status":"accepted"}',
mediaType: 'video'
}];

it('should get the correct bid response by display ad', function () {
let bidRequest = [{
'method': 'GET',
'url': RADS_ENDPOINT_URL,
'refererInfo': {
'referer': ''
},
'data': {
'bid_id': '30b31c1838de1e'
}
}];
let result = spec.interpretResponse(serverBannerResponse, bidRequest[0]);
expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0]));
});

it('should get the correct rads video bid response by display ad', function () {
let bidRequest = [{
'method': 'GET',
'url': RADS_ENDPOINT_URL,
'mediaTypes': {
'video': {
'playerSize': [640, 480],
'context': 'instream'
}
},
'data': {
'bid_id': '30b31c1838de1e'
}
}];
let result = spec.interpretResponse(serverVideoResponse, bidRequest[0]);
expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[1]));
});

it('handles empty bid response', function () {
let response = {
body: {}
};
let result = spec.interpretResponse(response);
expect(result.length).to.equal(0);
});
});
});

0 comments on commit 1031798

Please sign in to comment.