Skip to content

Commit f0a4701

Browse files
Merge pull request #26 from jwplayer/feature/jwplayer-adapter-buildRequests
JW Demand: Implemented buildRequests.
2 parents 7b4d9b6 + dc2e4db commit f0a4701

File tree

2 files changed

+228
-14
lines changed

2 files changed

+228
-14
lines changed

modules/jwplayerBidAdapter.js

+144-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,36 @@
1-
// import * as utils from 'src/utils';
21
import { registerBidder } from '../src/adapters/bidderFactory.js';
3-
// import { config } from 'src/config';
42
import { VIDEO } from '../src/mediaTypes.js';
3+
import {
4+
isFn,
5+
deepAccess,
6+
deepSetValue } from '../src/utils.js';
7+
import { config } from '../src/config.js';
58

69
const BIDDER_CODE = 'jwplayer';
10+
const URL = 'https://ib.adnxs.com/openrtb2/prebid';
11+
712
const GVLID = 1046;
813
const SUPPORTED_AD_TYPES = [VIDEO];
914

15+
// Video Parameters
16+
// https://docs.prebid.org/dev-docs/bidder-adaptor.html#step-2-accept-video-parameters-and-pass-them-to-your-server
17+
const VIDEO_ORTB_PARAMS = [
18+
'mimes',
19+
'minduration',
20+
'maxduration',
21+
'protocols',
22+
'startdelay',
23+
'placement',
24+
'skip',
25+
'skipafter',
26+
'minbitrate',
27+
'maxbitrate',
28+
'delivery',
29+
'playbackmethod',
30+
'api',
31+
'linearity'
32+
];
33+
1034
export const spec = {
1135
code: BIDDER_CODE,
1236
gvlid: GVLID,
@@ -29,10 +53,25 @@ export const spec = {
2953
/**
3054
* Make a server request from the list of BidRequests.
3155
*
32-
* @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be sent to the Server.
56+
* @param {BidRequest[]} bidRequests A non-empty list of bid requests, or ad units, which should be sent to the server.
57+
* @param bidderRequest
3358
* @return ServerRequest Info describing the request to the server.
3459
*/
35-
buildRequests: function(validBidRequests, bidderRequest) {},
60+
buildRequests: function(bidRequests, bidderRequest) {
61+
if (!bidRequests) {
62+
return;
63+
}
64+
65+
return bidRequests.map(bidRequest => {
66+
const payload = buildRequest(bidRequest, bidderRequest);
67+
68+
return {
69+
method: 'POST',
70+
url: URL,
71+
data: payload
72+
}
73+
});
74+
},
3675

3776
/**
3877
* Unpack the response from the server into a list of bids.
@@ -50,4 +89,105 @@ export const spec = {
5089
// onBidderError: function({ error, bidderRequest }) {}
5190
};
5291

92+
function buildRequest(bidRequest, bidderRequest) {
93+
const openrtbRequest = {
94+
id: bidRequest.bidId,
95+
imp: buildRequestImpression(bidRequest, bidderRequest),
96+
site: buildRequestSite(bidderRequest),
97+
device: buildRequestDevice()
98+
};
99+
100+
// Attaching GDPR Consent Params
101+
if (bidderRequest.gdprConsent) {
102+
deepSetValue(openrtbRequest, 'user.ext.consent', bidderRequest.gdprConsent.consentString);
103+
deepSetValue(openrtbRequest, 'regs.ext.gdpr', (bidderRequest.gdprConsent.gdprApplies ? 1 : 0));
104+
}
105+
106+
// CCPA
107+
if (bidderRequest.uspConsent) {
108+
deepSetValue(openrtbRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent);
109+
}
110+
111+
return JSON.stringify(openrtbRequest);
112+
}
113+
114+
function buildRequestImpression(bidRequest) {
115+
const impressionObject = {
116+
id: bidRequest.adUnitCode,
117+
};
118+
119+
impressionObject.video = buildImpressionVideo(bidRequest);
120+
121+
const bidFloorData = buildBidFloorData(bidRequest);
122+
if (bidFloorData) {
123+
impressionObject.bidfloor = bidFloorData.floor;
124+
impressionObject.bidfloorcur = bidFloorData.currency;
125+
}
126+
127+
impressionObject.ext = buildImpressionExtension(bidRequest);
128+
129+
return [impressionObject];
130+
}
131+
132+
function buildImpressionVideo(bidRequest) {
133+
const videoParams = deepAccess(bidRequest, 'mediaTypes.video', {});
134+
135+
const video = {};
136+
137+
VIDEO_ORTB_PARAMS.forEach((param) => {
138+
if (videoParams.hasOwnProperty(param)) {
139+
video[param] = videoParams[param];
140+
}
141+
});
142+
143+
return video;
144+
}
145+
146+
function buildImpressionExtension(bidRequest) {
147+
return {
148+
appnexus: {
149+
placement_id: bidRequest.params.placementId
150+
}
151+
};
152+
}
153+
154+
function buildBidFloorData(bidRequest) {
155+
const {params} = bidRequest;
156+
const currency = params.currency || 'USD';
157+
158+
let floorData;
159+
if (isFn(bidRequest.getFloor)) {
160+
const bidFloorRequest = {
161+
currency: currency,
162+
mediaType: VIDEO,
163+
size: '*'
164+
};
165+
floorData = bidRequest.getFloor(bidFloorRequest);
166+
} else if (params.bidfloor) {
167+
floorData = {floor: params.bidfloor, currency: currency};
168+
}
169+
170+
return floorData;
171+
}
172+
173+
function buildRequestSite(bidderRequest) {
174+
const site = config.getConfig('ortb2.site') || {};
175+
176+
site.domain = site.domain || config.publisherDomain || window.location.hostname;
177+
site.page = site.page || config.pageUrl || window.location.href;
178+
179+
const referer = bidderRequest.refererInfo && bidderRequest.refererInfo.referer;
180+
if (!site.ref && referer) {
181+
site.ref = referer;
182+
}
183+
184+
return site;
185+
}
186+
187+
function buildRequestDevice() {
188+
return {
189+
ua: navigator.userAgent
190+
};
191+
}
192+
53193
registerBidder(spec);

test/spec/modules/jwplayerBidAdapter_spec.js

+84-10
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@ import { spec } from 'modules/jwplayerBidAdapter.js';
33
import { config } from 'src/config.js';
44

55
describe('jwplayer adapter tests', function() {
6-
var sandbox, clock, frozenNow = new Date();
7-
86
beforeEach(function() {
9-
sandbox = sinon.sandbox.create();
10-
clock = sinon.useFakeTimers(frozenNow.getTime());
11-
});
12-
13-
afterEach(function() {
14-
sandbox.restore();
15-
clock.restore();
7+
this.defaultBidderRequest = {
8+
'gdprConsent': {
9+
'consentString': '',
10+
'gdprApplies': true
11+
},
12+
'uspConsent': true,
13+
'refererInfo': {
14+
'referer': 'https://example.com'
15+
}
16+
}
1617
});
1718

1819
describe('isBidRequestValid', function() {
@@ -37,7 +38,80 @@ describe('jwplayer adapter tests', function() {
3738
});
3839
});
3940

40-
describe('buildRequests for video', function() {});
41+
describe('buildRequests for video', function() {
42+
it('buildRequests works', function() {
43+
const bidRequests = [
44+
{
45+
'bidder': 'jwplayer',
46+
'params': {
47+
'placementId': 12345
48+
},
49+
'mediaTypes': {
50+
'video': {
51+
'playerSize': [640, 480],
52+
'content': {}
53+
}
54+
},
55+
'bidRequestsCount': 1,
56+
'adUnitCode': 'testAdUnitCode',
57+
'bidId': 'testBidId'
58+
}
59+
]
60+
61+
let sandbox = sinon.sandbox.create();
62+
sandbox.stub(config, 'getConfig').callsFake((key) => {
63+
const config = {
64+
'ortb2.site': {
65+
domain: 'page.example.com',
66+
page: 'https://examplepage.com'
67+
}
68+
};
69+
return config[key];
70+
});
71+
72+
const serverRequests = spec.buildRequests(bidRequests, this.defaultBidderRequest);
73+
74+
serverRequests.forEach(serverRequest => {
75+
expect(serverRequest.url).to.have.string('https://ib.adnxs.com/openrtb2/prebid');
76+
expect(serverRequest.method).to.equal('POST');
77+
78+
const openrtbRequest = JSON.parse(serverRequest.data);
79+
80+
expect(openrtbRequest.id).to.not.equal(null);
81+
expect(openrtbRequest.id).to.have.string('testBidId');
82+
83+
expect(openrtbRequest.site).to.not.equal(null);
84+
expect(openrtbRequest.site).to.be.an('object');
85+
expect(openrtbRequest.site.domain).to.be.a('string');
86+
expect(openrtbRequest.site.domain).to.have.string('page.example.com');
87+
expect(openrtbRequest.site.page).to.be.a('string');
88+
expect(openrtbRequest.site.page).to.have.string('https://examplepage.com');
89+
expect(openrtbRequest.site.ref).to.be.a('string');
90+
expect(openrtbRequest.site.ref).to.have.string('https://example.com');
91+
92+
expect(openrtbRequest.device).to.not.equal(null);
93+
expect(openrtbRequest.device.ua).to.equal(navigator.userAgent);
94+
95+
expect(openrtbRequest.imp).to.not.equal(null);
96+
expect(openrtbRequest.imp[0]).to.not.equal(null);
97+
expect(openrtbRequest.imp[0].video).to.not.equal(null);
98+
expect(openrtbRequest.imp[0].ext).to.not.equal(null);
99+
expect(openrtbRequest.imp[0].ext.appnexus).to.not.equal(null);
100+
expect(openrtbRequest.imp[0].ext.appnexus.placement_id).to.not.equal(null);
101+
expect(openrtbRequest.imp[0].ext.appnexus.placement_id).to.equal(12345);
102+
103+
expect(openrtbRequest.user).to.not.equal(null);
104+
expect(openrtbRequest.user.ext).to.not.equal(null);
105+
106+
expect(openrtbRequest.regs).to.not.equal(null);
107+
expect(openrtbRequest.regs.ext).to.not.equal(null);
108+
expect(openrtbRequest.regs.ext.gdpr).to.equal(1);
109+
expect(openrtbRequest.regs.ext.us_privacy).to.equal(true);
110+
});
111+
112+
sandbox.restore();
113+
});
114+
});
41115

42116
describe('interpretResponse for video', function() {});
43117

0 commit comments

Comments
 (0)