Skip to content

Commit 06b16f7

Browse files
vivekyadav15kiho-shige
authored andcommitted
Medianet Analytics Adapter: ADD bid properties in logs and small fix in bidTimeoutHandler (prebid#12526)
1 parent 42b98bd commit 06b16f7

File tree

2 files changed

+105
-29
lines changed

2 files changed

+105
-29
lines changed

modules/medianetAnalyticsAdapter.js

Lines changed: 96 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
logError,
99
logInfo,
1010
triggerPixel,
11-
uniques
11+
uniques,
12+
deepSetValue
1213
} from '../src/utils.js';
1314
import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js';
1415
import adapterManager from '../src/adapterManager.js';
@@ -18,6 +19,7 @@ import {getRefererInfo} from '../src/refererDetection.js';
1819
import {AUCTION_COMPLETED, AUCTION_IN_PROGRESS, getPriceGranularity} from '../src/auction.js';
1920
import {includes} from '../src/polyfill.js';
2021
import {getGlobal} from '../src/prebidGlobal.js';
22+
import {convertCurrency} from '../libraries/currencyUtils/currency.js';
2123

2224
const analyticsType = 'endpoint';
2325
const ENDPOINT = 'https://pb-logs.media.net/log?logid=kfk&evtid=prebid_analytics_events_client';
@@ -112,6 +114,7 @@ class Configure {
112114
pbv: PREBID_VERSION,
113115
pbav: ANALYTICS_VERSION,
114116
flt: 1,
117+
enableDbf: 1
115118
}
116119
}
117120

@@ -303,21 +306,17 @@ class BidWrapper {
303306
this.bidObjs.push(bidObj);
304307
}
305308

306-
getAdSlotBids(adSlot) {
307-
const bidResponses = this.getAdSlotBidObjs(adSlot);
308-
return bidResponses.map((bid) => bid.getLoggingData());
309+
getAdSlotBidRequests(adSlot) {
310+
return this.bidReqs.filter((bid) => bid.adUnitCode === adSlot);
309311
}
310312

311-
getAdSlotBidObjs(adSlot) {
312-
const bidResponses = this.bidObjs
313-
.filter((bid) => bid.adUnitCode === adSlot);
314-
const remResponses = this.bidReqs.filter(bid => !bid.used && bid.adUnitCode === adSlot);
315-
return [...bidResponses, ...remResponses];
313+
getAdSlotBidResponses(adSlot) {
314+
return this.bidObjs.filter((bid) => bid.adUnitCode === adSlot);
316315
}
317316
}
318317

319318
class Bid {
320-
constructor(bidId, bidder, src, start, adUnitCode, mediaType, allMediaTypeSizes) {
319+
constructor(bidId, bidder, src, start, adUnitCode, mediaType, allMediaTypeSizes, resSizes) {
321320
this.bidId = bidId;
322321
this.bidder = bidder;
323322
this.src = src;
@@ -348,6 +347,14 @@ class Bid {
348347
this.used = false;
349348
this.originalRequestId = bidId;
350349
this.requestId = undefined;
350+
this.advUrl = undefined;
351+
this.latestAcid = undefined;
352+
this.originalCurrency = undefined;
353+
this.currMul = undefined;
354+
this.inCurrMul = undefined;
355+
this.res_mtype = undefined;
356+
this.res_sizes = resSizes;
357+
this.req_mtype = mediaType;
351358
}
352359

353360
get size() {
@@ -374,7 +381,7 @@ class Bid {
374381
cbdp: this.dfpbd,
375382
dfpbd: this.dfpbd,
376383
szs: this.allMediaTypeSizes.join('|'),
377-
size: this.size,
384+
size: (this.res_sizes || [this.size]).join('|'),
378385
mtype: this.mediaType,
379386
dId: this.dealId,
380387
winner: this.winner,
@@ -389,6 +396,13 @@ class Bid {
389396
flrrule: this.floorRule,
390397
ext: JSON.stringify(this.ext),
391398
rtime: this.serverLatencyMillis,
399+
advurl: this.advUrl,
400+
lacid: this.latestAcid,
401+
icurr: this.originalCurrency,
402+
imul: this.inCurrMul,
403+
omul: this.currMul,
404+
res_mtype: this.res_mtype,
405+
req_mtype: this.req_mtype
392406
}
393407
}
394408
}
@@ -454,11 +468,12 @@ class Auction {
454468
return this.bidWrapper.findBidObj(key, value)
455469
}
456470

457-
getAdSlotBids(adSlot) {
458-
return this.bidWrapper.getAdSlotBids(adSlot);
471+
getAdSlotBidRequests(adSlot) {
472+
return this.bidWrapper.getAdSlotBidRequests(adSlot);
459473
}
460-
getAdSlotBidObjs(adSlot) {
461-
return this.bidWrapper.getAdSlotBidObjs(adSlot);
474+
475+
getAdSlotBidResponses(adSlot) {
476+
return this.bidWrapper.getAdSlotBidResponses(adSlot);
462477
}
463478

464479
_mergeFieldsToLog(objParams) {
@@ -558,8 +573,8 @@ function _getSizes(mediaTypes, sizes) {
558573
}
559574

560575
function bidResponseHandler(bid) {
561-
const { width, height, mediaType, cpm, requestId, timeToRespond, auctionId, dealId, originalRequestId, bidder } = bid;
562-
const {originalCpm, creativeId, adId, currency} = bid;
576+
const { width, height, mediaType, cpm, requestId, timeToRespond, auctionId, dealId, originalRequestId, bidder, meta } = bid;
577+
let {originalCpm, creativeId, adId, currency, originalCurrency} = bid;
563578

564579
if (!(auctions[auctionId] instanceof Auction)) {
565580
return;
@@ -575,13 +590,26 @@ function bidResponseHandler(bid) {
575590
bidObj = {};
576591
isBidOverridden = false;
577592
}
593+
currency = currency ? currency.toUpperCase() : '';
594+
originalCurrency = originalCurrency ? originalCurrency.toUpperCase() : currency;
578595
Object.assign(bidObj, bidReq,
579596
{ cpm, width, height, mediaType, timeToRespond, dealId, creativeId, originalRequestId, requestId },
580-
{ adId, currency }
597+
{ adId, currency, originalCurrency }
581598
);
582599
bidObj.floorPrice = deepAccess(bid, 'floorData.floorValue');
583600
bidObj.floorRule = deepAccess(bid, 'floorData.floorRule');
584601
bidObj.originalCpm = originalCpm || cpm;
602+
bidObj.advUrl = meta && meta.advertiserDomains && meta.advertiserDomains.join(',');
603+
bidObj.currMul = 1;
604+
bidObj.inCurrMul = 1;
605+
if (bidObj.originalCurrency !== 'USD') {
606+
bidObj.originalCpm = exchangeCurrency(bidObj.originalCpm, bidObj.originalCurrency, 'USD');
607+
bidObj.inCurrMul = exchangeCurrency(1, 'USD', bidObj.originalCurrency)
608+
}
609+
if (bidObj.currency !== 'USD') {
610+
bidObj.cpm = exchangeCurrency(bidObj.cpm, bidObj.currency, 'USD');
611+
bidObj.currMul = exchangeCurrency(1, 'USD', bidObj.currency)
612+
}
585613
let dfpbd = deepAccess(bid, 'adserverTargeting.hb_pb');
586614
if (!dfpbd) {
587615
let priceGranularity = getPriceGranularity(bid);
@@ -606,9 +634,19 @@ function bidResponseHandler(bid) {
606634
if (typeof bid.serverResponseTimeMs !== 'undefined') {
607635
bidObj.serverLatencyMillis = bid.serverResponseTimeMs;
608636
}
637+
bidObj.res_mtype = mediaType;
609638
!isBidOverridden && auctions[auctionId].addBidObj(bidObj);
610639
}
611640

641+
function exchangeCurrency(price, fromCurrency, toCurrency) {
642+
try {
643+
return convertCurrency(price, fromCurrency, toCurrency, false).toFixed(4)
644+
} catch (e) {
645+
logError(`Media.net Analytics Adapter: Could not convert ${fromCurrency} to ${toCurrency} for price ${price}`);
646+
}
647+
return price;
648+
}
649+
612650
function noBidResponseHandler({ auctionId, bidId }) {
613651
if (!(auctions[auctionId] instanceof Auction)) {
614652
return;
@@ -630,7 +668,7 @@ function bidTimeoutHandler(timedOutBids) {
630668
if (!(auctions[auctionId] instanceof Auction)) {
631669
return;
632670
}
633-
const bidReq = auctions[auctionId].findReqBid('bidId', bidId);
671+
const bidReq = auctions[auctionId].findReqBid(bidId);
634672
if (!(bidReq instanceof Bid) || bidReq.used) {
635673
return;
636674
}
@@ -710,6 +748,7 @@ function bidWonHandler(bid) {
710748
}).send();
711749
return;
712750
}
751+
bidObj.latestAcid = bid.latestTargetedAuctionId;
713752
auctions[auctionId].bidWonTime = Date.now();
714753
bidObj.winner = 1;
715754
sendEvent(auctionId, adUnitCode, LOG_TYPE.RA, bidObj.adId);
@@ -749,6 +788,43 @@ function getCommonLoggingData(acid, adtag) {
749788
return Object.assign(commonParams, adunitParams, auctionParams);
750789
}
751790

791+
function getResponseSizeMap(acid, adtag) {
792+
const responses = auctions[acid].getAdSlotBidResponses(adtag);
793+
const receivedResponse = {};
794+
// Set true in map for success bids
795+
responses.filter((bid) => bid.size !== '')
796+
.forEach((bid) => deepSetValue(receivedResponse, `${bid.bidId}.${bid.size}`, true));
797+
798+
// For non-success bids:
799+
// 1) set bid.res_sizes = (sizes for which no successful bid received)
800+
// 2) set true in map
801+
responses.filter((bid) => bid.size === '').forEach((bid) => {
802+
bid.res_sizes = bid.allMediaTypeSizes.filter((size) => !deepAccess(receivedResponse, `${bid.bidId}.${size}`));
803+
bid.allMediaTypeSizes.forEach((size) => deepSetValue(receivedResponse, `${bid.bidId}.${size}`, true));
804+
});
805+
return receivedResponse;
806+
}
807+
808+
function getDummyBids(acid, adtag, receivedResponse) {
809+
const emptyBids = [];
810+
auctions[acid].getAdSlotBidRequests(adtag).forEach(({ bidId, bidder, src, start, adUnitCode, mediaType, allMediaTypeSizes, status }) => {
811+
const emptySizes = allMediaTypeSizes.filter((size) => !deepAccess(receivedResponse, `${bidId}.${size}`));
812+
if (bidder !== DUMMY_BIDDER && emptySizes.length > 0) {
813+
const bid = new Bid(bidId, bidder, src, start, adUnitCode, mediaType, allMediaTypeSizes, emptySizes);
814+
bid.status = status === BID_SUCCESS ? BID_NOBID : status;
815+
emptyBids.push(bid);
816+
}
817+
});
818+
return emptyBids;
819+
}
820+
821+
function getLoggingBids(acid, adtag) {
822+
const receivedResponse = getResponseSizeMap(acid, adtag);
823+
const dummyBids = getDummyBids(acid, adtag, receivedResponse);
824+
825+
return [...auctions[acid].getAdSlotBidResponses(adtag), ...dummyBids];
826+
}
827+
752828
function fireAuctionLog(acid, adtag, logType, adId) {
753829
let commonParams = getCommonLoggingData(acid, adtag);
754830
commonParams.lgtp = logType;
@@ -766,7 +842,7 @@ function fireAuctionLog(acid, adtag, logType, adId) {
766842
bidParams = [winLogData];
767843
commonParams.lper = 1;
768844
} else {
769-
bidParams = auctions[acid].getAdSlotBids(adtag).map(({winner, ...restParams}) => restParams);
845+
bidParams = getLoggingBids(acid, adtag).map((bid) => bid.getLoggingData())
770846
delete commonParams.wts;
771847
}
772848
let mnetPresent = bidParams.filter(b => b.pvnm === MEDIANET_BIDDER_CODE).length > 0;

test/spec/modules/medianetAnalyticsAdapter_spec.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ describe('Media.net Analytics Adapter', function() {
210210
expect(noBidLog.pvnm).to.have.ordered.members(['-2', 'bidder1', 'bidder1', 'medianet']);
211211
expect(noBidLog.mtype).to.have.ordered.members([banner, banner, banner, banner]);
212212
expect(noBidLog.status).to.have.ordered.members(['1', '2', '2', '2']);
213-
expect(noBidLog.size).to.have.ordered.members(['', '', '', '']);
213+
expect(noBidLog.size).to.have.ordered.members(['300x100|300x250', '300x100', '300x250', '300x250|300x100']);
214214
expect(noBidLog.szs).to.have.ordered.members(['300x100|300x250', '300x100', '300x250', '300x250|300x100']);
215215
});
216216

@@ -225,7 +225,7 @@ describe('Media.net Analytics Adapter', function() {
225225
it('should have winner log in standard auction', function() {
226226
medianetAnalytics.clearlogsQueue();
227227
performStandardAuctionWithWinner();
228-
let winnerLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter((log) => log.winner);
228+
let winnerLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter((log) => log.winner === '1');
229229
medianetAnalytics.clearlogsQueue();
230230

231231
expect(winnerLog.length).to.equal(1);
@@ -234,7 +234,7 @@ describe('Media.net Analytics Adapter', function() {
234234
it('should have correct values in winner log', function() {
235235
medianetAnalytics.clearlogsQueue();
236236
performStandardAuctionWithWinner();
237-
let winnerLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter((log) => log.winner);
237+
let winnerLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter((log) => log.winner === '1');
238238
medianetAnalytics.clearlogsQueue();
239239

240240
expect(winnerLog[0]).to.include({
@@ -258,7 +258,7 @@ describe('Media.net Analytics Adapter', function() {
258258
it('should have correct bid floor data in winner log', function() {
259259
medianetAnalytics.clearlogsQueue();
260260
performAuctionWithFloorConfig();
261-
let winnerLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter((log) => log.winner);
261+
let winnerLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter((log) => log.winner === '1');
262262
medianetAnalytics.clearlogsQueue();
263263

264264
expect(winnerLog[0]).to.include({
@@ -309,32 +309,32 @@ describe('Media.net Analytics Adapter', function() {
309309

310310
it('should pick winning bid if multibids with same request id', function() {
311311
performStandardAuctionMultiBidWithSameRequestId(MOCK.BIDS_SAME_REQ_DIFF_CPM);
312-
let winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner)[0];
312+
let winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner === '1')[0];
313313
expect(winningBid.adid).equals('3e6e4bce5c8fb3');
314314
medianetAnalytics.clearlogsQueue();
315315

316316
const reversedResponseArray = [].concat(MOCK.BIDS_SAME_REQ_DIFF_CPM).reverse();
317317
performStandardAuctionMultiBidWithSameRequestId(reversedResponseArray);
318-
winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner)[0];
318+
winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner === '1')[0];
319319
expect(winningBid.adid).equals('3e6e4bce5c8fb3');
320320
});
321321

322322
it('should pick winning bid if multibids with same request id and same time to respond', function() {
323323
performStandardAuctionMultiBidWithSameRequestId(MOCK.BIDS_SAME_REQ_DIFF_CPM_SAME_TIME);
324-
let winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner)[0];
324+
let winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner === '1')[0];
325325
expect(winningBid.adid).equals('3e6e4bce5c8fb3');
326326
medianetAnalytics.clearlogsQueue();
327327
});
328328

329329
it('should pick winning bid if multibids with same request id and equal cpm', function() {
330330
performStandardAuctionMultiBidWithSameRequestId(MOCK.BIDS_SAME_REQ_EQUAL_CPM);
331-
let winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner)[0];
331+
let winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner === '1')[0];
332332
expect(winningBid.adid).equals('3e6e4bce5c8fb3');
333333
medianetAnalytics.clearlogsQueue();
334334

335335
const reversedResponseArray = [].concat(MOCK.BIDS_SAME_REQ_EQUAL_CPM).reverse();
336336
performStandardAuctionMultiBidWithSameRequestId(reversedResponseArray);
337-
winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner)[0];
337+
winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner === '1')[0];
338338
expect(winningBid.adid).equals('3e6e4bce5c8fb3');
339339
});
340340

0 commit comments

Comments
 (0)