Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NoBid Bid Adapter : add support for first party user id #10519

Merged
merged 37 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0eba11e
Enable supplyChain support
redaguermas Mar 4, 2020
c0fb8ee
Added support for COPPA
redaguermas Mar 5, 2020
36fab76
Merge branch 'master' of https://github.com/prebid/Prebid.js
redaguermas Mar 13, 2020
51525d7
Merge branch 'master' of https://github.com/prebid/Prebid.js
redaguermas Apr 13, 2020
c473780
Merge remote-tracking branch 'upstream/master'
Jun 1, 2020
33757b8
Merge branch 'master' of https://github.com/prebid/Prebid.js
Jun 4, 2020
9e1758b
Merge branch 'master' of https://github.com/prebid/Prebid.js
Jun 19, 2020
1d7db5d
Merge branch 'master' of https://github.com/prebid/Prebid.js
Aug 18, 2020
8fca715
Merge branch 'master' of https://github.com/prebid/Prebid.js
Aug 26, 2020
c11a5b3
rebuilt
Sep 27, 2020
c44bd3f
Merge branch 'master' of https://github.com/prebid/Prebid.js
Sep 27, 2020
9c8440c
Added support for Extended User IDs.
Sep 28, 2020
ec5cde7
Merge branch 'master' of https://github.com/prebid/Prebid.js
May 28, 2021
ff10bbe
Added support for the "meta" attribute in bid response.
May 28, 2021
4a4c253
Merge branch 'master' of https://github.com/prebid/Prebid.js
Jul 13, 2021
01a2d94
Merge branch 'master' of https://github.com/prebid/Prebid.js
Sep 27, 2021
61583a2
Merge branch 'master' of https://github.com/prebid/Prebid.js
Mar 7, 2023
00142cc
Merge branch 'master' of https://github.com/prebid/Prebid.js
Mar 31, 2023
d6160fa
Merge branch 'master' of https://github.com/prebid/Prebid.js
Jul 4, 2023
388d3e0
Delete nobidBidAdapter.js.orig
redaguermas Jul 28, 2023
1c3f853
Delete a
redaguermas Jul 28, 2023
38dc58a
Delete .jsdtscope
redaguermas Jul 28, 2023
2818cbe
Delete org.eclipse.wst.jsdt.ui.superType.container
redaguermas Jul 28, 2023
ad8662d
Delete org.eclipse.wst.jsdt.ui.superType.name
redaguermas Jul 28, 2023
8ddb9a9
Delete .project
redaguermas Jul 28, 2023
a164194
Merge branch 'master' of https://github.com/redaguermas/Prebid.js
Aug 7, 2023
0a5fbc6
Merge branch 'master' of https://github.com/prebid/Prebid.js
Aug 10, 2023
c2a5fc4
Merge branch 'master' of https://github.com/prebid/Prebid.js
Aug 10, 2023
a144f4a
Merge branch 'master' of https://github.com/prebid/Prebid.js
Aug 21, 2023
19caf0e
Merge branch 'master' of https://github.com/prebid/Prebid.js
Aug 21, 2023
e92612e
Merge branch 'master' of https://github.com/prebid/Prebid.js
Aug 24, 2023
b4cdf09
Merge branch 'master' of https://github.com/prebid/Prebid.js
Aug 29, 2023
d2b8b26
Merge branch 'master' of https://github.com/prebid/Prebid.js
Sep 19, 2023
b5e4f5c
Merge branch 'master' of https://github.com/prebid/Prebid.js
Sep 21, 2023
ca24cfb
Merge branch 'master' of https://github.com/prebid/Prebid.js
Sep 22, 2023
13367e7
Fix tests
Sep 22, 2023
85e9a2c
Added support for First Party User ID in NoBid Bid Adapter.
Sep 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 122 additions & 1 deletion modules/nobidBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,17 @@ import { hasPurpose1Consent } from '../src/utils/gpdr.js';
const GVLID = 816;
const BIDDER_CODE = 'nobid';
const storage = getStorageManager({bidderCode: BIDDER_CODE});
window.nobidVersion = '1.3.3';
window.nobidVersion = '1.4.1';
window.nobid = window.nobid || {};
window.nobid.bidResponses = window.nobid.bidResponses || {};
window.nobid.timeoutTotal = 0;
window.nobid.bidWonTotal = 0;
window.nobid.refreshCount = 0;
window.nobid.firstPartyIds = null;
window.nobid.firstPartyIdEnabled = false;
const FIRST_PARTY_KEY = 'fppcid.nobid.io';
const FIRST_PARTY_SOURCE_KEY = 'fpid.nobid.io';
const FIRST_PARTY_DATA_EXPIRY_DAYS = 7 * 24 * 3600 * 1000;
function log(msg, obj) {
logInfo('-NoBid- ' + msg, obj)
}
Expand Down Expand Up @@ -135,8 +140,10 @@ function nobidBuildRequests(bids, bidderRequest) {
src.push({source: eid.source, uids: ids});
}
});
if (window.nobid.firstPartyIds && window.nobid.firstPartyIds) src.push({source: FIRST_PARTY_SOURCE_KEY, uids: [{id: window.nobid.firstPartyIds.ids}]});
return src;
}
if (window.nobid.firstPartyIds && window.nobid.firstPartyIds.ids) return [{source: FIRST_PARTY_SOURCE_KEY, uids: [{id: window.nobid.firstPartyIds.ids}]}];
}
var state = {};
state['sid'] = siteId;
Expand Down Expand Up @@ -286,13 +293,20 @@ function nobidInterpretResponse(response, bidRequest) {
var setRefreshLimit = function(response) {
if (response && typeof response.rlimit !== 'undefined') window.nobid.refreshLimit = response.rlimit;
}
var setFirstPartyIdEnabled = function(response) {
if (response && typeof response.fpid !== 'undefined') window.nobid.firstPartyIdEnabled = response.fpid;
if (window?.nobid?.firstPartyIdEnabled) {
nobidFirstPartyData.loadOrCreateFirstPartyData();
}
}
var setUserBlock = function(response) {
if (response && typeof response.ublock !== 'undefined') {
nobidSetCookie('_ublock', '1', response.ublock);
}
}
setRefreshLimit(response);
setUserBlock(response);
setFirstPartyIdEnabled(response);
var bidResponses = [];
for (var i = 0; response.bids && i < response.bids.length; i++) {
var bid = response.bids[i];
Expand Down Expand Up @@ -359,6 +373,113 @@ window.addEventListener('message', function (event) {
}
}
}, false);
const nobidFirstPartyData = {
isJson: function (str) {
return str && str.startsWith('{') && str.endsWith('}');
},
hasLocalStorage: function () {
try {
return window.localStorage;
} catch (error) {
logWarn('Local storage api disabled', error);
}
return false;
},
readFirstPartyDataIds: function () {
try {
if (this.hasLocalStorage()) {
const idsStr = window.localStorage.getItem(FIRST_PARTY_SOURCE_KEY);
if (this.isJson(idsStr)) {
const idsObj = JSON.parse(idsStr);
if (idsObj.ts + FIRST_PARTY_DATA_EXPIRY_DAYS < Date.now()) return { pid: idsObj.pid }; // expired?
return idsObj;
}
return null;
}
} catch (error) {
logWarn('Local storage api disabled', error);
}
return null;
},
loadOrCreateFirstPartyData: function () {
const storeFirstPartyDataIds = function ({ids: theIds, pid: thePid}) {
try {
if (nobidFirstPartyData.hasLocalStorage()) {
window.localStorage.setItem(FIRST_PARTY_SOURCE_KEY, JSON.stringify({ids: theIds, pid: thePid, ts: Date.now()}));
}
} catch (error) {
logWarn('Local storage api disabled', error);
}
};
const readFirstPartyId = function () {
try {
if (nobidFirstPartyData.hasLocalStorage()) {
const idStr = window.localStorage.getItem(FIRST_PARTY_KEY);
if (nobidFirstPartyData.isJson(idStr)) {
return JSON.parse(idStr);
}
return null;
}
} catch (error) {
logWarn('Local storage api disabled', error);
}
return null;
};
const storeFirstPartyId = function (theId) {
try {
if (nobidFirstPartyData.hasLocalStorage()) {
window.localStorage.setItem(FIRST_PARTY_KEY, JSON.stringify(theId));
}
} catch (error) {
logWarn('Local storage api disabled', error);
}
};
const _loadOrCreateFirstPartyData = function () {
const generateGUID = function () {
let d = new Date().getTime();
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
});
};
const ajaxGet = function (ajaxParams, callback) {
const ajax = new XMLHttpRequest();
ajax.withCredentials = false;
ajax.timeout = ajaxParams.timeout;
ajax.open('GET', ajaxParams.url, true);
ajax.onreadystatechange = function () {
if (this.readyState === XMLHttpRequest.DONE) {
callback(this.response);
}
};
ajax.send(ajaxParams.data);
};
let firstPartyIdObj = readFirstPartyId();
if (!firstPartyIdObj || !firstPartyIdObj.id || !firstPartyIdObj.ts) {
const firstPartyId = generateGUID();
firstPartyIdObj = {id: firstPartyId, ts: Date.now()};
storeFirstPartyId(firstPartyIdObj);
}
let firstPartyIds = nobidFirstPartyData.readFirstPartyDataIds();
if (firstPartyIdObj?.ts && !firstPartyIds?.ids) {
const pid = firstPartyIds?.pid || '';
const pdate = firstPartyIdObj.ts;
const firstPartyId = firstPartyIdObj.id;
const url = `https://api.intentiq.com/profiles_engine/ProfilesEngineServlet?at=39&mi=10&pt=17&dpn=1&iiqidtype=2&dpi=430542822&iiqpcid=${firstPartyId}&iiqpciddate=${pdate}&pid=${pid}`;
if (window.nobid.firstPartyRequestInProgress) return;
window.nobid.firstPartyRequestInProgress = true;
ajaxGet({ url: url }, function (response) {
response = JSON.parse(response);
if (response?.data) storeFirstPartyDataIds({ ids: response.data, pid: response.pid });
});
}
};
window.nobid.firstPartyIds = this.readFirstPartyDataIds();
if (window.nobid.firstPartyIdEnabled && !window.nobid.firstPartyIds?.ids) _loadOrCreateFirstPartyData();
}
};
window.nobid.firstPartyIds = nobidFirstPartyData.readFirstPartyDataIds();
export const spec = {
code: BIDDER_CODE,
gvlid: GVLID,
Expand Down
129 changes: 90 additions & 39 deletions test/spec/modules/nobidBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,27 +57,26 @@ describe('Nobid Adapter', function () {
'auctionId': '1d1a030790a475',
};

it('should return true when required params found', function () {
it('should return true when required params found 1', function () {
expect(spec.isBidRequestValid(bid)).to.equal(true);
});

it('should return true when required params found', function () {
let bid = Object.assign({}, bid);
delete bid.params;
bid.params = {
it('should return true when required params found 2', function () {
let mybid = Object.assign({}, bid);
delete mybid.params;
mybid.params = {
'siteId': 2
};

expect(spec.isBidRequestValid(bid)).to.equal(true);
expect(spec.isBidRequestValid(mybid)).to.equal(true);
});

it('should return false when required params are not passed', function () {
let bid = Object.assign({}, bid);
delete bid.params;
bid.params = {
let mybid = Object.assign({}, bid);
delete mybid.params;
mybid.params = {
'siteId': 0
};
expect(spec.isBidRequestValid(bid)).to.equal(false);
expect(spec.isBidRequestValid(mybid)).to.equal(false);
});
});

Expand Down Expand Up @@ -253,12 +252,12 @@ describe('Nobid Adapter', function () {
});

it('sends bid request to site id', function () {
const request = spec.buildRequests(bidRequests);
const payload = JSON.parse(request.data);
expect(payload.a).to.exist;
expect(payload.a[0].sid).to.equal(2);
expect(payload.a[0].at).to.equal('banner');
expect(payload.a[0].params.siteId).to.equal(2);
const request = spec.buildRequests(bidRequests);
const payload = JSON.parse(request.data);
expect(payload.a).to.exist;
expect(payload.a[0].sid).to.equal(2);
expect(payload.a[0].at).to.equal('banner');
expect(payload.a[0].params.siteId).to.equal(2);
});

it('sends bid request to ad type', function () {
Expand Down Expand Up @@ -423,6 +422,58 @@ describe('Nobid Adapter', function () {
});
});

describe('First Party ID Test', function () {
const CREATIVE_ID_300x250 = 'CREATIVE-100';
const ADUNIT_300x250 = 'ADUNIT-1';
const ADMARKUP_300x250 = 'ADMARKUP-300x250';
const PRICE_300x250 = 0.51;
const REQUEST_ID = '3db3773286ee59';
const DEAL_ID = 'deal123';
let response = {
country: 'US',
ip: '68.83.15.75',
device: 'COMPUTER',
site: 2,
fpid: true,
bids: [
{id: 1,
bdrid: 101,
divid: ADUNIT_300x250,
creativeid: CREATIVE_ID_300x250,
size: {'w': 300, 'h': 250},
adm: ADMARKUP_300x250,
price: '' + PRICE_300x250
}
]
};

it('first party ID', function () {
const bidderRequest = {
bids: [{
bidId: REQUEST_ID,
adUnitCode: ADUNIT_300x250
}]
}
const bidRequests = [
{
'bidder': 'nobid',
'params': {
'siteId': 2
},
'adUnitCode': 'adunit-code',
'sizes': [[300, 250]],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
'auctionId': '1d1a030790a475',
}
];
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.method).to.equal('POST');
spec.interpretResponse({ body: response }, {bidderRequest: bidderRequest});
expect(window.nobid.firstPartyIdEnabled).to.equal(true);
});
});

describe('isVideoBidRequestValid', function () {
let bid = {
bidder: 'nobid',
Expand Down Expand Up @@ -635,12 +686,12 @@ describe('Nobid Adapter', function () {
});

it('sends bid request to site id', function () {
const request = spec.buildRequests(bidRequests);
const payload = JSON.parse(request.data);
expect(payload.a).to.exist;
expect(payload.a[0].sid).to.equal(2);
expect(payload.a[0].at).to.equal('banner');
expect(payload.a[0].params.siteId).to.equal(2);
const request = spec.buildRequests(bidRequests);
const payload = JSON.parse(request.data);
expect(payload.a).to.exist;
expect(payload.a[0].sid).to.equal(2);
expect(payload.a[0].at).to.equal('banner');
expect(payload.a[0].params.siteId).to.equal(2);
});

it('sends bid request to ad type', function () {
Expand Down Expand Up @@ -939,19 +990,19 @@ describe('Nobid Adapter', function () {
auctionId: '1d1a030790a475',
coppa: true,
schain: {
validation: 'strict',
config: {
ver: '1.0',
complete: 1,
nodes: [
{
asi: 'indirectseller.com',
sid: '00001',
name: 'name.com',
hp: 1
}
]
}
validation: 'strict',
config: {
ver: '1.0',
complete: 1,
nodes: [
{
asi: 'indirectseller.com',
sid: '00001',
name: 'name.com',
hp: 1
}
]
}
}
}
];
Expand Down Expand Up @@ -1001,7 +1052,7 @@ describe('Nobid Adapter', function () {
]
};

it('should ULimit be respected', function () {
it('Limit should be respected', function () {
const bidderRequest = {
bids: [{
bidId: REQUEST_ID,
Expand Down Expand Up @@ -1060,8 +1111,8 @@ describe('Nobid Adapter', function () {
});

it('should get correct user sync when !iframeEnabled', function () {
let pixel = spec.getUserSyncs({})
expect(pixel.length).to.equal(0);
let pixel = spec.getUserSyncs({})
expect(pixel.length).to.equal(0);
});
});

Expand Down