Skip to content

Commit b3e736a

Browse files
bansawbancheeafewcc
authored andcommitted
Add britepool userid submodule (prebid#4314)
* * 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
1 parent 3fa0392 commit b3e736a

File tree

6 files changed

+310
-13
lines changed

6 files changed

+310
-13
lines changed

modules/.submodules.json

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"id5IdSystem",
55
"criteortusIdSystem",
66
"parrableIdSystem",
7+
"britepoolIdSystem",
78
"liveIntentIdSystem",
89
"criteoIdSystem"
910
],

modules/britepoolIdSystem.js

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/**
2+
* This module adds BritePoolId to the User ID module
3+
* The {@link module:modules/userId} module is required
4+
* @module modules/britepoolIdSystem
5+
* @requires module:modules/userId
6+
*/
7+
8+
import * as utils from '../src/utils'
9+
import {ajax} from '../src/ajax';
10+
import {submodule} from '../src/hook';
11+
12+
/** @type {Submodule} */
13+
export const britepoolIdSubmodule = {
14+
/**
15+
* Used to link submodule with config
16+
* @type {string}
17+
*/
18+
name: 'britepoolId',
19+
/**
20+
* Decode the stored id value for passing to bid requests
21+
* @function
22+
* @param {string} value
23+
* @returns {{britepoolid:string}}
24+
*/
25+
decode(value) {
26+
return (value && typeof value['primaryBPID'] === 'string') ? { 'britepoolid': value['primaryBPID'] } : null;
27+
},
28+
/**
29+
* Performs action to obtain id and return a value in the callback's response argument
30+
* @function
31+
* @param {SubmoduleParams} [configParams]
32+
* @returns {function(callback:function)}
33+
*/
34+
getId(submoduleConfigParams, consentData) {
35+
const { params, headers, url, getter, errors } = britepoolIdSubmodule.createParams(submoduleConfigParams, consentData);
36+
let getterResponse = null;
37+
if (typeof getter === 'function') {
38+
getterResponse = getter(params);
39+
// First let's rule out that the response is not a function
40+
if (typeof getterResponse !== 'function') {
41+
// Optimization to return value from getter
42+
return {
43+
id: britepoolIdSubmodule.normalizeValue(getterResponse)
44+
};
45+
}
46+
}
47+
// Return for async operation
48+
return {
49+
callback: function(callback) {
50+
if (errors.length > 0) {
51+
errors.forEach(error => utils.logError(error));
52+
callback();
53+
return;
54+
}
55+
if (getterResponse) {
56+
// Resolve the getter function response
57+
try {
58+
getterResponse(function(response) {
59+
callback(britepoolIdSubmodule.normalizeValue(response));
60+
});
61+
} catch (error) {
62+
if (error !== '') utils.logError(error);
63+
callback();
64+
}
65+
} else {
66+
ajax(url, {
67+
success: response => {
68+
const responseObj = britepoolIdSubmodule.normalizeValue(response);
69+
callback(responseObj ? { primaryBPID: responseObj.primaryBPID } : null);
70+
},
71+
error: error => {
72+
if (error !== '') utils.logError(error);
73+
callback();
74+
}
75+
}, JSON.stringify(params), { customHeaders: headers, contentType: 'application/json', method: 'POST', withCredentials: true });
76+
}
77+
}
78+
}
79+
},
80+
/**
81+
* Helper method to create params for our API call
82+
* @param {SubmoduleParams} [configParams]
83+
* @returns {object} Object with parsed out params
84+
*/
85+
createParams(submoduleConfigParams, consentData) {
86+
let errors = [];
87+
const headers = {};
88+
let params = Object.assign({}, submoduleConfigParams);
89+
if (params.getter) {
90+
// Custom getter will not require other params
91+
if (typeof params.getter !== 'function') {
92+
errors.push(`${MODULE_NAME} - britepoolId submodule requires getter to be a function`);
93+
return { errors };
94+
}
95+
} else {
96+
if (params.api_key) {
97+
// Add x-api-key into the header
98+
headers['x-api-key'] = params.api_key;
99+
}
100+
}
101+
const url = params.url || 'https://api.britepool.com/v1/britepool/id';
102+
const getter = params.getter;
103+
delete params.api_key;
104+
delete params.url;
105+
delete params.getter;
106+
return {
107+
params,
108+
headers,
109+
url,
110+
getter,
111+
errors
112+
};
113+
},
114+
/**
115+
* Helper method to normalize a JSON value
116+
*/
117+
normalizeValue(value) {
118+
let valueObj = null;
119+
if (typeof value === 'object') {
120+
valueObj = value;
121+
} else if (typeof value === 'string') {
122+
try {
123+
valueObj = JSON.parse(value);
124+
} catch (error) {
125+
utils.logError(error);
126+
}
127+
}
128+
return valueObj;
129+
}
130+
};
131+
132+
submodule('userId', britepoolIdSubmodule);

modules/britepoolIdSystem.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
## BritePool User ID Submodule
2+
3+
BritePool User ID Module. For assistance setting up your module please contact us at [[email protected]]([email protected]).
4+
5+
### Prebid Params
6+
7+
Individual params may be set for the BritePool User ID Submodule. At least one identifier must be set in the params.
8+
```
9+
pbjs.setConfig({
10+
usersync: {
11+
userIds: [{
12+
name: 'britepoolId',
13+
storage: {
14+
name: 'britepoolid',
15+
type: 'cookie',
16+
expires: 30
17+
},
18+
params: {
19+
url: 'https://sandbox-api.britepool.com/v1/britepool/id', // optional
20+
api_key: '3fdbe297-3690-4f5c-9e11-ee9186a6d77c', // provided by britepool
21+
hash: '31c5543c1734d25c7206f5fd591525d0295bec6fe84ff82f946a34fe970a1e66', // example hash identifier (sha256)
22+
ssid: '221aa074-57fc-453b-81f0-6c74f628cd5c' // example identifier
23+
}
24+
}]
25+
}
26+
});
27+
```
28+
## Parameter Descriptions for the `usersync` Configuration Section
29+
The below parameters apply only to the BritePool User ID Module integration.
30+
31+
| Param under usersync.userIds[] | Scope | Type | Description | Example |
32+
| --- | --- | --- | --- | --- |
33+
| name | Required | String | ID value for the BritePool module - `"britepoolId"` | `"britepoolId"` |
34+
| params | Required | Object | Details for BritePool initialization. | |
35+
| params.api_key | Required | String |BritePool API Key provided by BritePool | "3fdbe297-3690-4f5c-9e11-ee9186a6d77c" |
36+
| params.url | Optional | String |BritePool API url | "https://sandbox-api.britepool.com/v1/britepool/id" |
37+
| 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` |
38+
| 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. | |
39+
| 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"` |
40+
| storage.name | Required | String | The name of the cookie or html5 local storage where the user ID will be stored. | `"britepoolid"` |
41+
| storage.expires | Optional | Integer | How long (in days) the user ID information will be stored. | `365` |
42+
| 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"}` |

modules/prebidServerBidAdapter/index.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ const OPEN_RTB_PROTOCOL = {
698698
}
699699

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

704704
if (bidUserId.tdid) {
@@ -764,6 +764,15 @@ const OPEN_RTB_PROTOCOL = {
764764
}]
765765
});
766766
}
767+
768+
if (bidUserId.britepoolid) {
769+
request.user.ext.eids.push({
770+
source: 'britepool.com',
771+
uids: [{
772+
id: bidUserId.britepoolid
773+
}]
774+
});
775+
}
767776
}
768777

769778
if (bidRequests && bidRequests[0].gdprConsent) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { expect } from 'chai';
2+
import {britepoolIdSubmodule} from 'modules/britepoolIdSystem';
3+
4+
describe('BritePool Submodule', () => {
5+
const api_key = '1111';
6+
const aaid = '4421ea96-34a9-45df-a4ea-3c41a48a18b1';
7+
const idfa = '2d1c4fac-5507-4e28-991c-ca544e992dba';
8+
const bpid = '279c0161-5152-487f-809e-05d7f7e653fd';
9+
const url_override = 'https://override';
10+
const getter_override = function(params) {
11+
return JSON.stringify({ 'primaryBPID': bpid });
12+
};
13+
const getter_callback_override = function(params) {
14+
return callback => {
15+
callback(JSON.stringify({ 'primaryBPID': bpid }));
16+
};
17+
};
18+
19+
it('sends x-api-key in header and one identifier', () => {
20+
const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, aaid });
21+
assert(errors.length === 0, errors);
22+
expect(headers['x-api-key']).to.equal(api_key);
23+
expect(params).to.eql({ aaid });
24+
});
25+
26+
it('sends x-api-key in header and two identifiers', () => {
27+
const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, aaid, idfa });
28+
assert(errors.length === 0, errors);
29+
expect(headers['x-api-key']).to.equal(api_key);
30+
expect(params).to.eql({ aaid, idfa });
31+
});
32+
33+
it('allows call without api_key', () => {
34+
const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ aaid, idfa });
35+
expect(params).to.eql({ aaid, idfa });
36+
expect(errors.length).to.equal(0);
37+
});
38+
39+
it('test url override', () => {
40+
const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, aaid, url: url_override });
41+
expect(url).to.equal(url_override);
42+
// Making sure it did not become part of params
43+
expect(params.url).to.be.undefined;
44+
});
45+
46+
it('test getter override with value', () => {
47+
const { params, headers, url, getter, errors } = britepoolIdSubmodule.createParams({ api_key, aaid, url: url_override, getter: getter_override });
48+
expect(getter).to.equal(getter_override);
49+
// Making sure it did not become part of params
50+
expect(params.getter).to.be.undefined;
51+
const response = britepoolIdSubmodule.getId({ api_key, aaid, url: url_override, getter: getter_override });
52+
assert.deepEqual(response, { id: { 'primaryBPID': bpid } });
53+
});
54+
55+
it('test getter override with callback', done => {
56+
const { params, headers, url, getter, errors } = britepoolIdSubmodule.createParams({ api_key, aaid, url: url_override, getter: getter_callback_override });
57+
expect(getter).to.equal(getter_callback_override);
58+
// Making sure it did not become part of params
59+
expect(params.getter).to.be.undefined;
60+
const response = britepoolIdSubmodule.getId({ api_key, aaid, url: url_override, getter: getter_callback_override });
61+
expect(response.callback).to.not.be.undefined;
62+
response.callback(result => {
63+
assert.deepEqual(result, { 'primaryBPID': bpid });
64+
done();
65+
});
66+
});
67+
});

0 commit comments

Comments
 (0)