Skip to content

Commit

Permalink
OpenX Adapter: GDPR Support (#2504)
Browse files Browse the repository at this point in the history
  • Loading branch information
jimee02 authored and harpere committed May 11, 2018
1 parent 877a58c commit fdadd14
Show file tree
Hide file tree
Showing 2 changed files with 212 additions and 12 deletions.
43 changes: 31 additions & 12 deletions modules/openxBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const spec = {
isBidRequestValid: function (bidRequest) {
return !!(bidRequest.params.unit && bidRequest.params.delDomain);
},
buildRequests: function (bidRequests) {
buildRequests: function (bidRequests, bidderRequest) {
if (bidRequests.length === 0) {
return [];
}
Expand All @@ -31,12 +31,12 @@ export const spec = {

// build banner requests
if (bannerBids.length > 0) {
requests.push(buildOXBannerRequest(bannerBids));
requests.push(buildOXBannerRequest(bannerBids, bidderRequest));
}
// build video requests
if (videoBids.length > 0) {
videoBids.forEach(videoBid => {
requests.push(buildOXVideoRequest(videoBid))
requests.push(buildOXVideoRequest(videoBid, bidderRequest))
});
}

Expand Down Expand Up @@ -177,10 +177,11 @@ function getMediaTypeFromRequest(serverRequest) {
return /avjp$/.test(serverRequest.url) ? VIDEO : BANNER;
}

function buildCommonQueryParamsFromBids(bids) {
function buildCommonQueryParamsFromBids(bids, bidderRequest) {
const isInIframe = utils.inIframe();
let defaultParams;

return {
defaultParams = {
ju: config.getConfig('pageUrl') || utils.getTopWindowUrl(),
jr: utils.getTopWindowReferrer(),
ch: document.charSet || document.characterSet,
Expand All @@ -190,12 +191,30 @@ function buildCommonQueryParamsFromBids(bids) {
tws: getViewportDimensions(isInIframe),
be: 1,
dddid: utils._map(bids, bid => bid.transactionId).join(','),
nocache: new Date().getTime(),
nocache: new Date().getTime()
};

if (utils.deepAccess(bidderRequest, 'gdprConsent')) {
let gdprConsentConfig = bidderRequest.gdprConsent;

if (gdprConsentConfig.consentString !== undefined) {
defaultParams.gdpr_consent = gdprConsentConfig.consentString;
}

if (gdprConsentConfig.gdprApplies !== undefined) {
defaultParams.gdpr = gdprConsentConfig.gdprApplies ? 1 : 0;
}

if (config.getConfig('consentManagement.cmpApi') === 'iab') {
defaultParams.x_gdpr_f = 1;
}
}

return defaultParams;
}

function buildOXBannerRequest(bids) {
let queryParams = buildCommonQueryParamsFromBids(bids);
function buildOXBannerRequest(bids, bidderRequest) {
let queryParams = buildCommonQueryParamsFromBids(bids, bidderRequest);

queryParams.auid = utils._map(bids, bid => bid.params.unit).join(',');
queryParams.aus = utils._map(bids, bid => utils.parseSizesInput(bid.sizes).join(',')).join('|');
Expand Down Expand Up @@ -240,9 +259,9 @@ function buildOXBannerRequest(bids) {
};
}

function buildOXVideoRequest(bid) {
function buildOXVideoRequest(bid, bidderRequest) {
let url = `//${bid.params.delDomain}/v/1.0/avjp`;
let oxVideoParams = generateVideoParameters(bid);
let oxVideoParams = generateVideoParameters(bid, bidderRequest);
return {
method: 'GET',
url: url,
Expand All @@ -251,8 +270,8 @@ function buildOXVideoRequest(bid) {
};
}

function generateVideoParameters(bid) {
let queryParams = buildCommonQueryParamsFromBids([bid]);
function generateVideoParameters(bid, bidderRequest) {
let queryParams = buildCommonQueryParamsFromBids([bid], bidderRequest);
let oxVideoConfig = utils.deepAccess(bid, 'params.video') || {};
let context = utils.deepAccess(bid, 'mediaTypes.video.context');
let playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize');
Expand Down
181 changes: 181 additions & 0 deletions test/spec/modules/openxBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {expect} from 'chai';
import {spec, resetBoPixel} from 'modules/openxBidAdapter';
import {newBidder} from 'src/adapters/bidderFactory';
import {userSync} from 'src/userSync';
import {config} from 'src/config';
import * as utils from 'src/utils';

const URLBASE = '/w/1.0/arj';
Expand Down Expand Up @@ -343,6 +344,186 @@ describe('OpenxAdapter', () => {
expect(dataParams.bc).to.exist;
expect(dataParams.bc).to.equal('hb_override');
});

it('should not send any consent management properties', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes);
expect(request[0].data.gdpr).to.equal(undefined);
expect(request[0].data.gdpr_consent).to.equal(undefined);
expect(request[0].data.x_gdpr_f).to.equal(undefined);
});

describe('when there is a consent management framework', () => {
let bidRequests;
let mockConfig;
let bidderRequest;
const IAB_CONSENT_FRAMEWORK_CODE = 1;

beforeEach(() => {
bidRequests = [{
bidder: 'openx',
params: {
unit: '12345678-banner',
delDomain: 'test-del-domain'
},
adUnitCode: 'adunit-code',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
bidId: 'test-bid-id',
bidderRequestId: 'test-bidder-request-id',
auctionId: 'test-auction-id'
}, {
'bidder': 'openx',
'mediaTypes': {
video: {
playerSize: [640, 480]
}
},
'params': {
'unit': '12345678-video',
'delDomain': 'test-del-domain'
},
'adUnitCode': 'adunit-code',

bidId: 'test-bid-id',
bidderRequestId: 'test-bidder-request-id',
auctionId: 'test-auction-id',
transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
}];
});

afterEach(function () {
config.getConfig.restore();
});

describe('when GDPR applies', function () {
beforeEach(function () {
bidderRequest = {
gdprConsent: {
consentString: 'test-gdpr-consent-string',
gdprApplies: true
}
};

mockConfig = {
consentManagement: {
cmpApi: 'iab',
timeout: 1111,
allowAuctionWithoutConsent: 'cancel'
}
};

sinon.stub(config, 'getConfig').callsFake((key) => {
return utils.deepAccess(mockConfig, key);
});
});

it('should send a signal to specify that GDPR applies to this request', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.gdpr).to.equal(1);
expect(request[1].data.gdpr).to.equal(1);
});

it('should send the consent string', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
expect(request[1].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
});

it('should send the consent management framework code', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
expect(request[1].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
});
});

describe('when GDPR does not apply', function () {
beforeEach(function () {
bidderRequest = {
gdprConsent: {
consentString: 'test-gdpr-consent-string',
gdprApplies: false
}
};

mockConfig = {
consentManagement: {
cmpApi: 'iab',
timeout: 1111,
allowAuctionWithoutConsent: 'cancel'
}
};

sinon.stub(config, 'getConfig').callsFake((key) => {
return utils.deepAccess(mockConfig, key);
});
});

it('should not send a signal to specify that GDPR does not apply to this request', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.gdpr).to.equal(0);
expect(request[1].data.gdpr).to.equal(0);
});

it('should send the consent string', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
expect(request[1].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
});

it('should send the consent management framework code', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
expect(request[1].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
});
});

describe('when GDPR consent has undefined data', function () {
beforeEach(function () {
bidderRequest = {
gdprConsent: {
consentString: 'test-gdpr-consent-string',
gdprApplies: true
}
};

mockConfig = {
consentManagement: {
cmpApi: 'iab',
timeout: 1111,
allowAuctionWithoutConsent: 'cancel'
}
};

sinon.stub(config, 'getConfig').callsFake((key) => {
return utils.deepAccess(mockConfig, key);
});
});

it('should not send a signal to specify whether GDPR applies to this request, when GDPR application is undefined', function () {
delete bidderRequest.gdprConsent.gdprApplies;
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data).to.not.have.property('gdpr');
expect(request[1].data).to.not.have.property('gdpr');
});

it('should not send the consent string, when consent string is undefined', function () {
delete bidderRequest.gdprConsent.consentString;
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data).to.not.have.property('gdpr_consent');
expect(request[1].data).to.not.have.property('gdpr_consent');
});

it('should not send the consent management framework code, when format is undefined', function () {
delete mockConfig.consentManagement.cmpApi;
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data).to.not.have.property('x_gdpr_f');
expect(request[1].data).to.not.have.property('x_gdpr_f');
});
});
});
});

describe('buildRequests for video', () => {
Expand Down

0 comments on commit fdadd14

Please sign in to comment.