Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CM-587][Do not merge] Allow resolving uid2 and custom attributes #5

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 39 additions & 5 deletions modules/liveIntentIdSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { MinimalLiveConnect } from 'live-connect-js/esm/minimal-live-connect.js'

const MODULE_NAME = 'liveIntentId';
export const storage = getStorageManager({gvlid: null, moduleName: MODULE_NAME});
const defaultRequestedAttributes = {'nonId': true}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The requirements from https://docs.google.com/document/d/16rEBF_RkkA_0-C142sKC6gbLm3ucCtGSZyXQ1NQGEL0/edit and https://liveintent.atlassian.net/browse/NAVY-484 seems to be contradictory as of what should be the default for uid2. Let's take it to our sync with @deepthivenkat.

const calls = {
ajaxGet: (url, onSuccess, onError, timeout) => {
ajaxBuilder(timeout)(
Expand Down Expand Up @@ -57,6 +58,23 @@ function parseLiveIntentCollectorConfig(collectConfig) {
return config;
}

/**
* Create requestedAttributes array to pass to liveconnect
* @function
* @param {Object} overrides - object with boolean values that will override defaults { 'foo': true, 'bar': false }
* @returns {Array}
*/
function parseRequestedAttributes(overrides) {
function createParameterArray(config) {
return Object.entries(config).flatMap(([k, v]) => (typeof v === 'boolean' && v) ? [k] : []);
}
if (typeof overrides === 'object') {
return createParameterArray({...defaultRequestedAttributes, ...overrides})
} else {
return createParameterArray(defaultRequestedAttributes);
}
}

function initializeLiveConnect(configParams) {
configParams = configParams || {};
if (liveConnect) {
Expand All @@ -66,7 +84,8 @@ function initializeLiveConnect(configParams) {
const publisherId = configParams.publisherId || 'any';
const identityResolutionConfig = {
source: 'prebid',
publisherId: publisherId
publisherId: publisherId,
requestedAttributes: parseRequestedAttributes(configParams.requestedAttributesOverrides)
};
if (configParams.url) {
identityResolutionConfig.url = configParams.url
Expand Down Expand Up @@ -136,17 +155,32 @@ export const liveIntentIdSubmodule = {
decode(value, config) {
const configParams = (config && config.params) || {};
function composeIdObject(value) {
const base = { 'lipbid': value.unifiedId };
delete value.unifiedId;
return { 'lipb': { ...base, ...value } };
const result = {};

// old versions stored lipbid in unifiedId. Ensure that we can still read the data.
const lipbid = value.nonId || value.unifiedId
if (lipbid) {
value.lipbid = lipbid
delete value.unifiedId
result.lipb = value
}

// Lift usage of uid2 by exposing uid2 if we were asked to resolve it.
// As adapters are applied in lexicographical order, we will always
// be overwritten by the 'proper' uid2 module if it is present.
if (value.uid2) {
result.uid2 = { 'id': value.uid2 }
}

return result
}

if (!liveConnect) {
initializeLiveConnect(configParams);
}
tryFireEvent();

return (value && typeof value['unifiedId'] === 'string') ? composeIdObject(value) : undefined;
return composeIdObject(value);
},

/**
Expand Down
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
"express": "^4.15.4",
"fun-hooks": "^0.9.9",
"just-clone": "^1.0.2",
"live-connect-js": "2.3.3"
"live-connect-js": "2.4.0-alpha.1"
},
"optionalDependencies": {
"fsevents": "^2.3.2"
Expand Down
70 changes: 62 additions & 8 deletions test/spec/modules/liveIntentIdMinimalSystem_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('LiveIntentMinimalId', function() {

it('should not return a decoded identifier when the unifiedId is not present in the value', function() {
const result = liveIntentIdSubmodule.decode({ additionalData: 'data' });
expect(result).to.be.undefined;
expect(result).to.be.eql({});
});

it('should initialize LiveConnect and send no data', function() {
Expand All @@ -64,7 +64,7 @@ describe('LiveIntentMinimalId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId({ params: {...defaultConfigParams.params, ...{'url': 'https://dummy.liveintent.com/idex'}} }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/prebid/89899');
expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/prebid/89899?resolve=nonId');
request.respond(
200,
responseHeader,
Expand All @@ -85,7 +85,7 @@ describe('LiveIntentMinimalId', function() {
} }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/rubicon/89899');
expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/rubicon/89899?resolve=nonId');
request.respond(
200,
responseHeader,
Expand All @@ -100,7 +100,7 @@ describe('LiveIntentMinimalId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899');
expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?resolve=nonId');
request.respond(
200,
responseHeader,
Expand All @@ -115,7 +115,7 @@ describe('LiveIntentMinimalId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899');
expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?resolve=nonId');
request.respond(
503,
responseHeader,
Expand All @@ -132,7 +132,7 @@ describe('LiveIntentMinimalId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}`);
expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}&resolve=nonId`);
request.respond(
200,
responseHeader,
Expand All @@ -155,7 +155,7 @@ describe('LiveIntentMinimalId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(configParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}&_thirdPC=third-pc`);
expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}&_thirdPC=third-pc&resolve=nonId`);
request.respond(
200,
responseHeader,
Expand All @@ -177,7 +177,61 @@ describe('LiveIntentMinimalId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(configParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?_thirdPC=%7B%22key%22%3A%22value%22%7D');
expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?_thirdPC=%7B%22key%22%3A%22value%22%7D&resolve=nonId');
request.respond(
200,
responseHeader,
JSON.stringify({})
);
expect(callBackSpy.calledOnce).to.be.true;
});

it('should decode a unifiedId to lipbId and remove it', function() {
const result = liveIntentIdSubmodule.decode({ unifiedId: 'data' });
expect(result).to.eql({'lipb': {'lipbid': 'data'}});
});

it('should decode a nonId to lipbId', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'data' });
expect(result).to.eql({'lipb': {'lipbid': 'data', 'nonId': 'data'}});
});

it('should resolve extra attributes', function() {
let callBackSpy = sinon.spy();
let submoduleCallback = liveIntentIdSubmodule.getId({ params: {
...defaultConfigParams.params,
...{ requestedAttributesOverrides: { 'foo': true, 'bar': false } }
} }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?resolve=nonId&resolve=foo`);
request.respond(
200,
responseHeader,
JSON.stringify({})
);
expect(callBackSpy.calledOnce).to.be.true;
});

it('should decode a uid2 to a seperate object when present', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', uid2: 'bar' });
expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'uid2': 'bar'}, 'uid2': {'id': 'bar'}});
});

it('should decode values with uid2 but no nonId', function() {
const result = liveIntentIdSubmodule.decode({ uid2: 'bar' });
expect(result).to.eql({'uid2': {'id': 'bar'}});
});

it('should allow disabling nonId resolution', function() {
let callBackSpy = sinon.spy();
let submoduleCallback = liveIntentIdSubmodule.getId({ params: {
...defaultConfigParams.params,
...{ requestedAttributesOverrides: { 'nonId': false, 'uid2': true } }
} }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?resolve=uid2`);
request.respond(
200,
responseHeader,
Expand Down
70 changes: 62 additions & 8 deletions test/spec/modules/liveIntentIdSystem_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ describe('LiveIntentId', function() {

it('should not return a decoded identifier when the unifiedId is not present in the value', function() {
const result = liveIntentIdSubmodule.decode({ additionalData: 'data' });
expect(result).to.be.undefined;
expect(result).to.be.eql({});
});

it('should fire an event when decode', function() {
Expand All @@ -133,7 +133,7 @@ describe('LiveIntentId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId({ params: {...defaultConfigParams.params, ...{'url': 'https://dummy.liveintent.com/idex'}} }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[1];
expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/prebid/89899');
expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/prebid/89899?resolve=nonId');
request.respond(
204,
responseHeader
Expand All @@ -153,7 +153,7 @@ describe('LiveIntentId', function() {
} }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[1];
expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/rubicon/89899');
expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/rubicon/89899?resolve=nonId');
request.respond(
200,
responseHeader,
Expand All @@ -168,7 +168,7 @@ describe('LiveIntentId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[1];
expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899');
expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?resolve=nonId');
request.respond(
200,
responseHeader,
Expand All @@ -183,7 +183,7 @@ describe('LiveIntentId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[1];
expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899');
expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?resolve=nonId');
request.respond(
503,
responseHeader,
Expand All @@ -200,7 +200,7 @@ describe('LiveIntentId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[1];
expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}`);
expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}&resolve=nonId`);
request.respond(
200,
responseHeader,
Expand All @@ -223,7 +223,7 @@ describe('LiveIntentId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(configParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[1];
expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}&_thirdPC=third-pc`);
expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}&_thirdPC=third-pc&resolve=nonId`);
request.respond(
200,
responseHeader,
Expand All @@ -245,7 +245,7 @@ describe('LiveIntentId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(configParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[1];
expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?_thirdPC=%7B%22key%22%3A%22value%22%7D');
expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?_thirdPC=%7B%22key%22%3A%22value%22%7D&resolve=nonId');
request.respond(
200,
responseHeader,
Expand All @@ -259,4 +259,58 @@ describe('LiveIntentId', function() {
liveIntentIdSubmodule.getId(defaultConfigParams);
expect(imgStub.getCall(0).args[0]).to.match(/.*ae=.+/);
});

it('should decode a unifiedId to lipbId and remove it', function() {
const result = liveIntentIdSubmodule.decode({ unifiedId: 'data' });
expect(result).to.eql({'lipb': {'lipbid': 'data'}});
});

it('should decode a nonId to lipbId', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'data' });
expect(result).to.eql({'lipb': {'lipbid': 'data', 'nonId': 'data'}});
});

it('should resolve extra attributes', function() {
let callBackSpy = sinon.spy();
let submoduleCallback = liveIntentIdSubmodule.getId({ params: {
...defaultConfigParams.params,
...{ requestedAttributesOverrides: { 'foo': true, 'bar': false } }
} }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[1];
expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?resolve=nonId&resolve=foo`);
request.respond(
200,
responseHeader,
JSON.stringify({})
);
expect(callBackSpy.calledOnce).to.be.true;
});

it('should decode a uid2 to a seperate object when present', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', uid2: 'bar' });
expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'uid2': 'bar'}, 'uid2': {'id': 'bar'}});
});

it('should decode values with uid2 but no nonId', function() {
const result = liveIntentIdSubmodule.decode({ uid2: 'bar' });
expect(result).to.eql({'uid2': {'id': 'bar'}});
});

it('should allow disabling nonId resolution', function() {
let callBackSpy = sinon.spy();
let submoduleCallback = liveIntentIdSubmodule.getId({ params: {
...defaultConfigParams.params,
...{ requestedAttributesOverrides: { 'nonId': false, 'uid2': true } }
} }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[1];
expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?resolve=uid2`);
request.respond(
200,
responseHeader,
JSON.stringify({})
);
expect(callBackSpy.calledOnce).to.be.true;
});
});