Skip to content

Commit

Permalink
Add britepool userid submodule (prebid#4314)
Browse files Browse the repository at this point in the history
* * Added BritePool User ID Submodule

* * Refactor getId() and allow it to return a sync value from getter()

* * Pull only primaryBPID key out of hardened API response

* add check for decoded primaryBPID value and update readme

* * Added BritePool User ID Submodule

* * Refactor getId() and allow it to return a sync value from getter()

* * Pull only primaryBPID key out of hardened API response

* add check for decoded primaryBPID value and update readme

* update userId_spec.js tests

* update userId_spec.js tests and add britepoolIdSystem to submodules.json

* moved our module specific tests to own spec file

* * Update to use getId() with callback key
* Add test for our getId() returning value or callback

* * Revert comment to "Use existing cookie"

* add support for prebid server

* add comma back to submodules.json

* updating markdown for email address

* * Allow the britepool call without parameters (identifiers)

* fixed merging error of double ||

* * Fix the immediate value response to be in id key

* * Fixed test which was expecting id key

* * Touch

* * Update doc

* * Suggested changes to move britepoolIdSystem out of userId default

* * Change weird backticks to single quotes

* * Added functional identifiers
  • Loading branch information
bansawbanchee authored and tadam75 committed Jan 9, 2020
1 parent f2a588c commit 7d32733
Show file tree
Hide file tree
Showing 6 changed files with 310 additions and 13 deletions.
1 change: 1 addition & 0 deletions modules/.submodules.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"id5IdSystem",
"criteortusIdSystem",
"parrableIdSystem",
"britepoolIdSystem",
"liveIntentIdSystem",
"criteoIdSystem"
],
Expand Down
132 changes: 132 additions & 0 deletions modules/britepoolIdSystem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/**
* This module adds BritePoolId to the User ID module
* The {@link module:modules/userId} module is required
* @module modules/britepoolIdSystem
* @requires module:modules/userId
*/

import * as utils from '../src/utils'
import {ajax} from '../src/ajax';
import {submodule} from '../src/hook';

/** @type {Submodule} */
export const britepoolIdSubmodule = {
/**
* Used to link submodule with config
* @type {string}
*/
name: 'britepoolId',
/**
* Decode the stored id value for passing to bid requests
* @function
* @param {string} value
* @returns {{britepoolid:string}}
*/
decode(value) {
return (value && typeof value['primaryBPID'] === 'string') ? { 'britepoolid': value['primaryBPID'] } : null;
},
/**
* Performs action to obtain id and return a value in the callback's response argument
* @function
* @param {SubmoduleParams} [configParams]
* @returns {function(callback:function)}
*/
getId(submoduleConfigParams, consentData) {
const { params, headers, url, getter, errors } = britepoolIdSubmodule.createParams(submoduleConfigParams, consentData);
let getterResponse = null;
if (typeof getter === 'function') {
getterResponse = getter(params);
// First let's rule out that the response is not a function
if (typeof getterResponse !== 'function') {
// Optimization to return value from getter
return {
id: britepoolIdSubmodule.normalizeValue(getterResponse)
};
}
}
// Return for async operation
return {
callback: function(callback) {
if (errors.length > 0) {
errors.forEach(error => utils.logError(error));
callback();
return;
}
if (getterResponse) {
// Resolve the getter function response
try {
getterResponse(function(response) {
callback(britepoolIdSubmodule.normalizeValue(response));
});
} catch (error) {
if (error !== '') utils.logError(error);
callback();
}
} else {
ajax(url, {
success: response => {
const responseObj = britepoolIdSubmodule.normalizeValue(response);
callback(responseObj ? { primaryBPID: responseObj.primaryBPID } : null);
},
error: error => {
if (error !== '') utils.logError(error);
callback();
}
}, JSON.stringify(params), { customHeaders: headers, contentType: 'application/json', method: 'POST', withCredentials: true });
}
}
}
},
/**
* Helper method to create params for our API call
* @param {SubmoduleParams} [configParams]
* @returns {object} Object with parsed out params
*/
createParams(submoduleConfigParams, consentData) {
let errors = [];
const headers = {};
let params = Object.assign({}, submoduleConfigParams);
if (params.getter) {
// Custom getter will not require other params
if (typeof params.getter !== 'function') {
errors.push(`${MODULE_NAME} - britepoolId submodule requires getter to be a function`);
return { errors };
}
} else {
if (params.api_key) {
// Add x-api-key into the header
headers['x-api-key'] = params.api_key;
}
}
const url = params.url || 'https://api.britepool.com/v1/britepool/id';
const getter = params.getter;
delete params.api_key;
delete params.url;
delete params.getter;
return {
params,
headers,
url,
getter,
errors
};
},
/**
* Helper method to normalize a JSON value
*/
normalizeValue(value) {
let valueObj = null;
if (typeof value === 'object') {
valueObj = value;
} else if (typeof value === 'string') {
try {
valueObj = JSON.parse(value);
} catch (error) {
utils.logError(error);
}
}
return valueObj;
}
};

submodule('userId', britepoolIdSubmodule);
42 changes: 42 additions & 0 deletions modules/britepoolIdSystem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
## BritePool User ID Submodule

BritePool User ID Module. For assistance setting up your module please contact us at [[email protected]]([email protected]).

### Prebid Params

Individual params may be set for the BritePool User ID Submodule. At least one identifier must be set in the params.
```
pbjs.setConfig({
usersync: {
userIds: [{
name: 'britepoolId',
storage: {
name: 'britepoolid',
type: 'cookie',
expires: 30
},
params: {
url: 'https://sandbox-api.britepool.com/v1/britepool/id', // optional
api_key: '3fdbe297-3690-4f5c-9e11-ee9186a6d77c', // provided by britepool
hash: '31c5543c1734d25c7206f5fd591525d0295bec6fe84ff82f946a34fe970a1e66', // example hash identifier (sha256)
ssid: '221aa074-57fc-453b-81f0-6c74f628cd5c' // example identifier
}
}]
}
});
```
## Parameter Descriptions for the `usersync` Configuration Section
The below parameters apply only to the BritePool User ID Module integration.

| Param under usersync.userIds[] | Scope | Type | Description | Example |
| --- | --- | --- | --- | --- |
| name | Required | String | ID value for the BritePool module - `"britepoolId"` | `"britepoolId"` |
| params | Required | Object | Details for BritePool initialization. | |
| params.api_key | Required | String |BritePool API Key provided by BritePool | "3fdbe297-3690-4f5c-9e11-ee9186a6d77c" |
| params.url | Optional | String |BritePool API url | "https://sandbox-api.britepool.com/v1/britepool/id" |
| params.identifier | Required | String | Where identifier in the params object is the key name. At least one identifier is required. Available Identifiers `aaid` `dtid` `idfa` `ilid` `luid` `mmid` `msid` `mwid` `rida` `ssid` `hash` | `params.ssid` `params.aaid` |
| storage | Required | Object | The publisher must specify the local storage in which to store the results of the call to get the user ID. This can be either cookie or HTML5 storage. | |
| storage.type | Required | String | This is where the results of the user ID will be stored. The recommended method is `localStorage` by specifying `html5`. | `"html5"` |
| storage.name | Required | String | The name of the cookie or html5 local storage where the user ID will be stored. | `"britepoolid"` |
| storage.expires | Optional | Integer | How long (in days) the user ID information will be stored. | `365` |
| value | Optional | Object | Used only if the page has a separate mechanism for storing the BritePool ID. The value is an object containing the values to be sent to the adapters. In this scenario, no URL is called and nothing is added to local storage | `{"primaryBPID": "eb33b0cb-8d35-4722-b9c0-1a31d4064888"}` |
11 changes: 10 additions & 1 deletion modules/prebidServerBidAdapter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ const OPEN_RTB_PROTOCOL = {
}

const bidUserId = utils.deepAccess(bidRequests, '0.bids.0.userId');
if (bidUserId && typeof bidUserId === 'object' && (bidUserId.tdid || bidUserId.pubcid || bidUserId.parrableid || bidUserId.lipb || bidUserId.id5id || bidUserId.criteoId)) {
if (bidUserId && typeof bidUserId === 'object' && (bidUserId.tdid || bidUserId.pubcid || bidUserId.parrableid || bidUserId.lipb || bidUserId.id5id || bidUserId.criteoId || bidUserId.britepoolid)) {
utils.deepSetValue(request, 'user.ext.eids', []);

if (bidUserId.tdid) {
Expand Down Expand Up @@ -764,6 +764,15 @@ const OPEN_RTB_PROTOCOL = {
}]
});
}

if (bidUserId.britepoolid) {
request.user.ext.eids.push({
source: 'britepool.com',
uids: [{
id: bidUserId.britepoolid
}]
});
}
}

if (bidRequests && bidRequests[0].gdprConsent) {
Expand Down
67 changes: 67 additions & 0 deletions test/spec/modules/britepoolIdSystem_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { expect } from 'chai';
import {britepoolIdSubmodule} from 'modules/britepoolIdSystem';

describe('BritePool Submodule', () => {
const api_key = '1111';
const aaid = '4421ea96-34a9-45df-a4ea-3c41a48a18b1';
const idfa = '2d1c4fac-5507-4e28-991c-ca544e992dba';
const bpid = '279c0161-5152-487f-809e-05d7f7e653fd';
const url_override = 'https://override';
const getter_override = function(params) {
return JSON.stringify({ 'primaryBPID': bpid });
};
const getter_callback_override = function(params) {
return callback => {
callback(JSON.stringify({ 'primaryBPID': bpid }));
};
};

it('sends x-api-key in header and one identifier', () => {
const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, aaid });
assert(errors.length === 0, errors);
expect(headers['x-api-key']).to.equal(api_key);
expect(params).to.eql({ aaid });
});

it('sends x-api-key in header and two identifiers', () => {
const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, aaid, idfa });
assert(errors.length === 0, errors);
expect(headers['x-api-key']).to.equal(api_key);
expect(params).to.eql({ aaid, idfa });
});

it('allows call without api_key', () => {
const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ aaid, idfa });
expect(params).to.eql({ aaid, idfa });
expect(errors.length).to.equal(0);
});

it('test url override', () => {
const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, aaid, url: url_override });
expect(url).to.equal(url_override);
// Making sure it did not become part of params
expect(params.url).to.be.undefined;
});

it('test getter override with value', () => {
const { params, headers, url, getter, errors } = britepoolIdSubmodule.createParams({ api_key, aaid, url: url_override, getter: getter_override });
expect(getter).to.equal(getter_override);
// Making sure it did not become part of params
expect(params.getter).to.be.undefined;
const response = britepoolIdSubmodule.getId({ api_key, aaid, url: url_override, getter: getter_override });
assert.deepEqual(response, { id: { 'primaryBPID': bpid } });
});

it('test getter override with callback', done => {
const { params, headers, url, getter, errors } = britepoolIdSubmodule.createParams({ api_key, aaid, url: url_override, getter: getter_callback_override });
expect(getter).to.equal(getter_callback_override);
// Making sure it did not become part of params
expect(params.getter).to.be.undefined;
const response = britepoolIdSubmodule.getId({ api_key, aaid, url: url_override, getter: getter_callback_override });
expect(response.callback).to.not.be.undefined;
response.callback(result => {
assert.deepEqual(result, { 'primaryBPID': bpid });
done();
});
});
});
Loading

0 comments on commit 7d32733

Please sign in to comment.