Skip to content

Commit

Permalink
Add GDPR and UID module support to Undertone adapter (#4102)
Browse files Browse the repository at this point in the history
* Added user sync support for undertone bid adapter (new pull request)

* Added user sync support for undertone bid adapter

* undertone adapter - send gdpr data in bid request in user sync request

* undertone adapter
- send gdpr data in bid request in user sync request
- send external uids in the bid request

* undertone adapter
- send gdpr data in bid request in user sync request
- send external uids and prebid version in the bid request

* Update undertoneBidAdapter_spec.js

* Update undertoneBidAdapter.js
  • Loading branch information
omerko authored and Mike Chowla committed Aug 27, 2019
1 parent d5ee713 commit 11801ba
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 29 deletions.
40 changes: 32 additions & 8 deletions modules/undertoneBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ function extractDomainFromHost(pageHost) {
return domain;
}

function getGdprQueryParams(gdprConsent) {
if (!gdprConsent) {
return null;
}

let gdpr = gdprConsent.gdprApplies ? '1' : '0';
let gdprstr = gdprConsent.consentString ? gdprConsent.consentString : '';
return `gdpr=${gdpr}&gdprstr=${gdprstr}`;
}

export const spec = {
code: BIDDER_CODE,
isBidRequestValid: function(bid) {
Expand All @@ -51,15 +61,24 @@ export const spec = {
},
buildRequests: function(validBidRequests, bidderRequest) {
const payload = {
'x-ut-hb-params': []
'x-ut-hb-params': [],
'commons': {
'adapterVersion': '$prebid.version$',
'uids': validBidRequests[0].userId
}
};
const referer = bidderRequest.refererInfo.referer;
const hostname = urlUtils.parse(referer).hostname;
let domain = extractDomainFromHost(hostname);
const pageUrl = getCanonicalUrl() || referer;

const pubid = validBidRequests[0].params.publisherId;
const REQ_URL = `${URL}?pid=${pubid}&domain=${domain}`;
let reqUrl = `${URL}?pid=${pubid}&domain=${domain}`;

let gdprParams = getGdprQueryParams(bidderRequest.gdprConsent);
if (gdprParams) {
reqUrl += `&${gdprParams}`;
}

validBidRequests.map(bidReq => {
const bid = {
Expand All @@ -76,7 +95,7 @@ export const spec = {
});
return {
method: 'POST',
url: REQ_URL,
url: reqUrl,
withCredentials: true,
data: JSON.stringify(payload)
};
Expand Down Expand Up @@ -107,23 +126,28 @@ export const spec = {
},
getUserSyncs: function(syncOptions, serverResponses, gdprConsent) {
const syncs = [];
if (gdprConsent && gdprConsent.gdprApplies === true) {
return syncs;

let gdprParams = getGdprQueryParams(gdprConsent);
let iframeGdprParams = '';
let pixelGdprParams = '';
if (gdprParams) {
iframeGdprParams += `?${gdprParams}`;
pixelGdprParams += `&${gdprParams}`;
}

if (syncOptions.iframeEnabled) {
syncs.push({
type: 'iframe',
url: FRAME_USER_SYNC
url: FRAME_USER_SYNC + iframeGdprParams
});
} else if (syncOptions.pixelEnabled) {
syncs.push({
type: 'image',
url: PIXEL_USER_SYNC_1
url: PIXEL_USER_SYNC_1 + pixelGdprParams
},
{
type: 'image',
url: PIXEL_USER_SYNC_2
url: PIXEL_USER_SYNC_2 + pixelGdprParams
});
}
return syncs;
Expand Down
139 changes: 118 additions & 21 deletions test/spec/modules/undertoneBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const validBidReq = {
},
sizes: [[300, 250], [300, 600]],
bidId: '263be71e91dd9d',
auctionId: '9ad1fa8d-2297-4660-a018-b39945054746',
auctionId: '9ad1fa8d-2297-4660-a018-b39945054747',
};

const invalidBidReq = {
Expand Down Expand Up @@ -44,12 +44,46 @@ const bidReq = [{
auctionId: '6c22f5a5-59df-4dc6-b92c-f433bcf0a874'
}];

const bidReqUserIds = [{
bidder: BIDDER_CODE,
params: {
placementId: '10433394',
publisherId: 12345
},
sizes: [[300, 250], [300, 600]],
bidId: '263be71e91dd9d',
auctionId: '9ad1fa8d-2297-4660-a018-b39945054746',
userId: {
tdid: '123456',
digitrustid: {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}}
}
},
{
bidder: BIDDER_CODE,
params: {
publisherId: 12345
},
sizes: [[1, 1]],
bidId: '453cf42d72bb3c',
auctionId: '6c22f5a5-59df-4dc6-b92c-f433bcf0a874'
}];

const bidderReq = {
refererInfo: {
referer: 'http://prebid.org/dev-docs/bidder-adaptor.html'
}
};

const bidderReqGdpr = {
refererInfo: {
referer: 'http://prebid.org/dev-docs/bidder-adaptor.html'
},
gdprConsent: {
gdprApplies: true,
consentString: 'acdefgh'
}
};

const validBidRes = {
ad: '<div>Hello</div>',
publisherId: 12345,
Expand Down Expand Up @@ -103,7 +137,7 @@ describe('Undertone Adapter', function () {
});
});
describe('build request', function () {
it('should send request to correct url via POST', function () {
it('should send request to correct url via POST not in GDPR', function () {
const request = spec.buildRequests(bidReq, bidderReq);
const domainStart = bidderReq.refererInfo.referer.indexOf('//');
const domainEnd = bidderReq.refererInfo.referer.indexOf('/', domainStart + 2);
Expand All @@ -112,6 +146,16 @@ describe('Undertone Adapter', function () {
expect(request.url).to.equal(REQ_URL);
expect(request.method).to.equal('POST');
});
it('should send request to correct url via POST when in GDPR', function () {
const request = spec.buildRequests(bidReq, bidderReqGdpr);
const domainStart = bidderReq.refererInfo.referer.indexOf('//');
const domainEnd = bidderReq.refererInfo.referer.indexOf('/', domainStart + 2);
const domain = bidderReq.refererInfo.referer.substring(domainStart + 2, domainEnd);
let gdpr = bidderReqGdpr.gdprConsent.gdprApplies ? 1 : 0
const REQ_URL = `${URL}?pid=${bidReq[0].params.publisherId}&domain=${domain}&gdpr=${gdpr}&gdprstr=${bidderReqGdpr.gdprConsent.consentString}`;
expect(request.url).to.equal(REQ_URL);
expect(request.method).to.equal('POST');
});
it('should have all relevant fields', function () {
const request = spec.buildRequests(bidReq, bidderReq);
const bid1 = JSON.parse(request.data)['x-ut-hb-params'][0];
Expand All @@ -127,6 +171,14 @@ describe('Undertone Adapter', function () {
expect(bid2.publisherId).to.equal(12345);
expect(bid2.params).to.be.an('object');
});
it('should send all userIds data to server', function () {
const request = spec.buildRequests(bidReqUserIds, bidderReq);
const bidCommons = JSON.parse(request.data)['commons'];
expect(bidCommons).to.be.an('object');
expect(bidCommons.uids).to.be.an('object');
expect(bidCommons.uids.tdid).to.equal('123456');
expect(bidCommons.uids.digitrustid.data.id).to.equal('DTID');
});
});

describe('interpretResponse', function () {
Expand Down Expand Up @@ -160,25 +212,70 @@ describe('Undertone Adapter', function () {
});

describe('getUserSyncs', () => {
it('verifies gdpr consent checked', () => {
const options = ({ iframeEnabled: true, pixelEnabled: true });
expect(spec.getUserSyncs(options, {}, { gdprApplies: true }).length).to.equal(0);
});

it('Verifies sync iframe option', function () {
const result = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true });
expect(result).to.have.lengthOf(1);
expect(result[0].type).to.equal('iframe');
expect(result[0].url).to.equal('//cdn.undertone.com/js/usersync.html');
});
let testParams = [
{
name: 'with iframe and no gdpr data',
arguments: [{ iframeEnabled: true, pixelEnabled: true }, {}, null],
expect: {
type: 'iframe',
pixels: ['//cdn.undertone.com/js/usersync.html']
}
},
{
name: 'with iframe and gdpr on',
arguments: [{ iframeEnabled: true, pixelEnabled: true }, {}, {gdprApplies: true, consentString: '234234'}],
expect: {
type: 'iframe',
pixels: ['//cdn.undertone.com/js/usersync.html?gdpr=1&gdprstr=234234']
}
},
{
name: 'with iframe and no gdpr off',
arguments: [{ iframeEnabled: true, pixelEnabled: true }, {}, {gdprApplies: false}],
expect: {
type: 'iframe',
pixels: ['//cdn.undertone.com/js/usersync.html?gdpr=0&gdprstr=']
}
},
{
name: 'with pixels and no gdpr data',
arguments: [{ pixelEnabled: true }, {}, null],
expect: {
type: 'image',
pixels: ['//usr.undertone.com/userPixel/syncOne?id=1&of=2',
'//usr.undertone.com/userPixel/syncOne?id=2&of=2']
}
},
{
name: 'with pixels and gdpr on',
arguments: [{ pixelEnabled: true }, {}, {gdprApplies: true, consentString: '234234'}],
expect: {
type: 'image',
pixels: ['//usr.undertone.com/userPixel/syncOne?id=1&of=2&gdpr=1&gdprstr=234234',
'//usr.undertone.com/userPixel/syncOne?id=2&of=2&gdpr=1&gdprstr=234234']
}
},
{
name: 'with pixels and gdpr off',
arguments: [{ pixelEnabled: true }, {}, {gdprApplies: false}],
expect: {
type: 'image',
pixels: ['//usr.undertone.com/userPixel/syncOne?id=1&of=2&gdpr=0&gdprstr=',
'//usr.undertone.com/userPixel/syncOne?id=2&of=2&gdpr=0&gdprstr=']
}
}
];

it('Verifies sync image option', function () {
const result = spec.getUserSyncs({ pixelEnabled: true });
expect(result).to.have.lengthOf(2);
expect(result[0].type).to.equal('image');
expect(result[0].url).to.equal('//usr.undertone.com/userPixel/syncOne?id=1&of=2');
expect(result[1].type).to.equal('image');
expect(result[1].url).to.equal('//usr.undertone.com/userPixel/syncOne?id=2&of=2');
});
for (let i = 0; i < testParams.length; i++) {
let currParams = testParams[i];
it(currParams.name, function () {
const result = spec.getUserSyncs.apply(this, currParams.arguments);
expect(result).to.have.lengthOf(currParams.expect.pixels.length);
for (let ix = 0; ix < currParams.expect.pixels.length; ix++) {
expect(result[ix].url).to.equal(currParams.expect.pixels[ix]);
expect(result[ix].type).to.equal(currParams.expect.type);
}
});
}
});
});

0 comments on commit 11801ba

Please sign in to comment.