Skip to content

Commit

Permalink
Connatix Bid Adapter : listen for user id's (#12312)
Browse files Browse the repository at this point in the history
* added event listener in cnx bid adapter

* deleted console logs and added cache variable

* deleted test file

* deleted test change

* renamed response data

* modified url in event listener

* updated response naming

* remove event listener when i get all providers

* formatting

* wrote data instead of response

* fixed receiving id values

* check if undefined before parsing

* PR comments

* changed naming to be the same as on BE side

* PR comments

* changed naming

* changed to camelcase

* checked for all events

* unit tests

* exported functions

* added one more test for buildRequests

---------

Co-authored-by: Octavia Suceava <[email protected]>
  • Loading branch information
OctaviaS20 and Octavia Suceava authored Oct 29, 2024
1 parent 9058a09 commit aaafef7
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 1 deletion.
52 changes: 51 additions & 1 deletion modules/connatixBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import { percentInView } from '../libraries/percentInView/percentInView.js';

import { config } from '../src/config.js';

import { getStorageManager } from '../src/storageManager.js';
import { ajax } from '../src/ajax.js';
import {
deepAccess,
Expand All @@ -31,6 +31,12 @@ const BIDDER_CODE = 'connatix';
const AD_URL = 'https://capi.connatix.com/rtb/hba';
const DEFAULT_MAX_TTL = '3600';
const DEFAULT_CURRENCY = 'USD';
const CNX_IDS_LOCAL_STORAGE_COOKIES_KEY = 'cnx_user_ids';
const CNX_IDS_EXPIRY = 24 * 30 * 60 * 60 * 1000; // 30 days
export const storage = getStorageManager({ bidderCode: BIDDER_CODE });
const ALL_PROVIDERS_RESOLVED_EVENT = 'cnx_all_identity_providers_resolved';
const IDENTITY_PROVIDER_RESOLVED_EVENT = 'cnx_identity_provider_resolved';
let cnxIdsValues;

const EVENTS_URL = 'https://capi.connatix.com/tr/am';

Expand Down Expand Up @@ -182,6 +188,25 @@ function _handleEids(payload, validBidRequests) {
}
}

export function saveOnAllStorages(name, value, expirationTimeMs) {
const date = new Date();
date.setTime(date.getTime() + expirationTimeMs);
const expires = `expires=${date.toUTCString()}`;
storage.setCookie(name, JSON.stringify(value), expires);
storage.setDataInLocalStorage(name, JSON.stringify(value));
cnxIdsValues = value;
}

export function readFromAllStorages(name) {
const fromCookie = storage.getCookie(name);
const fromLocalStorage = storage.getDataFromLocalStorage(name);

const parsedCookie = fromCookie ? JSON.parse(fromCookie) : undefined;
const parsedLocalStorage = fromLocalStorage ? JSON.parse(fromLocalStorage) : undefined;

return parsedCookie || parsedLocalStorage || undefined;
}

export const spec = {
code: BIDDER_CODE,
gvlid: 143,
Expand Down Expand Up @@ -225,13 +250,20 @@ export const spec = {
*/
buildRequests: (validBidRequests = [], bidderRequest = {}) => {
const bidRequests = _getBidRequests(validBidRequests);
let userIds;
try {
userIds = readFromAllStorages(CNX_IDS_LOCAL_STORAGE_COOKIES_KEY) || cnxIdsValues;
} catch (error) {
userIds = cnxIdsValues;
}

const requestPayload = {
ortb2: bidderRequest.ortb2,
gdprConsent: bidderRequest.gdprConsent,
uspConsent: bidderRequest.uspConsent,
gppConsent: bidderRequest.gppConsent,
refererInfo: bidderRequest.refererInfo,
identityProviderData: userIds,
bidRequests,
};

Expand Down Expand Up @@ -308,6 +340,24 @@ export const spec = {
params['us_privacy'] = encodeURIComponent(uspConsent);
}

window.addEventListener('message', function handler(event) {
if (!event.data || event.origin !== 'https://cds.connatix.com') {
return;
}

if (event.data.type === ALL_PROVIDERS_RESOLVED_EVENT) {
this.removeEventListener('message', handler);
event.stopImmediatePropagation();
}

if (event.data.type === ALL_PROVIDERS_RESOLVED_EVENT || event.data.type === IDENTITY_PROVIDER_RESOLVED_EVENT) {
const response = event.data;
if (response.data) {
saveOnAllStorages(CNX_IDS_LOCAL_STORAGE_COOKIES_KEY, response.data, CNX_IDS_EXPIRY);
}
}
}, true)

const syncUrl = serverResponses[0].body.UserSyncEndpoint;
const queryParams = Object.keys(params).length > 0 ? formatQS(params) : '';

Expand Down
114 changes: 114 additions & 0 deletions test/spec/modules/connatixBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {
_getMinSize as connatixGetMinSize,
_getViewability as connatixGetViewability,
_isViewabilityMeasurable as connatixIsViewabilityMeasurable,
saveOnAllStorages as connatixSaveOnAllStorages,
readFromAllStorages as connatixReadFromAllStorages,
storage,
spec
} from '../../../modules/connatixBidAdapter.js';
import adapterManager from '../../../src/adapterManager.js';
Expand Down Expand Up @@ -564,6 +567,7 @@ describe('connatixBidAdapter', function () {

describe('buildRequests', function () {
let serverRequest;
let setCookieStub, setDataInLocalStorageStub;
let bidderRequest = {
refererInfo: {
canonicalUrl: '',
Expand Down Expand Up @@ -592,10 +596,21 @@ describe('connatixBidAdapter', function () {
};

this.beforeEach(function () {
const mockIdentityProviderData = { mockKey: 'mockValue' };
const CNX_IDS_EXPIRY = 24 * 30 * 60 * 60 * 1000;
setCookieStub = sinon.stub(storage, 'setCookie');
setDataInLocalStorageStub = sinon.stub(storage, 'setDataInLocalStorage');
connatixSaveOnAllStorages('test_ids_cnx', mockIdentityProviderData, CNX_IDS_EXPIRY);

bid = mockBidRequest();
serverRequest = spec.buildRequests([bid], bidderRequest);
})

this.afterEach(function() {
setCookieStub.restore();
setDataInLocalStorageStub.restore();
});

it('Creates a ServerRequest object with method, URL and data', function () {
expect(serverRequest).to.exist;
expect(serverRequest.method).to.exist;
Expand All @@ -622,6 +637,7 @@ describe('connatixBidAdapter', function () {
expect(serverRequest.data.uspConsent).to.equal(bidderRequest.uspConsent);
expect(serverRequest.data.gppConsent).to.equal(bidderRequest.gppConsent);
expect(serverRequest.data.ortb2).to.equal(bidderRequest.ortb2);
expect(serverRequest.data.identityProviderData).to.deep.equal({ mockKey: 'mockValue' });
});
});

Expand Down Expand Up @@ -935,4 +951,102 @@ describe('connatixBidAdapter', function () {
expect(floor).to.equal(0);
});
});
describe('getUserSyncs with message event listener', function() {
const CNX_IDS_EXPIRY = 24 * 30 * 60 * 60 * 1000;
const CNX_IDS_LOCAL_STORAGE_COOKIES_KEY = 'cnx_user_ids';
const ALL_PROVIDERS_RESOLVED_EVENT = 'cnx_all_identity_providers_resolved';

const mockData = {
providerName: 'nonId',
data: {
supplementalEids: [{ provider: 2, group: 1, eidsList: ['123', '456'] }]
}
};

function messageHandler(event) {
if (!event.data || event.origin !== 'https://cds.connatix.com') {
return;
}

if (event.data.type === ALL_PROVIDERS_RESOLVED_EVENT) {
window.removeEventListener('message', messageHandler);
event.stopImmediatePropagation();
}

if (event.data.type === ALL_PROVIDERS_RESOLVED_EVENT || event.data.type === IDENTITY_PROVIDER_RESOLVED_EVENT) {
const response = event.data;
if (response.data) {
connatixSaveOnAllStorages(CNX_IDS_LOCAL_STORAGE_COOKIES_KEY, response.data, CNX_IDS_EXPIRY);
}
}
}

let sandbox;

beforeEach(() => {
sandbox = sinon.createSandbox();
sandbox.stub(storage, 'setCookie');
sandbox.stub(storage, 'setDataInLocalStorage');
sandbox.stub(window, 'removeEventListener');
sandbox.stub(storage, 'cookiesAreEnabled').returns(true);
sandbox.stub(storage, 'localStorageIsEnabled').returns(true);
sandbox.stub(storage, 'getCookie');
sandbox.stub(storage, 'getDataFromLocalStorage');
});

afterEach(() => {
sandbox.restore();
});

it('Should set a cookie and save to local storage when a valid message is received', () => {
const fakeEvent = {
data: { type: 'cnx_all_identity_providers_resolved', data: mockData },
origin: 'https://cds.connatix.com',
stopImmediatePropagation: sinon.spy()
};

messageHandler(fakeEvent);

expect(fakeEvent.stopImmediatePropagation.calledOnce).to.be.true;
expect(window.removeEventListener.calledWith('message', messageHandler)).to.be.true;
expect(storage.setCookie.calledWith(CNX_IDS_LOCAL_STORAGE_COOKIES_KEY, JSON.stringify(mockData), sinon.match.string)).to.be.true;
expect(storage.setDataInLocalStorage.calledWith(CNX_IDS_LOCAL_STORAGE_COOKIES_KEY, JSON.stringify(mockData))).to.be.true;

storage.getCookie.returns(JSON.stringify(mockData));
storage.getDataFromLocalStorage.returns(JSON.stringify(mockData));

const retrievedData = connatixReadFromAllStorages(CNX_IDS_LOCAL_STORAGE_COOKIES_KEY);
expect(retrievedData).to.deep.equal(mockData);
});

it('Should should not do anything when there is no data in the payload', () => {
const fakeEvent = {
data: null,
origin: 'https://cds.connatix.com',
stopImmediatePropagation: sinon.spy()
};

messageHandler(fakeEvent);

expect(fakeEvent.stopImmediatePropagation.notCalled).to.be.true;
expect(window.removeEventListener.notCalled).to.be.true;
expect(storage.setCookie.notCalled).to.be.true;
expect(storage.setDataInLocalStorage.notCalled).to.be.true;
});

it('Should should not do anything when the origin is invalid', () => {
const fakeEvent = {
data: { type: 'cnx_all_identity_providers_resolved', data: mockData },
origin: 'https://notConnatix.com',
stopImmediatePropagation: sinon.spy()
};

messageHandler(fakeEvent);

expect(fakeEvent.stopImmediatePropagation.notCalled).to.be.true;
expect(window.removeEventListener.notCalled).to.be.true;
expect(storage.setCookie.notCalled).to.be.true;
expect(storage.setDataInLocalStorage.notCalled).to.be.true;
});
});
});

0 comments on commit aaafef7

Please sign in to comment.