Skip to content

Commit

Permalink
Index Exchange Bid Adapter: coppa support, dealid & ttl field updates (
Browse files Browse the repository at this point in the history
…#6782)

* set bidderRequestId to be a string in r.id

* set coppa value in r.reqs.coppa

* added support for seat[].bid[].exp ttl value

* read dealid from openrtb first, then fallback to ext

* use utils.isInteger

Co-authored-by: Kajan Umakanthan <umakajan@umakajan.com>
Co-authored-by: punkiller <pankajkumar555@gmail.com>
  • Loading branch information
3 people authored and idettman committed May 21, 2021
1 parent 9515506 commit cea4a58
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 15 deletions.
20 changes: 14 additions & 6 deletions modules/ixBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as utils from '../src/utils.js';
import { BANNER, VIDEO } from '../src/mediaTypes.js';
import { config } from '../src/config.js';
import find from 'core-js-pure/features/array/find.js';
import isInteger from 'core-js-pure/features/number/is-integer.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';

const BIDDER_CODE = 'ix';
Expand Down Expand Up @@ -206,6 +205,8 @@ function _applyFloor(bid, imp, mediaType) {
*/
function parseBid(rawBid, currency, bidRequest) {
const bid = {};
const isValidExpiry = !!((utils.deepAccess(rawBid, 'exp') && utils.isInteger(rawBid.exp)));
const dealID = utils.deepAccess(rawBid, 'dealid') || utils.deepAccess(rawBid, 'ext.dealid');

if (PRICE_TO_DOLLAR_FACTOR.hasOwnProperty(currency)) {
bid.cpm = rawBid.price / PRICE_TO_DOLLAR_FACTOR[currency];
Expand All @@ -215,7 +216,10 @@ function parseBid(rawBid, currency, bidRequest) {

bid.requestId = rawBid.impid;

bid.dealId = utils.deepAccess(rawBid, 'ext.dealid');
if (dealID) {
bid.dealId = dealID;
}

bid.netRevenue = NET_REVENUE;
bid.currency = currency;
bid.creativeId = rawBid.hasOwnProperty('crid') ? rawBid.crid : '-';
Expand All @@ -226,13 +230,13 @@ function parseBid(rawBid, currency, bidRequest) {
bid.width = bidRequest.video.w;
bid.height = bidRequest.video.h;
bid.mediaType = VIDEO;
bid.ttl = VIDEO_TIME_TO_LIVE;
bid.ttl = isValidExpiry ? rawBid.exp : VIDEO_TIME_TO_LIVE;
} else {
bid.ad = rawBid.adm;
bid.width = rawBid.w;
bid.height = rawBid.h;
bid.mediaType = BANNER;
bid.ttl = BANNER_TIME_TO_LIVE;
bid.ttl = isValidExpiry ? rawBid.exp : BANNER_TIME_TO_LIVE;
}

bid.meta = {};
Expand All @@ -253,7 +257,7 @@ function parseBid(rawBid, currency, bidRequest) {
* @return {boolean} True if this is a valid size format, and false otherwise.
*/
function isValidSize(size) {
return Array.isArray(size) && size.length === 2 && isInteger(size[0]) && isInteger(size[1]);
return Array.isArray(size) && size.length === 2 && utils.isInteger(size[0]) && utils.isInteger(size[1]);
}

/**
Expand Down Expand Up @@ -385,7 +389,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
const r = {};

// Since bidderRequestId are the same for different bid request, just use the first one.
r.id = validBidRequests[0].bidderRequestId;
r.id = validBidRequests[0].bidderRequestId.toString();

r.site = {};
r.ext = {};
Expand Down Expand Up @@ -452,6 +456,10 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
}
}

if (config.getConfig('coppa')) {
utils.deepSetValue(r, 'regs.coppa', 1);
}

const payload = {};

// Parse additional runtime configs.
Expand Down
124 changes: 115 additions & 9 deletions test/spec/modules/ixBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,7 @@ describe('IndexexchangeAdapter', function () {
});

describe('buildRequests', function () {
const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0];
let request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0];
const requestUrl = request.url;
const requestMethod = request.method;
const query = request.data;
Expand Down Expand Up @@ -1254,6 +1254,7 @@ describe('IndexexchangeAdapter', function () {
it('payload should have correct format and value', function () {
const payload = JSON.parse(query.r);
expect(payload.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidderRequestId);
expect(payload.id).to.be.a('string');
expect(payload.site).to.exist;
expect(payload.site.page).to.equal(DEFAULT_OPTION.refererInfo.referer);
expect(payload.site.ref).to.equal(document.referrer);
Expand All @@ -1265,6 +1266,18 @@ describe('IndexexchangeAdapter', function () {
expect(payload.imp).to.have.lengthOf(2);
});

it('payload should have correct format and value for r.id when bidderRequestId is a number ', function () {
const bidWithIntId = utils.deepClone(DEFAULT_BANNER_VALID_BID);
bidWithIntId[0].bidderRequestId = 123456;

request = spec.buildRequests(bidWithIntId, DEFAULT_OPTION)[0];

const payload = JSON.parse(request.data.r);
expect(bidWithIntId[0].bidderRequestId).to.be.a('number');
expect(payload.id).to.equal(bidWithIntId[0].bidderRequestId.toString());
expect(payload.id).to.be.a('string');
});

it('payload should not include schain when not provided', function () {
const payload = JSON.parse(queryWithoutSchain.r);
expect(payload.source).to.not.exist; // source object currently only written for schain
Expand Down Expand Up @@ -1963,7 +1976,6 @@ describe('IndexexchangeAdapter', function () {
currency: 'USD',
ttl: 300,
netRevenue: true,
dealId: undefined,
meta: {
networkId: 50,
brandId: 303325,
Expand All @@ -1989,7 +2001,6 @@ describe('IndexexchangeAdapter', function () {
currency: 'USD',
ttl: 300,
netRevenue: true,
dealId: undefined,
meta: {
networkId: 50,
brandId: 303325,
Expand All @@ -2016,7 +2027,6 @@ describe('IndexexchangeAdapter', function () {
currency: 'USD',
ttl: 300,
netRevenue: true,
dealId: undefined,
meta: {
networkId: 50,
brandId: 303325,
Expand All @@ -2043,7 +2053,6 @@ describe('IndexexchangeAdapter', function () {
currency: 'JPY',
ttl: 300,
netRevenue: true,
dealId: undefined,
meta: {
networkId: 50,
brandId: 303325,
Expand All @@ -2056,9 +2065,38 @@ describe('IndexexchangeAdapter', function () {
expect(result[0]).to.deep.equal(expectedParse[0]);
});

it('should set dealId correctly', function () {
it('should prioritize bid[].dealid over bid[].ext.dealid ', function () {
const bidResponse = utils.deepClone(DEFAULT_BANNER_BID_RESPONSE);
bidResponse.seatbid[0].bid[0].ext.dealid = 'ext-deal';
bidResponse.seatbid[0].bid[0].dealid = 'outter-deal';
const expectedParse = [
{
requestId: '1a2b3c4d',
cpm: 1,
creativeId: '12345',
width: 300,
height: 250,
mediaType: 'banner',
ad: '<a target="_blank" href="https://www.indexexchange.com"></a>',
currency: 'USD',
ttl: 300,
netRevenue: true,
dealId: 'outter-deal',
meta: {
networkId: 50,
brandId: 303325,
brandName: 'OECTA',
advertiserDomains: ['www.abc.com']
}
}
];
const result = spec.interpretResponse({ body: bidResponse }, { data: DEFAULT_BIDDER_REQUEST_DATA });

expect(result[0].dealId).to.equal(expectedParse[0].dealId);
});

it('should not set bid[].dealid if dealid is not present', function () {
const bidResponse = utils.deepClone(DEFAULT_BANNER_BID_RESPONSE);
bidResponse.seatbid[0].bid[0].ext.dealid = 'deal';
const expectedParse = [
{
requestId: '1a2b3c4d',
Expand All @@ -2071,7 +2109,6 @@ describe('IndexexchangeAdapter', function () {
currency: 'USD',
ttl: 300,
netRevenue: true,
dealId: 'deal',
meta: {
networkId: 50,
brandId: 303325,
Expand All @@ -2084,6 +2121,34 @@ describe('IndexexchangeAdapter', function () {
expect(result[0]).to.deep.equal(expectedParse[0]);
});

it('should use set bid[].ext.dealid if bid[].dealid is not present', function () {
const bidResponse = utils.deepClone(DEFAULT_BANNER_BID_RESPONSE);
bidResponse.seatbid[0].bid[0].ext.dealid = 'ext-deal';
const expectedParse = [
{
requestId: '1a2b3c4d',
cpm: 1,
creativeId: '12345',
width: 300,
height: 250,
mediaType: 'banner',
ad: '<a target="_blank" href="https://www.indexexchange.com"></a>',
currency: 'USD',
ttl: 300,
dealId: 'ext-deal',
netRevenue: true,
meta: {
networkId: 50,
brandId: 303325,
brandName: 'OECTA',
advertiserDomains: ['www.abc.com']
}
}
];
const result = spec.interpretResponse({ body: bidResponse }, { data: DEFAULT_BIDDER_REQUEST_DATA });
expect(result[0].dealId).to.deep.equal(expectedParse[0].dealId);
});

it('should get correct bid response for video ad', function () {
const expectedParse = [
{
Expand All @@ -2096,7 +2161,6 @@ describe('IndexexchangeAdapter', function () {
currency: 'USD',
ttl: 3600,
netRevenue: true,
dealId: undefined,
vastUrl: 'www.abcd.com/vast',
meta: {
networkId: 51,
Expand Down Expand Up @@ -2142,6 +2206,26 @@ describe('IndexexchangeAdapter', function () {
expect(requestWithoutreferInfo.site.page).to.equal(options.refererInfo.referer);
expect(validBidWithoutreferInfo[0].url).to.equal(IX_SECURE_ENDPOINT);
});

it('should set bid[].ttl to seatbid[].bid[].exp value from response', function () {
const BANNER_RESPONSE_WITH_EXP = utils.deepClone(DEFAULT_BANNER_BID_RESPONSE);
const VIDEO_RESPONSE_WITH_EXP = utils.deepClone(DEFAULT_VIDEO_BID_RESPONSE);
VIDEO_RESPONSE_WITH_EXP.seatbid[0].bid[0].exp = 200;
BANNER_RESPONSE_WITH_EXP.seatbid[0].bid[0].exp = 100;
const bannerResult = spec.interpretResponse({ body: BANNER_RESPONSE_WITH_EXP }, { data: DEFAULT_BIDDER_REQUEST_DATA });
const videoResult = spec.interpretResponse({ body: VIDEO_RESPONSE_WITH_EXP }, { data: DEFAULT_BIDDER_REQUEST_DATA });

expect(bannerResult[0].ttl).to.equal(100);
expect(videoResult[0].ttl).to.equal(200);
});

it('should default bid[].ttl if seat[].bid[].exp is not in the resposne', function () {
const bannerResult = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, { data: DEFAULT_BIDDER_REQUEST_DATA });
const videoResult = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { data: DEFAULT_BIDDER_REQUEST_DATA });

expect(bannerResult[0].ttl).to.equal(300);
expect(videoResult[0].ttl).to.equal(3600);
});
});

describe('bidrequest consent', function () {
Expand Down Expand Up @@ -2248,5 +2332,27 @@ describe('IndexexchangeAdapter', function () {
expect(utils.deepAccess(requestWithConsent, 'user.ext.consented_providers_settings')).to.not.exist;
expect(utils.deepAccess(requestWithConsent, 'user.ext.consent')).to.not.exist;
});

it('should set coppa to 1 in config when enabled', () => {
config.setConfig({ coppa: true })
const bid = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION);
const r = JSON.parse(bid[0].data.r);

expect(r.regs.coppa).to.equal(1);
});
it('should not set coppa in config when disabled', () => {
config.setConfig({ coppa: false })
const bid = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION);
const r = JSON.parse(bid[0].data.r);

expect(r.regs.coppa).to.be.undefined;
});
it('should not set coppa when not specified in config', () => {
config.resetConfig();
const bid = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION);
const r = JSON.parse(bid[0].data.r);

expect(r.regs.coppa).to.be.undefined;
});
});
});

0 comments on commit cea4a58

Please sign in to comment.