Skip to content

Commit 35c58e0

Browse files
vfedoseevIsaac Dettman
authored and
Isaac Dettman
committed
Added myTarget Adapter (prebid#3599)
* Add myTargetBidAdapter * myTargetBidAdapter: replace legacy substr function
1 parent 9d5b9b4 commit 35c58e0

File tree

3 files changed

+347
-0
lines changed

3 files changed

+347
-0
lines changed

modules/mytargetBidAdapter.js

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import * as utils from '../src/utils';
2+
import * as url from '../src/url';
3+
import { config } from '../src/config';
4+
import { registerBidder } from '../src/adapters/bidderFactory';
5+
6+
const BIDDER_CODE = 'mytarget';
7+
const BIDDER_URL = '//ad.mail.ru/hbid_prebid/';
8+
const DEFAULT_CURRENCY = 'RUB';
9+
const DEFAULT_TTL = 180;
10+
11+
function buildPlacement(bidRequest) {
12+
let { bidId, params } = bidRequest;
13+
let { placementId, position, response, bidfloor } = params;
14+
let placement = {
15+
placementId,
16+
id: bidId,
17+
position: position || 0,
18+
response: response || 0
19+
};
20+
21+
if (typeof bidfloor !== 'undefined') {
22+
placement.bidfloor = bidfloor;
23+
}
24+
25+
return placement;
26+
}
27+
28+
function getSiteName(referrer) {
29+
let sitename = config.getConfig('mytarget.sitename');
30+
31+
if (!sitename) {
32+
sitename = url.parse(referrer).hostname;
33+
}
34+
35+
return sitename;
36+
}
37+
38+
function generateRandomId() {
39+
return Math.random().toString(16).substring(2);
40+
}
41+
42+
export const spec = {
43+
code: BIDDER_CODE,
44+
45+
isBidRequestValid: function(bid) {
46+
return !!bid.params.placementId;
47+
},
48+
49+
buildRequests: function(validBidRequests, bidderRequest) {
50+
let referrer = '';
51+
52+
if (bidderRequest && bidderRequest.refererInfo) {
53+
referrer = bidderRequest.refererInfo.referer;
54+
}
55+
56+
const payload = {
57+
places: utils._map(validBidRequests, buildPlacement),
58+
site: {
59+
sitename: getSiteName(referrer),
60+
page: referrer
61+
},
62+
settings: {
63+
currency: DEFAULT_CURRENCY,
64+
windowSize: {
65+
width: window.screen.width,
66+
height: window.screen.height
67+
}
68+
}
69+
};
70+
71+
return {
72+
method: 'POST',
73+
url: BIDDER_URL,
74+
data: payload,
75+
};
76+
},
77+
78+
interpretResponse: function(serverResponse, bidRequest) {
79+
let { body } = serverResponse;
80+
81+
if (body.bids) {
82+
return utils._map(body.bids, (bid) => {
83+
let bidResponse = {
84+
requestId: bid.id,
85+
cpm: bid.price,
86+
width: bid.size.width,
87+
height: bid.size.height,
88+
ttl: bid.ttl || DEFAULT_TTL,
89+
currency: bid.currency || DEFAULT_CURRENCY,
90+
creativeId: bid.creativeId || generateRandomId(),
91+
netRevenue: true
92+
}
93+
94+
if (bid.adm) {
95+
bidResponse.ad = bid.adm;
96+
} else {
97+
bidResponse.adUrl = bid.displayUrl;
98+
}
99+
100+
return bidResponse;
101+
});
102+
}
103+
104+
return [];
105+
}
106+
}
107+
108+
registerBidder(spec);

modules/mytargetBidAdapter.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Overview
2+
3+
```
4+
Module Name: myTarget Bidder Adapter
5+
Module Type: Bidder Adapter
6+
Maintainer: [email protected]
7+
```
8+
9+
# Description
10+
11+
Module that connects to myTarget demand sources.
12+
13+
# Test Parameters
14+
15+
```
16+
var adUnits = [{
17+
code: 'placementCode',
18+
mediaTypes: {
19+
banner: {
20+
sizes: [[240, 400]],
21+
}
22+
},
23+
bids: [{
24+
bidder: 'mytarget',
25+
params: {
26+
placementId: '379783',
27+
28+
// OPTIONAL: custom bid floor
29+
bidfloor: 10000,
30+
31+
// OPTIONAL: if you know the ad position on the page, specify it here
32+
// (this corresponds to "Ad Position" in OpenRTB 2.3, section 5.4)
33+
position: 0,
34+
35+
// OPTIONAL: bid response type: 0 - ad url (default), 1 - ad markup
36+
response: 0
37+
}
38+
}]
39+
}];
40+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
import { expect } from 'chai';
2+
import { spec } from 'modules/mytargetBidAdapter';
3+
4+
describe('MyTarget Adapter', function() {
5+
describe('isBidRequestValid', function () {
6+
it('should return true when required params found', function () {
7+
let validBid = {
8+
bidder: 'mytarget',
9+
params: {
10+
placementId: '1'
11+
}
12+
};
13+
14+
expect(spec.isBidRequestValid(validBid)).to.equal(true);
15+
});
16+
17+
it('should return false for when required params are not passed', function () {
18+
let invalidBid = {
19+
bidder: 'mytarget',
20+
params: {}
21+
};
22+
23+
expect(spec.isBidRequestValid(invalidBid)).to.equal(false);
24+
});
25+
});
26+
27+
describe('buildRequests', function () {
28+
let bidRequests = [
29+
{
30+
bidId: 'bid1',
31+
bidder: 'mytarget',
32+
params: {
33+
placementId: '1'
34+
}
35+
},
36+
{
37+
bidId: 'bid2',
38+
bidder: 'mytarget',
39+
params: {
40+
placementId: '2',
41+
position: 1,
42+
response: 1,
43+
bidfloor: 10000
44+
}
45+
}
46+
];
47+
let bidderRequest = {
48+
refererInfo: {
49+
referer: 'https://example.com?param=value'
50+
}
51+
};
52+
53+
let bidRequest = spec.buildRequests(bidRequests, bidderRequest);
54+
55+
it('should build single POST request for multiple bids', function() {
56+
expect(bidRequest.method).to.equal('POST');
57+
expect(bidRequest.url).to.equal('//ad.mail.ru/hbid_prebid/');
58+
expect(bidRequest.data).to.be.an('object');
59+
expect(bidRequest.data.places).to.be.an('array');
60+
expect(bidRequest.data.places).to.have.lengthOf(2);
61+
});
62+
63+
it('should pass bid parameters', function() {
64+
let place1 = bidRequest.data.places[0];
65+
let place2 = bidRequest.data.places[1];
66+
67+
expect(place1.placementId).to.equal('1');
68+
expect(place2.placementId).to.equal('2');
69+
expect(place1.id).to.equal('bid1');
70+
expect(place2.id).to.equal('bid2');
71+
});
72+
73+
it('should pass default position and response type', function() {
74+
let place = bidRequest.data.places[0];
75+
76+
expect(place.position).to.equal(0);
77+
expect(place.response).to.equal(0);
78+
});
79+
80+
it('should pass provided position and response type', function() {
81+
let place = bidRequest.data.places[1];
82+
83+
expect(place.position).to.equal(1);
84+
expect(place.response).to.equal(1);
85+
});
86+
87+
it('should not pass default bidfloor', function() {
88+
let place = bidRequest.data.places[0];
89+
90+
expect(place.bidfloor).not.to.exist;
91+
});
92+
93+
it('should not pass provided bidfloor', function() {
94+
let place = bidRequest.data.places[1];
95+
96+
expect(place.bidfloor).to.exist;
97+
expect(place.bidfloor).to.equal(10000);
98+
});
99+
100+
it('should pass site parameters', function() {
101+
let site = bidRequest.data.site;
102+
103+
expect(site).to.be.an('object');
104+
expect(site.sitename).to.equal('example.com');
105+
expect(site.page).to.equal('https://example.com?param=value');
106+
});
107+
108+
it('should pass settings', function() {
109+
let settings = bidRequest.data.settings;
110+
111+
expect(settings).to.be.an('object');
112+
expect(settings.currency).to.equal('RUB');
113+
expect(settings.windowSize).to.be.an('object');
114+
expect(settings.windowSize.width).to.equal(window.screen.width);
115+
expect(settings.windowSize.height).to.equal(window.screen.height);
116+
});
117+
});
118+
119+
describe('interpretResponse', function () {
120+
let serverResponse = {
121+
body: {
122+
'bidder_status':
123+
[
124+
{
125+
'bidder': 'mail.ru',
126+
'response_time_ms': 100,
127+
'num_bids': 2
128+
}
129+
],
130+
'bids':
131+
[
132+
{
133+
'displayUrl': 'https://ad.mail.ru/hbid_imp/12345',
134+
'size':
135+
{
136+
'height': '400',
137+
'width': '240'
138+
},
139+
'id': '1',
140+
'currency': 'RUB',
141+
'price': 100,
142+
'ttl': 360,
143+
'creativeId': '123456'
144+
},
145+
{
146+
'adm': '<p>Ad</p>',
147+
'size':
148+
{
149+
'height': '250',
150+
'width': '300'
151+
},
152+
'id': '2',
153+
'price': 200
154+
}
155+
]
156+
}
157+
};
158+
159+
let bids = spec.interpretResponse(serverResponse);
160+
161+
it('should return empty array for response with no bids', function() {
162+
let emptyBids = spec.interpretResponse({ body: {} });
163+
164+
expect(emptyBids).to.have.lengthOf(0);
165+
});
166+
167+
it('should parse all bids from response', function() {
168+
expect(bids).to.have.lengthOf(2);
169+
});
170+
171+
it('should parse bid with ad url', function() {
172+
expect(bids[0].requestId).to.equal('1');
173+
expect(bids[0].cpm).to.equal(100);
174+
expect(bids[0].width).to.equal('240');
175+
expect(bids[0].height).to.equal('400');
176+
expect(bids[0].ttl).to.equal(360);
177+
expect(bids[0].currency).to.equal('RUB');
178+
expect(bids[0]).to.have.property('creativeId');
179+
expect(bids[0].creativeId).to.equal('123456');
180+
expect(bids[0].netRevenue).to.equal(true);
181+
expect(bids[0].adUrl).to.equal('https://ad.mail.ru/hbid_imp/12345');
182+
expect(bids[0]).to.not.have.property('ad');
183+
});
184+
185+
it('should parse bid with ad markup', function() {
186+
expect(bids[1].requestId).to.equal('2');
187+
expect(bids[1].cpm).to.equal(200);
188+
expect(bids[1].width).to.equal('300');
189+
expect(bids[1].height).to.equal('250');
190+
expect(bids[1].ttl).to.equal(180);
191+
expect(bids[1].currency).to.equal('RUB');
192+
expect(bids[1]).to.have.property('creativeId');
193+
expect(bids[1].creativeId).not.to.equal('123456');
194+
expect(bids[1].netRevenue).to.equal(true);
195+
expect(bids[1].ad).to.equal('<p>Ad</p>');
196+
expect(bids[1]).to.not.have.property('adUrl');
197+
});
198+
});
199+
});

0 commit comments

Comments
 (0)