forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 0
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
sovrn analytics adapter #12
Closed
Closed
Changes from all commits
Commits
Show all changes
53 commits
Select commit
Hold shift + click to select a range
c0c28d7
fix sovrn dealid
d7df108
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn 0700e91
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn cf0ca21
send 'iv' param if present
aprakash-sovrn f89135c
`page` field in `site` object sends full url
aprakash-sovrn be091fd
Merge pull request #1 from sovrn/HS-303_Send_iv_param
aprakash-sovrn af86376
Merge remote-tracking branch 'upstream/master'
c2f2350
Enhance location detection within util function.
4867c53
Merge pull request #3 from sovrn/enhanced-location-detection
28f3e0e
fix func call
497723b
fix tagid var type
aprakash-sovrn f90b2e0
add test for converting tagid to string
aprakash-sovrn 2e9e413
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn 74ed7f9
merge upstream master
aprakash-sovrn 1269a33
CR
55284d5
Merge pull request #4 from sovrn/enhanced-location-detection
3c2f8bc
Reorg gettopwindowlocation util & add tests.
fee1789
Merge branch 'master' into enhanced-location-detection
cd78968
Merge pull request #5 from sovrn/enhanced-location-detection
68a8afa
lint fixes
35b3f4c
Merge remote-tracking branch 'upstream/master'
b2bc2a4
search param is string in window location objects
7da5620
Merge branch 'master' into master
1f5f2a3
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn 6763f3a
set creativeId to crid if present in response
aprakash-sovrn ad9e191
Merge pull request #7 from sovrn/HS-368_Add_crid_if_present
aprakash-sovrn f83afca
Merge remote-tracking branch 'upstream/master'
de65514
Merge branch 'master' of https://github.com/prebid/Prebid.js
bbcd0b9
send gdpr info
0d80a5e
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn cbcf727
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn e1310df
Merge pull request #8 from prebid/master
tpottersovrn 232aca6
Getting a new package to use for pre1api module
tpottersovrn 809a11a
Merge pull request #9 from sovrn/pre1api
tpottersovrn eb4e1bf
Merge branch 'master' of github.com:sovrn/Prebid.js
aprakash-sovrn 198ea7e
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn d17b2ec
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn 0a051c3
send iv as query param
aprakash-sovrn 5511c2e
Merge pull request #11 from sovrn/HS-403_WIP
aprakash-sovrn 9c69f81
Merge remote-tracking branch 'upstream/master'
aaa288e
Merge remote-tracking branch 'upstream/master'
9c98a34
add sovrn analytics adapter
cprokopiak 6b28055
new pba url. also pba url is configurable.
fea5f03
updated URL endpoint
5405eb2
Fixed some possible value mutations, added error payload, check for a…
3ac0641
added test and determined that error and body are not the same word
87901a1
using proper version of find
2fc7d16
updated package.json to move all files
4280bae
missed a polyfil
2abd64a
should have saved before commiting
7f34b16
should be correct version of file
7c82ce5
ready for testing
c5abc46
added md file
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,277 @@ | ||
import adapter from 'src/AnalyticsAdapter' | ||
import adaptermanager from 'src/adaptermanager' | ||
import CONSTANTS from 'src/constants.json' | ||
import {ajaxBuilder} from 'src/ajax' | ||
import * as utils from 'src/utils' | ||
import {config} from 'src/config' | ||
import find from 'core-js/library/fn/array/find' | ||
import includes from 'core-js/library/fn/array/includes' | ||
|
||
const ajax = ajaxBuilder(0) | ||
|
||
const { | ||
EVENTS: { | ||
AUCTION_END, | ||
BID_REQUESTED, | ||
BID_ADJUSTMENT, | ||
BID_RESPONSE, | ||
BID_WON | ||
} | ||
} = CONSTANTS | ||
|
||
let pbaUrl = 'https://pba.aws.lijit.com/analytics' | ||
let currentAuctions = {}; | ||
const analyticsType = 'endpoint' | ||
|
||
let sovrnAnalyticsAdapter = Object.assign(adapter({url: pbaUrl, analyticsType}), { | ||
track({ eventType, args }) { | ||
try { | ||
if (eventType === BID_WON) { | ||
new BidWinner(this.sovrnId, args).send(); | ||
return | ||
} | ||
if (args.auctionId && currentAuctions[args.auctionId] && currentAuctions[args.auctionId].status === 'complete') { | ||
throw new Error('Event Received after Auction Close Auction Id ' + args.auctionId) | ||
} | ||
if (args.auctionId && currentAuctions[args.auctionId] === undefined) { | ||
currentAuctions[args.auctionId] = new AuctionData(this.sovrnId, args.auctionId) | ||
} | ||
switch (eventType) { | ||
case BID_REQUESTED: | ||
currentAuctions[args.auctionId].bidRequested(args) | ||
break | ||
case BID_ADJUSTMENT: | ||
currentAuctions[args.auctionId].originalBid(args) | ||
break | ||
case BID_RESPONSE: | ||
currentAuctions[args.auctionId].adjustedBid(args) | ||
break | ||
case AUCTION_END: | ||
currentAuctions[args.auctionId].send(); | ||
break | ||
} | ||
} catch (e) { | ||
new LogError(e, this.sovrnId, {eventType, args}).send() | ||
} | ||
}, | ||
}) | ||
|
||
sovrnAnalyticsAdapter.getAuctions = function () { | ||
return currentAuctions; | ||
}; | ||
|
||
sovrnAnalyticsAdapter.originEnableAnalytics = sovrnAnalyticsAdapter.enableAnalytics; | ||
|
||
// override enableAnalytics so we can get access to the config passed in from the page | ||
sovrnAnalyticsAdapter.enableAnalytics = function (config) { | ||
let sovrnId = '' | ||
if (config && config.options && (config.options.sovrnId || config.options.affiliateId)) { | ||
sovrnId = config.options.sovrnId || config.options.affiliateId; | ||
} else { | ||
utils.logError('Need Sovrn Id to log auction results. Please contact a Sovrn representative if you do not know your Sovrn Id.') | ||
return | ||
} | ||
sovrnAnalyticsAdapter.sovrnId = sovrnId; | ||
if (config.options.pbaUrl) { | ||
pbaUrl = config.options.pbaUrl; | ||
} | ||
sovrnAnalyticsAdapter.originEnableAnalytics(config) // call the base class function | ||
}; | ||
|
||
adaptermanager.registerAnalyticsAdapter({ | ||
adapter: sovrnAnalyticsAdapter, | ||
code: 'sovrn' | ||
}); | ||
|
||
/** Class Representing a Winning Bid */ | ||
class BidWinner { | ||
/** | ||
* Creates a new bid winner | ||
* @param {string} sovrnId - the affiliate id from the analytics config | ||
* @param {*} event - the args object from the auction event | ||
*/ | ||
constructor(sovrnId, event) { | ||
this.body = {} | ||
this.body.prebidVersion = CONSTANTS.REPO_AND_VERSION | ||
this.body.sovrnId = sovrnId | ||
this.body.winningBid = JSON.parse(JSON.stringify(event)) | ||
this.body.url = utils.getTopWindowLocation().href | ||
this.body.payload = 'winner' | ||
delete this.body.winningBid.ad | ||
} | ||
|
||
/** | ||
* Sends the auction to the the ingest server | ||
*/ | ||
send() { | ||
this.body.ts = utils.timestamp() | ||
ajax( | ||
pbaUrl, | ||
null, | ||
JSON.stringify(this.body), | ||
{ | ||
contentType: 'application/json', | ||
method: 'POST', | ||
} | ||
) | ||
} | ||
} | ||
|
||
/** Class representing an Auction */ | ||
class AuctionData { | ||
/** | ||
* Create a new auction data collector | ||
* @param {string} sovrnId - the affiliate id from the analytics config | ||
* @param {string} auctionId - the auction id from the auction event | ||
*/ | ||
constructor(sovrnId, auctionId) { | ||
this.auction = {} | ||
this.auction.prebidVersion = CONSTANTS.REPO_AND_VERSION | ||
this.auction.sovrnId = sovrnId | ||
this.auction.auctionId = auctionId | ||
this.auction.payload = 'auction' | ||
this.auction.timeouts = { | ||
buffer: config.getConfig('timeoutBuffer'), | ||
bidder: config.getConfig('bidderTimeout'), | ||
} | ||
this.auction.priceGranularity = config.getConfig('priceGranularity') | ||
this.auction.url = utils.getTopWindowLocation().href | ||
this.auction.requests = [] | ||
this.auction.unsynced = [] | ||
this.dropBidFields = ['auctionId', 'ad', 'requestId', 'bidderCode'] | ||
|
||
setTimeout(function(id) { | ||
delete currentAuctions[id] | ||
}, 300000, this.auction.auctionId) | ||
} | ||
|
||
/** | ||
* Record a bid request event | ||
* @param {*} event - the args object from the auction event | ||
*/ | ||
bidRequested(event) { | ||
const eventCopy = JSON.parse(JSON.stringify(event)) | ||
delete eventCopy.doneCbCallCount | ||
delete eventCopy.auctionId | ||
this.auction.requests.push(eventCopy) | ||
} | ||
|
||
/** | ||
* Finds the bid from the auction that the event is associated with | ||
* @param {*} event - the args object from the auction event | ||
* @return {*} - the bid | ||
*/ | ||
findBid(event) { | ||
const bidder = find(this.auction.requests, r => (r.bidderCode === event.bidderCode)) | ||
if (!bidder) { | ||
this.auction.unsynced.push(JSON.parse(JSON.stringify(event))) | ||
} | ||
let bid = find(bidder.bids, b => (b.bidId === event.requestId)) | ||
|
||
if (!bid) { | ||
event.unmatched = true | ||
bidder.bids.push(JSON.parse(JSON.stringify(event))) | ||
} | ||
return bid | ||
} | ||
|
||
/** | ||
* Records the original bid before any adjustments have been made | ||
* @param {*} event - the args object from the auction event | ||
* NOTE: the bid adjustment occurs before the bid response | ||
* the bid adjustment seems to be the bid ready to be adjusted | ||
*/ | ||
originalBid(event) { | ||
let bid = this.findBid(event) | ||
if (bid) { | ||
Object.assign(bid, JSON.parse(JSON.stringify(event))) | ||
this.dropBidFields.forEach((f) => delete bid[f]) | ||
} | ||
} | ||
|
||
/** | ||
* Replaces original values with adjusted values and records the original values for changed values | ||
* in bid.originalValues | ||
* @param {*} event - the args object from the auction event | ||
*/ | ||
adjustedBid(event) { | ||
let bid = this.findBid(event) | ||
if (bid) { | ||
bid.originalValues = Object.keys(event).reduce((o, k) => { | ||
if (JSON.stringify(bid[k]) !== JSON.stringify(event[k]) && !includes(this.dropBidFields, k)) { | ||
o[k] = bid[k] | ||
bid[k] = event[k] | ||
} | ||
return o | ||
}, {}) | ||
} | ||
} | ||
|
||
/** | ||
* Sends the auction to the the ingest server | ||
*/ | ||
send() { | ||
let maxbid = {cpm: 0} | ||
this.auction.requests.forEach(request => { | ||
request.bids.forEach(bid => { | ||
if (bid.cpm > maxbid.cpm) { | ||
maxbid = bid | ||
} | ||
}) | ||
}) | ||
maxbid.isAuctionWinner = true | ||
this.auction.ts = utils.timestamp() | ||
ajax( | ||
pbaUrl, | ||
() => { | ||
currentAuctions[this.auction.auctionId] = {status: 'complete', auctionId: this.auction.auctionId} | ||
}, | ||
JSON.stringify(this.auction), | ||
{ | ||
contentType: 'application/json', | ||
method: 'POST', | ||
} | ||
) | ||
} | ||
} | ||
class LogError { | ||
constructor(e, sovrnId, data) { | ||
this.error = {} | ||
this.error.payload = 'error' | ||
this.error.message = e.message | ||
this.error.stack = e.stack | ||
this.error.data = data | ||
this.error.prebidVersion = CONSTANTS.REPO_AND_VERSION | ||
this.error.sovrnId = sovrnId | ||
this.error.url = utils.getTopWindowLocation().href | ||
this.error.userAgent = navigator.userAgent | ||
} | ||
send() { | ||
if (this.error.data && this.error.data.requests) { | ||
this.error.data.requests.forEach(request => { | ||
if (request.bids) { | ||
request.bids.forEach(bid => { | ||
if (bid.ad) { | ||
delete bid.ad | ||
} | ||
}) | ||
} | ||
}) | ||
} | ||
if (ErrorEvent.data && error.data.ad) { | ||
delete error.data.ad | ||
} | ||
this.error.ts = utils.timestamp() | ||
ajax( | ||
pbaUrl, | ||
null, | ||
JSON.stringify(this.error), | ||
{ | ||
contentType: 'application/json', | ||
method: 'POST', | ||
} | ||
) | ||
} | ||
} | ||
|
||
export default sovrnAnalyticsAdapter; |
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,21 @@ | ||
# Overview | ||
|
||
``` | ||
Module Name: Sovrn Analytics Adapter | ||
Module Type: Analytics Adapter | ||
Maintainer: jrosendahl@sovrn.com | ||
``` | ||
|
||
# Description | ||
|
||
Sovrn's analytics adaptor allows you to view detailed auction information in Meridian. | ||
|
||
For more information, visit Sovrn.com. | ||
|
||
#Test Parameters | ||
{ | ||
provider: 'sovrn', | ||
options: { | ||
sovrnId: 'xxxxx', // Sovrn ID (required) you can get this by contacting Sovrn support. | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have we run any tests with CPM adjustments to verify this is getting populated? I tried running some tests, but never saw anything in
originalValues
. But that could definitely be an error on my part in configuring the adapter.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're right. I don't think the originalValues are getting populated correctly. Working on that now. (and there will be a test for it)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
False alarm. Jon pointed out that the bidadjustment occurs before the bidresponse. I added criteria to the bidadjustment test to verify the original values get populated. I also commented on this since its not obvious.