Skip to content

Commit

Permalink
Merge pull request #26 from jwplayer/feature/jwplayer-adapter-buildRe…
Browse files Browse the repository at this point in the history
…quests

JW Demand: Implemented buildRequests.
  • Loading branch information
jorgeluisrocha committed Jun 30, 2022
2 parents 7b4d9b6 + dc2e4db commit f0a4701
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 14 deletions.
148 changes: 144 additions & 4 deletions modules/jwplayerBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
// import * as utils from 'src/utils';
import { registerBidder } from '../src/adapters/bidderFactory.js';
// import { config } from 'src/config';
import { VIDEO } from '../src/mediaTypes.js';
import {
isFn,
deepAccess,
deepSetValue } from '../src/utils.js';
import { config } from '../src/config.js';

const BIDDER_CODE = 'jwplayer';
const URL = 'https://ib.adnxs.com/openrtb2/prebid';

const GVLID = 1046;
const SUPPORTED_AD_TYPES = [VIDEO];

// Video Parameters
// https://docs.prebid.org/dev-docs/bidder-adaptor.html#step-2-accept-video-parameters-and-pass-them-to-your-server
const VIDEO_ORTB_PARAMS = [
'mimes',
'minduration',
'maxduration',
'protocols',
'startdelay',
'placement',
'skip',
'skipafter',
'minbitrate',
'maxbitrate',
'delivery',
'playbackmethod',
'api',
'linearity'
];

export const spec = {
code: BIDDER_CODE,
gvlid: GVLID,
Expand All @@ -29,10 +53,25 @@ export const spec = {
/**
* 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.
* @param {BidRequest[]} bidRequests A non-empty list of bid requests, or ad units, which should be sent to the server.
* @param bidderRequest
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function(validBidRequests, bidderRequest) {},
buildRequests: function(bidRequests, bidderRequest) {
if (!bidRequests) {
return;
}

return bidRequests.map(bidRequest => {
const payload = buildRequest(bidRequest, bidderRequest);

return {
method: 'POST',
url: URL,
data: payload
}
});
},

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

function buildRequest(bidRequest, bidderRequest) {
const openrtbRequest = {
id: bidRequest.bidId,
imp: buildRequestImpression(bidRequest, bidderRequest),
site: buildRequestSite(bidderRequest),
device: buildRequestDevice()
};

// Attaching GDPR Consent Params
if (bidderRequest.gdprConsent) {
deepSetValue(openrtbRequest, 'user.ext.consent', bidderRequest.gdprConsent.consentString);
deepSetValue(openrtbRequest, 'regs.ext.gdpr', (bidderRequest.gdprConsent.gdprApplies ? 1 : 0));
}

// CCPA
if (bidderRequest.uspConsent) {
deepSetValue(openrtbRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent);
}

return JSON.stringify(openrtbRequest);
}

function buildRequestImpression(bidRequest) {
const impressionObject = {
id: bidRequest.adUnitCode,
};

impressionObject.video = buildImpressionVideo(bidRequest);

const bidFloorData = buildBidFloorData(bidRequest);
if (bidFloorData) {
impressionObject.bidfloor = bidFloorData.floor;
impressionObject.bidfloorcur = bidFloorData.currency;
}

impressionObject.ext = buildImpressionExtension(bidRequest);

return [impressionObject];
}

function buildImpressionVideo(bidRequest) {
const videoParams = deepAccess(bidRequest, 'mediaTypes.video', {});

const video = {};

VIDEO_ORTB_PARAMS.forEach((param) => {
if (videoParams.hasOwnProperty(param)) {
video[param] = videoParams[param];
}
});

return video;
}

function buildImpressionExtension(bidRequest) {
return {
appnexus: {
placement_id: bidRequest.params.placementId
}
};
}

function buildBidFloorData(bidRequest) {
const {params} = bidRequest;
const currency = params.currency || 'USD';

let floorData;
if (isFn(bidRequest.getFloor)) {
const bidFloorRequest = {
currency: currency,
mediaType: VIDEO,
size: '*'
};
floorData = bidRequest.getFloor(bidFloorRequest);
} else if (params.bidfloor) {
floorData = {floor: params.bidfloor, currency: currency};
}

return floorData;
}

function buildRequestSite(bidderRequest) {
const site = config.getConfig('ortb2.site') || {};

site.domain = site.domain || config.publisherDomain || window.location.hostname;
site.page = site.page || config.pageUrl || window.location.href;

const referer = bidderRequest.refererInfo && bidderRequest.refererInfo.referer;
if (!site.ref && referer) {
site.ref = referer;
}

return site;
}

function buildRequestDevice() {
return {
ua: navigator.userAgent
};
}

registerBidder(spec);
94 changes: 84 additions & 10 deletions test/spec/modules/jwplayerBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import { spec } from 'modules/jwplayerBidAdapter.js';
import { config } from 'src/config.js';

describe('jwplayer adapter tests', function() {
var sandbox, clock, frozenNow = new Date();

beforeEach(function() {
sandbox = sinon.sandbox.create();
clock = sinon.useFakeTimers(frozenNow.getTime());
});

afterEach(function() {
sandbox.restore();
clock.restore();
this.defaultBidderRequest = {
'gdprConsent': {
'consentString': '',
'gdprApplies': true
},
'uspConsent': true,
'refererInfo': {
'referer': 'https://example.com'
}
}
});

describe('isBidRequestValid', function() {
Expand All @@ -37,7 +38,80 @@ describe('jwplayer adapter tests', function() {
});
});

describe('buildRequests for video', function() {});
describe('buildRequests for video', function() {
it('buildRequests works', function() {
const bidRequests = [
{
'bidder': 'jwplayer',
'params': {
'placementId': 12345
},
'mediaTypes': {
'video': {
'playerSize': [640, 480],
'content': {}
}
},
'bidRequestsCount': 1,
'adUnitCode': 'testAdUnitCode',
'bidId': 'testBidId'
}
]

let sandbox = sinon.sandbox.create();
sandbox.stub(config, 'getConfig').callsFake((key) => {
const config = {
'ortb2.site': {
domain: 'page.example.com',
page: 'https://examplepage.com'
}
};
return config[key];
});

const serverRequests = spec.buildRequests(bidRequests, this.defaultBidderRequest);

serverRequests.forEach(serverRequest => {
expect(serverRequest.url).to.have.string('https://ib.adnxs.com/openrtb2/prebid');
expect(serverRequest.method).to.equal('POST');

const openrtbRequest = JSON.parse(serverRequest.data);

expect(openrtbRequest.id).to.not.equal(null);
expect(openrtbRequest.id).to.have.string('testBidId');

expect(openrtbRequest.site).to.not.equal(null);
expect(openrtbRequest.site).to.be.an('object');
expect(openrtbRequest.site.domain).to.be.a('string');
expect(openrtbRequest.site.domain).to.have.string('page.example.com');
expect(openrtbRequest.site.page).to.be.a('string');
expect(openrtbRequest.site.page).to.have.string('https://examplepage.com');
expect(openrtbRequest.site.ref).to.be.a('string');
expect(openrtbRequest.site.ref).to.have.string('https://example.com');

expect(openrtbRequest.device).to.not.equal(null);
expect(openrtbRequest.device.ua).to.equal(navigator.userAgent);

expect(openrtbRequest.imp).to.not.equal(null);
expect(openrtbRequest.imp[0]).to.not.equal(null);
expect(openrtbRequest.imp[0].video).to.not.equal(null);
expect(openrtbRequest.imp[0].ext).to.not.equal(null);
expect(openrtbRequest.imp[0].ext.appnexus).to.not.equal(null);
expect(openrtbRequest.imp[0].ext.appnexus.placement_id).to.not.equal(null);
expect(openrtbRequest.imp[0].ext.appnexus.placement_id).to.equal(12345);

expect(openrtbRequest.user).to.not.equal(null);
expect(openrtbRequest.user.ext).to.not.equal(null);

expect(openrtbRequest.regs).to.not.equal(null);
expect(openrtbRequest.regs.ext).to.not.equal(null);
expect(openrtbRequest.regs.ext.gdpr).to.equal(1);
expect(openrtbRequest.regs.ext.us_privacy).to.equal(true);
});

sandbox.restore();
});
});

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

Expand Down

0 comments on commit f0a4701

Please sign in to comment.