-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Verizon Media user id module #5786
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
Merged
smenzer
merged 13 commits into
prebid:master
from
slimkrazy:feature/verizonmedia-user-id-module
Oct 21, 2020
Merged
Changes from 9 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
720f200
Initial work on Verizon Media User ID module
67b6412
Merge branch 'master' into feature/verizonmedia-user-id-module
55f45c1
Submodule tests
0c15502
Add sample eid object for Verizon Media
b121c41
Documentation update
2bd0630
Switch to HTTP GET, update tests.
33e70b1
Remove single test restriction.
2754e4b
Documentation update
3c2d709
Addressing initial PR feedback.
4775c7b
Accept pixelId parameter to construct VMUID URL
2497c4e
Merge branch 'master' of https://github.com/prebid/Prebid.js into fea…
91d306b
Fix tests following API signature change
0c7592d
Add IAB vendor ID
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,89 @@ | ||||||||
/** | ||||||||
* This module adds verizonMediaId to the User ID module | ||||||||
* The {@link module:modules/userId} module is required | ||||||||
* @module modules/verizonMediaIdSystem | ||||||||
* @requires module:modules/userId | ||||||||
*/ | ||||||||
|
||||||||
import {ajax} from '../src/ajax.js'; | ||||||||
import {submodule} from '../src/hook.js'; | ||||||||
import * as utils from '../src/utils.js'; | ||||||||
|
||||||||
const MODULE_NAME = 'verizonMediaId'; | ||||||||
const VMUID_ENDPOINT = 'https://ups.analytics.yahoo.com/ups/58300/fed'; | ||||||||
|
||||||||
function isEUConsentRequired(consentData) { | ||||||||
return !!(consentData && consentData.gdpr && consentData.gdpr.gdprApplies); | ||||||||
} | ||||||||
|
||||||||
/** @type {Submodule} */ | ||||||||
export const verizonMediaIdSubmodule = { | ||||||||
/** | ||||||||
* used to link submodule with config | ||||||||
* @type {string} | ||||||||
*/ | ||||||||
name: MODULE_NAME, | ||||||||
/** | ||||||||
* decode the stored id value for passing to bid requests | ||||||||
* @function | ||||||||
* @returns {{vmuid: string} | undefined} | ||||||||
*/ | ||||||||
decode(value) { | ||||||||
return (value && typeof value.vmuid === 'string') ? {vmuid: value.vmuid} : undefined; | ||||||||
}, | ||||||||
/** | ||||||||
* get the VerizonMedia Id | ||||||||
* @function | ||||||||
* @param {SubmoduleParams} [configParams] | ||||||||
* @param {ConsentData} [consentData] | ||||||||
* @returns {IdResponse|undefined} | ||||||||
*/ | ||||||||
getId(configParams, consentData) { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
if (!configParams || typeof configParams.he !== 'string') { | ||||||||
utils.logError('The verizonMediaId submodule requires the \'he\' parameter to be defined.'); | ||||||||
return; | ||||||||
} | ||||||||
|
||||||||
const data = { | ||||||||
'1p': [1, '1', true].includes(configParams['1p']) ? '1' : '0', | ||||||||
smenzer marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
he: configParams.he, | ||||||||
gdpr: isEUConsentRequired(consentData) ? '1' : '0', | ||||||||
euconsent: isEUConsentRequired(consentData) ? consentData.gdpr.consentString : '', | ||||||||
us_privacy: consentData && consentData.uspConsent ? consentData.uspConsent : '' | ||||||||
}; | ||||||||
|
||||||||
const resp = function (callback) { | ||||||||
const callbacks = { | ||||||||
success: response => { | ||||||||
let responseObj; | ||||||||
if (response) { | ||||||||
try { | ||||||||
responseObj = JSON.parse(response); | ||||||||
} catch (error) { | ||||||||
utils.logError(error); | ||||||||
} | ||||||||
} | ||||||||
callback(responseObj); | ||||||||
}, | ||||||||
error: error => { | ||||||||
utils.logError(`${MODULE_NAME}: ID fetch encountered an error`, error); | ||||||||
callback(); | ||||||||
} | ||||||||
}; | ||||||||
let url = `${configParams.endpoint || VMUID_ENDPOINT}?${utils.formatQS(data)}`; | ||||||||
verizonMediaIdSubmodule.getAjaxFn()(url, callbacks, null, {method: 'GET', withCredentials: true}); | ||||||||
}; | ||||||||
return {callback: resp}; | ||||||||
}, | ||||||||
|
||||||||
/** | ||||||||
* Return the function used to perform XHR calls. | ||||||||
* Utilised for each of testing. | ||||||||
* @returns {Function} | ||||||||
*/ | ||||||||
getAjaxFn() { | ||||||||
return ajax; | ||||||||
} | ||||||||
}; | ||||||||
|
||||||||
submodule('userId', verizonMediaIdSubmodule); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
## Verizon Media User ID Submodule | ||
|
||
Verizon Media User ID Module. | ||
|
||
### Prebid Params | ||
|
||
``` | ||
pbjs.setConfig({ | ||
userSync: { | ||
userIds: [{ | ||
name: 'verizonMediaId', | ||
storage: { | ||
name: 'vmuid', | ||
type: 'html5', | ||
expires: 30 | ||
}, | ||
params: { | ||
he: '0bef996248d63cea1529cb86de31e9547a712d9f380146e98bbd39beec70355a' | ||
} | ||
}] | ||
} | ||
}); | ||
``` | ||
## Parameter Descriptions for the `usersync` Configuration Section | ||
The below parameters apply only to the Verizon Media User ID Module integration. | ||
|
||
| Param under usersync.userIds[] | Scope | Type | Description | Example | | ||
| --- | --- | --- | --- | --- | | ||
| name | Required | String | ID value for the Verizon Media module - `"verizonMediaId"` | `"verizonMediaId"` | | ||
| params | Required | Object | Data for Verizon Media ID initialization. | | | ||
| params.he | Required | String | The SHA-256 hashed user email address | `"529cb86de31e9547a712d9f380146e98bbd39beec"` | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
import {expect} from 'chai'; | ||
import * as utils from 'src/utils.js'; | ||
import {verizonMediaIdSubmodule} from 'modules/verizonMediaIdSystem.js'; | ||
|
||
describe('Verizon Media ID Submodule', () => { | ||
const HASHED_EMAIL = '6bda6f2fa268bf0438b5423a9861a2cedaa5dec163c03f743cfe05c08a8397b2'; | ||
const PROD_ENDPOINT = 'https://ups.analytics.yahoo.com/ups/58300/fed'; | ||
const OVERRIDE_ENDPOINT = 'https://foo/bar'; | ||
|
||
it('should have the correct module name declared', () => { | ||
expect(verizonMediaIdSubmodule.name).to.equal('verizonMediaId'); | ||
}); | ||
|
||
describe('getId()', () => { | ||
let ajaxStub; | ||
let getAjaxFnStub; | ||
let consentData; | ||
beforeEach(() => { | ||
ajaxStub = sinon.stub(); | ||
getAjaxFnStub = sinon.stub(verizonMediaIdSubmodule, 'getAjaxFn'); | ||
getAjaxFnStub.returns(ajaxStub); | ||
|
||
consentData = { | ||
gdpr: { | ||
gdprApplies: 1, | ||
consentString: 'GDPR_CONSENT_STRING' | ||
}, | ||
uspConsent: 'USP_CONSENT_STRING' | ||
}; | ||
}); | ||
|
||
afterEach(() => { | ||
getAjaxFnStub.restore(); | ||
}); | ||
|
||
function invokeGetIdAPI(configParams, consentData) { | ||
let result = verizonMediaIdSubmodule.getId(configParams, consentData); | ||
result.callback(sinon.stub()); | ||
return result; | ||
} | ||
|
||
it('returns undefined if the hashed email address is not passed', () => { | ||
expect(verizonMediaIdSubmodule.getId({}, consentData)).to.be.undefined; | ||
expect(ajaxStub.callCount).to.equal(0); | ||
}); | ||
|
||
it('returns an object with the callback function if the correct params are passed', () => { | ||
let result = verizonMediaIdSubmodule.getId({ | ||
he: HASHED_EMAIL | ||
}, consentData); | ||
expect(result).to.be.an('object').that.has.all.keys('callback'); | ||
expect(result.callback).to.be.a('function'); | ||
}); | ||
|
||
it('Makes an ajax GET request to the production API endpoint with query params', () => { | ||
invokeGetIdAPI({ | ||
he: HASHED_EMAIL, | ||
}, consentData); | ||
|
||
const expectedParams = { | ||
he: HASHED_EMAIL, | ||
'1p': '0', | ||
gdpr: '1', | ||
euconsent: consentData.gdpr.consentString, | ||
us_privacy: consentData.uspConsent | ||
}; | ||
const requestQueryParams = utils.parseQS(ajaxStub.firstCall.args[0].split('?')[1]); | ||
|
||
expect(ajaxStub.firstCall.args[0].indexOf(PROD_ENDPOINT)).to.equal(0); | ||
expect(requestQueryParams).to.deep.equal(expectedParams); | ||
expect(ajaxStub.firstCall.args[3]).to.deep.equal({method: 'GET', withCredentials: true}); | ||
}); | ||
|
||
it('Makes an ajax GET request to the specified override API endpoint with query params', () => { | ||
invokeGetIdAPI({ | ||
he: HASHED_EMAIL, | ||
endpoint: OVERRIDE_ENDPOINT | ||
}, consentData); | ||
|
||
const expectedParams = { | ||
he: HASHED_EMAIL, | ||
'1p': '0', | ||
gdpr: '1', | ||
euconsent: consentData.gdpr.consentString, | ||
us_privacy: consentData.uspConsent | ||
}; | ||
const requestQueryParams = utils.parseQS(ajaxStub.firstCall.args[0].split('?')[1]); | ||
|
||
expect(ajaxStub.firstCall.args[0].indexOf(OVERRIDE_ENDPOINT)).to.equal(0); | ||
expect(requestQueryParams).to.deep.equal(expectedParams); | ||
expect(ajaxStub.firstCall.args[3]).to.deep.equal({method: 'GET', withCredentials: true}); | ||
}); | ||
|
||
it('sets the callbacks param of the ajax function call correctly', () => { | ||
invokeGetIdAPI({ | ||
he: HASHED_EMAIL | ||
}, consentData); | ||
|
||
expect(ajaxStub.firstCall.args[1]).to.be.an('object').that.has.all.keys(['success', 'error']); | ||
}); | ||
|
||
it('sets GDPR consent data flag correctly when call is under GDPR jurisdiction.', () => { | ||
invokeGetIdAPI({ | ||
he: HASHED_EMAIL | ||
}, consentData); | ||
|
||
const requestQueryParams = utils.parseQS(ajaxStub.firstCall.args[0].split('?')[1]); | ||
expect(requestQueryParams.gdpr).to.equal('1'); | ||
expect(requestQueryParams.euconsent).to.equal(consentData.gdpr.consentString); | ||
}); | ||
|
||
it('sets GDPR consent data flag correctly when call is NOT under GDPR jurisdiction.', () => { | ||
consentData.gdpr.gdprApplies = false; | ||
|
||
invokeGetIdAPI({ | ||
he: HASHED_EMAIL | ||
}, consentData); | ||
|
||
const requestQueryParams = utils.parseQS(ajaxStub.firstCall.args[0].split('?')[1]); | ||
expect(requestQueryParams.gdpr).to.equal('0'); | ||
expect(requestQueryParams.euconsent).to.equal(''); | ||
}); | ||
|
||
[1, '1', true].forEach(firstPartyParamValue => { | ||
it(`sets 1p payload property to '1' for a config value of ${firstPartyParamValue}`, () => { | ||
invokeGetIdAPI({ | ||
'1p': firstPartyParamValue, | ||
he: HASHED_EMAIL | ||
}, consentData); | ||
|
||
const requestQueryParams = utils.parseQS(ajaxStub.firstCall.args[0].split('?')[1]); | ||
expect(requestQueryParams['1p']).to.equal('1'); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('decode()', () => { | ||
const VALID_API_RESPONSE = { | ||
vmuid: '1234' | ||
}; | ||
it('should return a newly constructed object with the vmuid property', () => { | ||
expect(verizonMediaIdSubmodule.decode(VALID_API_RESPONSE)).to.deep.equal(VALID_API_RESPONSE); | ||
expect(verizonMediaIdSubmodule.decode(VALID_API_RESPONSE)).to.not.equal(VALID_API_RESPONSE); | ||
}); | ||
|
||
[{}, '', {foo: 'bar'}].forEach((response) => { | ||
it(`should return undefined for an invalid response "${JSON.stringify(response)}"`, () => { | ||
expect(verizonMediaIdSubmodule.decode(response)).to.be.undefined; | ||
}); | ||
}); | ||
}); | ||
}); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.