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

sovrn analytics adapter #12

Closed
wants to merge 53 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
c0c28d7
fix sovrn dealid
Feb 8, 2018
d7df108
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn Feb 9, 2018
0700e91
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn Feb 14, 2018
cf0ca21
send 'iv' param if present
aprakash-sovrn Feb 14, 2018
f89135c
`page` field in `site` object sends full url
aprakash-sovrn Feb 14, 2018
be091fd
Merge pull request #1 from sovrn/HS-303_Send_iv_param
aprakash-sovrn Feb 14, 2018
af86376
Merge remote-tracking branch 'upstream/master'
Feb 16, 2018
c2f2350
Enhance location detection within util function.
Feb 16, 2018
4867c53
Merge pull request #3 from sovrn/enhanced-location-detection
Feb 20, 2018
28f3e0e
fix func call
Feb 20, 2018
497723b
fix tagid var type
aprakash-sovrn Feb 22, 2018
f90b2e0
add test for converting tagid to string
aprakash-sovrn Feb 23, 2018
2e9e413
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn Feb 23, 2018
74ed7f9
merge upstream master
aprakash-sovrn Feb 26, 2018
1269a33
CR
Mar 1, 2018
55284d5
Merge pull request #4 from sovrn/enhanced-location-detection
Mar 1, 2018
3c2f8bc
Reorg gettopwindowlocation util & add tests.
Mar 8, 2018
fee1789
Merge branch 'master' into enhanced-location-detection
Mar 12, 2018
cd78968
Merge pull request #5 from sovrn/enhanced-location-detection
Mar 12, 2018
68a8afa
lint fixes
Mar 12, 2018
35b3f4c
Merge remote-tracking branch 'upstream/master'
Mar 12, 2018
b2bc2a4
search param is string in window location objects
Mar 12, 2018
7da5620
Merge branch 'master' into master
Mar 26, 2018
1f5f2a3
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn Apr 13, 2018
6763f3a
set creativeId to crid if present in response
aprakash-sovrn Apr 13, 2018
ad9e191
Merge pull request #7 from sovrn/HS-368_Add_crid_if_present
aprakash-sovrn Apr 18, 2018
f83afca
Merge remote-tracking branch 'upstream/master'
Apr 25, 2018
de65514
Merge branch 'master' of https://github.com/prebid/Prebid.js
May 1, 2018
bbcd0b9
send gdpr info
May 1, 2018
0d80a5e
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn May 7, 2018
cbcf727
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn Jun 4, 2018
e1310df
Merge pull request #8 from prebid/master
tpottersovrn Jun 8, 2018
232aca6
Getting a new package to use for pre1api module
tpottersovrn Jun 8, 2018
809a11a
Merge pull request #9 from sovrn/pre1api
tpottersovrn Jun 9, 2018
eb4e1bf
Merge branch 'master' of github.com:sovrn/Prebid.js
aprakash-sovrn Jun 12, 2018
198ea7e
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn Jun 12, 2018
d17b2ec
Merge branch 'master' of https://github.com/prebid/Prebid.js
aprakash-sovrn Jun 27, 2018
0a051c3
send iv as query param
aprakash-sovrn Jun 27, 2018
5511c2e
Merge pull request #11 from sovrn/HS-403_WIP
aprakash-sovrn Jun 27, 2018
9c69f81
Merge remote-tracking branch 'upstream/master'
Jul 16, 2018
aaa288e
Merge remote-tracking branch 'upstream/master'
Jul 25, 2018
9c98a34
add sovrn analytics adapter
cprokopiak Jul 10, 2018
6b28055
new pba url. also pba url is configurable.
Aug 1, 2018
fea5f03
updated URL endpoint
Aug 14, 2018
5405eb2
Fixed some possible value mutations, added error payload, check for a…
Sep 19, 2018
3ac0641
added test and determined that error and body are not the same word
Sep 25, 2018
87901a1
using proper version of find
Oct 4, 2018
2fc7d16
updated package.json to move all files
Oct 5, 2018
4280bae
missed a polyfil
Oct 8, 2018
2abd64a
should have saved before commiting
Oct 8, 2018
7f34b16
should be correct version of file
Apr 2, 2019
7c82ce5
ready for testing
Apr 2, 2019
c5abc46
added md file
Apr 2, 2019
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
277 changes: 277 additions & 0 deletions modules/sovrnAnalyticsAdapter.js
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) => {

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.

Copy link
Author

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)

Copy link
Author

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.

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;
21 changes: 21 additions & 0 deletions modules/sovrnAnalyticsAdapter.md
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.
}
}
Loading