From 9bbd8e8c72f87ca7dfcb496fd74bcac424b97444 Mon Sep 17 00:00:00 2001 From: IX-Prebid-Support Date: Fri, 26 Jun 2020 15:46:46 -0400 Subject: [PATCH 1/2] Added support for Liveramp userId submodule --- modules/ixBidAdapter.js | 53 ++++++- test/spec/modules/ixBidAdapter_spec.js | 192 +++++++++++++++++++++++++ 2 files changed, 242 insertions(+), 3 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index f4c42080f58..25eabd8f8eb 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -194,6 +194,39 @@ function getBidRequest(id, impressions) { return find(impressions, imp => imp.id === id); } +/** + * 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. + */ +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; + } + + utils.logWarn('Tried to add a user ID from Prebid, the ID received was null'); + return false; +} + /** * Builds a request object to be sent to the ad server based on bid requests. * @@ -210,6 +243,17 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { // 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'); + } + } + // RTI ids will be included in the bid request if the function getIdentityInfo() is loaded // and if the data for the partner exist if (window.headertag && typeof window.headertag.getIdentityInfo === 'function') { @@ -217,9 +261,12 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { if (identityInfo && typeof identityInfo === 'object') { for (const partnerName in identityInfo) { if (identityInfo.hasOwnProperty(partnerName)) { - let response = identityInfo[partnerName]; - if (!response.responsePending && response.data && typeof response.data === 'object' && Object.keys(response.data).length) { - userEids.push(response.data); + // 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); + } } } } diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index 114a2226770..d06bdc48f1a 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -190,6 +190,22 @@ describe('IndexexchangeAdapter', function () { v: 8.1 }; + const DEFAULT_USERID_DATA = { + idl_env: '1234-5678-9012-3456', // Liveramp + }; + + const DEFAULT_USERID_PAYLOAD = [ + { + source: 'liveramp.com', + uids: [{ + id: DEFAULT_USERID_DATA.idl_env, + ext: { + rtiPartner: 'idl' + } + }] + } + ]; + describe('inherited functions', function () { it('should exists and is a function', function () { const adapter = newBidder(spec); @@ -365,13 +381,16 @@ describe('IndexexchangeAdapter', function () { request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; query = request.data; }); + afterEach(function () { delete window.headertag; }); + describe('buildRequestSingleRTI', function () { before(function () { testCopy = JSON.parse(JSON.stringify(DEFAULT_IDENTITY_RESPONSE)); }); + it('payload should have correct format and value (single identity partner)', function () { const payload = JSON.parse(query.r); @@ -400,6 +419,7 @@ describe('IndexexchangeAdapter', function () { } ); }); + it('payload should have correct format and value (single identity w/ multi ids)', function () { const payload = JSON.parse(query.r); @@ -443,6 +463,7 @@ describe('IndexexchangeAdapter', function () { } } }); + it('payload should have correct format and value (multiple identity partners)', function () { const payload = JSON.parse(query.r); @@ -519,6 +540,177 @@ describe('IndexexchangeAdapter', function () { }); }); + describe('buildRequestsUserId', function () { + let validIdentityResponse; + let validUserIdPayload; + + beforeEach(function () { + window.headertag = {}; + window.headertag.getIdentityInfo = function () { + return validIdentityResponse; + }; + }); + + afterEach(function () { + delete window.headertag; + }); + + it('IX adapter reads LiveRamp IDL envelope from Prebid and adds it to Video', function () { + const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID); + cloneValidBid[0].userId = utils.deepClone(DEFAULT_USERID_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.deep.include(DEFAULT_USERID_PAYLOAD[0]); + }); + + it('We continue to send in IXL identity info and Prebid takes precedence over IXL', function () { + validIdentityResponse = { + AdserverOrgIp: { + responsePending: false, + data: { + source: 'adserver.org', + uids: [ + { + id: '1234-5678-9012-3456', + ext: { + rtiPartner: 'TDID' + } + }, + { + id: 'FALSE', + ext: { + rtiPartner: 'TDID_LOOKUP' + } + }, + { + id: '2020-06-24T14:43:48.860Z', + ext: { + rtiPartner: 'TDID_CREATED_AT' + } + } + ] + } + }, + MerkleIp: { + responsePending: false, + data: { + source: 'merkle.com', + uids: [{ + id: '1234-5678-9012-3456', + ext: { + keyID: '1234-5678', + enc: 1 + } + }] + } + }, + LiveRampIp: { + source: 'liveramp.com', + uids: [ + { + id: '0000-1234-4567-8901', + ext: { + rtiPartner: 'idl' + } + } + ] + } + }; + + const cloneValidBid = utils.deepClone(DEFAULT_BANNER_VALID_BID); + cloneValidBid[0].userId = utils.deepClone(DEFAULT_USERID_DATA) + + const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; + const payload = JSON.parse(request.data.r); + + validUserIdPayload = utils.deepClone(DEFAULT_USERID_PAYLOAD); + validUserIdPayload.push({ + source: 'merkle.com', + uids: [{ + id: '1234-5678-9012-3456', + ext: { + keyID: '1234-5678', + enc: 1 + } + }] + }) + validUserIdPayload.push({ + source: 'adserver.org', + uids: [ + { + id: '1234-5678-9012-3456', + ext: { + rtiPartner: 'TDID' + } + }, + { + id: 'FALSE', + ext: { + rtiPartner: 'TDID_LOOKUP' + } + }, + { + id: '2020-06-24T14:43:48.860Z', + ext: { + rtiPartner: 'TDID_CREATED_AT' + } + } + ] + }) + + expect(payload.user).to.exist; + expect(payload.user.eids).to.have.lengthOf(3); + 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]); + }); + + it('IXL and Prebid are mutually exclusive', function () { + validIdentityResponse = { + LiveIntentIp: { + responsePending: false, + data: { + source: 'liveintent.com', + uids: [{ + id: '1234-5678-9012-3456', + ext: { + keyID: '1234-5678', + rtiPartner: 'LDID', + enc: 1 + } + }] + } + } + }; + + const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID); + cloneValidBid[0].userId = utils.deepClone(DEFAULT_USERID_DATA); + + const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; + + validUserIdPayload = utils.deepClone(DEFAULT_USERID_PAYLOAD); + validUserIdPayload.push({ + source: 'liveintent.com', + uids: [{ + id: '1234-5678-9012-3456', + ext: { + keyID: '1234-5678', + rtiPartner: 'LDID', + enc: 1 + } + }] + }); + + const payload = JSON.parse(request.data.r); + expect(payload.user.eids).to.have.lengthOf(2); + expect(payload.user.eids).to.deep.include(validUserIdPayload[0]); + expect(payload.user.eids).to.deep.include(validUserIdPayload[1]); + }); + }); + describe('buildRequests', function () { const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; const requestUrl = request.url; From f91e406d96d3bd5214da24ca6744b290e87b5ec9 Mon Sep 17 00:00:00 2001 From: IX-Prebid-Support Date: Mon, 20 Jul 2020 16:14:35 -0400 Subject: [PATCH 2/2] Update endpoint to htlb.casalemedia.com --- modules/ixBidAdapter.js | 2 +- test/spec/modules/ixBidAdapter_spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 62d4b015aa7..b54114c176e 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -6,7 +6,7 @@ import isInteger from 'core-js-pure/features/number/is-integer.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'ix'; -const SECURE_BID_URL = 'https://as-sec.casalemedia.com/cygnus'; +const SECURE_BID_URL = 'https://htlb.casalemedia.com/cygnus'; const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; const BANNER_ENDPOINT_VERSION = 7.2; const VIDEO_ENDPOINT_VERSION = 8.1; diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index 680ffdc0fcc..b2b8885a2f8 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -5,7 +5,7 @@ import { newBidder } from 'src/adapters/bidderFactory.js'; import { spec } from 'modules/ixBidAdapter.js'; describe('IndexexchangeAdapter', function () { - const IX_SECURE_ENDPOINT = 'https://as-sec.casalemedia.com/cygnus'; + const IX_SECURE_ENDPOINT = 'https://htlb.casalemedia.com/cygnus'; const VIDEO_ENDPOINT_VERSION = 8.1; const BANNER_ENDPOINT_VERSION = 7.2;