Skip to content

Commit

Permalink
Trustpid User ID Module: initial release (#7945)
Browse files Browse the repository at this point in the history
* feature: Add trustpid user id module

* refactor: Update trustpidSystem module, comments and md file

* refactor: Update trustpidSystem file to handle domain setting regardless of message events

* refactor: Update trustpidSystem module and dependent tests and docs

* refactor: Update trustpid undefined checks and returns

* tests: Update trustpid tests

* docs: Update trustpid docs typo

* refactor: Update trustpid module with storage and logging utils. Adjust tests.

Co-authored-by: Tomasz Januszek <tomasz@teavaro.com>
  • Loading branch information
jkthomas and Tomasz Januszek authored Jan 26, 2022
1 parent 1d3ce5f commit 2288ea4
Show file tree
Hide file tree
Showing 7 changed files with 511 additions and 4 deletions.
1 change: 1 addition & 0 deletions modules/.submodules.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"quantcastIdSystem",
"sharedIdSystem",
"tapadIdSystem",
"trustpidSystem",
"uid2IdSystem",
"unifiedIdSystem",
"verizonMediaIdSystem",
Expand Down
197 changes: 197 additions & 0 deletions modules/trustpidSystem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/**
* This module adds TrustPid provided by Vodafone Sales and Services Limited to the User ID module
* The {@link module:modules/userId} module is required
* @module modules/trustpidSystem
* @requires module:modules/userId
*/
import { logInfo, logError } from '../src/utils.js';
import { submodule } from '../src/hook.js';
import { getStorageManager } from '../src/storageManager.js';

const MODULE_NAME = 'trustpid';
const LOG_PREFIX = 'Trustpid module'
let mnoAcronym = '';
let mnoDomain = '';

export const storage = getStorageManager(null, MODULE_NAME);

/**
* Handle an event for an iframe.
* Takes the body.url parameter from event and returns the string domain.
* i.e.: "fc.vodafone.de"
* @param event
*/
function messageHandler(event) {
let msg;
try {
if (event && event.data && typeof event.data === 'string' && event.data) {
msg = JSON.parse(event.data);
if (msg.msgType === 'MNOSELECTOR' && msg.body && msg.body.url) {
let URL = msg.body.url.split('//');
let domainURL = URL[1].split('/');
mnoDomain = domainURL[0];
logInfo(`${LOG_PREFIX}: Message handler set domain to ${mnoDomain}`);
getDomainAcronym(mnoDomain);
}
}
} catch (e) {
logError(e);
}
}

/**
* Properly sets the trustpid acronym depending on the domain value.
* @param domain
*/
function getDomainAcronym(domain) {
let acronym = '';
const prefix = '-';
switch (domain) {
case 'tmi.mno.link':
acronym = 'ndye';
break;
case 'tmi.vodafone.de':
acronym = 'pqnx';
break;
case 'tmi.telekom.de':
acronym = 'avgw';
break;
case 'tmi.tmid.es':
acronym = 'kjws';
break;
case 'uat.mno.link':
acronym = 'xxxx';
break;
case 'es.tmiservice.orange.com':
acronym = 'aplw';
break;
default:
return 'none';
}
return mnoAcronym = prefix + acronym;
}

// Set a listener to handle the iframe response message.
window.addEventListener('message', messageHandler, false);

/**
* Get the "umid" from html5 local storage to make it available to the UserId module.
* @param config
* @returns {{trustpid: (*|string), acr: (string)}}
*/
function getTrustpidFromStorage() {
// Get the domain either from localStorage or global
let domain = JSON.parse(storage.getDataFromLocalStorage('fcIdConnectDomain')) || mnoDomain;
logInfo(`${LOG_PREFIX}: Local storage domain: ${domain}`);

if (!domain) {
logInfo(`${LOG_PREFIX}: Local storage domain not found, returning null`);
return {
trustpid: null,
acr: null,
};
}

// Get the acronym from global
let acronym = mnoAcronym;
// if acronym is empty, but "domain" is available, get the acronym from domain
if (!acronym) {
getDomainAcronym(domain);
acronym = mnoAcronym;
}

logInfo(`${LOG_PREFIX}: Domain acronym found: ${acronym}`);

// Domain is correct in both local storage and idGraph, but no acronym is existing for the domain
if (domain && !acronym) {
return {
trustpid: null,
acr: null
}
}

let fcIdConnectObject;
let fcIdConnectData = JSON.parse(storage.getDataFromLocalStorage('fcIdConnectData'));
logInfo(`${LOG_PREFIX}: Local storage fcIdConnectData: ${JSON.stringify(fcIdConnectData)}`);

if (fcIdConnectData &&
fcIdConnectData.connectId &&
Array.isArray(fcIdConnectData.connectId.idGraph) &&
fcIdConnectData.connectId.idGraph.length > 0) {
fcIdConnectObject = fcIdConnectData.connectId.idGraph.find(item => {
return item.domain === domain;
});
}
logInfo(`${LOG_PREFIX}: Local storage fcIdConnectObject for domain: ${JSON.stringify(fcIdConnectObject)}`);

return {
trustpid: (fcIdConnectObject && fcIdConnectObject.umid)
? fcIdConnectObject.umid
: null,
acr: acronym,
};
}

/** @type {Submodule} */
export const trustpidSubmodule = {
/**
* Used to link submodule with config
* @type {string}
*/
name: MODULE_NAME,
/**
* Decodes the stored id value for passing to bid requests.
* @function
* @returns {{trustpid: string} | null}
*/
decode(bidId) {
logInfo(`${LOG_PREFIX}: Decoded ID value ${JSON.stringify(bidId)}`);
return bidId.trustpid ? bidId : null;
},
/**
* Get the id from helper function and initiate a new user sync.
* @param config
* @returns {{callback: result}|{id: {trustpid: string}}}
*/
getId: function(config) {
const data = getTrustpidFromStorage();
if (data.trustpid) {
logInfo(`${LOG_PREFIX}: Local storage ID value ${JSON.stringify(data)}`);
return {id: {trustpid: data.trustpid + data.acr}};
} else {
if (!config) {
config = {};
}
if (!config.params) {
config.params = {};
}
if (typeof config.params.maxDelayTime === 'undefined' || config.params.maxDelayTime === null) {
config.params.maxDelayTime = 1000;
}
// Current delay and delay step in milliseconds
let currentDelay = 0;
const delayStep = 50;
const result = (callback) => {
const data = getTrustpidFromStorage();
if (!data.trustpid) {
if (currentDelay > config.params.maxDelayTime) {
logInfo(`${LOG_PREFIX}: No trustpid value set after ${config.params.maxDelayTime} max allowed delay time`);
callback(null);
} else {
currentDelay += delayStep;
setTimeout(() => {
result(callback);
}, delayStep);
}
} else {
const dataToReturn = { trustpid: data.trustpid + data.acr };
logInfo(`${LOG_PREFIX}: Returning ID value data of ${JSON.stringify(dataToReturn)}`);
callback(dataToReturn);
}
};
return { callback: result };
}
},
};

submodule('userId', trustpidSubmodule);
45 changes: 45 additions & 0 deletions modules/trustpidSystem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## trustpid User Id Submodule

trustpid User Id Module.

First, make sure to add the trustpid submodule to your Prebid.js package with:

```
gulp build --modules=userId,adfBidAdapter,trustpidSystem
```

The following configuration parameters are available:

```
pbjs.setConfig({
userSync: {
userIds: [
{
name: 'trustpid',
params: {
maxDelayTime: 1000,
},
bidders: ["adf"],
storage: {
type: "html5",
name: "trustpid",
expires: 1, //days
},
}
],
}
});
```

## Parameter Descriptions

| Param under userSync.userIds[] | Scope | Type | Description | Example |
| --- | --- | --- | --- | --- |
| name | Required | String | The name of the module | `"trustpid"`
| params | Required | Object | Object with configuration parameters for trustpid User Id submodule | - |
| params.maxDelayTime | Required | Integer | Max amount of time (in seconds) before looking into storage for data | 2500 |
| bidders | Required | Array of Strings | An array of bidder codes to which this user ID may be sent. Currently required and supporting AdformOpenRTB | `["adf"]` |
| storage | Required | Object | Local storage configuration object | - |
| storage.type | Required | String | Type of the storage that would be used to store user ID. Must be `"html5"` to utilise HTML5 local storage. | `"html5"` |
| storage.name | Required | String | The name of the key in local storage where the user ID will be stored. | `"trustpid"` |
| storage.expires | Required | Integer | How long (in days) the user ID information will be stored. For safety reasons, this information is required.| `1` |
9 changes: 9 additions & 0 deletions modules/userId/eids.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ const USER_IDS_CONFIG = {

// key-name : {config}

// trustpid
'trustpid': {
source: 'trustpid.com',
atype: 1,
getValue: function (data) {
return data;
},
},

// intentIqId
'intentIqId': {
source: 'intentiq.com',
Expand Down
12 changes: 10 additions & 2 deletions modules/userId/eids.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

```
userIdAsEids = [
{
source: 'trustpid.com',
uids: [{
id: 'some-random-id-value',
atype: 1
}]
},
{
source: 'pubcid.org',
uids: [{
Expand All @@ -28,7 +36,7 @@ userIdAsEids = [
atype: 1
}]
},
{
source: 'neustar.biz',
uids: [{
Expand Down Expand Up @@ -203,7 +211,7 @@ userIdAsEids = [
id: 'some-random-id-value',
atype: 3
}]
},
},
{
source: 'kpuid.com',
uids: [{
Expand Down
19 changes: 17 additions & 2 deletions modules/userId/userId.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## User ID Example Configuration

Example showing `cookie` storage for user id data for each of the submodules

```
pbjs.setConfig({
userSync: {
Expand Down Expand Up @@ -147,10 +148,23 @@ pbjs.setConfig({
```

Example showing `localStorage` for user id data for some submodules

```
pbjs.setConfig({
userSync: {
userIds: [{
userIds: [
{
name: 'trustpid',
params: {
maxDelayTime: 2500
},
bidders: ['adform'],
storage: {
type: 'html5',
name: 'trustpid',
expires: 60
}
}, {
name: "unifiedId",
params: {
partner: "prebid",
Expand Down Expand Up @@ -278,7 +292,7 @@ pbjs.setConfig({
name: "knssoId",
expires: 30
},
}
}
},
{
name: 'imuid',
Expand Down Expand Up @@ -312,6 +326,7 @@ pbjs.setConfig({
```

Example showing how to configure a `value` object to pass directly to bid adapters

```
pbjs.setConfig({
userSync: {
Expand Down
Loading

0 comments on commit 2288ea4

Please sign in to comment.