-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add analytics adapter by Sigmoid (#2316)
* Add analytics adapter and tests * Linting code * +Linting code * Date change * ++Linting code * +++Fix Linting * Add docs * Remove dead code and alert * Change let to const and typo fix * use includes by importing from core-js * +use includes by importing from core-js * Increase test coverage to 75% * Fix travis build error * +Fix travis build error
- Loading branch information
1 parent
a76420c
commit 1b29d1f
Showing
3 changed files
with
375 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,285 @@ | ||
/* Sigmoid Analytics Adapter for prebid.js v1.1.0-pre | ||
Updated : 2018-03-28 */ | ||
import includes from 'core-js/library/fn/array/includes'; | ||
import adapter from 'src/AnalyticsAdapter'; | ||
import CONSTANTS from 'src/constants.json'; | ||
import adaptermanager from 'src/adaptermanager'; | ||
|
||
const utils = require('src/utils'); | ||
|
||
const url = 'https://kinesis.us-east-1.amazonaws.com/'; | ||
const analyticsType = 'endpoint'; | ||
|
||
const auctionInitConst = CONSTANTS.EVENTS.AUCTION_INIT; | ||
const auctionEndConst = CONSTANTS.EVENTS.AUCTION_END; | ||
const bidWonConst = CONSTANTS.EVENTS.BID_WON; | ||
const bidRequestConst = CONSTANTS.EVENTS.BID_REQUESTED; | ||
const bidAdjustmentConst = CONSTANTS.EVENTS.BID_ADJUSTMENT; | ||
const bidResponseConst = CONSTANTS.EVENTS.BID_RESPONSE; | ||
|
||
let initOptions = { publisherIds: [], utmTagData: [], adUnits: [] }; | ||
let bidWon = {options: {}, events: []}; | ||
let eventStack = {options: {}, events: []}; | ||
|
||
let auctionStatus = 'not_started'; | ||
|
||
let localStoragePrefix = 'sigmoid_analytics_'; | ||
let utmTags = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']; | ||
let utmTimeoutKey = 'utm_timeout'; | ||
let utmTimeout = 60 * 60 * 1000; | ||
let sessionTimeout = 60 * 60 * 1000; | ||
let sessionIdStorageKey = 'session_id'; | ||
let sessionTimeoutKey = 'session_timeout'; | ||
|
||
function getParameterByName(param) { | ||
let vars = {}; | ||
window.location.href.replace(location.hash, '').replace( | ||
/[?&]+([^=&]+)=?([^&]*)?/gi, | ||
function(m, key, value) { | ||
vars[key] = value !== undefined ? value : ''; | ||
} | ||
); | ||
|
||
return vars[param] ? vars[param] : ''; | ||
} | ||
|
||
function buildSessionIdLocalStorageKey() { | ||
return localStoragePrefix.concat(sessionIdStorageKey); | ||
} | ||
|
||
function buildSessionIdTimeoutLocalStorageKey() { | ||
return localStoragePrefix.concat(sessionTimeoutKey); | ||
} | ||
|
||
function updateSessionId() { | ||
if (isSessionIdTimeoutExpired()) { | ||
let newSessionId = utils.generateUUID(); | ||
localStorage.setItem(buildSessionIdLocalStorageKey(), newSessionId); | ||
} | ||
initOptions.sessionId = getSessionId(); | ||
updateSessionIdTimeout(); | ||
} | ||
|
||
function updateSessionIdTimeout() { | ||
localStorage.setItem(buildSessionIdTimeoutLocalStorageKey(), Date.now()); | ||
} | ||
|
||
function isSessionIdTimeoutExpired() { | ||
let cpmSessionTimestamp = localStorage.getItem(buildSessionIdTimeoutLocalStorageKey()); | ||
return Date.now() - cpmSessionTimestamp > sessionTimeout; | ||
} | ||
|
||
function getSessionId() { | ||
return localStorage.getItem(buildSessionIdLocalStorageKey()) ? localStorage.getItem(buildSessionIdLocalStorageKey()) : ''; | ||
} | ||
|
||
function updateUtmTimeout() { | ||
localStorage.setItem(buildUtmLocalStorageTimeoutKey(), Date.now()); | ||
} | ||
|
||
function isUtmTimeoutExpired() { | ||
let utmTimestamp = localStorage.getItem(buildUtmLocalStorageTimeoutKey()); | ||
return (Date.now() - utmTimestamp) > utmTimeout; | ||
} | ||
|
||
function buildUtmLocalStorageTimeoutKey() { | ||
return localStoragePrefix.concat(utmTimeoutKey); | ||
} | ||
|
||
function buildUtmLocalStorageKey(utmMarkKey) { | ||
return localStoragePrefix.concat(utmMarkKey); | ||
} | ||
|
||
function checkOptions() { | ||
if (typeof initOptions.publisherIds === 'undefined') { | ||
return false; | ||
} | ||
|
||
return initOptions.publisherIds.length > 0; | ||
} | ||
|
||
function checkAdUnitConfig() { | ||
if (typeof initOptions.adUnits === 'undefined') { | ||
return false; | ||
} | ||
|
||
return initOptions.adUnits.length > 0; | ||
} | ||
|
||
function buildBidWon(eventType, args) { | ||
bidWon.options = initOptions; | ||
if (checkAdUnitConfig()) { | ||
if (includes(initOptions.adUnits, args.adUnitCode)) { | ||
bidWon.events = [{ args: args, eventType: eventType }]; | ||
} | ||
} else { | ||
bidWon.events = [{ args: args, eventType: eventType }]; | ||
} | ||
} | ||
|
||
function buildEventStack() { | ||
eventStack.options = initOptions; | ||
} | ||
|
||
function filterBidsByAdUnit(bids) { | ||
var filteredBids = []; | ||
bids.forEach(function (bid) { | ||
if (includes(initOptions.adUnits, bid.placementCode)) { | ||
filteredBids.push(bid); | ||
} | ||
}); | ||
return filteredBids; | ||
} | ||
|
||
function isValidEvent(eventType, adUnitCode) { | ||
if (checkAdUnitConfig()) { | ||
let validationEvents = [bidAdjustmentConst, bidResponseConst, bidWonConst]; | ||
if (!includes(initOptions.adUnits, adUnitCode) && includes(validationEvents, eventType)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
function isValidEventStack() { | ||
if (eventStack.events.length > 0) { | ||
return eventStack.events.some(function(event) { | ||
return bidRequestConst === event.eventType || bidWonConst === event.eventType; | ||
}); | ||
} | ||
return false; | ||
} | ||
|
||
function isValidBidWon() { | ||
return bidWon.events.length > 0; | ||
} | ||
|
||
function flushEventStack() { | ||
eventStack.events = []; | ||
} | ||
|
||
let sigmoidAdapter = Object.assign(adapter({url, analyticsType}), | ||
{ | ||
track({eventType, args}) { | ||
if (!checkOptions()) { | ||
return; | ||
} | ||
|
||
let info = Object.assign({}, args); | ||
|
||
if (info && info.ad) { | ||
info.ad = ''; | ||
} | ||
|
||
if (eventType === auctionInitConst) { | ||
auctionStatus = 'started'; | ||
} | ||
|
||
if (eventType === bidWonConst && auctionStatus === 'not_started') { | ||
updateSessionId(); | ||
buildBidWon(eventType, info); | ||
if (isValidBidWon()) { | ||
send(eventType, bidWon, 'bidWon'); | ||
} | ||
return; | ||
} | ||
|
||
if (eventType === auctionEndConst) { | ||
updateSessionId(); | ||
buildEventStack(); | ||
if (isValidEventStack()) { | ||
send(eventType, eventStack, 'eventStack'); | ||
} | ||
auctionStatus = 'not_started'; | ||
} else { | ||
pushEvent(eventType, info); | ||
} | ||
}, | ||
|
||
}); | ||
|
||
sigmoidAdapter.originEnableAnalytics = sigmoidAdapter.enableAnalytics; | ||
|
||
sigmoidAdapter.enableAnalytics = function (config) { | ||
initOptions = config.options; | ||
initOptions.utmTagData = this.buildUtmTagData(); | ||
utils.logInfo('Sigmoid Analytics enabled with config', initOptions); | ||
sigmoidAdapter.originEnableAnalytics(config); | ||
}; | ||
|
||
sigmoidAdapter.buildUtmTagData = function () { | ||
let utmTagData = {}; | ||
let utmTagsDetected = false; | ||
utmTags.forEach(function(utmTagKey) { | ||
let utmTagValue = getParameterByName(utmTagKey); | ||
if (utmTagValue !== '') { | ||
utmTagsDetected = true; | ||
} | ||
utmTagData[utmTagKey] = utmTagValue; | ||
}); | ||
utmTags.forEach(function(utmTagKey) { | ||
if (utmTagsDetected) { | ||
localStorage.setItem(buildUtmLocalStorageKey(utmTagKey), utmTagData[utmTagKey]); | ||
updateUtmTimeout(); | ||
} else { | ||
if (!isUtmTimeoutExpired()) { | ||
utmTagData[utmTagKey] = localStorage.getItem(buildUtmLocalStorageKey(utmTagKey)) ? localStorage.getItem(buildUtmLocalStorageKey(utmTagKey)) : ''; | ||
updateUtmTimeout(); | ||
} | ||
} | ||
}); | ||
return utmTagData; | ||
}; | ||
|
||
function send(eventType, data, sendDataType) { | ||
AWS.config.credentials = new AWS.Credentials({ | ||
accessKeyId: 'accesskey', secretAccessKey: 'secretkey' | ||
}); | ||
|
||
AWS.config.region = 'us-east-1'; | ||
AWS.config.credentials.get(function(err) { | ||
// attach event listener | ||
if (err) { | ||
utils.logError(err); | ||
return; | ||
} | ||
// create kinesis service object | ||
var kinesis = new AWS.Kinesis({ | ||
apiVersion: '2013-12-02' | ||
}); | ||
var dataList = []; | ||
var jsonData = {}; | ||
jsonData['Data'] = JSON.stringify(data) + '\n'; | ||
jsonData['PartitionKey'] = 'partition-' + Math.random().toString(36).substring(7); | ||
dataList.push(jsonData); | ||
kinesis.putRecords({ | ||
Records: dataList, | ||
StreamName: 'sample-stream' | ||
}); | ||
if (sendDataType === 'eventStack') { | ||
flushEventStack(); | ||
} | ||
}); | ||
}; | ||
|
||
function pushEvent(eventType, args) { | ||
if (eventType === bidRequestConst) { | ||
if (checkAdUnitConfig()) { | ||
args.bids = filterBidsByAdUnit(args.bids); | ||
} | ||
if (args.bids.length > 0) { | ||
eventStack.events.push({ eventType: eventType, args: args }); | ||
} | ||
} else { | ||
if (isValidEvent(eventType, args.adUnitCode)) { | ||
eventStack.events.push({ eventType: eventType, args: args }); | ||
} | ||
} | ||
} | ||
|
||
adaptermanager.registerAnalyticsAdapter({ | ||
adapter: sigmoidAdapter, | ||
code: 'sigmoid' | ||
}); | ||
|
||
export default sigmoidAdapter; |
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: Sigmoid Analytics Adapter | ||
|
||
Module Type: Analytics Adapter | ||
|
||
Maintainer: ramees@sigmoidanalytics.com | ||
|
||
# Description | ||
|
||
Analytics adapter for Sigmoid. We are an advanced analytical solutions company. | ||
https://www.sigmoid.com/ | ||
|
||
# Test Parameters | ||
|
||
``` | ||
{ | ||
provider: 'sigmoid', | ||
options : { | ||
publisherIds: ["3gxdf18d32"] | ||
} | ||
} | ||
``` |
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,67 @@ | ||
import sigmoidAnalytic from 'modules/sigmoidAnalyticsAdapter'; | ||
import { expect } from 'chai'; | ||
let events = require('src/events'); | ||
let adaptermanager = require('src/adaptermanager'); | ||
let constants = require('src/constants.json'); | ||
|
||
describe('sigmoid Prebid Analytic', function () { | ||
let xhr; | ||
before(() => { | ||
xhr = sinon.useFakeXMLHttpRequest(); | ||
}) | ||
after(() => { | ||
sigmoidAnalytic.disableAnalytics(); | ||
xhr.restore(); | ||
}); | ||
|
||
describe('enableAnalytics', function () { | ||
beforeEach(() => { | ||
sinon.spy(sigmoidAnalytic, 'track'); | ||
sinon.stub(events, 'getEvents').returns([]); | ||
}); | ||
|
||
afterEach(() => { | ||
sigmoidAnalytic.track.restore(); | ||
events.getEvents.restore(); | ||
}); | ||
it('should catch all events', function () { | ||
adaptermanager.registerAnalyticsAdapter({ | ||
code: 'sigmoid', | ||
adapter: sigmoidAnalytic | ||
}); | ||
|
||
adaptermanager.enableAnalytics({ | ||
provider: 'sigmoid', | ||
options: { | ||
publisherIds: ['test_sigmoid_prebid_analytid_publisher_id'] | ||
} | ||
}); | ||
|
||
events.emit(constants.EVENTS.AUCTION_INIT, {}); | ||
events.emit(constants.EVENTS.AUCTION_END, {}); | ||
events.emit(constants.EVENTS.BID_REQUESTED, {}); | ||
events.emit(constants.EVENTS.BID_RESPONSE, {}); | ||
events.emit(constants.EVENTS.BID_WON, {}); | ||
|
||
sinon.assert.callCount(sigmoidAnalytic.track, 5); | ||
}); | ||
}); | ||
describe('build utm tag data', () => { | ||
beforeEach(() => { | ||
localStorage.setItem('sigmoid_analytics_utm_source', 'utm_source'); | ||
localStorage.setItem('sigmoid_analytics_utm_medium', 'utm_medium'); | ||
localStorage.setItem('sigmoid_analytics_utm_campaign', ''); | ||
localStorage.setItem('sigmoid_analytics_utm_term', ''); | ||
localStorage.setItem('sigmoid_analytics_utm_content', ''); | ||
localStorage.setItem('sigmoid_analytics_utm_timeout', Date.now()); | ||
}); | ||
it('should build utm data from local storage', () => { | ||
let utmTagData = sigmoidAnalytic.buildUtmTagData(); | ||
expect(utmTagData.utm_source).to.equal('utm_source'); | ||
expect(utmTagData.utm_medium).to.equal('utm_medium'); | ||
expect(utmTagData.utm_campaign).to.equal(''); | ||
expect(utmTagData.utm_term).to.equal(''); | ||
expect(utmTagData.utm_content).to.equal(''); | ||
}); | ||
}); | ||
}); |