From 0b48ea978e8440aae7598c78775753b821569b90 Mon Sep 17 00:00:00 2001 From: atkachov Date: Tue, 24 Oct 2017 14:31:44 +0300 Subject: [PATCH 01/14] Migrating to Prebid 1.0 --- modules/admixerBidAdapter.js | 152 +++++---- modules/admixerBidAdapter.md | 52 +++ test/spec/modules/admixerBidAdapter_spec.js | 332 ++++++-------------- 3 files changed, 224 insertions(+), 312 deletions(-) create mode 100644 modules/admixerBidAdapter.md diff --git a/modules/admixerBidAdapter.js b/modules/admixerBidAdapter.js index 71220732540..e0939a7560b 100644 --- a/modules/admixerBidAdapter.js +++ b/modules/admixerBidAdapter.js @@ -1,88 +1,76 @@ -var bidfactory = require('src/bidfactory.js'); -var bidmanager = require('src/bidmanager.js'); -var Ajax = require('src/ajax'); -var utils = require('src/utils.js'); -var adaptermanager = require('src/adaptermanager'); +import * as utils from 'src/utils'; +import {registerBidder} from 'src/adapters/bidderFactory'; -/** - * Adapter for requesting bids from Admixer. - * - * @returns {{callBids: _callBids,responseCallback: _responseCallback}} - */ -var AdmixerAdapter = function AdmixerAdapter() { - var invUrl = '//inv-nets.admixer.net/prebid.aspx'; - var invVastUrl = '//inv-nets.admixer.net/videoprebid.aspx'; - - function _callBids(data) { - var bids = data.bids || []; - for (var i = 0, ln = bids.length; i < ln; i++) { - var bid = bids[i]; - var params = { - 'sizes': utils.parseSizesInput(bid.sizes).join('-'), - 'zone': bid.params && bid.params.zone, - 'callback_uid': bid.placementCode - }; - if (params.zone) { - if (bid.mediaType === 'video') { - var videoParams = {}; - if (typeof bid.video === 'object') { - Object.assign(videoParams, bid.video); - } - Object.assign(videoParams, params); - _requestBid(invVastUrl, params); - } else { - _requestBid(invUrl, params); - } - } else { - var bidObject = bidfactory.createBid(2); - bidObject.bidderCode = 'admixer'; - bidmanager.addBidResponse(params.callback_uid, bidObject); +const BIDDER_CODE = 'admixer'; +const ENDPOINT_URL = '//inv-nets.admixer.net/prebid.1.0.aspx'; +export const spec = { + code: BIDDER_CODE, + aliases: [], + supportedMediaTypes: ['banner', 'video'], + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function (bid) { + return !!bid.params.zone; + }, + /** + * Make a server request from the list of BidRequests. + * + * @param {bidderRequest} - bidderRequest.bids[] is an array of AdUnits and bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function (bidderRequest) { + const payload = { + imps: [], + referrer: utils.getTopWindowUrl(), + }; + bidderRequest.forEach((bid) => { + if (bid.bidder === BIDDER_CODE) { + payload.imps.push(bid); } - } - } - - function _requestBid(url, params) { - Ajax.ajax(url, _responseCallback, params, {method: 'GET', withCredentials: true}); - } - - function _responseCallback(adUnit) { + }); + const payloadString = JSON.stringify(payload); + return { + method: 'GET', + url: ENDPOINT_URL, + data: `data=${payloadString}`, + }; + }, + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse, bidRequest) { + const bidResponses = []; + // loop through serverResponses { try { - adUnit = JSON.parse(adUnit); - } catch (_error) { - adUnit = {result: {cpm: 0}}; - utils.logError(_error); + serverResponse.forEach((bidResponse) => { + const bidResp = { + requestId: bidResponse.bidId, + id: bidResponse.bidId, + bidderCode: BIDDER_CODE, + cpm: bidResponse.cpm, + width: bidResponse.width, + height: bidResponse.height, + ad: bidResponse.ad, + ttl: bidResponse.ttl, + creativeId: bidResponse.creativeId, + netRevenue: bidResponse.netRevenue, + currency: bidResponse.currency, + vastUrl: bidResponse.vastUrl, + }; + bidResponses.push(bidResp); + }); + } catch (e) { } - var adUnitCode = adUnit.callback_uid; - var bid = adUnit.result; - var bidObject; - if (bid.cpm > 0) { - bidObject = bidfactory.createBid(1); - bidObject.bidderCode = 'admixer'; - bidObject.cpm = bid.cpm; - if (bid.vastUrl) { - bidObject.mediaType = 'video'; - bidObject.vastUrl = bid.vastUrl; - bidObject.descriptionUrl = bid.vastUrl; - } else { - bidObject.ad = bid.ad; - } - bidObject.width = bid.width; - bidObject.height = bid.height; - } else { - bidObject = bidfactory.createBid(2); - bidObject.bidderCode = 'admixer'; - } - bidmanager.addBidResponse(adUnitCode, bidObject); + return bidResponses; + }, + getUserSyncs: function (syncOptions) { } - - return { - callBids: _callBids, - responseCallback: _responseCallback - }; }; - -adaptermanager.registerBidAdapter(new AdmixerAdapter(), 'admixer', { - supportedMediaTypes: ['video'] -}); - -module.exports = AdmixerAdapter; +registerBidder(spec); diff --git a/modules/admixerBidAdapter.md b/modules/admixerBidAdapter.md new file mode 100644 index 00000000000..682f5629115 --- /dev/null +++ b/modules/admixerBidAdapter.md @@ -0,0 +1,52 @@ +# Overview + +Module Name: Admixer Bidder Adapter +Module Type: Bidder Adapter +Maintainer: contact@admixer.net + +# Description + +Connects to Admixer demand source to fetch bids. +Banner and Video formats are supported. +Please use ```admixer``` as the bidder code. + +# Test Parameters +``` + var adUnits = [ + { + code: 'desktop-banner-ad-div', + sizes: [[300, 250]], // a display size + bids: [ + { + bidder: "admixer", + params: { + zone: '2eb6bd58-865c-47ce-af7f-a918108c3fd2' + } + } + ] + },{ + code: 'mobile-banner-ad-div', + sizes: [[300, 50]], // a mobile size + bids: [ + { + bidder: "admixer", + params: { + zone: '62211486-c50b-4356-9f0f-411778d31fcc' + } + } + ] + },{ + code: 'video-ad', + sizes: [[300, 50]], + mediaType: 'video', + bids: [ + { + bidder: "admixer", + params: { + zone: 'ebeb1e79-8cb4-4473-b2d0-2e24b7ff47fd' + } + } + ] + }, + ]; +``` diff --git a/test/spec/modules/admixerBidAdapter_spec.js b/test/spec/modules/admixerBidAdapter_spec.js index 0b66f8a9469..89cb4a3afab 100644 --- a/test/spec/modules/admixerBidAdapter_spec.js +++ b/test/spec/modules/admixerBidAdapter_spec.js @@ -1,244 +1,116 @@ -var chai = require('chai'); -var Adapter = require('modules/admixerBidAdapter')(); -var Ajax = require('src/ajax'); -var bidmanager = require('src/bidmanager.js'); -var CONSTANTS = require('src/constants.json'); +import {expect} from 'chai'; +import {spec} from 'modules/admixerBidAdapter'; +import {newBidder} from 'src/adapters/bidderFactory'; -describe('Admixer adapter', function () { - var validData_1 = { - bids: [ - { - bidder: 'admixer', - bidId: 'bid_id', - params: {zone: 'zone_id'}, - placementCode: 'ad-unit-1', - sizes: [[300, 250], [300, 600]] - } - ] - }; - var validData_2 = { - bids: [ - { - bidder: 'admixer', - bidId: 'bid_id', - params: {zone: 'zone_id'}, - placementCode: 'ad-unit-1', - sizes: [300, 250] - } - ] - }; - var invalidData = { - bids: [ - { - bidder: 'admixer', - bidId: 'bid_id', - params: {}, - placementCode: 'ad-unit-1', - sizes: [[300, 250], [300, 600]] - } - ] - }; - var validVideoData_1 = { - bids: [ - { - mediaType: 'video', - bidder: 'admixer', - bidId: 'bid_id', - params: {zone: 'zone_id'}, - placementCode: 'ad-unit-1', - sizes: [[300, 250], [300, 600]] - } - ] - }; - var validVideoData_2 = { - bids: [ - { - mediaType: 'video', - bidder: 'admixer', - bidId: 'bid_id', - params: {zone: 'zone_id'}, - placementCode: 'ad-unit-1', - sizes: [300, 250] - } - ] - }; - var validVideoData_3 = { - bids: [ - { - mediaType: 'video', - bidder: 'admixer', - bidId: 'bid_id', - params: {zone: 'zone_id', video: {skippable: true}}, - placementCode: 'ad-unit-1', - sizes: [300, 250] - } - ] - }; - var invalidVideoData = { - bids: [ - { - mediaType: 'video', - bidder: 'admixer', - bidId: 'bid_id', - params: {}, - placementCode: 'ad-unit-1', - sizes: [[300, 250], [300, 600]] - } - ] - }; - var responseWithAd = JSON.stringify({ - 'result': { - 'cpm': 2.2, - 'ad': '
response ad
', - 'width': 300, - 'height': 250 - }, - 'callback_uid': 'ad-unit-1' - }); - var responseWithoutAd = JSON.stringify({ - 'result': { - 'cpm': 0, - 'ad': '', - 'width': 0, - 'height': 0 - }, - 'callback_uid': 'ad-unit-1' - }); - var responseWithVideoAd = JSON.stringify({ - 'result': { - 'cpm': 2.2, - 'vastUrl': 'http://inv-nets.admixer.net/vastxml.aspx?req=9d651544-daf4-48ed-ae0c-38a60a4e1920&vk=e914f026449e49aeb6eea07b9642a2ce', - 'width': 300, - 'height': 250 - }, - 'callback_uid': 'ad-unit-1' - }); - var responseWithoutVideoAd = JSON.stringify({ - 'result': { - 'cpm': 0, - 'vastUrl': '', - 'width': 0, - 'height': 0 - }, - 'callback_uid': 'ad-unit-1' - }); - var responseEmpty = ''; - var invUrl = '//inv-nets.admixer.net/prebid.aspx'; - var invVastUrl = '//inv-nets.admixer.net/videoprebid.aspx'; - var validJsonParams = { - zone: 'zone_id', - callback_uid: 'ad-unit-1', - sizes: '300x250-300x600' - }; - var validJsonVideoParams = { - zone: 'zone_id', - callback_uid: 'ad-unit-1', - sizes: '300x250-300x600', - skippable: true - }; - describe('bid request with valid data', function () { - var stubAjax; - beforeEach(function () { - stubAjax = sinon.stub(Ajax, 'ajax'); - }); +const BIDDER_CODE = 'admixer'; +const ENDPOINT_URL = '//inv-nets.admixer.net/prebid.1.0.aspx'; +const ZONE_ID = '2eb6bd58-865c-47ce-af7f-a918108c3fd2'; - afterEach(function () { - stubAjax.restore(); - }); - it('display: bid request should be called. sizes style -> [[],[]]', function () { - Adapter.callBids(validData_1); - sinon.assert.calledOnce(stubAjax); - }); - it('video: bid request should be called. sizes style -> [[],[]]', function () { - Adapter.callBids(validVideoData_1); - sinon.assert.calledOnce(stubAjax); - }); - it('display: bid request should be called. sizes style -> []', function () { - Adapter.callBids(validData_2); - sinon.assert.calledOnce(stubAjax); - }); - it('video: bid request should be called. sizes style -> []', function () { - Adapter.callBids(validVideoData_2); - sinon.assert.calledOnce(stubAjax); - }); - it('display: ajax params should be matched', function () { - Adapter.callBids(validData_1); - sinon.assert.calledWith(stubAjax, sinon.match(invUrl, function () { - }, validJsonParams, {method: 'GET'})); - }); - it('video: ajax params should be matched', function () { - Adapter.callBids(validVideoData_3); - sinon.assert.calledWith(stubAjax, sinon.match(invVastUrl, function () { - }, validJsonVideoParams, {method: 'GET'})); +describe('AdmixerAdapter', () => { + const adapter = newBidder(spec); + + describe('inherited functions', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.be.exist.and.to.be.a('function'); }); }); - describe('bid request with invalid data', function () { - var addBidResponse, stubAjax; - beforeEach(function () { - addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - stubAjax = sinon.stub(Ajax, 'ajax'); - }); - afterEach(function () { - addBidResponse.restore(); - stubAjax.restore(); - }); - it('display: ajax shouldn\'t be called', function () { - Adapter.callBids(invalidData); - sinon.assert.notCalled(stubAjax); - }); - it('video: ajax shouldn\'t be called', function () { - Adapter.callBids(invalidVideoData); - sinon.assert.notCalled(stubAjax); - }); - it('display: bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID + '"', function () { - Adapter.callBids(invalidData); - expect(addBidResponse.firstCall.args[1].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - expect(addBidResponse.firstCall.args[1].bidderCode).to.equal('admixer'); + describe('isBidRequestValid', () => { + let bid = { + 'bidder': BIDDER_CODE, + 'params': { + 'zone': ZONE_ID + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }; + + it('should return true when required params found', () => { + expect(spec.isBidRequestValid(bid)).to.equal(true); }); - it('video: bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID + '"', function () { - Adapter.callBids(invalidVideoData); - expect(addBidResponse.firstCall.args[1].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - expect(addBidResponse.firstCall.args[1].bidderCode).to.equal('admixer'); + + it('should return false when required params are not passed', () => { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + 'placementId': 0 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); }); }); - describe('bid response', function () { - var addBidResponse; - beforeEach(function () { - addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - }); - afterEach(function () { - addBidResponse.restore(); - }); - it('display: response with ad. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.GOOD + '"', function () { - Adapter.responseCallback(responseWithAd); - var arg = addBidResponse.firstCall.args[1]; - expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(arg.bidderCode).to.equal('admixer'); - }); - it('video: response with ad. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.GOOD + '"', function () { - Adapter.responseCallback(responseWithVideoAd); - var arg = addBidResponse.firstCall.args[1]; - expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(arg.bidderCode).to.equal('admixer'); + + describe('buildRequests', () => { + let bidRequests = [ + { + 'bidder': BIDDER_CODE, + 'params': { + 'zone': ZONE_ID + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + } + ]; + + it('should add referrer and imp to be equal bidRequest', () => { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data.substr(5)); + expect(payload.referrer).to.not.be.undefined; + expect(payload.imps[0]).to.deep.equal(bidRequests[0]); }); - it('display: response without ad. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID, function () { - Adapter.responseCallback(responseWithoutAd); - var arg = addBidResponse.firstCall.args[1]; - expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - expect(arg.bidderCode).to.equal('admixer'); + + it('sends bid request to ENDPOINT via GET', () => { + const request = spec.buildRequests(bidRequests); + expect(request.url).to.equal(ENDPOINT_URL); + expect(request.method).to.equal('GET'); }); - it('video: response without ad. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID, function () { - Adapter.responseCallback(responseWithoutVideoAd); - var arg = addBidResponse.firstCall.args[1]; - expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - expect(arg.bidderCode).to.equal('admixer'); + }); + + describe('interpretResponse', () => { + let response = [{ + 'currency': 'USD', + 'cpm': 6.210000, + 'ad': '
ad
', + 'width': 300, + 'height': 600, + 'creativeId': 'ccca3e5e-0c54-4761-9667-771322fbdffc', + 'ttl': 360, + 'netRevenue': false, + 'bidId': '5e4e763b6bc60b' + }]; + + it('should get correct bid response', () => { + let expectedResponse = [ + { + 'requestId': response[0].bidId, + 'id': response[0].bidId, + 'bidderCode': BIDDER_CODE, + 'cpm': response[0].cpm, + 'creativeId': response[0].creativeId, + 'width': response[0].width, + 'height': response[0].height, + 'ad': response[0].ad, + 'vastUrl': undefined, + 'currency': response[0].currency, + 'netRevenue': response[0].netRevenue, + 'ttl': response[0].ttl, + } + ]; + + let result = spec.interpretResponse(response); + expect(result[0]).to.deep.equal(expectedResponse[0]); }); - it('display/video: response empty. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID, function () { - Adapter.responseCallback(responseEmpty); - var arg = addBidResponse.firstCall.args[1]; - expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - expect(arg.bidderCode).to.equal('admixer'); + + it('handles nobid responses', () => { + let response = []; + + let result = spec.interpretResponse(response); + expect(result.length).to.equal(0); }); }); }); From 6ec18f4488f68bd2847bdac18a5d585848188515 Mon Sep 17 00:00:00 2001 From: atkachov Date: Mon, 11 Dec 2017 14:56:14 +0200 Subject: [PATCH 02/14] Migrating to Prebid 1.0 --- modules/admixerBidAdapter.js | 6 +-- test/spec/modules/admixerBidAdapter_spec.js | 45 +++++++++++---------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/modules/admixerBidAdapter.js b/modules/admixerBidAdapter.js index e0939a7560b..6851a7d3bd5 100644 --- a/modules/admixerBidAdapter.js +++ b/modules/admixerBidAdapter.js @@ -49,11 +49,10 @@ export const spec = { const bidResponses = []; // loop through serverResponses { try { + serverResponse = serverResponse.body; serverResponse.forEach((bidResponse) => { const bidResp = { requestId: bidResponse.bidId, - id: bidResponse.bidId, - bidderCode: BIDDER_CODE, cpm: bidResponse.cpm, width: bidResponse.width, height: bidResponse.height, @@ -67,10 +66,9 @@ export const spec = { bidResponses.push(bidResp); }); } catch (e) { + utils.logError(e); } return bidResponses; - }, - getUserSyncs: function (syncOptions) { } }; registerBidder(spec); diff --git a/test/spec/modules/admixerBidAdapter_spec.js b/test/spec/modules/admixerBidAdapter_spec.js index 89cb4a3afab..5b777de64e6 100644 --- a/test/spec/modules/admixerBidAdapter_spec.js +++ b/test/spec/modules/admixerBidAdapter_spec.js @@ -72,33 +72,36 @@ describe('AdmixerAdapter', () => { }); describe('interpretResponse', () => { - let response = [{ - 'currency': 'USD', - 'cpm': 6.210000, - 'ad': '
ad
', - 'width': 300, - 'height': 600, - 'creativeId': 'ccca3e5e-0c54-4761-9667-771322fbdffc', - 'ttl': 360, - 'netRevenue': false, - 'bidId': '5e4e763b6bc60b' - }]; + let response = { + body: [{ + 'currency': 'USD', + 'cpm': 6.210000, + 'ad': '
ad
', + 'width': 300, + 'height': 600, + 'creativeId': 'ccca3e5e-0c54-4761-9667-771322fbdffc', + 'ttl': 360, + 'netRevenue': false, + 'bidId': '5e4e763b6bc60b' + }] + }; it('should get correct bid response', () => { + const body = response.body; let expectedResponse = [ { - 'requestId': response[0].bidId, - 'id': response[0].bidId, + 'requestId': body[0].bidId, + 'id': body[0].bidId, 'bidderCode': BIDDER_CODE, - 'cpm': response[0].cpm, - 'creativeId': response[0].creativeId, - 'width': response[0].width, - 'height': response[0].height, - 'ad': response[0].ad, + 'cpm': body[0].cpm, + 'creativeId': body[0].creativeId, + 'width': body[0].width, + 'height': body[0].height, + 'ad': body[0].ad, 'vastUrl': undefined, - 'currency': response[0].currency, - 'netRevenue': response[0].netRevenue, - 'ttl': response[0].ttl, + 'currency': body[0].currency, + 'netRevenue': body[0].netRevenue, + 'ttl': body[0].ttl, } ]; From 63928ed157ebf1c25cd8b75c488b6a274c1772e6 Mon Sep 17 00:00:00 2001 From: atkachov Date: Mon, 11 Dec 2017 15:01:34 +0200 Subject: [PATCH 03/14] Fix spec --- test/spec/modules/admixerBidAdapter_spec.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/spec/modules/admixerBidAdapter_spec.js b/test/spec/modules/admixerBidAdapter_spec.js index 5b777de64e6..13312e3d24e 100644 --- a/test/spec/modules/admixerBidAdapter_spec.js +++ b/test/spec/modules/admixerBidAdapter_spec.js @@ -91,8 +91,6 @@ describe('AdmixerAdapter', () => { let expectedResponse = [ { 'requestId': body[0].bidId, - 'id': body[0].bidId, - 'bidderCode': BIDDER_CODE, 'cpm': body[0].cpm, 'creativeId': body[0].creativeId, 'width': body[0].width, From 961c25ff7831d1d915e701056884eb72610bcfcf Mon Sep 17 00:00:00 2001 From: Galphimbl Date: Mon, 27 Apr 2020 15:10:52 +0300 Subject: [PATCH 04/14] add gdpr and usp --- integrationExamples/gpt/gdpr_hello_world.html | 46 +++++++++++-------- modules/admixerBidAdapter.js | 16 ++++++- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/integrationExamples/gpt/gdpr_hello_world.html b/integrationExamples/gpt/gdpr_hello_world.html index de0630178f1..81df670a321 100644 --- a/integrationExamples/gpt/gdpr_hello_world.html +++ b/integrationExamples/gpt/gdpr_hello_world.html @@ -82,7 +82,7 @@ - + + + - +

Prebid.js Test

Div-1
diff --git a/modules/admixerBidAdapter.js b/modules/admixerBidAdapter.js index e8a27a033b4..b2f24cfa910 100644 --- a/modules/admixerBidAdapter.js +++ b/modules/admixerBidAdapter.js @@ -20,8 +20,22 @@ export const spec = { buildRequests: function (validRequest, bidderRequest) { const payload = { imps: [], - referrer: encodeURIComponent(bidderRequest.refererInfo.referer), }; + if (bidderRequest) { + if (bidderRequest.refererInfo && bidderRequest.refererInfo.referer) { + payload.referrer = encodeURIComponent(bidderRequest.refererInfo.referer); + } + if (bidderRequest.gdprConsent) { + payload.gdprConsent = { + consentString: bidderRequest.gdprConsent.consentString, + // will check if the gdprApplies field was populated with a boolean value (ie from page config). If it's undefined, then default to true + gdprApplies: (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true + } + } + if (bidderRequest.uspConsent) { + payload.uspConsent = bidderRequest.uspConsent; + } + } validRequest.forEach((bid) => { payload.imps.push(bid); }); From 81b156eb427cff836c2af436392c7015474b623b Mon Sep 17 00:00:00 2001 From: Galphimbl Date: Mon, 27 Apr 2020 15:20:31 +0300 Subject: [PATCH 05/14] remove changes in gdpr_hello_world.html --- integrationExamples/gpt/gdpr_hello_world.html | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/integrationExamples/gpt/gdpr_hello_world.html b/integrationExamples/gpt/gdpr_hello_world.html index 81df670a321..2d70af8d34f 100644 --- a/integrationExamples/gpt/gdpr_hello_world.html +++ b/integrationExamples/gpt/gdpr_hello_world.html @@ -93,9 +93,9 @@ // Replace this object to test a new Adapter! bids: [{ - bidder: 'admixer', + bidder: 'appnexus', params: { - zone: '2eb6bd58-865c-47ce-af7f-a918108c3fd2' + placementId: 13144370 } }] @@ -117,19 +117,9 @@ pbjs.addAdUnits(adUnits); pbjs.setConfig({ consentManagement: { - gdpr: { - cmpApi: 'iab', - allowAuctionWithoutConsent: false, // suppress auctions if there's no GDPR consent string - timeout: 3000 // GDPR timeout 3000ms - }, - usp: { - cmpApi: 'static', - consentData: { - getUSPData: { - uspString: '1YYY' - } - } - } + cmpApi: 'iab', + timeout: 5000, + allowAuctionWithoutConsent: true }, pubcid: { enable: false From 3315d3c885a7322e64a72b30cc48d1b1b3edafe8 Mon Sep 17 00:00:00 2001 From: Galphimbl Date: Tue, 5 May 2020 10:28:04 +0300 Subject: [PATCH 06/14] Update gdpr_hello_world.html add spaces --- integrationExamples/gpt/gdpr_hello_world.html | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/integrationExamples/gpt/gdpr_hello_world.html b/integrationExamples/gpt/gdpr_hello_world.html index 2d70af8d34f..de0630178f1 100644 --- a/integrationExamples/gpt/gdpr_hello_world.html +++ b/integrationExamples/gpt/gdpr_hello_world.html @@ -82,7 +82,7 @@ - + + + - +

Prebid.js Test

Div-1
From 891faba5a476300418ce4b2d82c0092f9202461d Mon Sep 17 00:00:00 2001 From: Galphimbl Date: Tue, 24 Nov 2020 10:28:56 +0200 Subject: [PATCH 07/14] add user syncs --- modules/admixerBidAdapter.js | 30 ++++++++++++-- test/spec/modules/admixerBidAdapter_spec.js | 46 +++++++++++---------- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/modules/admixerBidAdapter.js b/modules/admixerBidAdapter.js index b2f24cfa910..e6f6f5adde1 100644 --- a/modules/admixerBidAdapter.js +++ b/modules/admixerBidAdapter.js @@ -3,7 +3,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'admixer'; const ALIASES = ['go2net']; -const ENDPOINT_URL = 'https://inv-nets.admixer.net/prebid.1.0.aspx'; +const ENDPOINT_URL = 'https://inv-nets.admixer.net/prebid.1.1.aspx'; export const spec = { code: BIDDER_CODE, aliases: ALIASES, @@ -53,8 +53,8 @@ export const spec = { const bidResponses = []; // loop through serverResponses { try { - serverResponse = serverResponse.body; - serverResponse.forEach((bidResponse) => { + const {body: {ads = []} = {}} = serverResponse; + ads.forEach((bidResponse) => { const bidResp = { requestId: bidResponse.bidId, cpm: bidResponse.cpm, @@ -73,6 +73,30 @@ export const spec = { utils.logError(e); } return bidResponses; + }, + getUserSyncs: function(syncOptions, serverResponses, gdprConsent) { + const pixels = []; + serverResponses.forEach(({body: {cm = {}} = {}}) => { + const {pixels: img = [], iframes: frm = []} = cm; + if (syncOptions.pixelEnabled) { + img.forEach((url) => pixels.push({type: 'image', url})); + } + if (syncOptions.iframeEnabled) { + frm.forEach((url) => pixels.push({type: 'iframe', url})); + } + }); + // if (syncOptions.iframeEnabled && serverResponses.length > 0) { + // const account = serverResponses[0].account; + // if (account) { + // let syncurl = USER_SYNC_BASE_URL + '?account=' + account; + // if (gdprConsent) { + // syncurl += '&gdpr=' + (gdprConsent.gdprApplies ? 1 : 0); + // syncurl += '&consentString=' + encodeURIComponent(gdprConsent.consentString || ''); + // } + // return [{type: 'iframe', url: syncurl}]; + // } + // } + return pixels; } }; registerBidder(spec); diff --git a/test/spec/modules/admixerBidAdapter_spec.js b/test/spec/modules/admixerBidAdapter_spec.js index 6d2e3059dc8..f044b038e47 100644 --- a/test/spec/modules/admixerBidAdapter_spec.js +++ b/test/spec/modules/admixerBidAdapter_spec.js @@ -3,7 +3,7 @@ import {spec} from 'modules/admixerBidAdapter.js'; import {newBidder} from 'src/adapters/bidderFactory.js'; const BIDDER_CODE = 'admixer'; -const ENDPOINT_URL = 'https://inv-nets.admixer.net/prebid.1.0.aspx'; +const ENDPOINT_URL = 'https://inv-nets.admixer.net/prebid.1.1.aspx'; const ZONE_ID = '2eb6bd58-865c-47ce-af7f-a918108c3fd2'; describe('AdmixerAdapter', function () { @@ -78,33 +78,35 @@ describe('AdmixerAdapter', function () { describe('interpretResponse', function () { let response = { - body: [{ - 'currency': 'USD', - 'cpm': 6.210000, - 'ad': '
ad
', - 'width': 300, - 'height': 600, - 'creativeId': 'ccca3e5e-0c54-4761-9667-771322fbdffc', - 'ttl': 360, - 'netRevenue': false, - 'bidId': '5e4e763b6bc60b' - }] + body: { + ads: [{ + 'currency': 'USD', + 'cpm': 6.210000, + 'ad': '
ad
', + 'width': 300, + 'height': 600, + 'creativeId': 'ccca3e5e-0c54-4761-9667-771322fbdffc', + 'ttl': 360, + 'netRevenue': false, + 'bidId': '5e4e763b6bc60b' + }] + } }; it('should get correct bid response', function () { - const body = response.body; + const ads = response.body.ads; let expectedResponse = [ { - 'requestId': body[0].bidId, - 'cpm': body[0].cpm, - 'creativeId': body[0].creativeId, - 'width': body[0].width, - 'height': body[0].height, - 'ad': body[0].ad, + 'requestId': ads[0].bidId, + 'cpm': ads[0].cpm, + 'creativeId': ads[0].creativeId, + 'width': ads[0].width, + 'height': ads[0].height, + 'ad': ads[0].ad, 'vastUrl': undefined, - 'currency': body[0].currency, - 'netRevenue': body[0].netRevenue, - 'ttl': body[0].ttl, + 'currency': ads[0].currency, + 'netRevenue': ads[0].netRevenue, + 'ttl': ads[0].ttl, } ]; From ee38d00103bdac380ab88a64f6362ccb95c7f245 Mon Sep 17 00:00:00 2001 From: Galphimbl Date: Tue, 24 Nov 2020 10:41:16 +0200 Subject: [PATCH 08/14] remove comments --- modules/admixerBidAdapter.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/modules/admixerBidAdapter.js b/modules/admixerBidAdapter.js index e6f6f5adde1..3bb392538ff 100644 --- a/modules/admixerBidAdapter.js +++ b/modules/admixerBidAdapter.js @@ -51,7 +51,6 @@ export const spec = { */ interpretResponse: function (serverResponse, bidRequest) { const bidResponses = []; - // loop through serverResponses { try { const {body: {ads = []} = {}} = serverResponse; ads.forEach((bidResponse) => { @@ -85,17 +84,6 @@ export const spec = { frm.forEach((url) => pixels.push({type: 'iframe', url})); } }); - // if (syncOptions.iframeEnabled && serverResponses.length > 0) { - // const account = serverResponses[0].account; - // if (account) { - // let syncurl = USER_SYNC_BASE_URL + '?account=' + account; - // if (gdprConsent) { - // syncurl += '&gdpr=' + (gdprConsent.gdprApplies ? 1 : 0); - // syncurl += '&consentString=' + encodeURIComponent(gdprConsent.consentString || ''); - // } - // return [{type: 'iframe', url: syncurl}]; - // } - // } return pixels; } }; From dfd97f649bcf305656c94536851cc6202e3fcef3 Mon Sep 17 00:00:00 2001 From: Galphimbl Date: Wed, 25 Nov 2020 13:15:31 +0200 Subject: [PATCH 09/14] tests --- test/spec/modules/admixerBidAdapter_spec.js | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/spec/modules/admixerBidAdapter_spec.js b/test/spec/modules/admixerBidAdapter_spec.js index f044b038e47..6298eac4448 100644 --- a/test/spec/modules/admixerBidAdapter_spec.js +++ b/test/spec/modules/admixerBidAdapter_spec.js @@ -121,4 +121,34 @@ describe('AdmixerAdapter', function () { expect(result.length).to.equal(0); }); }); + + describe('getUserSyncs', function () { + let imgUrl = 'https://example.com/img1'; + let frmUrl = 'https://example.com/frm2'; + let responses = [{ + body: { + cm: { + pixels: [ + imgUrl + ], + iframes: [ + frmUrl + ], + } + } + }]; + + it('Returns valid values', function () { + let userSyncAll = spec.getUserSyncs({pixelEnabled: true, iframeEnabled: true}, responses); + let userSyncImg = spec.getUserSyncs({pixelEnabled: true, iframeEnabled: false}, responses); + let userSyncFrm = spec.getUserSyncs({pixelEnabled: false, iframeEnabled: true}, responses); + expect(userSyncAll).to.be.an('array').with.lengthOf(2); + expect(userSyncImg).to.be.an('array').with.lengthOf(1); + expect(userSyncImg[0].url).to.be.equal(imgUrl); + expect(userSyncImg[0].type).to.be.equal('image'); + expect(userSyncFrm).to.be.an('array').with.lengthOf(1); + expect(userSyncFrm[0].url).to.be.equal(frmUrl); + expect(userSyncFrm[0].type).to.be.equal('iframe'); + }); + }); }); From 0dd729cce2e41676d835d0a5355c27a9a21cd30d Mon Sep 17 00:00:00 2001 From: Galphimbl Date: Thu, 28 Jan 2021 10:56:40 +0200 Subject: [PATCH 10/14] admixer id system --- modules/admixerIdSystem.js | 92 +++++++++++++++++++++++ modules/userId/eids.js | 6 ++ test/spec/modules/admixerIdSystem_spec.js | 81 ++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 modules/admixerIdSystem.js create mode 100644 test/spec/modules/admixerIdSystem_spec.js diff --git a/modules/admixerIdSystem.js b/modules/admixerIdSystem.js new file mode 100644 index 00000000000..93c39adda84 --- /dev/null +++ b/modules/admixerIdSystem.js @@ -0,0 +1,92 @@ +/** + * This module adds IdentityLink to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/identityLinkSubmodule + * @requires module:modules/userId + */ + +import * as utils from '../src/utils.js' +import { ajax } from '../src/ajax.js'; +import { submodule } from '../src/hook.js'; +import {getStorageManager} from '../src/storageManager.js'; + +export const storage = getStorageManager(); + +/** @type {Submodule} */ +export const admixerIdSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: 'admixerId', + /** + * used to specify vendor id + * @type {number} + */ + gvlid: 511, + /** + * decode the stored id value for passing to bid requests + * @function + * @param {string} value + * @returns {{__adm__admixer:string}} + */ + decode(value) { + return { '__adm__admixer': value } + }, + /** + * performs action to obtain id and return a value in the callback's response argument + * @function + * @param {ConsentData} [consentData] + * @param {SubmoduleConfig} [config] + * @returns {IdResponse|undefined} + */ + getId(config, consentData) { + const {e, p, pid} = (config && config.params) || {}; + if (!pid || typeof pid !== 'string') { + utils.logError('admixerId submodule requires partner id to be defined'); + return; + } + const gdpr = (consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies) ? 1 : 0; + const consentString = gdpr ? consentData.consentString : ''; + if (gdpr && !consentString) { + utils.logInfo('Consent string is required to call admixer id.'); + return; + } + const url = `https://inv-nets.admixer.net/cntcm.aspx?ssp=${pid}${e ? `&e=${e}` : ''}${p ? `&p=${p}` : ''}${consentString ? `&cs=${consentString}` : ''}`; + const resp = function(callback) { + if (window.admixTMLoad && window.admixTMLoad.push) { + window.admixTMLoad.push(function() { + window.admixTM.retrieveVisitorId(function(visitorId) { + if (visitorId) { + callback(visitorId); + } else { + callback(); + } + }); + }); + } else { + retrieveVisitorId(url, callback); + } + }; + + return { callback: resp }; + } +}; +function retrieveVisitorId(url, callback) { + ajax(url, { + success: response => { + const {setData: {visitorid} = {}} = JSON.parse(response || '{}'); + if (visitorid) { + callback(visitorid); + } else { + callback(); + } + }, + error: error => { + utils.logInfo(`admixerId: fetch encountered an error`, error); + callback(); + } + }, undefined, { method: 'GET', withCredentials: true }); +} + +submodule('userId', admixerIdSubmodule); diff --git a/modules/userId/eids.js b/modules/userId/eids.js index d714d09962d..80f8947d298 100644 --- a/modules/userId/eids.js +++ b/modules/userId/eids.js @@ -168,6 +168,12 @@ const USER_IDS_CONFIG = { 'fabrickId': { source: 'neustar.biz', atype: 1 + }, + + // Admixer Id + '__adm__admixer': { + source: 'admixer.net', + atype: 1 } }; diff --git a/test/spec/modules/admixerIdSystem_spec.js b/test/spec/modules/admixerIdSystem_spec.js new file mode 100644 index 00000000000..18107b780db --- /dev/null +++ b/test/spec/modules/admixerIdSystem_spec.js @@ -0,0 +1,81 @@ +import {admixerIdSubmodule} from 'modules/admixerIdSystem.js'; +import * as utils from 'src/utils.js'; +import {server} from 'test/mocks/xhr.js'; +import {getStorageManager} from '../../../src/storageManager.js'; + +export const storage = getStorageManager(); + +const pid = '4D393FAC-B6BB-4E19-8396-0A4813607316'; +const getIdParams = {params: {pid: pid}}; +describe('admixerId tests', function () { + let logErrorStub; + + beforeEach(function () { + logErrorStub = sinon.stub(utils, 'logError'); + }); + + afterEach(function () { + logErrorStub.restore(); + }); + + it('should log an error if pid configParam was not passed when getId', function () { + admixerIdSubmodule.getId(); + expect(logErrorStub.callCount).to.be.equal(1); + + admixerIdSubmodule.getId({}); + expect(logErrorStub.callCount).to.be.equal(2); + + admixerIdSubmodule.getId({params: {}}); + expect(logErrorStub.callCount).to.be.equal(3); + + admixerIdSubmodule.getId({params: {pid: 123}}); + expect(logErrorStub.callCount).to.be.equal(4); + }); + + it('should NOT call the admixer id endpoint if gdpr applies but consent string is missing', function () { + let submoduleCallback = admixerIdSubmodule.getId(getIdParams, { gdprApplies: true }); + expect(submoduleCallback).to.be.undefined; + }); + + it('should call the admixer id endpoint', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = admixerIdSubmodule.getId(getIdParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq(`https://inv-nets.admixer.net/cntcm.aspx?ssp=${pid}`); + request.respond( + 200, + {}, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should call callback with user id', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = admixerIdSubmodule.getId(getIdParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq(`https://inv-nets.admixer.net/cntcm.aspx?ssp=${pid}`); + request.respond( + 200, + {}, + JSON.stringify({setData: {visitorid: '571058d70bce453b80e6d98b4f8a81e3'}}) + ); + expect(callBackSpy.calledOnce).to.be.true; + expect(callBackSpy.args[0][0]).to.be.eq('571058d70bce453b80e6d98b4f8a81e3'); + }); + + it('should continue to callback if ajax response 204', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = admixerIdSubmodule.getId(getIdParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq(`https://inv-nets.admixer.net/cntcm.aspx?ssp=${pid}`); + request.respond( + 204 + ); + expect(callBackSpy.calledOnce).to.be.true; + expect(callBackSpy.args[0][0]).to.be.undefined; + }); +}); From 713d23e9faea6269863802feb619043b1471a92e Mon Sep 17 00:00:00 2001 From: Galphimbl Date: Thu, 28 Jan 2021 13:46:29 +0200 Subject: [PATCH 11/14] admixer id system --- modules/admixerIdSystem.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/admixerIdSystem.js b/modules/admixerIdSystem.js index 93c39adda84..e2b7b20e777 100644 --- a/modules/admixerIdSystem.js +++ b/modules/admixerIdSystem.js @@ -1,7 +1,7 @@ /** - * This module adds IdentityLink to the User ID module + * This module adds AdmixerId to the User ID module * The {@link module:modules/userId} module is required - * @module modules/identityLinkSubmodule + * @module modules/admixerIdSubmodule * @requires module:modules/userId */ From 517a397f082c477bc82371ac7b607a6c652ef3f1 Mon Sep 17 00:00:00 2001 From: Galphimbl Date: Sun, 31 Jan 2021 19:20:11 +0200 Subject: [PATCH 12/14] admixer id system eids.md userId.md --- modules/userId/eids.md | 7 +++++++ modules/userId/userId.md | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/modules/userId/eids.md b/modules/userId/eids.md index b69c4b9bd5e..b70948d6634 100644 --- a/modules/userId/eids.md +++ b/modules/userId/eids.md @@ -148,6 +148,13 @@ userIdAsEids = [ id: 'some-random-id-value', atype: 1 }] + }, + { + source: 'admixer.net', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] } ] ``` diff --git a/modules/userId/userId.md b/modules/userId/userId.md index 267b3a60cea..07e1632ff70 100644 --- a/modules/userId/userId.md +++ b/modules/userId/userId.md @@ -77,6 +77,18 @@ pbjs.setConfig({ name: '_criteoId', expires: 1 } + }, { + name: 'admixerId', + params: { + pid: "4D393FAC-B6BB-4E19-8396-0A4813607316", // example id + e: "3d400b57e069c993babea0bd9efa79e5dc698e16c042686569faae20391fd7ea", // example hashed email (sha256) + p: "05de6c07eb3ea4bce45adca4e0182e771d80fbb99e12401416ca84ddf94c3eb9" //example hashed phone (sha256) + }, + storage: { + type: 'cookie', + name: '__adm__admixer', + expires: 30 + } }], syncDelay: 5000, auctionDelay: 1000 @@ -155,6 +167,18 @@ pbjs.setConfig({ name: '_criteoId', expires: 1 } + }, { + name: 'admixerId', + params: { + pid: "4D393FAC-B6BB-4E19-8396-0A4813607316", // example id + e: "3d400b57e069c993babea0bd9efa79e5dc698e16c042686569faae20391fd7ea", // example hashed email (sha256) + p: "05de6c07eb3ea4bce45adca4e0182e771d80fbb99e12401416ca84ddf94c3eb9" //example hashed phone (sha256) + }, + storage: { + type: 'html5', + name: '__adm__admixer', + expires: 30 + } }], syncDelay: 5000 } From 0387a682cdace665e9895816b750a5eba855186b Mon Sep 17 00:00:00 2001 From: Galphimbl Date: Sun, 31 Jan 2021 19:25:22 +0200 Subject: [PATCH 13/14] admixer id system .submodules.json --- modules/.submodules.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/.submodules.json b/modules/.submodules.json index fc69dd276a3..394770ca350 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -20,7 +20,8 @@ "fabrickIdSystem", "verizonMediaIdSystem", "pubProvidedIdSystem", - "tapadIdSystem" + "tapadIdSystem", + "admixerIdSystem" ], "adpod": [ "freeWheelAdserverVideo", From cefe9d1b0444c1eaac7cb9abff9077ec9fdbb8d7 Mon Sep 17 00:00:00 2001 From: Galphimbl Date: Mon, 5 Apr 2021 16:59:45 +0300 Subject: [PATCH 14/14] admixer id system --- modules/admixerIdSystem.js | 6 +- modules/userId/eids.js | 4 +- test/spec/modules/userId_spec.js | 112 +++++++++++++++++++++++++------ 3 files changed, 97 insertions(+), 25 deletions(-) diff --git a/modules/admixerIdSystem.js b/modules/admixerIdSystem.js index e2b7b20e777..c963f1e5b88 100644 --- a/modules/admixerIdSystem.js +++ b/modules/admixerIdSystem.js @@ -28,16 +28,16 @@ export const admixerIdSubmodule = { * decode the stored id value for passing to bid requests * @function * @param {string} value - * @returns {{__adm__admixer:string}} + * @returns {{admixerId:string}} */ decode(value) { - return { '__adm__admixer': value } + return { 'admixerId': value } }, /** * performs action to obtain id and return a value in the callback's response argument * @function - * @param {ConsentData} [consentData] * @param {SubmoduleConfig} [config] + * @param {ConsentData} [consentData] * @returns {IdResponse|undefined} */ getId(config, consentData) { diff --git a/modules/userId/eids.js b/modules/userId/eids.js index c3ac632fc9d..261916332a4 100644 --- a/modules/userId/eids.js +++ b/modules/userId/eids.js @@ -175,9 +175,9 @@ const USER_IDS_CONFIG = { }, // Admixer Id - '__adm__admixer': { + 'admixerId': { source: 'admixer.net', - atype: 1 + atype: 3 } }; diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index ed592c0cba5..ddfc0e2dfb8 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -39,6 +39,7 @@ import {haloIdSubmodule} from 'modules/haloIdSystem.js'; import {pubProvidedIdSubmodule} from 'modules/pubProvidedIdSystem.js'; import {criteoIdSubmodule} from 'modules/criteoIdSystem.js'; import {tapadIdSubmodule} from 'modules/tapadIdSystem.js'; +import {admixerIdSubmodule} from 'modules/admixerIdSystem.js'; let assert = require('chai').assert; let expect = require('chai').expect; @@ -457,7 +458,7 @@ describe('User ID', function () { }); it('handles config with no usersync object', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({}); // usersync is undefined, and no logInfo message for 'User ID - usersync config updated' @@ -465,14 +466,14 @@ describe('User ID', function () { }); it('handles config with empty usersync object', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({userSync: {}}); expect(typeof utils.logInfo.args[0]).to.equal('undefined'); }); it('handles config with usersync and userIds that are empty objs', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -483,7 +484,7 @@ describe('User ID', function () { }); it('handles config with usersync and userIds with empty names or that dont match a submodule.name', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -500,15 +501,15 @@ describe('User ID', function () { }); it('config with 1 configurations should create 1 submodules', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule, admixerIdSubmodule]); init(config); config.setConfig(getConfigMock(['unifiedId', 'unifiedid', 'cookie'])); expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 1 submodules'); }); - it('config with 14 configurations should result in 14 submodules add', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, liveIntentIdSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule]); + it('config with 15 configurations should result in 15 submodules add', function () { + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, liveIntentIdSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -551,14 +552,17 @@ describe('User ID', function () { }, { name: 'tapadId', storage: {name: 'tapad_id', type: 'cookie'} + }, { + name: 'admixerId', + storage: {name: 'admixerId', type: 'cookie'} }] } }); - expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 14 submodules'); + expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 15 submodules'); }); it('config syncDelay updates module correctly', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -573,7 +577,7 @@ describe('User ID', function () { }); it('config auctionDelay updates module correctly', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -588,7 +592,7 @@ describe('User ID', function () { }); it('config auctionDelay defaults to 0 if not a number', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, tapadIdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -1494,7 +1498,54 @@ describe('User ID', function () { }, {adUnits}); }); - it('test hook when pubCommonId, unifiedId, id5Id, identityLink, britepoolId, intentIqId, zeotapIdPlus, sharedId, netId, haloId and Criteo have data to pass', function (done) { + it('test hook from admixerId html5', function (done) { + // simulate existing browser local storage values + localStorage.setItem('admixerId', 'testadmixerId'); + localStorage.setItem('admixerId_exp', ''); + + setSubmoduleRegistry([admixerIdSubmodule]); + init(config); + config.setConfig(getConfigMock(['admixerId', 'admixerId', 'html5'])); + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.admixerId'); + expect(bid.userId.admixerId).to.equal('testadmixerId'); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: 'admixer.net', + uids: [{id: 'testadmixerId', atype: 3}] + }); + }); + }); + localStorage.removeItem('admixerId'); + done(); + }, {adUnits}); + }); + + it('test hook from admixerId cookie', function (done) { + coreStorage.setCookie('admixerId', 'testadmixerId', (new Date(Date.now() + 100000).toUTCString())); + + setSubmoduleRegistry([admixerIdSubmodule]); + init(config); + config.setConfig(getConfigMock(['admixerId', 'admixerId', 'cookie'])); + + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.admixerId'); + expect(bid.userId.admixerId).to.equal('testadmixerId'); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: 'admixer.net', + uids: [{id: 'testadmixerId', atype: 3}] + }); + }); + }); + coreStorage.setCookie('admixerId', '', EXPIRED_COOKIE_DATE); + done(); + }, {adUnits}); + }); + + it('test hook when pubCommonId, unifiedId, id5Id, identityLink, britepoolId, intentIqId, zeotapIdPlus, sharedId, netId, haloId, admixerId and Criteo have data to pass', function (done) { coreStorage.setCookie('pubcid', 'testpubcid', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('unifiedid', JSON.stringify({'TDID': 'testunifiedid'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('id5id', JSON.stringify({'universal_uid': 'testid5id'}), (new Date(Date.now() + 5000).toUTCString())); @@ -1509,8 +1560,9 @@ describe('User ID', function () { }), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('haloId', JSON.stringify({'haloId': 'testHaloId'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('storage_criteo', JSON.stringify({'criteoId': 'test_bidid'}), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('admixerId', 'testadmixerId', (new Date(Date.now() + 5000).toUTCString())); - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, criteoIdSubmodule, tapadIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, criteoIdSubmodule, tapadIdSubmodule, admixerIdSubmodule]); init(config); config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie'], ['unifiedId', 'unifiedid', 'cookie'], @@ -1523,7 +1575,8 @@ describe('User ID', function () { ['zeotapIdPlus', 'IDP', 'cookie'], ['haloId', 'haloId', 'cookie'], ['criteo', 'storage_criteo', 'cookie'], - ['tapadId', 'tapad_id', 'cookie'])); + ['tapadId', 'tapad_id', 'cookie'], + ['admixerId', 'admixerId', 'cookie'])); requestBidsHook(function () { adUnits.forEach(unit => { @@ -1563,8 +1616,11 @@ describe('User ID', function () { // also check that criteo id was copied to bid expect(bid).to.have.deep.nested.property('userId.criteoId'); expect(bid.userId.criteoId).to.equal('test_bidid'); + // also check that criteo id was copied to bid + expect(bid).to.have.deep.nested.property('userId.admixerId'); + expect(bid.userId.admixerId).to.equal('testadmixerId'); - expect(bid.userIdAsEids.length).to.equal(11); + expect(bid.userIdAsEids.length).to.equal(12); }); }); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); @@ -1578,11 +1634,12 @@ describe('User ID', function () { coreStorage.setCookie('IDP', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('haloId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('storage_criteo', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('admixerId', '', EXPIRED_COOKIE_DATE); done(); }, {adUnits}); }); - it('test hook when pubCommonId, unifiedId, id5Id, britepoolId, intentIqId, zeotapIdPlus, sharedId, criteo, netId and haloId have their modules added before and after init', function (done) { + it('test hook when pubCommonId, unifiedId, id5Id, britepoolId, intentIqId, zeotapIdPlus, sharedId, criteo, netId, admixerId and haloId have their modules added before and after init', function (done) { coreStorage.setCookie('pubcid', 'testpubcid', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('unifiedid', JSON.stringify({'TDID': 'cookie-value-add-module-variations'}), new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('id5id', JSON.stringify({'universal_uid': 'testid5id'}), (new Date(Date.now() + 5000).toUTCString())); @@ -1597,6 +1654,7 @@ describe('User ID', function () { coreStorage.setCookie('IDP', btoa(JSON.stringify('zeotapId')), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('haloId', JSON.stringify({'haloId': 'testHaloId'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('storage_criteo', JSON.stringify({'criteoId': 'test_bidid'}), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('admixerId', 'testadmixerId', (new Date(Date.now() + 5000).toUTCString())); setSubmoduleRegistry([]); @@ -1617,6 +1675,7 @@ describe('User ID', function () { attachIdSystem(haloIdSubmodule); attachIdSystem(criteoIdSubmodule); attachIdSystem(tapadIdSubmodule); + attachIdSystem(admixerIdSubmodule); config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie'], ['unifiedId', 'unifiedid', 'cookie'], @@ -1629,7 +1688,8 @@ describe('User ID', function () { ['zeotapIdPlus', 'IDP', 'cookie'], ['haloId', 'haloId', 'cookie'], ['criteo', 'storage_criteo', 'cookie'], - ['tapadId', 'tapad_id', 'cookie'])); + ['tapadId', 'tapad_id', 'cookie'], + ['admixerId', 'admixerId', 'cookie'])); requestBidsHook(function () { adUnits.forEach(unit => { @@ -1672,7 +1732,11 @@ describe('User ID', function () { expect(bid).to.have.deep.nested.property('userId.criteoId'); expect(bid.userId.criteoId).to.equal('test_bidid'); - expect(bid.userIdAsEids.length).to.equal(11); + // also check that criteo id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.admixerId'); + expect(bid.userId.admixerId).to.equal('testadmixerId'); + + expect(bid.userIdAsEids.length).to.equal(12); }); }); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); @@ -1686,6 +1750,7 @@ describe('User ID', function () { coreStorage.setCookie('IDP', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('haloId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('storage_criteo', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('admixerId', '', EXPIRED_COOKIE_DATE); done(); }, {adUnits}); }); @@ -1914,9 +1979,10 @@ describe('User ID', function () { coreStorage.setCookie('intentIqId', 'testintentIqId', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('IDP', btoa(JSON.stringify('zeotapId')), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('haloId', JSON.stringify({'haloId': 'testHaloId'}), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('admixerId', 'testadmixerId', new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('MOCKID', JSON.stringify({'MOCKID': '123456778'}), new Date(Date.now() + 5000).toUTCString()); - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ @@ -1942,6 +2008,8 @@ describe('User ID', function () { name: 'zeotapIdPlus' }, { name: 'haloId', storage: {name: 'haloId', type: 'cookie'} + }, { + name: 'admixerId', storage: {name: 'admixerId', type: 'cookie'} }, { name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'} }] @@ -2001,7 +2069,10 @@ describe('User ID', function () { // also check that haloId id data was copied to bid expect(bid).to.have.deep.nested.property('userId.haloId'); expect(bid.userId.haloId).to.equal('testHaloId'); - expect(bid.userIdAsEids.length).to.equal(10); + // also check that admixerId id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.admixerId'); + expect(bid.userId.admixerId).to.equal('testadmixerId'); + expect(bid.userIdAsEids.length).to.equal(11); }); }); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); @@ -2014,6 +2085,7 @@ describe('User ID', function () { coreStorage.setCookie('intentIqId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('IDP', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('haloId', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('admixerId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('MOCKID', '', EXPIRED_COOKIE_DATE); done(); }, {adUnits});