From bdb661fb67a390a5f062049971b1d0d4d10114a9 Mon Sep 17 00:00:00 2001 From: li-ran <70167305+li-ran@users.noreply.github.com> Date: Wed, 17 Feb 2021 06:08:17 -0500 Subject: [PATCH] IndexExchange Bid Adapter: Added support for netID, ID+ and FabrickId userId (#6286) * added more userID partner support for IX adapter - TDID, LI, NetID, Neustar, Zeotap * removed liveintent and adsrvr.org [DNA-5040] * updated neustar id * fixed fabrickid * frabrickId instead of id * added more userID partner support for IX adapter - NetID, Neustar, Zeotap (#1) * added more userID partner support for IX adapter - TDID, LI, NetID, Neustar, Zeotap * added tests * added tests for new userinfo modules * missed a few checks * Dna 5040 ix userid support (#2) * added more userID partner support for IX adapter - TDID, LI, NetID, Neustar, Zeotap * removed liveintent and adsrvr.org [DNA-5040] * updated neustar id * fixed fabrickid * frabrickId instead of id * added tests * added tests for new userinfo modules * missed a few checks Co-authored-by: Ran Li * added few missing checks in IX adapter * Use userIdAsEids instead of userId (#3) * use eids, revert package-lock * test update Co-authored-by: Ran Li Co-authored-by: amykwyang --- modules/ixBidAdapter.js | 78 ++++++++++------------ test/spec/modules/ixBidAdapter_spec.js | 90 ++++++++++++++++++++++++-- 2 files changed, 116 insertions(+), 52 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 699209a12e9..7ddad134451 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -212,36 +212,35 @@ function getBidRequest(id, impressions) { } /** - * Adds a User ID module's response into user Eids array. - * - * @param {array} userEids An array of objects containing user ids, - * will be attached to bid request later. - * @param {object} seenIdPartners An object with Identity partners names already added, - * updated with new partner name. - * @param {*} id The id obtained from User ID module. - * @param {string} source The URL of the User ID module. - * @param {string} ixlPartnerName The name of the Identity Partner in IX Library. - * @param {string} rtiPartner The name of the User ID provider in Prebid. - * @return {boolean} True if successfully added the ID to the userEids, false otherwise. + * From the userIdAsEids array, filter for the ones our adserver can use, and modify them + * for our purposes, e.g. add rtiPartner + * @param {array} allEids userIdAsEids passed in by prebid + * @return {object} contains toSend (eids to send to the adserver) and seenSources (used to filter + * identity info from IX Library) */ -function addUserEids(userEids, seenIdPartners, id, source, ixlPartnerName, rtiPartner) { - if (id) { - // mark the partnername that IX RTI uses - seenIdPartners[ixlPartnerName] = 1; - userEids.push({ - source: source, - uids: [{ - id: id, - ext: { - rtiPartner: rtiPartner - } - }] - }); - return true; +function getEidInfo(allEids) { + // determines which eids we send and the rtiPartner field in ext + var sourceRTIMapping = { + 'liveramp.com': 'idl', + 'netid.de': 'NETID', + 'neustar.biz': 'fabrickId', + 'zeotap.com': 'zeotapIdPlus' + }; + var toSend = []; + var seenSources = {}; + if (utils.isArray(allEids)) { + for (var i = 0; i < allEids.length; i++) { + if (sourceRTIMapping[allEids[i].source] && utils.deepAccess(allEids[i], 'uids.0')) { + seenSources[allEids[i].source] = 1; + allEids[i].uids[0].ext = { + rtiPartner: sourceRTIMapping[allEids[i].source] + }; + delete allEids[i].uids[0].atype; + toSend.push(allEids[i]); + } + } } - - utils.logWarn('Tried to add a user ID from Prebid, the ID received was null'); - return false; + return { toSend: toSend, seenSources: seenSources }; } /** @@ -255,21 +254,12 @@ function addUserEids(userEids, seenIdPartners, id, source, ixlPartnerName, rtiPa * */ function buildRequest(validBidRequests, bidderRequest, impressions, version) { - const userEids = []; - // Always use secure HTTPS protocol. let baseUrl = SECURE_BID_URL; - // Dict for identity partners already populated from prebid - let seenIdPartners = {}; - // Get ids from Prebid User ID Modules - const userId = validBidRequests[0].userId; - if (userId && typeof userId === 'object') { - if (userId.idl_env) { - addUserEids(userEids, seenIdPartners, userId.idl_env, 'liveramp.com', 'LiveRampIp', 'idl'); - } - } + var eidInfo = getEidInfo(utils.deepAccess(validBidRequests, '0.userIdAsEids')); + var userEids = eidInfo.toSend; // RTI ids will be included in the bid request if the function getIdentityInfo() is loaded // and if the data for the partner exist @@ -278,12 +268,10 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { if (identityInfo && typeof identityInfo === 'object') { for (const partnerName in identityInfo) { if (identityInfo.hasOwnProperty(partnerName)) { - // check if not already populated by prebid cache - if (!seenIdPartners.hasOwnProperty(partnerName)) { - let response = identityInfo[partnerName]; - if (!response.responsePending && response.data && typeof response.data === 'object' && Object.keys(response.data).length) { - userEids.push(response.data); - } + let response = identityInfo[partnerName]; + if (!response.responsePending && response.data && typeof response.data === 'object' && + Object.keys(response.data).length && !eidInfo.seenSources[response.data.source]) { + userEids.push(response.data); } } } diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index 354898207a5..6d7b3a397bd 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -3,6 +3,7 @@ import { config } from 'src/config.js'; import { expect } from 'chai'; import { newBidder } from 'src/adapters/bidderFactory.js'; import { spec } from 'modules/ixBidAdapter.js'; +import { createEidsArray } from 'modules/userId/eids.js'; describe('IndexexchangeAdapter', function () { const IX_SECURE_ENDPOINT = 'https://htlb.casalemedia.com/cygnus'; @@ -351,8 +352,13 @@ describe('IndexexchangeAdapter', function () { const DEFAULT_USERID_DATA = { idl_env: '1234-5678-9012-3456', // Liveramp + netId: 'testnetid123', // NetId + IDP: 'userIDP000', // IDP + fabrickId: 'fabrickId9000', // FabrickId }; + const DEFAULT_USERIDASEIDS_DATA = createEidsArray(DEFAULT_USERID_DATA); + const DEFAULT_USERID_PAYLOAD = [ { source: 'liveramp.com', @@ -362,6 +368,30 @@ describe('IndexexchangeAdapter', function () { rtiPartner: 'idl' } }] + }, { + source: 'netid.de', + uids: [{ + id: DEFAULT_USERID_DATA.netId, + ext: { + rtiPartner: 'NETID' + } + }] + }, { + source: 'neustar.biz', + uids: [{ + id: DEFAULT_USERID_DATA.fabrickId, + ext: { + rtiPartner: 'fabrickId' + } + }] + }, { + source: 'zeotap.com', + uids: [{ + id: DEFAULT_USERID_DATA.IDP, + ext: { + rtiPartner: 'zeotapIdPlus' + } + }] } ]; @@ -761,14 +791,18 @@ describe('IndexexchangeAdapter', function () { delete window.headertag; }); - it('IX adapter reads LiveRamp IDL envelope from Prebid and adds it to Video', function () { + it('IX adapter reads supported user modules from Prebid and adds it to Video', function () { const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID); - cloneValidBid[0].userId = utils.deepClone(DEFAULT_USERID_DATA); + // cloneValidBid[0].userId = utils.deepClone(DEFAULT_USERID_DATA); + cloneValidBid[0].userIdAsEids = utils.deepClone(DEFAULT_USERIDASEIDS_DATA); const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; const payload = JSON.parse(request.data.r); - expect(payload.user.eids).to.have.lengthOf(1); + expect(payload.user.eids).to.have.lengthOf(4); expect(payload.user.eids).to.deep.include(DEFAULT_USERID_PAYLOAD[0]); + expect(payload.user.eids).to.deep.include(DEFAULT_USERID_PAYLOAD[1]); + expect(payload.user.eids).to.deep.include(DEFAULT_USERID_PAYLOAD[2]); + expect(payload.user.eids).to.deep.include(DEFAULT_USERID_PAYLOAD[3]); }); it('We continue to send in IXL identity info and Prebid takes precedence over IXL', function () { @@ -822,11 +856,45 @@ describe('IndexexchangeAdapter', function () { } } ] + }, + NetIdIp: { + source: 'netid.de', + uids: [ + { + id: 'testnetid', + ext: { + rtiPartner: 'NETID' + } + } + ] + }, + NeustarIp: { + source: 'neustar.biz', + uids: [ + { + id: 'testfabrick', + ext: { + rtiPartner: 'fabrickId' + } + } + ] + }, + ZeotapIp: { + source: 'zeotap.com', + uids: [ + { + id: 'testzeotap', + ext: { + rtiPartner: 'zeotapIdPlus' + } + } + ] } }; const cloneValidBid = utils.deepClone(DEFAULT_BANNER_VALID_BID); - cloneValidBid[0].userId = utils.deepClone(DEFAULT_USERID_DATA) + // cloneValidBid[0].userId = utils.deepClone(DEFAULT_USERID_DATA); + cloneValidBid[0].userIdAsEids = utils.deepClone(DEFAULT_USERIDASEIDS_DATA); const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; const payload = JSON.parse(request.data.r); @@ -867,10 +935,14 @@ describe('IndexexchangeAdapter', function () { }) expect(payload.user).to.exist; - expect(payload.user.eids).to.have.lengthOf(3); + expect(payload.user.eids).to.have.lengthOf(6); + expect(payload.user.eids).to.deep.include(validUserIdPayload[0]); expect(payload.user.eids).to.deep.include(validUserIdPayload[1]); expect(payload.user.eids).to.deep.include(validUserIdPayload[2]); + expect(payload.user.eids).to.deep.include(validUserIdPayload[3]); + expect(payload.user.eids).to.deep.include(validUserIdPayload[4]); + expect(payload.user.eids).to.deep.include(validUserIdPayload[5]); }); it('IXL and Prebid are mutually exclusive', function () { @@ -892,7 +964,8 @@ describe('IndexexchangeAdapter', function () { }; const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID); - cloneValidBid[0].userId = utils.deepClone(DEFAULT_USERID_DATA); + // cloneValidBid[0].userId = utils.deepClone(DEFAULT_USERID_DATA); + cloneValidBid[0].userIdAsEids = utils.deepClone(DEFAULT_USERIDASEIDS_DATA); const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; @@ -910,9 +983,12 @@ describe('IndexexchangeAdapter', function () { }); const payload = JSON.parse(request.data.r); - expect(payload.user.eids).to.have.lengthOf(2); + expect(payload.user.eids).to.have.lengthOf(5); expect(payload.user.eids).to.deep.include(validUserIdPayload[0]); expect(payload.user.eids).to.deep.include(validUserIdPayload[1]); + expect(payload.user.eids).to.deep.include(validUserIdPayload[2]); + expect(payload.user.eids).to.deep.include(validUserIdPayload[3]); + expect(payload.user.eids).to.deep.include(validUserIdPayload[4]); }); });