Skip to content
This repository was archived by the owner on Mar 12, 2025. It is now read-only.

Commit 0ad0bd3

Browse files
onlsolrobertrmartinez
authored andcommitted
3 display banner and video vast support for rads (prebid#4209)
* add stv adapter * remove comments from adapter file * start rads adapter * fix adapter and tests * fixes * fix adapter and doc * fix adapter * fix tests * little fix * add ip param * fix dev url * #3 radsBidAdapter.md * #3 radsBidAdapter.md: cleanup * fix code and doc
1 parent 2ab711b commit 0ad0bd3

File tree

3 files changed

+394
-0
lines changed

3 files changed

+394
-0
lines changed

modules/radsBidAdapter.js

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import * as utils from '../src/utils';
2+
import {config} from '../src/config';
3+
import {registerBidder} from '../src/adapters/bidderFactory';
4+
import { BANNER, VIDEO } from '../src/mediaTypes';
5+
6+
const BIDDER_CODE = 'rads';
7+
const ENDPOINT_URL = 'https://rads.recognified.net/md.request.php';
8+
const ENDPOINT_URL_DEV = 'https://dcradn1.online-solution.biz/md.request.php';
9+
const DEFAULT_VAST_FORMAT = 'vast2';
10+
11+
export const spec = {
12+
code: BIDDER_CODE,
13+
aliases: ['rads'],
14+
supportedMediaTypes: [BANNER, VIDEO],
15+
isBidRequestValid: function(bid) {
16+
return !!(bid.params.placement);
17+
},
18+
buildRequests: function(validBidRequests, bidderRequest) {
19+
return validBidRequests.map(bidRequest => {
20+
const params = bidRequest.params;
21+
const videoData = utils.deepAccess(bidRequest, 'mediaTypes.video') || {};
22+
const sizes = utils.parseSizesInput(videoData.playerSize || bidRequest.sizes)[0];
23+
const [width, height] = sizes.split('x');
24+
const placementId = params.placement;
25+
26+
const rnd = Math.floor(Math.random() * 99999999999);
27+
const referrer = encodeURIComponent(bidderRequest.refererInfo.referer);
28+
const bidId = bidRequest.bidId;
29+
const isDev = params.devMode || false;
30+
31+
let endpoint = isDev ? ENDPOINT_URL_DEV : ENDPOINT_URL;
32+
33+
let payload = {};
34+
if (isVideoRequest(bidRequest)) {
35+
let vastFormat = params.vastFormat || DEFAULT_VAST_FORMAT;
36+
payload = {
37+
rt: vastFormat,
38+
_f: 'prebid_js',
39+
_ps: placementId,
40+
srw: width,
41+
srh: height,
42+
idt: 100,
43+
rnd: rnd,
44+
p: referrer,
45+
bid_id: bidId,
46+
};
47+
} else {
48+
payload = {
49+
rt: 'bid-response',
50+
_f: 'prebid_js',
51+
_ps: placementId,
52+
srw: width,
53+
srh: height,
54+
idt: 100,
55+
rnd: rnd,
56+
p: referrer,
57+
bid_id: bidId,
58+
};
59+
}
60+
prepareExtraParams(params, payload);
61+
62+
return {
63+
method: 'GET',
64+
url: endpoint,
65+
data: objectToQueryString(payload),
66+
}
67+
});
68+
},
69+
interpretResponse: function(serverResponse, bidRequest) {
70+
const bidResponses = [];
71+
const response = serverResponse.body;
72+
const crid = response.crid || 0;
73+
const cpm = response.cpm / 1000000 || 0;
74+
if (cpm !== 0 && crid !== 0) {
75+
const dealId = response.dealid || '';
76+
const currency = response.currency || 'EUR';
77+
const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue;
78+
const bidResponse = {
79+
requestId: response.bid_id,
80+
cpm: cpm,
81+
width: response.width,
82+
height: response.height,
83+
creativeId: crid,
84+
dealId: dealId,
85+
currency: currency,
86+
netRevenue: netRevenue,
87+
ttl: config.getConfig('_bidderTimeout')
88+
};
89+
90+
if (response.vastXml) {
91+
bidResponse.vastXml = response.vastXml;
92+
bidResponse.mediaType = 'video';
93+
} else {
94+
bidResponse.ad = response.adTag;
95+
}
96+
97+
bidResponses.push(bidResponse);
98+
}
99+
return bidResponses;
100+
}
101+
}
102+
103+
function objectToQueryString(obj, prefix) {
104+
let str = [];
105+
let p;
106+
for (p in obj) {
107+
if (obj.hasOwnProperty(p)) {
108+
let k = prefix ? prefix + '[' + p + ']' : p;
109+
let v = obj[p];
110+
str.push((v !== null && typeof v === 'object')
111+
? objectToQueryString(v, k)
112+
: encodeURIComponent(k) + '=' + encodeURIComponent(v));
113+
}
114+
}
115+
return str.join('&');
116+
}
117+
118+
/**
119+
* Check if it's a video bid request
120+
*
121+
* @param {BidRequest} bid - Bid request generated from ad slots
122+
* @returns {boolean} True if it's a video bid
123+
*/
124+
function isVideoRequest(bid) {
125+
return bid.mediaType === 'video' || !!utils.deepAccess(bid, 'mediaTypes.video');
126+
}
127+
128+
function prepareExtraParams(params, payload) {
129+
if (params.pfilter !== undefined) {
130+
payload.pfilter = params.pfilter;
131+
}
132+
if (params.bcat !== undefined) {
133+
payload.bcat = params.bcat;
134+
}
135+
if (params.dvt !== undefined) {
136+
payload.dvt = params.dvt;
137+
}
138+
139+
if (params.latitude !== undefined) {
140+
payload.latitude = params.latitude;
141+
}
142+
143+
if (params.longitude !== undefined) {
144+
payload.longitude = params.longitude;
145+
}
146+
if (params.ip !== undefined) {
147+
payload.i = params.ip;
148+
}
149+
}
150+
151+
registerBidder(spec);

modules/radsBidAdapter.md

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Overview
2+
3+
```
4+
Module Name: RADS Bidder Adapter
5+
Module Type: Bidder Adapter
6+
Maintainer: [email protected]
7+
```
8+
9+
# Description
10+
11+
RADS Bidder Adapter for Prebid.js 1.x
12+
13+
# Test Parameters
14+
```
15+
var adUnits = [
16+
{
17+
code: "test-div",
18+
mediaTypes: {
19+
banner: {
20+
sizes: [[320, 50]]
21+
}
22+
},
23+
bids: [
24+
{
25+
bidder: "rads",
26+
params: {
27+
placement: 3, // placement ID
28+
devMode: true // if true: library uses dev server for tests
29+
}
30+
}
31+
]
32+
}
33+
];
34+
```
35+
36+
Required param field is only `placement`.
37+
+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import { expect } from 'chai';
2+
import { spec } from 'modules/radsBidAdapter';
3+
import { newBidder } from 'src/adapters/bidderFactory';
4+
5+
const RADS_ENDPOINT_URL = 'https://rads.recognified.net/md.request.php';
6+
7+
describe('radsAdapter', function () {
8+
const adapter = newBidder(spec);
9+
10+
describe('isBidRequestValid', function () {
11+
let bid = {
12+
'bidder': 'rads',
13+
'params': {
14+
'placement': '6682',
15+
'pfilter': {
16+
'floorprice': 1000000
17+
},
18+
'bcat': 'IAB2,IAB4',
19+
'dvt': 'desktop',
20+
'ip': '1.1.1.1'
21+
},
22+
'sizes': [
23+
[300, 250]
24+
],
25+
'bidId': '30b31c1838de1e',
26+
'bidderRequestId': '22edbae2733bf6',
27+
'auctionId': '1d1a030790a475'
28+
};
29+
30+
it('should return true when required params found', function () {
31+
expect(spec.isBidRequestValid(bid)).to.equal(true);
32+
});
33+
34+
it('should return false when required params are not passed', function () {
35+
let bid = Object.assign({}, bid);
36+
delete bid.params;
37+
bid.params = {
38+
'someIncorrectParam': 0
39+
};
40+
expect(spec.isBidRequestValid(bid)).to.equal(false);
41+
});
42+
});
43+
44+
describe('buildRequests', function () {
45+
let bidRequests = [{
46+
'bidder': 'rads',
47+
'params': {
48+
'placement': '6682',
49+
'pfilter': {
50+
'floorprice': 1000000,
51+
'geo': {
52+
'country': 'DE'
53+
}
54+
},
55+
'bcat': 'IAB2,IAB4',
56+
'dvt': 'desktop',
57+
'ip': '1.1.1.1'
58+
},
59+
'sizes': [
60+
[300, 250]
61+
],
62+
'bidId': '30b31c1838de1e',
63+
'bidderRequestId': '22edbae2733bf6',
64+
'auctionId': '1d1a030790a475'
65+
}, {
66+
'bidder': 'rads',
67+
'params': {
68+
'placement': '6682',
69+
'pfilter': {
70+
'floorprice': 1000000,
71+
'geo': {
72+
'country': 'DE',
73+
'region': 'DE-BE'
74+
},
75+
},
76+
'bcat': 'IAB2,IAB4',
77+
'dvt': 'desktop'
78+
},
79+
'mediaTypes': {
80+
'video': {
81+
'playerSize': [640, 480],
82+
'context': 'instream'
83+
}
84+
},
85+
'bidId': '30b31c1838de1e',
86+
'bidderRequestId': '22edbae2733bf6',
87+
'auctionId': '1d1a030790a475'
88+
}];
89+
90+
let bidderRequest = {
91+
refererInfo: {
92+
referer: 'some_referrer.net'
93+
}
94+
}
95+
96+
const request = spec.buildRequests(bidRequests, bidderRequest);
97+
it('sends bid request to our endpoint via GET', function () {
98+
expect(request[0].method).to.equal('GET');
99+
let data = request[0].data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid');
100+
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');
101+
});
102+
103+
it('sends bid video request to our rads endpoint via GET', function () {
104+
expect(request[1].method).to.equal('GET');
105+
let data = request[1].data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid');
106+
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');
107+
});
108+
});
109+
110+
describe('interpretResponse', function () {
111+
let serverBannerResponse = {
112+
'body': {
113+
'cpm': 5000000,
114+
'crid': 100500,
115+
'width': '300',
116+
'height': '250',
117+
'adTag': '<!-- test creative -->',
118+
'requestId': '220ed41385952a',
119+
'currency': 'EUR',
120+
'ttl': 60,
121+
'netRevenue': true,
122+
'zone': '6682'
123+
}
124+
};
125+
let serverVideoResponse = {
126+
'body': {
127+
'cpm': 5000000,
128+
'crid': 100500,
129+
'width': '300',
130+
'height': '250',
131+
'vastXml': '{"reason":7001,"status":"accepted"}',
132+
'requestId': '220ed41385952a',
133+
'currency': 'EUR',
134+
'ttl': 60,
135+
'netRevenue': true,
136+
'zone': '6682'
137+
}
138+
};
139+
140+
let expectedResponse = [{
141+
requestId: '23beaa6af6cdde',
142+
cpm: 0.5,
143+
width: 0,
144+
height: 0,
145+
creativeId: 100500,
146+
dealId: '',
147+
currency: 'EUR',
148+
netRevenue: true,
149+
ttl: 300,
150+
ad: '<!-- test creative -->'
151+
}, {
152+
requestId: '23beaa6af6cdde',
153+
cpm: 0.5,
154+
width: 0,
155+
height: 0,
156+
creativeId: 100500,
157+
dealId: '',
158+
currency: 'EUR',
159+
netRevenue: true,
160+
ttl: 300,
161+
vastXml: '{"reason":7001,"status":"accepted"}',
162+
mediaType: 'video'
163+
}];
164+
165+
it('should get the correct bid response by display ad', function () {
166+
let bidRequest = [{
167+
'method': 'GET',
168+
'url': RADS_ENDPOINT_URL,
169+
'refererInfo': {
170+
'referer': ''
171+
},
172+
'data': {
173+
'bid_id': '30b31c1838de1e'
174+
}
175+
}];
176+
let result = spec.interpretResponse(serverBannerResponse, bidRequest[0]);
177+
expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0]));
178+
});
179+
180+
it('should get the correct rads video bid response by display ad', function () {
181+
let bidRequest = [{
182+
'method': 'GET',
183+
'url': RADS_ENDPOINT_URL,
184+
'mediaTypes': {
185+
'video': {
186+
'playerSize': [640, 480],
187+
'context': 'instream'
188+
}
189+
},
190+
'data': {
191+
'bid_id': '30b31c1838de1e'
192+
}
193+
}];
194+
let result = spec.interpretResponse(serverVideoResponse, bidRequest[0]);
195+
expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[1]));
196+
});
197+
198+
it('handles empty bid response', function () {
199+
let response = {
200+
body: {}
201+
};
202+
let result = spec.interpretResponse(response);
203+
expect(result.length).to.equal(0);
204+
});
205+
});
206+
});

0 commit comments

Comments
 (0)