Skip to content

Commit b48b569

Browse files
haruka-yamashita2JacobKlein26
authored andcommitted
Dac ID Module: (prebid#9040)
* update dacIdSystem module and related files * modify decoded id and related files * remove useless import * update dacIdSystem.md * fix the linting errors
1 parent 5af37e7 commit b48b569

File tree

5 files changed

+254
-47
lines changed

5 files changed

+254
-47
lines changed

modules/dacIdSystem.js

Lines changed: 145 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,111 @@
55
* @requires module:modules/userId
66
*/
77

8-
import { submodule } from '../src/hook.js';
9-
import { getStorageManager } from '../src/storageManager.js';
8+
import {
9+
logError,
10+
logInfo,
11+
logWarn
12+
} from '../src/utils.js';
13+
import {
14+
ajax
15+
} from '../src/ajax.js'
16+
import {
17+
submodule
18+
} from '../src/hook.js';
19+
import {
20+
getStorageManager
21+
} from '../src/storageManager.js';
1022

1123
export const storage = getStorageManager();
1224

13-
export const cookieKey = '_a1_f';
25+
export const FUUID_COOKIE_NAME = '_a1_f';
26+
export const AONEID_COOKIE_NAME = '_a1_d';
27+
export const API_URL = 'https://penta.a.one.impact-ad.jp/aud';
28+
const COOKIES_EXPIRES = 60 * 60 * 24 * 1000; // 24h
29+
const LOG_PREFIX = 'User ID - dacId submodule: ';
30+
31+
/**
32+
* @returns {{fuuid: string, uid: string}} -
33+
*/
34+
function getCookieId() {
35+
return {
36+
fuuid: storage.getCookie(FUUID_COOKIE_NAME),
37+
uid: storage.getCookie(AONEID_COOKIE_NAME)
38+
};
39+
}
40+
41+
/**
42+
* set uid to cookie.
43+
* @param {string} uid -
44+
* @returns {void} -
45+
*/
46+
function setAoneidToCookie(uid) {
47+
if (uid) {
48+
const expires = new Date(Date.now() + COOKIES_EXPIRES).toUTCString();
49+
storage.setCookie(
50+
AONEID_COOKIE_NAME,
51+
uid,
52+
expires,
53+
'none'
54+
);
55+
}
56+
}
57+
58+
/**
59+
* @param {string} oid -
60+
* @param {string} fuuid -
61+
* @returns {string} -
62+
*/
63+
function getApiUrl(oid, fuuid) {
64+
return `${API_URL}?oid=${oid}&fu=${fuuid}`;
65+
}
66+
67+
/**
68+
* @param {string} oid -
69+
* @param {string} fuuid -
70+
* @returns {{callback: function}} -
71+
*/
72+
function fetchAoneId(oid, fuuid) {
73+
return {
74+
callback: (callback) => {
75+
const ret = {
76+
fuuid,
77+
uid: undefined
78+
};
79+
const callbacks = {
80+
success: (response) => {
81+
if (response) {
82+
try {
83+
const responseObj = JSON.parse(response);
84+
if (responseObj.error) {
85+
logWarn(LOG_PREFIX + 'There is no permission to use API: ' + responseObj.error);
86+
return callback(ret);
87+
}
88+
if (!responseObj.uid) {
89+
logWarn(LOG_PREFIX + 'AoneId is null');
90+
return callback(ret);
91+
}
92+
ret.uid = responseObj.uid;
93+
setAoneidToCookie(ret.uid);
94+
} catch (error) {
95+
logError(LOG_PREFIX + error);
96+
}
97+
}
98+
callback(ret);
99+
},
100+
error: (error) => {
101+
logError(LOG_PREFIX + error);
102+
callback(ret);
103+
}
104+
};
105+
const apiUrl = getApiUrl(oid, fuuid);
106+
ajax(apiUrl, callbacks, undefined, {
107+
method: 'GET',
108+
withCredentials: true
109+
});
110+
},
111+
};
112+
}
14113

15114
export const dacIdSystemSubmodule = {
16115
/**
@@ -20,38 +119,57 @@ export const dacIdSystemSubmodule = {
20119
name: 'dacId',
21120

22121
/**
23-
* performs action to obtain id
24-
* @function
25-
* @returns { {id: {dacId: string}} | undefined }
122+
* decode the stored id value for passing to bid requests
123+
* @param { {fuuid: string, uid: string} } id
124+
* @returns { {dacId: {fuuid: string, dacId: string} } | undefined }
26125
*/
27-
getId: function() {
28-
const newId = storage.getCookie(cookieKey);
29-
if (!newId) {
30-
return undefined;
31-
}
32-
const result = {
33-
dacId: newId
126+
decode(id) {
127+
if (id && typeof id === 'object') {
128+
return {
129+
dacId: {
130+
fuuid: id.fuuid,
131+
id: id.uid
132+
}
133+
}
34134
}
35-
return {id: result};
36135
},
37136

38137
/**
39-
* decode the stored id value for passing to bid requests
138+
* performs action to obtain id
40139
* @function
41-
* @param { {dacId: string} } value
42-
* @returns { {dacId: {id: string} } | undefined }
140+
* @returns { {id: {fuuid: string, uid: string}} | undefined }
43141
*/
44-
decode: function(value) {
45-
if (value && typeof value === 'object') {
46-
const result = {};
47-
if (value.dacId) {
48-
result.id = value.dacId
49-
}
50-
return {dacId: result};
142+
getId(config) {
143+
const cookie = getCookieId();
144+
145+
if (!cookie.fuuid) {
146+
logInfo(LOG_PREFIX + 'There is no fuuid in cookie')
147+
return undefined;
51148
}
52-
return undefined;
53-
},
54149

55-
}
150+
if (cookie.fuuid && cookie.uid) {
151+
logInfo(LOG_PREFIX + 'There is fuuid and AoneId in cookie')
152+
return {
153+
id: {
154+
fuuid: cookie.fuuid,
155+
uid: cookie.uid
156+
}
157+
};
158+
}
159+
160+
const configParams = (config && config.params) || {};
161+
if (!configParams || typeof configParams.oid !== 'string') {
162+
logWarn(LOG_PREFIX + 'oid is not defined');
163+
return {
164+
id: {
165+
fuuid: cookie.fuuid,
166+
uid: undefined
167+
}
168+
};
169+
}
170+
171+
return fetchAoneId(configParams.oid, cookie.fuuid);
172+
}
173+
};
56174

57175
submodule('userId', dacIdSystemSubmodule);

modules/dacIdSystem.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
## AudienceOne User ID Submodule
22

33
AudienceOne ID, provided by [D.A.Consortium Inc.](https://www.dac.co.jp/), is ID for ad targeting by using 1st party cookie.
4-
Please contact D.A.Consortium Inc. before using this ID.
4+
Please visit [https://solutions.dac.co.jp/audienceone](https://solutions.dac.co.jp/audienceone) and request your Owner ID to get started.
55

66
## Building Prebid with AudienceOne ID Support
77

@@ -17,7 +17,10 @@ The following configuration parameters are available:
1717
pbjs.setConfig({
1818
userSync: {
1919
userIds: [{
20-
name: 'dacId'
20+
name: 'dacId',
21+
params: {
22+
'oid': '55h67qm4ck37vyz5'
23+
}
2124
}]
2225
}
2326
});
@@ -26,3 +29,5 @@ pbjs.setConfig({
2629
| Param under userSync.userIds[] | Scope | Type | Description | Example |
2730
| --- | --- | --- | --- | --- |
2831
| name | Required | String | The name of this module. | `"dacId"` |
32+
| params | Required | Object | Details of module params. | |
33+
| params.oid | Required | String | This is the Owner ID value obtained via D.A.Consortium Inc. | `"55h67qm4ck37vyz5"` |

modules/yieldoneBidAdapter.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,13 @@ export const spec = {
7474
}
7575

7676
// DACID
77-
const dacId = deepAccess(bidRequest, 'userId.dacId.id');
78-
if (isStr(dacId) && !isEmpty(dacId)) {
79-
payload.dac_id = dacId;
80-
payload.fuuid = dacId;
77+
const fuuid = deepAccess(bidRequest, 'userId.dacId.fuuid');
78+
const dacid = deepAccess(bidRequest, 'userId.dacId.id');
79+
if (isStr(fuuid) && !isEmpty(fuuid)) {
80+
payload.fuuid = fuuid;
81+
}
82+
if (isStr(dacid) && !isEmpty(dacid)) {
83+
payload.dac_id = dacid;
8184
}
8285

8386
// ID5

test/spec/modules/dacIdSystem_spec.js

Lines changed: 93 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1-
import { dacIdSystemSubmodule, storage, cookieKey } from 'modules/dacIdSystem.js';
1+
import {
2+
dacIdSystemSubmodule,
3+
storage,
4+
FUUID_COOKIE_NAME,
5+
AONEID_COOKIE_NAME
6+
} from 'modules/dacIdSystem.js';
7+
import { server } from 'test/mocks/xhr.js';
28

3-
const DACID_DUMMY_VALUE = 'dacIdTest';
9+
const FUUID_DUMMY_VALUE = 'dacIdTest';
10+
const AONEID_DUMMY_VALUE = '12345'
411
const DACID_DUMMY_OBJ = {
5-
dacId: DACID_DUMMY_VALUE
12+
fuuid: FUUID_DUMMY_VALUE,
13+
uid: AONEID_DUMMY_VALUE
614
};
715

816
describe('dacId module', function () {
@@ -23,24 +31,98 @@ describe('dacId module', function () {
2331
''
2432
]
2533

34+
const configParamTestCase = {
35+
params: {
36+
oid: [
37+
'637c1b6fc26bfad0', // valid
38+
'e8316b39c08029e1' // invalid
39+
]
40+
}
41+
}
42+
2643
describe('getId()', function () {
27-
it('should return the uid when it exists in cookie', function () {
28-
getCookieStub.withArgs(cookieKey).returns(DACID_DUMMY_VALUE);
44+
it('should return undefined when oid & fuuid not exist', function () {
45+
// no oid, no fuuid
2946
const id = dacIdSystemSubmodule.getId();
30-
expect(id).to.be.deep.equal({id: {dacId: DACID_DUMMY_VALUE}});
47+
expect(id).to.equal(undefined);
3148
});
3249

33-
cookieTestCasesForEmpty.forEach(testCase => it('should return the uid when it not exists in cookie', function () {
34-
getCookieStub.withArgs(cookieKey).returns(testCase);
50+
it('should return fuuid when oid not exists but fuuid exists', function () {
51+
// no oid, fuuid
52+
getCookieStub.withArgs(FUUID_COOKIE_NAME).returns(FUUID_DUMMY_VALUE);
3553
const id = dacIdSystemSubmodule.getId();
36-
expect(id).to.be.deep.equal(undefined);
54+
expect(id).to.be.deep.equal({
55+
id: {
56+
fuuid: FUUID_DUMMY_VALUE,
57+
uid: undefined
58+
}
59+
});
60+
});
61+
62+
it('should return fuuid when oid is invalid but fuuid exists', function () {
63+
// invalid oid, fuuid, no AoneId
64+
getCookieStub.withArgs(FUUID_COOKIE_NAME).returns(FUUID_DUMMY_VALUE);
65+
const id = dacIdSystemSubmodule.getId(configParamTestCase.params.oid[1]);
66+
expect(id).to.be.deep.equal({
67+
id: {
68+
fuuid: FUUID_DUMMY_VALUE,
69+
uid: undefined
70+
}
71+
});
72+
});
73+
74+
cookieTestCasesForEmpty.forEach(testCase => it('should return undefined when fuuid not exists', function () {
75+
// valid oid, no fuuid, no AoneId
76+
getCookieStub.withArgs(FUUID_COOKIE_NAME).returns(testCase);
77+
const id = dacIdSystemSubmodule.getId(configParamTestCase.params.oid[0]);
78+
expect(id).to.equal(undefined);
3779
}));
80+
81+
it('should return AoneId when AoneId not exists', function () {
82+
// valid oid, fuuid, no AoneId
83+
getCookieStub.withArgs(FUUID_COOKIE_NAME).returns(FUUID_DUMMY_VALUE);
84+
const callbackSpy = sinon.spy();
85+
const callback = dacIdSystemSubmodule.getId({params: {oid: configParamTestCase.params.oid[0]}}).callback;
86+
callback(callbackSpy);
87+
const request = server.requests[0];
88+
request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({'uid': AONEID_DUMMY_VALUE}));
89+
expect(callbackSpy.lastCall.lastArg).to.deep.equal({fuuid: 'dacIdTest', uid: AONEID_DUMMY_VALUE});
90+
});
91+
92+
cookieTestCasesForEmpty.forEach(testCase => it('should return undefined when AoneId not exists & API result is empty', function () {
93+
// valid oid, fuuid, no AoneId, API result empty
94+
getCookieStub.withArgs(FUUID_COOKIE_NAME).returns(FUUID_DUMMY_VALUE);
95+
const callbackSpy = sinon.spy();
96+
const callback = dacIdSystemSubmodule.getId({params: {oid: configParamTestCase.params.oid[0]}}).callback;
97+
callback(callbackSpy);
98+
const request = server.requests[0];
99+
request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({'uid': testCase}));
100+
expect(callbackSpy.lastCall.lastArg).to.deep.equal({fuuid: 'dacIdTest', uid: undefined});
101+
}));
102+
103+
it('should return the fuuid & AoneId when they exist', function () {
104+
// valid oid, fuuid, AoneId
105+
getCookieStub.withArgs(FUUID_COOKIE_NAME).returns(FUUID_DUMMY_VALUE);
106+
getCookieStub.withArgs(AONEID_COOKIE_NAME).returns(AONEID_DUMMY_VALUE);
107+
const id = dacIdSystemSubmodule.getId(configParamTestCase.params.oid[0]);
108+
expect(id).to.be.deep.equal({
109+
id: {
110+
fuuid: FUUID_DUMMY_VALUE,
111+
uid: AONEID_DUMMY_VALUE
112+
}
113+
});
114+
});
38115
});
39116

40117
describe('decode()', function () {
41-
it('should return the uid when it exists in cookie', function () {
118+
it('should return fuuid & AoneId when they exist', function () {
42119
const decoded = dacIdSystemSubmodule.decode(DACID_DUMMY_OBJ);
43-
expect(decoded).to.be.deep.equal({dacId: {id: DACID_DUMMY_VALUE}});
120+
expect(decoded).to.be.deep.equal({
121+
dacId: {
122+
fuuid: FUUID_DUMMY_VALUE,
123+
id: AONEID_DUMMY_VALUE
124+
}
125+
});
44126
});
45127

46128
it('should return the undefined when decode id is not "string"', function () {

test/spec/modules/yieldoneBidAdapter_spec.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { expect } from 'chai';
22
import { spec } from 'modules/yieldoneBidAdapter.js';
33
import { newBidder } from 'src/adapters/bidderFactory.js';
4-
import { deepClone } from 'src/utils.js';
54

65
const ENDPOINT = 'https://y.one.impact-ad.jp/h_bid';
76
const USER_SYNC_URL = 'https://y.one.impact-ad.jp/push_sync';
@@ -428,12 +427,12 @@ describe('yieldoneBidAdapter', function() {
428427
const bidRequests = [
429428
{
430429
params: {placementId: '0'},
431-
userId: {dacId: {id: 'dacId_sample'}},
430+
userId: {dacId: {fuuid: 'fuuid_sample', id: 'dacId_sample'}},
432431
},
433432
];
434433
const request = spec.buildRequests(bidRequests, bidderRequest);
434+
expect(request[0].data.fuuid).to.equal('fuuid_sample');
435435
expect(request[0].data.dac_id).to.equal('dacId_sample');
436-
expect(request[0].data.fuuid).to.equal('dacId_sample');
437436
});
438437
});
439438

0 commit comments

Comments
 (0)