forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ucfunnelAnalyticsAdapter (prebid#4432)
* Add a new ucfunnel Adapter and test page * Add a new ucfunnel Adapter and test page * 1. Use prebid lib in the repo to keep updated 2. Replace var with let 3. Put JSON.parse(JSON.stringify()) into try catch block * utils.getTopWindowLocation is a function * Change to modules from adapters * Migrate to module design * [Dev Fix] Remove width and height which can be got from ad unit id * Update ucfunnelBidAdapter to fit into new spec * Correct the endpoint. Fix the error of query string * Add test case for ucfunnelBidAdapter * Fix lint error * Update version number * Combine all checks on bid request * Add GDPR support for ucfunnel adapter * Add in-stream video and native support for ucfunnel adapter * Remove demo page. Add more test cases. * Change request method from POST to GET * Remove unnecessary comment * Support vastXml and vastUrl for video request * update TTL to 30 mins * Avoid using arrow function which is not discuraged in mocha * ucfunnel tdid support * ucfunnel fix error message in debug mode * Create ucfunnelAnalyticsAdapter.js * [Dev Fix]add id * Update ucfunnelAnalyticsAdapter.js * Update ucfunnelAnalyticsAdapter.md * add test * Bug Fix and test passed
- Loading branch information
Showing
3 changed files
with
712 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
import {ajax} from '../src/ajax'; | ||
import adapter from '../src/AnalyticsAdapter'; | ||
import CONSTANTS from '../src/constants.json'; | ||
import adapterManager from '../src/adapterManager'; | ||
import {logError, logInfo, deepClone} from '../src/utils'; | ||
|
||
const analyticsType = 'endpoint'; | ||
|
||
export const ANALYTICS_VERSION = '1.0.0'; | ||
|
||
const ANALYTICS_SERVER = 'https://hbwa.aralego.com'; | ||
|
||
const { | ||
EVENTS: { | ||
AUCTION_END, | ||
BID_WON, | ||
BID_TIMEOUT | ||
} | ||
} = CONSTANTS; | ||
|
||
export const BIDDER_STATUS = { | ||
BID: 'bid', | ||
NO_BID: 'noBid', | ||
BID_WON: 'bidWon', | ||
TIMEOUT: 'timeout' | ||
}; | ||
|
||
const analyticsOptions = {}; | ||
|
||
export const parseBidderCode = function (bid) { | ||
let bidderCode = bid.bidderCode || bid.bidder; | ||
return bidderCode.toLowerCase(); | ||
}; | ||
|
||
export const parseAdUnitCode = function (bidResponse) { | ||
return bidResponse.adUnitCode.toLowerCase(); | ||
}; | ||
|
||
export const ucfunnelAnalyticsAdapter = Object.assign(adapter({ANALYTICS_SERVER, analyticsType}), { | ||
|
||
cachedAuctions: {}, | ||
|
||
initConfig(config) { | ||
/** | ||
* Required option: pbuid | ||
* Required option: adid | ||
* @type {boolean} | ||
*/ | ||
analyticsOptions.options = deepClone(config.options); | ||
if (typeof config.options.pbuid !== 'string' || config.options.pbuid.length < 1) { | ||
logError('"options.pbuid" is required.'); | ||
return false; | ||
} | ||
if (typeof config.options.adid !== 'string' || config.options.adid.length < 1) { | ||
logError('"options.adid" is required.'); | ||
return false; | ||
} | ||
analyticsOptions.sampled = true; | ||
if (typeof config.options.sampling === 'number') { | ||
analyticsOptions.sampled = Math.random() < parseFloat(config.options.sampling); | ||
} | ||
|
||
analyticsOptions.pbuid = config.options.pbuid | ||
analyticsOptions.adid = config.options.adid | ||
analyticsOptions.server = ANALYTICS_SERVER; | ||
return true; | ||
}, | ||
sendEventMessage(endPoint, data) { | ||
logInfo(`AJAX: ${endPoint}: ` + JSON.stringify(data)); | ||
|
||
ajax(`${analyticsOptions.server}/${endPoint}`, null, JSON.stringify(data), { | ||
contentType: 'application/json', | ||
withCredentials: true | ||
}); | ||
}, | ||
createCommonMessage(auctionId) { | ||
return { | ||
version: ANALYTICS_VERSION, | ||
auctionId: auctionId, | ||
referrer: window.location.href, | ||
sampling: analyticsOptions.options.sampling, | ||
prebid: '$prebid.version$', | ||
adid: analyticsOptions.adid, | ||
pbuid: analyticsOptions.pbuid, | ||
adUnits: {}, | ||
}; | ||
}, | ||
serializeBidResponse(bid, status) { | ||
const result = { | ||
prebidWon: (status === BIDDER_STATUS.BID_WON), | ||
isTimeout: (status === BIDDER_STATUS.TIMEOUT), | ||
status: status, | ||
}; | ||
if (status === BIDDER_STATUS.BID || status === BIDDER_STATUS.BID_WON) { | ||
Object.assign(result, { | ||
time: bid.timeToRespond, | ||
cpm: bid.cpm, | ||
currency: bid.currency, | ||
}); | ||
} | ||
return result; | ||
}, | ||
addBidResponseToMessage(message, bid, status) { | ||
const adUnitCode = parseAdUnitCode(bid); | ||
message.adUnits[adUnitCode] = message.adUnits[adUnitCode] || {}; | ||
const bidder = parseBidderCode(bid); | ||
const bidResponse = this.serializeBidResponse(bid, status); | ||
message.adUnits[adUnitCode][bidder] = bidResponse; | ||
}, | ||
createBidMessage(auctionEndArgs, winningBids, timeoutBids) { | ||
const {auctionId, timestamp, auctionEnd, adUnitCodes, bidsReceived, noBids} = auctionEndArgs; | ||
const message = this.createCommonMessage(auctionId); | ||
|
||
message.auctionElapsed = (auctionEnd - timestamp); | ||
|
||
adUnitCodes.forEach((adUnitCode) => { | ||
message.adUnits[adUnitCode] = {}; | ||
}); | ||
|
||
// In this situation, the bid exists in both noBids and bids arrays. | ||
noBids.forEach(bid => this.addBidResponseToMessage(message, bid, BIDDER_STATUS.NO_BID)); | ||
|
||
// This array may contain some timeout bids (responses come back after auction timeout) | ||
bidsReceived.forEach(bid => this.addBidResponseToMessage(message, bid, BIDDER_STATUS.BID)); | ||
|
||
// We handle timeout after bids since it's possible that a bid has a response, but the response comes back | ||
// after auction end. In this case, the bid exists in both bidsReceived and timeoutBids arrays. | ||
timeoutBids.forEach(bid => this.addBidResponseToMessage(message, bid, BIDDER_STATUS.TIMEOUT)); | ||
|
||
// mark the winning bids with prebidWon = true | ||
winningBids.forEach(bid => { | ||
const adUnitCode = parseAdUnitCode(bid); | ||
const bidder = parseBidderCode(bid); | ||
message.adUnits[adUnitCode][bidder].prebidWon = true; | ||
}); | ||
return message; | ||
}, | ||
createImpressionMessage(bid) { | ||
const message = this.createCommonMessage(bid.auctionId); | ||
this.addBidResponseToMessage(message, bid, BIDDER_STATUS.BID_WON); | ||
return message; | ||
}, | ||
getCachedAuction(auctionId) { | ||
this.cachedAuctions[auctionId] = this.cachedAuctions[auctionId] || { | ||
timeoutBids: [], | ||
}; | ||
return this.cachedAuctions[auctionId]; | ||
}, | ||
handleAuctionEnd(auctionEndArgs) { | ||
const cachedAuction = this.getCachedAuction(auctionEndArgs.auctionId); | ||
const highestCpmBids = pbjs.getHighestCpmBids(); | ||
this.sendEventMessage('bid', | ||
this.createBidMessage(auctionEndArgs, highestCpmBids, cachedAuction.timeoutBids) | ||
); | ||
}, | ||
handleBidTimeout(timeoutBids) { | ||
timeoutBids.forEach((bid) => { | ||
const cachedAuction = this.getCachedAuction(bid.auctionId); | ||
cachedAuction.timeoutBids.push(bid); | ||
}); | ||
}, | ||
handleBidWon(bidWonArgs) { | ||
this.sendEventMessage('imp', this.createImpressionMessage(bidWonArgs)); | ||
}, | ||
track({eventType, args}) { | ||
if (analyticsOptions.sampled) { | ||
switch (eventType) { | ||
case BID_WON: | ||
this.handleBidWon(args); | ||
break; | ||
case BID_TIMEOUT: | ||
this.handleBidTimeout(args); | ||
break; | ||
case AUCTION_END: | ||
this.handleAuctionEnd(args); | ||
break; | ||
} | ||
} | ||
}, | ||
getAnalyticsOptions() { | ||
return analyticsOptions; | ||
}, | ||
}); | ||
|
||
// save the base class function | ||
ucfunnelAnalyticsAdapter.originEnableAnalytics = ucfunnelAnalyticsAdapter.enableAnalytics; | ||
|
||
// override enableAnalytics so we can get access to the config passed in from the page | ||
ucfunnelAnalyticsAdapter.enableAnalytics = function (config) { | ||
if (this.initConfig(config)) { | ||
ucfunnelAnalyticsAdapter.originEnableAnalytics(config); // call the base class function | ||
} | ||
}; | ||
|
||
adapterManager.registerAnalyticsAdapter({ | ||
adapter: ucfunnelAnalyticsAdapter, | ||
code: 'ucfunnelAnalytics' | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Overview | ||
|
||
``` | ||
Module Name: ucfunnel Analytics Adapter | ||
Module Type: Analytics Adapter | ||
Maintainer: [email protected] | ||
``` | ||
|
||
# Description | ||
|
||
Analytics adapter for ucfunnel | ||
|
||
# Test Parameters | ||
|
||
``` | ||
{ | ||
provider: 'ucfunnelAnalytics', | ||
options: { | ||
pbuid: "PBUID_FROM_UCFUNNEL" | ||
adid: "BIDDING_ADID_FROM_UCFUNNEL" | ||
} | ||
} | ||
``` |
Oops, something went wrong.