Skip to content

Commit

Permalink
InvibesBidAdapter - gdpr support (#3151)
Browse files Browse the repository at this point in the history
  • Loading branch information
rcheptanariu authored and idettman committed Oct 8, 2018
1 parent 3ba867a commit 3fec73f
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 40 deletions.
60 changes: 38 additions & 22 deletions modules/invibesBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const CONSTANTS = {
TIME_TO_LIVE: 300,
DEFAULT_CURRENCY: 'EUR',
PREBID_VERSION: 1,
METHOD: 'GET'
METHOD: 'GET',
INVIBES_VENDOR_ID: 436
};

export const spec = {
Expand All @@ -23,9 +24,7 @@ export const spec = {
* @param bidderRequest
* @return ServerRequest[]
*/
buildRequests: function (bidRequests, bidderRequest) {
return buildRequest(bidRequests, bidderRequest != null ? bidderRequest.auctionStart : null);
},
buildRequests: buildRequest,
/**
* @param {*} responseObj
* @param {requestParams} bidRequests
Expand Down Expand Up @@ -55,6 +54,11 @@ let invibes = topWin.invibes = topWin.invibes || {};
let _customUserSync;

function isBidRequestValid(bid) {
if (invibes && typeof invibes.bidResponse === 'object') {
utils.logInfo('Invibes Adapter - Bid response already received. Invibes only responds to one bid request per user visit');
return false;
}

if (typeof bid.params !== 'object') {
return false;
}
Expand All @@ -67,11 +71,11 @@ function isBidRequestValid(bid) {
return true;
}

function buildRequest(bidRequests, auctionStart) {
// invibes only responds to 1 bid request for each user visit
function buildRequest(bidRequests, bidderRequest) {
bidderRequest = bidderRequest || {};
const _placementIds = [];
let _loginId, _customEndpoint;
let _ivAuctionStart = auctionStart || Date.now();
let _ivAuctionStart = bidderRequest.auctionStart || Date.now();

bidRequests.forEach(function (bidRequest) {
bidRequest.startTime = new Date().getTime();
Expand All @@ -85,9 +89,9 @@ function buildRequest(bidRequests, auctionStart) {

cookieDomain = detectTopmostCookieDomain();
invibes.noCookies = invibes.noCookies || invibes.getCookie('ivNoCookie');
invibes.optIn = invibes.optIn || invibes.getCookie('ivOptIn');
invibes.optIn = invibes.optIn || invibes.getCookie('ivOptIn') || readGdprConsent(bidderRequest.gdprConsent);

initDomainId();
initDomainId(invibes.domainOptions);

const currentQueryStringParams = parseQueryStringParams();

Expand All @@ -96,7 +100,6 @@ function buildRequest(bidRequests, auctionStart) {
videoAdHtmlId: generateRandomId(),
showFallback: currentQueryStringParams['advs'] === '0',
ivbsCampIdsLocal: invibes.getCookie('IvbsCampIdsLocal'),
lId: invibes.dom.id,

bidParamsJson: JSON.stringify({
placementIds: _placementIds,
Expand All @@ -110,11 +113,12 @@ function buildRequest(bidRequests, auctionStart) {
width: topWin.innerWidth,
height: topWin.innerHeight,

noc: !cookieDomain
noc: !cookieDomain,
oi: invibes.optIn
};

if (invibes.optIn) {
data.oi = 1;
if (invibes.dom.id) {
data.lId = invibes.dom.id;
}

const parametersToPassForward = 'videoaddebug,advs,bvci,bvid,istop,trybvid,trybvci'.split(',');
Expand Down Expand Up @@ -323,10 +327,7 @@ function initLogger() {
function buildSyncUrl() {
let syncUrl = _customUserSync || CONSTANTS.SYNC_ENDPOINT;
syncUrl += '?visitId=' + invibes.visitId;

if (invibes.optIn) {
syncUrl += '&optIn=1';
}
syncUrl += '&optIn=' + invibes.optIn;

const did = invibes.getCookie('ivbsdid');
if (did) {
Expand Down Expand Up @@ -358,6 +359,14 @@ function acceptPostMessage(e) {
}
}

function readGdprConsent(gdprConsent) {
if (gdprConsent && gdprConsent.vendorData && gdprConsent.vendorData.vendorConsents) {
return !!gdprConsent.vendorData.vendorConsents[CONSTANTS.INVIBES_VENDOR_ID.toString(10)] === true ? 2 : -2;
}

return 0;
}

const ivLogger = initLogger();

/// Local domain cookie management =====================
Expand Down Expand Up @@ -400,9 +409,9 @@ invibes.setCookie = function (name, value, exdays, domain) {

let detectTopmostCookieDomain = function () {
let testCookie = invibes.Uid.generate();
let hostParts = location.host.split('.');
let hostParts = location.hostname.split('.');
if (hostParts.length === 1) {
return location.host;
return location.hostname;
}
for (let i = hostParts.length - 1; i >= 0; i--) {
let domain = '.' + hostParts.slice(i).join('.');
Expand Down Expand Up @@ -463,8 +472,8 @@ let initDomainId = function (options) {

let setId = function () {
invibes.dom = {
id: !state.cr && invibes.optIn ? state.id : undefined,
tempId: invibes.optIn ? state.id : undefined,
id: (!state.cr && invibes.optIn > 0) ? state.id : undefined,
tempId: (invibes.optIn > 0) ? state.id : undefined,
graduate: graduate
};
};
Expand All @@ -481,7 +490,7 @@ let initDomainId = function (options) {
if (state.hc < minHC) {
state.hc++;
}
if (state.hc >= minHC && validGradTime(state)) {
if ((state.hc >= minHC && validGradTime(state)) || options.skipGraduation) {
graduate();
}
}
Expand All @@ -496,4 +505,11 @@ export function resetInvibes() {
invibes.noCookies = undefined;
invibes.dom = undefined;
invibes.bidResponse = undefined;
invibes.domainOptions = undefined;
}

export function stubDomainOptions(persistence) {
invibes.domainOptions = {
persistence: persistence
};
}
77 changes: 59 additions & 18 deletions test/spec/modules/invibesBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect } from 'chai';
import { spec, resetInvibes } from 'modules/invibesBidAdapter';
import { spec, resetInvibes, stubDomainOptions } from 'modules/invibesBidAdapter';

describe('invibesBidAdapter:', function () {
const BIDDER_CODE = 'invibes';
Expand Down Expand Up @@ -40,6 +40,21 @@ describe('invibesBidAdapter:', function () {
}
];

let StubbedPersistence = function(initialValue) {
var value = initialValue;
return {
load: function () {
let str = value || '';
try {
return JSON.parse(str);
} catch (e) { }
},
save: function (obj) {
value = JSON.stringify(obj);
}
}
};

beforeEach(function () {
resetInvibes();
document.cookie = '';
Expand Down Expand Up @@ -83,6 +98,18 @@ describe('invibesBidAdapter:', function () {

expect(spec.isBidRequestValid(invalidBid)).to.be.false;
});

it('returns false when bid response was previously received', function() {
const validBid = {
bidder: BIDDER_CODE,
params: {
placementId: PLACEMENT_ID
}
}

top.window.invibes.bidResponse = { prop: 'prop' };
expect(spec.isBidRequestValid(validBid)).to.be.false;
});
});
});

Expand Down Expand Up @@ -126,38 +153,52 @@ describe('invibesBidAdapter:', function () {
expect(request.data.lId).to.not.exist;
});

it('try to graduate but not enough count - doesnt send the domain id', function () {
global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":1521818537626,"hc":5}';
let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } };
let request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.data.lId).to.not.exist;
});

it('try to graduate but not old enough - doesnt send the domain id', function () {
let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } };
global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":' + Date.now() + ',"hc":5}';
let request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.data.lId).to.not.exist;
});

it('graduate and send the domain id', function () {
top.window.invibes.optIn = 1;
global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":1521818537626,"hc":7}';
let request = spec.buildRequests(bidRequests);
let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } };
stubDomainOptions(new StubbedPersistence('{"id":"dvdjkams6nkq","cr":1521818537626,"hc":7}'));
let request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.data.lId).to.exist;
});

it('send the domain id if already graduated', function () {
top.window.invibes.optIn = 1;
global.document.cookie = 'ivbsdid={"id":"f8zoh044p9oi"}';
let request = spec.buildRequests(bidRequests);
let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } };
stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi"}'));
let request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.data.lId).to.exist;
});

it('send the domain id after replacing it with new format', function () {
top.window.invibes.optIn = 1;
global.document.cookie = 'ivbsdid={"id":"f8zoh044p9oi.8537626"}';
let request = spec.buildRequests(bidRequests);
let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } };
stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi.8537626"}'));
let request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.data.lId).to.exist;
});

it('try to graduate but not enough count - doesnt send the domain id', function () {
top.window.invibes.optIn = 1;
global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":1521818537626,"hc":5}';
let request = spec.buildRequests(bidRequests);
it('dont send the domain id if consent declined', function () {
let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: false } } } };
stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi.8537626"}'));
let request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.data.lId).to.not.exist;
});

it('try to graduate but not old enough - doesnt send the domain id', function () {
top.window.invibes.optIn = 1;
global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":' + Date.now() + ',"hc":5}';
let request = spec.buildRequests(bidRequests);
it('dont send the domain id if no consent', function () {
let bidderRequest = { };
stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi.8537626"}'));
let request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.data.lId).to.not.exist;
});
});
Expand Down

0 comments on commit 3fec73f

Please sign in to comment.