Skip to content

Commit

Permalink
Invibes Bid Adapter: write id to first party from bid adapter (#8202)
Browse files Browse the repository at this point in the history
* Invibes Bid Adapter: added support for LiD generation on Invibes servers

* Invibes Bid Adapter: replaced all cookies storing with local storage
removed cookie storing logic

* invibesBidAdapter: applied lint formatting  updated unit tests to reflect reading from localStorage

* Update invibesBidAdapter_spec.js

updated Invibes Bid Adapter unit tests to pass for when the default storage allowed will be changed.
  • Loading branch information
mihaisandu07 authored May 13, 2022
1 parent f41a6a7 commit 5534049
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 41 deletions.
89 changes: 55 additions & 34 deletions modules/invibesBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const CONSTANTS = {
SYNC_ENDPOINT: 'https://k.r66net.com/GetUserSync',
TIME_TO_LIVE: 300,
DEFAULT_CURRENCY: 'EUR',
PREBID_VERSION: 7,
PREBID_VERSION: 8,
METHOD: 'GET',
INVIBES_VENDOR_ID: 436,
USERID_PROVIDERS: ['pubcid', 'pubProvidedId', 'uid2', 'zeotapIdPlus', 'id5id'],
Expand Down Expand Up @@ -95,8 +95,6 @@ function buildRequest(bidRequests, bidderRequest) {
invibes.optIn = invibes.optIn || readGdprConsent(bidderRequest.gdprConsent);

invibes.visitId = invibes.visitId || generateRandomId();
invibes.noCookies = invibes.noCookies || invibes.getCookie('ivNoCookie');
let lid = initDomainId(invibes.domainOptions);

const currentQueryStringParams = parseQueryStringParams();
let userIdModel = getUserIds(_userId);
Expand All @@ -113,7 +111,7 @@ function buildRequest(bidRequests, bidderRequest) {
location: getDocumentLocation(topWin),
videoAdHtmlId: generateRandomId(),
showFallback: currentQueryStringParams['advs'] === '0',
ivbsCampIdsLocal: invibes.getCookie('IvbsCampIdsLocal'),
ivbsCampIdsLocal: readFromLocalStorage('IvbsCampIdsLocal'),

bidParamsJson: JSON.stringify(bidParamsJson),
capCounts: getCappedCampaignsAsString(),
Expand All @@ -129,9 +127,21 @@ function buildRequest(bidRequests, bidderRequest) {
purposes: invibes.purposes.toString(),
li: invibes.legitimateInterests.toString(),

tc: invibes.gdpr_consent
tc: invibes.gdpr_consent,
isLocalStorageEnabled: storage.hasLocalStorage(),
};

let lid = readFromLocalStorage('ivbsdid');
if (!lid) {
let str = invibes.getCookie('ivbsdid');
if (str) {
try {
let cookieLid = JSON.parse(str);
lid = cookieLid.id ? cookieLid.id : cookieLid;
} catch (e) {
}
}
}
if (lid) {
data.lId = lid;
}
Expand Down Expand Up @@ -172,6 +182,15 @@ function handleResponse(responseObj, bidRequests) {
responseObj = responseObj.body || responseObj;
responseObj = responseObj.videoAdContentResult || responseObj;

if (responseObj.ShouldSetLId && responseObj.LId) {
if ((!invibes.optIn || !invibes.purposes[0]) && responseObj.PrivacyPolicyRule && responseObj.TcModel && responseObj.TcModel.PurposeConsents) {
invibes.optIn = responseObj.PrivacyPolicyRule;
invibes.purposes = responseObj.TcModel.PurposeConsents;
}

setInLocalStorage('ivbsdid', responseObj.LId);
}

if (typeof invibes.bidResponse === 'object') {
if (responseObj.MultipositionEnabled === true) {
invibes.bidResponse.AdPlacements = invibes.bidResponse.AdPlacements.concat(responseObj.AdPlacements);
Expand Down Expand Up @@ -411,6 +430,22 @@ function renderCreative(bidModel) {
.replace('creativeHtml', bidModel.CreativeHtml);
}

function readFromLocalStorage(key) {
if (invibes.GdprModuleInstalled && (!invibes.optIn || !invibes.purposes[0])) {
return;
}

return storage.getDataFromLocalStorage(key) || '';
}

function setInLocalStorage(key, value) {
if (!invibes.optIn || !invibes.purposes[0]) {
return;
}

storage.setDataInLocalStorage(key, value);
}

function getCappedCampaignsAsString() {
const key = 'ivvcap';

Expand Down Expand Up @@ -471,21 +506,28 @@ function buildSyncUrl() {
syncUrl += '?visitId=' + invibes.visitId;
syncUrl += '&optIn=' + invibes.optIn;

const did = invibes.getCookie('ivbsdid');
if (did) {
syncUrl += '&ivbsdid=' + encodeURIComponent(did);
let did = readFromLocalStorage('ivbsdid');
if (!did) {
let str = invibes.getCookie('ivbsdid');
if (str) {
try {
let cookieLid = JSON.parse(str);
did = cookieLid.id ? cookieLid.id : cookieLid;
} catch (e) {
}
}
}

const bks = invibes.getCookie('ivvbks');
if (bks) {
syncUrl += '&ivvbks=' + encodeURIComponent(bks);
if (did) {
syncUrl += '&ivbsdid=' + encodeURIComponent(did);
}

return syncUrl;
}

function readGdprConsent(gdprConsent) {
if (gdprConsent && gdprConsent.vendorData) {
invibes.GdprModuleInstalled = true;
invibes.gdpr_consent = getVendorConsentData(gdprConsent.vendorData);

if (!gdprConsent.vendorData.gdprApplies || gdprConsent.vendorData.hasGlobalConsent) {
Expand Down Expand Up @@ -528,6 +570,7 @@ function readGdprConsent(gdprConsent) {
return 2;
}

invibes.GdprModuleInstalled = false;
return 0;
}

Expand Down Expand Up @@ -637,34 +680,13 @@ invibes.getCookie = function (name) {
return;
}

if (!invibes.optIn || !invibes.purposes[0]) {
if (invibes.GdprModuleInstalled && (!invibes.optIn || !invibes.purposes[0])) {
return;
}

return storage.getCookie(name);
};

let initDomainId = function (options) {
let cookiePersistence = {
cname: 'ivbsdid',
load: function () {
let str = invibes.getCookie(this.cname) || '';
try {
return JSON.parse(str);
} catch (e) {
}
}
};

options = options || {};

var persistence = options.persistence || cookiePersistence;

let state = persistence.load();

return state ? (state.id || state.tempId) : undefined;
};

let keywords = (function () {
const cap = 300;
let headTag = document.getElementsByTagName('head')[0];
Expand Down Expand Up @@ -738,7 +760,6 @@ let keywords = (function () {

export function resetInvibes() {
invibes.optIn = undefined;
invibes.noCookies = undefined;
invibes.dom = undefined;
invibes.bidResponse = undefined;
invibes.domainOptions = undefined;
Expand Down
105 changes: 98 additions & 7 deletions test/spec/modules/invibesBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {expect} from 'chai';
import { config } from 'src/config.js';
import {spec, resetInvibes, stubDomainOptions, readGdprConsent} from 'modules/invibesBidAdapter.js';

describe('invibesBidAdapter:', function () {
Expand Down Expand Up @@ -93,13 +94,25 @@ describe('invibesBidAdapter:', function () {
}
};

let SetBidderAccess = function() {
config.setConfig({
deviceAccess: true
});
$$PREBID_GLOBAL$$.bidderSettings = {
invibes: {
storageAllowed: true
}
};
}

beforeEach(function () {
resetInvibes();
document.cookie = '';
this.cStub1 = sinon.stub(console, 'info');
});

afterEach(function () {
$$PREBID_GLOBAL$$.bidderSettings = {};
this.cStub1.restore();
});

Expand Down Expand Up @@ -296,13 +309,40 @@ describe('invibesBidAdapter:', function () {
top.window.invibes.optIn = 1;
top.window.invibes.purposes = [true, false, false, false, false, false, false, false, false, false];
localStorage.ivvcap = '{"9731":[1,1768600800000]}';
SetBidderAccess();

const request = spec.buildRequests(bidRequests, {auctionStart: Date.now()});

expect(request.data.capCounts).to.equal('9731=1');
});

it('does not have capped ids if local storage variable is correctly formatted but no opt in', function () {
let bidderRequest = {
auctionStart: Date.now(),
gdprConsent: {
vendorData: {
gdprApplies: true,
hasGlobalConsent: false,
purpose: {
consents: {
1: false,
2: false,
3: false,
4: false,
5: false,
6: false,
7: false,
8: false,
9: false,
10: false
}
}
}
}
};

localStorage.ivvcap = '{"9731":[1,1768600800000]}';
const request = spec.buildRequests(bidRequests, {auctionStart: Date.now()});
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.data.capCounts).to.equal('');
});

Expand Down Expand Up @@ -369,6 +409,8 @@ describe('invibesBidAdapter:', function () {
top.window.invibes.purposes = [true, false, false, false, false, false, false, false, false, false];
global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":' + Date.now() + ',"hc":0}';
let bidderRequest = {gdprConsent: {vendorData: {vendorConsents: {436: true}}}};
SetBidderAccess();

let request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.data.lId).to.exist;
});
Expand Down Expand Up @@ -496,7 +538,7 @@ describe('invibesBidAdapter:', function () {
let request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.data.li.split(',')[1] && request.data.li.split(',')[6]).to.equal('true');
});
it('should send oi = 0 when vendorData is null', function () {
it('should send oi = 1 when vendorData is null (calculation will be performed by ADWEB)', function () {
let bidderRequest = {
gdprConsent: {
vendorData: null
Expand Down Expand Up @@ -962,7 +1004,29 @@ describe('invibesBidAdapter:', function () {
UseAdUnitCode: true
};

var buildResponse = function(placementId, cid, blcids, creativeId) {
var buildResponse = function(placementId, cid, blcids, creativeId, ShouldSetLId) {
if (ShouldSetLId) {
return {
MultipositionEnabled: true,
AdPlacements: [{
Ads: [{
BidPrice: 0.5,
VideoExposedId: creativeId,
Cid: cid,
Blcids: blcids
}],
BidModel: {
BidVersion: 1,
PlacementId: placementId,
AuctionStartTime: Date.now(),
CreativeHtml: '<!-- Creative -->'
}
}],
ShouldSetLId: true,
LId: 'dvdjkams6nkq'
}
}

return {
MultipositionEnabled: true,
AdPlacements: [{
Expand Down Expand Up @@ -1066,6 +1130,22 @@ describe('invibesBidAdapter:', function () {
});
});

context('AdWeb generates LIDs', function() {
it('works when no LID is not sent from AdWeb', function() {
var firstResponse = buildResponse('12345', 1, [], 123);

var firstResult = spec.interpretResponse({body: firstResponse}, {bidRequests});
expect(firstResult[0].creativeId).to.equal(123);
});

it('sets lid when AdWeb sends it', function() {
var firstResponse = buildResponse('12345', 1, [], 123, true);

spec.interpretResponse({body: firstResponse}, {bidRequests});
expect(global.document.cookie.indexOf('ivbsdid')).to.greaterThanOrEqual(0);
});
});

context('in multiposition context, with conflicting ads', function() {
it('registers the second ad when no conflict', function() {
var firstResponse = buildResponse('12345', 1, [1], 123);
Expand Down Expand Up @@ -1123,22 +1203,33 @@ describe('invibesBidAdapter:', function () {

it('returns an iframe with params if enabled', function () {
top.window.invibes.optIn = 1;
global.document.cookie = 'ivvbks=17639.0,1,2';
let response = spec.getUserSyncs({iframeEnabled: true});
expect(response.type).to.equal('iframe');
expect(response.url).to.include(SYNC_ENDPOINT);
expect(response.url).to.include('optIn');
expect(response.url).to.include('ivvbks');
});

it('returns an iframe with params including if enabled', function () {
top.window.invibes.optIn = 1;
global.document.cookie = 'ivvbks=17639.0,1,2;ivbsdid={"id":"dvdjkams6nkq","cr":' + Date.now() + ',"hc":0}';
global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":' + Date.now() + ',"hc":0}';
SetBidderAccess();

let response = spec.getUserSyncs({iframeEnabled: true});
expect(response.type).to.equal('iframe');
expect(response.url).to.include(SYNC_ENDPOINT);
expect(response.url).to.include('optIn');
expect(response.url).to.include('ivbsdid');
});

it('returns an iframe with params including if enabled read from LocalStorage', function () {
top.window.invibes.optIn = 1;
localStorage.ivbsdid = 'dvdjkams6nkq';
SetBidderAccess();

let response = spec.getUserSyncs({iframeEnabled: true});
expect(response.type).to.equal('iframe');
expect(response.url).to.include(SYNC_ENDPOINT);
expect(response.url).to.include('optIn');
expect(response.url).to.include('ivvbks');
expect(response.url).to.include('ivbsdid');
});

Expand Down

0 comments on commit 5534049

Please sign in to comment.