Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Medianet Analytics Adapter: fix and support for multibid module #9602

Merged
merged 1 commit into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 120 additions & 56 deletions modules/medianetAnalyticsAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import {
logError,
logInfo,
triggerPixel,
uniques,
getHighestCpm
uniques
} from '../src/utils.js';
import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js';
import adapterManager from '../src/adapterManager.js';
Expand Down Expand Up @@ -41,6 +40,7 @@ const PREBID_VERSION = $$PREBID_GLOBAL$$.version;
const ERROR_CONFIG_JSON_PARSE = 'analytics_config_parse_fail';
const ERROR_CONFIG_FETCH = 'analytics_config_ajax_fail';
const ERROR_WINNING_BID_ABSENT = 'winning_bid_absent';
const ERROR_WINNING_AUCTION_MISSING = 'winning_auction_missing';
const BID_SUCCESS = 1;
const BID_NOBID = 2;
const BID_TIMEOUT = 3;
Expand Down Expand Up @@ -72,7 +72,7 @@ class ErrorLogger {
this.evtid = 'projectevents';
this.project = 'prebidanalytics';
this.dn = pageDetails.domain || '';
this.requrl = pageDetails.requrl || '';
this.requrl = pageDetails.topmostLocation || '';
this.pbversion = PREBID_VERSION;
this.cid = config.cid || '';
this.rd = additionalData;
Expand Down Expand Up @@ -270,6 +270,52 @@ class AdSlot {
}
}

class BidWrapper {
constructor() {
this.bidReqs = [];
this.bidObjs = [];
}

findReqBid(bidId) {
return this.bidReqs.find(bid => {
return bid['bidId'] === bidId
});
}

findBidObj(key, value) {
return this.bidObjs.find(bid => {
return bid[key] === value
});
}

addBidReq(bidRequest) {
this.bidReqs.push(bidRequest)
}

addBidObj(bidObj) {
if (!(bidObj instanceof Bid)) {
bidObj = Bid.getInstance(bidObj);
}
const bidReq = this.findReqBid(bidObj.bidId);
if (bidReq instanceof Bid) {
bidReq.used = true;
}
this.bidObjs.push(bidObj);
}

getAdSlotBids(adSlot) {
const bidResponses = this.getAdSlotBidObjs(adSlot);
return bidResponses.map((bid) => bid.getLoggingData());
}

getAdSlotBidObjs(adSlot) {
const bidResponses = this.bidObjs
.filter((bid) => bid.adUnitCode === adSlot);
const remResponses = this.bidReqs.filter(bid => !bid.used && bid.adUnitCode === adSlot);
return [...bidResponses, ...remResponses];
}
}

class Bid {
constructor(bidId, bidder, src, start, adUnitCode, mediaType, allMediaTypeSizes) {
this.bidId = bidId;
Expand Down Expand Up @@ -299,6 +345,9 @@ class Bid {
this.floorPrice = undefined;
this.floorRule = undefined;
this.serverLatencyMillis = undefined;
this.used = false;
this.originalRequestId = bidId;
this.requestId = undefined;
}

get size() {
Expand All @@ -308,8 +357,15 @@ class Bid {
return this.width + 'x' + this.height;
}

static getInstance(bidProps) {
const bidObj = new Bid();
return bidProps && Object.assign(bidObj, bidProps);
}

getLoggingData() {
return {
reqId: this.requestId || this.bidId,
ogReqId: this.originalRequestId,
adid: this.adId,
pvnm: this.bidder,
src: this.src,
Expand Down Expand Up @@ -341,7 +397,7 @@ class Auction {
constructor(acid) {
this.acid = acid;
this.status = AUCTION_IN_PROGRESS;
this.bids = [];
this.bidWrapper = new BidWrapper();
this.adSlots = {};
this.auctionInitTime = undefined;
this.auctionStartTime = undefined;
Expand Down Expand Up @@ -378,24 +434,31 @@ class Auction {
addSlot({ adUnitCode, supplyAdCode, mediaTypes, allMediaTypeSizes, tmax, adext, context }) {
if (adUnitCode && this.adSlots[adUnitCode] === undefined) {
this.adSlots[adUnitCode] = new AdSlot(tmax, supplyAdCode, context, adext);
this.addBid(new Bid('-1', DUMMY_BIDDER, 'client', '-1', adUnitCode, mediaTypes, allMediaTypeSizes));
this.addBidObj(new Bid('-1', DUMMY_BIDDER, 'client', Date.now(), adUnitCode, mediaTypes, allMediaTypeSizes));
}
}

addBid(bid) {
this.bids.push(bid);
this.bidWrapper.addBidReq(bid);
}

findBid(key, value) {
return this.bids.filter(bid => {
return bid[key] === value
})[0];
addBidObj(bidObj) {
this.bidWrapper.addBidObj(bidObj)
}

getAdslotBids(adslot) {
return this.bids
.filter((bid) => bid.adUnitCode === adslot)
.map((bid) => bid.getLoggingData());
findReqBid(bidId) {
return this.bidWrapper.findReqBid(bidId)
}

findBidObj(key, value) {
return this.bidWrapper.findBidObj(key, value)
}

getAdSlotBids(adSlot) {
return this.bidWrapper.getAdSlotBids(adSlot);
}
getAdSlotBidObjs(adSlot) {
return this.bidWrapper.getAdSlotBidObjs(adSlot);
}

_mergeFieldsToLog(objParams) {
Expand Down Expand Up @@ -494,41 +557,26 @@ function _getSizes(mediaTypes, sizes) {
}
}

/*
- The code is used to determine if the current bid is higher than the previous bid.
- If it is, then the code will return true and if not, it will return false.
*/
function canSelectCurrentBid(previousBid, currentBid) {
if (!(previousBid instanceof Bid)) return false;

// For first bid response the previous bid will be containing bid request obj
// in which the cpm would be undefined so the current bid can directly be selected.
const isFirstBidResponse = previousBid.cpm === undefined && currentBid.cpm !== undefined;
if (isFirstBidResponse) return true;

// if there are 2 bids, get the highest bid
const selectedBid = getHighestCpm(previousBid, currentBid);

// Return true if selectedBid is currentBid,
// The timeToRespond field is used as an identifier for distinguishing
// between the current iterating bid and the previous bid.
return selectedBid.timeToRespond === currentBid.timeToRespond;
}

function bidResponseHandler(bid) {
const { width, height, mediaType, cpm, requestId, timeToRespond, auctionId, dealId } = bid;
const {originalCpm, bidderCode, creativeId, adId, currency} = bid;
const { width, height, mediaType, cpm, requestId, timeToRespond, auctionId, dealId, originalRequestId, bidder } = bid;
const {originalCpm, creativeId, adId, currency} = bid;

if (!(auctions[auctionId] instanceof Auction)) {
return;
}
let bidObj = auctions[auctionId].findBid('bidId', requestId);
if (!canSelectCurrentBid(bidObj, bid)) {
return;
const reqId = originalRequestId || requestId;
const bidReq = auctions[auctionId].findReqBid(reqId);

if (!(bidReq instanceof Bid)) return;

let bidObj = auctions[auctionId].findBidObj('bidId', requestId);
let isBidOverridden = true;
if (!bidObj || bidObj.status === BID_SUCCESS) {
bidObj = {};
isBidOverridden = false;
}
Object.assign(
bidObj,
{ cpm, width, height, mediaType, timeToRespond, dealId, creativeId },
Object.assign(bidObj, bidReq,
{ cpm, width, height, mediaType, timeToRespond, dealId, creativeId, originalRequestId, requestId },
{ adId, currency }
);
bidObj.floorPrice = deepAccess(bid, 'floorData.floorValue');
Expand All @@ -547,7 +595,7 @@ function bidResponseHandler(bid) {
bidObj.status = BID_SUCCESS;
}

if (bidderCode === MEDIANET_BIDDER_CODE && bid.ext instanceof Object) {
if (bidder === MEDIANET_BIDDER_CODE && bid.ext instanceof Object) {
Object.assign(
bidObj,
{ 'ext': bid.ext },
Expand All @@ -558,6 +606,7 @@ function bidResponseHandler(bid) {
if (typeof bid.serverResponseTimeMs !== 'undefined') {
bidObj.serverLatencyMillis = bid.serverResponseTimeMs;
}
!isBidOverridden && auctions[auctionId].addBidObj(bidObj);
}

function noBidResponseHandler({ auctionId, bidId }) {
Expand All @@ -567,23 +616,27 @@ function noBidResponseHandler({ auctionId, bidId }) {
if (auctions[auctionId].hasEnded()) {
return;
}
let bidObj = auctions[auctionId].findBid('bidId', bidId);
if (!(bidObj instanceof Bid)) {
const bidReq = auctions[auctionId].findReqBid(bidId);
if (!(bidReq instanceof Bid) || bidReq.used) {
return;
}
const bidObj = {...bidReq};
bidObj.status = BID_NOBID;
auctions[auctionId].addBidObj(bidObj);
}

function bidTimeoutHandler(timedOutBids) {
timedOutBids.map(({bidId, auctionId}) => {
if (!(auctions[auctionId] instanceof Auction)) {
return;
}
let bidObj = auctions[auctionId].findBid('bidId', bidId);
if (!(bidObj instanceof Bid)) {
const bidReq = auctions[auctionId].findReqBid('bidId', bidId);
if (!(bidReq instanceof Bid) || bidReq.used) {
return;
}
const bidObj = {...bidReq};
bidObj.status = BID_TIMEOUT;
auctions[auctionId].addBidObj(bidObj);
})
}

Expand Down Expand Up @@ -614,13 +667,13 @@ function setTargetingHandler(params) {
const winnerAdId = params[adunit][CONSTANTS.TARGETING_KEYS.AD_ID];
let winningBid;
let bidAdIds = Object.keys(targetingObj).map(k => targetingObj[k]);
auctionObj.bids.filter((bid) => bidAdIds.indexOf(bid.adId) !== -1).map(function(bid) {
auctionObj.bidWrapper.bidObjs.filter((bid) => bidAdIds.indexOf(bid.adId) !== -1).map(function(bid) {
bid.iwb = 1;
if (bid.adId === winnerAdId) {
winningBid = bid;
}
});
auctionObj.bids.forEach(bid => {
auctionObj.bidWrapper.bidObjs.forEach(bid => {
if (bid.bidder === DUMMY_BIDDER && bid.adUnitCode === adunit) {
bid.iwb = bidAdIds.length === 0 ? 0 : 1;
bid.width = deepAccess(winningBid, 'width');
Expand All @@ -633,16 +686,27 @@ function setTargetingHandler(params) {
}

function bidWonHandler(bid) {
const { auctionId, adUnitCode, adId } = bid;
const { auctionId, adUnitCode, adId, bidder, requestId, originalRequestId } = bid;
if (!(auctions[auctionId] instanceof Auction)) {
new ErrorLogger(ERROR_WINNING_AUCTION_MISSING, {
adId,
auctionId,
adUnitCode,
bidder,
requestId,
originalRequestId
}).send();
return;
}
let bidObj = auctions[auctionId].findBid('adId', adId);
let bidObj = auctions[auctionId].findBidObj('adId', adId);
if (!(bidObj instanceof Bid)) {
new ErrorLogger(ERROR_WINNING_BID_ABSENT, {
adId: adId,
acid: auctionId,
adId,
auctionId,
adUnitCode,
bidder,
requestId,
originalRequestId
}).send();
return;
}
Expand Down Expand Up @@ -696,13 +760,13 @@ function fireAuctionLog(acid, adtag, logType, adId) {
let bidParams;

if (logType === LOG_TYPE.RA) {
const winningBidObj = auctions[acid].findBid('adId', adId);
const winningBidObj = auctions[acid].findBidObj('adId', adId);
if (!winningBidObj) return;
const winLogData = winningBidObj.getLoggingData();
bidParams = [winLogData];
commonParams.lper = 1;
} else {
bidParams = auctions[acid].getAdslotBids(adtag).map(({winner, ...restParams}) => restParams);
bidParams = auctions[acid].getAdSlotBids(adtag).map(({winner, ...restParams}) => restParams);
delete commonParams.wts;
}
let mnetPresent = bidParams.filter(b => b.pvnm === MEDIANET_BIDDER_CODE).length > 0;
Expand Down
Loading