Skip to content

Commit

Permalink
Mygaru Id System: Initial release (prebid#10848)
Browse files Browse the repository at this point in the history
  • Loading branch information
GeneGenie authored Jan 2, 2024
1 parent 233695d commit 04a7659
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 1 deletion.
3 changes: 2 additions & 1 deletion modules/.submodules.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
"adqueryIdSystem",
"gravitoIdSystem",
"freepassIdSystem",
"operaadsIdSystem"
"operaadsIdSystem",
"mygaruIdSystem"
],
"adpod": [
"freeWheelAdserverVideo",
Expand Down
98 changes: 98 additions & 0 deletions modules/mygaruIdSystem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* This module adds MyGaru Real Time User Sync to the User ID module
* The {@link module:modules/userId} module is required
* @module modules/mygaruIdSystem
* @requires module:modules/userId
*/

import { ajax } from '../src/ajax.js';
import { submodule } from '../src/hook.js';

const bidderCode = 'mygaruId';
const syncUrl = 'https://ident.mygaru.com/v2/id';

export function buildUrl(opts) {
const queryPairs = [];
for (let key in opts) {
if (opts[key] !== undefined) {
queryPairs.push(`${key}=${encodeURIComponent(opts[key])}`);
}
}
return `${syncUrl}?${queryPairs.join('&')}`;
}

function requestRemoteIdAsync(url) {
return new Promise((resolve) => {
ajax(
url,
{
success: response => {
try {
const jsonResponse = JSON.parse(response);
const { iuid } = jsonResponse;
resolve(iuid);
} catch (e) {
resolve();
}
},
error: () => {
resolve();
},
},
undefined,
{
method: 'GET',
contentType: 'application/json'
}
);
});
}

/** @type {Submodule} */
export const mygaruIdSubmodule = {
/**
* used to link submodule with config
* @type {string}
*/
name: bidderCode,
/**
* decode the stored id value for passing to bid requests
* @function
* @returns {{id: string} | null}
*/
decode(id) {
return id;
},
/**
* get the MyGaru Id from local storages and initiate a new user sync
* @function
* @param {SubmoduleConfig} [config]
* @param {ConsentData} [consentData]
* @returns {{id: string | undefined}}
*/
getId(config, consentData) {
const gdprApplies = consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies ? 1 : 0;
const gdprConsentString = gdprApplies ? consentData.consentString : undefined;
const url = buildUrl({
gdprApplies,
gdprConsentString
});

return {
url,
callback: function (done) {
return requestRemoteIdAsync(url).then((id) => {
done({ mygaruId: id });
})
}
}
},
eids: {
'mygaruId': {
source: 'mygaru.com',
atype: 1
},
}
};

submodule('userId', mygaruIdSubmodule);
24 changes: 24 additions & 0 deletions modules/mygaruIdSystem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## Mygaru User ID Submodule

MyGaru provides single use tokens as a UserId for SSPs and DSP that consume telecom DMP data.

## Building Prebid with Mygaru ID Support

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

```
gulp build --modules=userId,mygaruIdSystem
```
Params configuration is not required.
Also mygaru is async, in order to get ids for initial ad auctions you need to add auctionDelay param to userSync config.

```javascript
pbjs.setConfig({
userSync: {
auctionDelay: 100,
userIds: [{
name: 'mygaruId',
}]
}
});
```
7 changes: 7 additions & 0 deletions modules/userId/eids.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,13 @@ userIdAsEids = [
id: 'some-random-id-value',
atype: 3
}]
},
{
source: 'mygaru.com',
uids: [{
id: 'some-random-id-value',
atype: 1
}]
}
]
```
3 changes: 3 additions & 0 deletions modules/userId/userId.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ pbjs.setConfig({
},
{
name: "gravitompId"
},
{
name: "mygaruId"
}
],
syncDelay: 5000,
Expand Down
62 changes: 62 additions & 0 deletions test/spec/modules/mygaruIdSystem_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { mygaruIdSubmodule } from 'modules/mygaruIdSystem.js';
import { server } from '../../mocks/xhr';

describe('MygaruID module', function () {
it('should respond with async callback and get valid id', async () => {
const callBackSpy = sinon.spy();
const expectedUrl = `https://ident.mygaru.com/v2/id?gdprApplies=0`;
const result = mygaruIdSubmodule.getId({});

expect(result.callback).to.be.an('function');
const promise = result.callback(callBackSpy);

const request = server.requests[0];
expect(request.url).to.be.eq(expectedUrl);

request.respond(
200,
{ 'Content-Type': 'application/json' },
JSON.stringify({ iuid: '123' })
);
await promise;

expect(callBackSpy.calledOnce).to.be.true;
expect(callBackSpy.calledWith({mygaruId: '123'})).to.be.true;
});
it('should not fail on error', async () => {
const callBackSpy = sinon.spy();
const expectedUrl = `https://ident.mygaru.com/v2/id?gdprApplies=0`;
const result = mygaruIdSubmodule.getId({});

expect(result.callback).to.be.an('function');
const promise = result.callback(callBackSpy);

const request = server.requests[0];
expect(request.url).to.be.eq(expectedUrl);

request.respond(
500,
{},
''
);
await promise;

expect(callBackSpy.calledOnce).to.be.true;
expect(callBackSpy.calledWith({mygaruId: undefined})).to.be.true;
});

it('should not modify while decoding', () => {
const id = '222';
const newId = mygaruIdSubmodule.decode(id)

expect(id).to.eq(newId);
})
it('should buildUrl with consent data', () => {
const result = mygaruIdSubmodule.getId({}, {
gdprApplies: true,
consentString: 'consentString'
});

expect(result.url).to.eq('https://ident.mygaru.com/v2/id?gdprApplies=1&gdprConsentString=consentString');
})
});

0 comments on commit 04a7659

Please sign in to comment.