Skip to content

Commit

Permalink
Analytic Adaptor by YuktaMedia (#2392)
Browse files Browse the repository at this point in the history
* Analytic Adaptor by YuktaMedia

* removed optional bid request params

* test case modified
  • Loading branch information
shrikantpatwari authored and jaiminpanchal27 committed Apr 18, 2018
1 parent c1e6e1d commit 2e27a33
Show file tree
Hide file tree
Showing 3 changed files with 343 additions and 0 deletions.
144 changes: 144 additions & 0 deletions modules/yuktamediaAnalyticsAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { ajax } from 'src/ajax';
import adapter from 'src/AnalyticsAdapter';
import adaptermanager from 'src/adaptermanager';
import CONSTANTS from 'src/constants.json';
import * as url from 'src/url';
import * as utils from 'src/utils';

const emptyUrl = '';
const analyticsType = 'endpoint';
const yuktamediaAnalyticsVersion = 'v1.0.0';

let initOptions;
let auctionTimestamp;
let events = {
bids: []
};

var yuktamediaAnalyticsAdapter = Object.assign(adapter(
{
emptyUrl,
analyticsType
}), {
track({ eventType, args }) {
if (typeof args !== 'undefined') {
if (eventType === CONSTANTS.EVENTS.BID_TIMEOUT) {
args.forEach(item => { mapBidResponse(item, 'timeout'); });
} else if (eventType === CONSTANTS.EVENTS.AUCTION_INIT) {
events.auctionInit = args;
auctionTimestamp = args.timestamp;
} else if (eventType === CONSTANTS.EVENTS.BID_REQUESTED) {
mapBidRequests(args).forEach(item => { events.bids.push(item) });
} else if (eventType === CONSTANTS.EVENTS.BID_RESPONSE) {
mapBidResponse(args, 'response');
} else if (eventType === CONSTANTS.EVENTS.BID_WON) {
send({
bidWon: mapBidResponse(args, 'win')
}, 'won');
}
}

if (eventType === CONSTANTS.EVENTS.AUCTION_END) {
send(events, 'auctionEnd');
}
}
});

function mapBidRequests(params) {
let arr = [];
if (typeof params.bids !== 'undefined' && params.bids.length) {
params.bids.forEach(function (bid) {
arr.push({
bidderCode: bid.bidder,
bidId: bid.bidId,
adUnitCode: bid.adUnitCode,
requestId: bid.bidderRequestId,
auctionId: bid.auctionId,
transactionId: bid.transactionId,
sizes: utils.parseSizesInput(bid.sizes).toString(),
renderStatus: 1,
requestTimestamp: params.auctionStart
});
});
}
return arr;
}

function mapBidResponse(bidResponse, status) {
if (status !== 'win') {
let bid = events.bids.filter(o => o.bidId == bidResponse.bidId || o.bidId == bidResponse.requestId)[0];
Object.assign(bid, {
bidderCode: bidResponse.bidder,
bidId: status == 'timeout' ? bidResponse.bidId : bidResponse.requestId,
adUnitCode: bidResponse.adUnitCode,
auctionId: bidResponse.auctionId,
creativeId: bidResponse.creativeId,
transactionId: bidResponse.transactionId,
currency: bidResponse.currency,
cpm: bidResponse.cpm,
netRevenue: bidResponse.netRevenue,
mediaType: bidResponse.mediaType,
statusMessage: bidResponse.statusMessage,
status: bidResponse.status,
renderStatus: status == 'timeout' ? 3 : 2,
timeToRespond: bidResponse.timeToRespond,
requestTimestamp: bidResponse.requestTimestamp,
responseTimestamp: bidResponse.responseTimestamp
});
} else if (status == 'win') {
return {
bidderCode: bidResponse.bidder,
bidId: bidResponse.requestId,
adUnitCode: bidResponse.adUnitCode,
auctionId: bidResponse.auctionId,
creativeId: bidResponse.creativeId,
transactionId: bidResponse.transactionId,
currency: bidResponse.currency,
cpm: bidResponse.cpm,
netRevenue: bidResponse.netRevenue,
renderedSize: bidResponse.size,
mediaType: bidResponse.mediaType,
statusMessage: bidResponse.statusMessage,
status: bidResponse.status,
renderStatus: 4,
timeToRespond: bidResponse.timeToRespond,
requestTimestamp: bidResponse.requestTimestamp,
responseTimestamp: bidResponse.responseTimestamp
}
}
}

function send(data, status) {
let location = utils.getTopWindowLocation();
let secure = location.protocol == 'https:';
if (typeof data !== 'undefined' && typeof data.auctionInit !== 'undefined') {
data.auctionInit = Object.assign({ host: location.host, path: location.pathname, hash: location.hash, search: location.search }, data.auctionInit);
}
data.initOptions = initOptions;

let yuktamediaAnalyticsRequestUrl = url.format({
protocol: secure ? 'https' : 'http',
hostname: 'analytics-prebid.yuktamedia.com',
pathname: status == 'auctionEnd' ? '/api/bids' : '/api/bid/won',
search: {
auctionTimestamp: auctionTimestamp,
yuktamediaAnalyticsVersion: yuktamediaAnalyticsVersion,
prebidVersion: $$PREBID_GLOBAL$$.version
}
});

ajax(yuktamediaAnalyticsRequestUrl, undefined, JSON.stringify(data), { method: 'POST', contentType: 'application/json' });
}

yuktamediaAnalyticsAdapter.originEnableAnalytics = yuktamediaAnalyticsAdapter.enableAnalytics;
yuktamediaAnalyticsAdapter.enableAnalytics = function (config) {
initOptions = config.options;
yuktamediaAnalyticsAdapter.originEnableAnalytics(config);
};

adaptermanager.registerAnalyticsAdapter({
adapter: yuktamediaAnalyticsAdapter,
code: 'yuktamedia'
});

export default yuktamediaAnalyticsAdapter;
22 changes: 22 additions & 0 deletions modules/yuktamediaAnalyticsAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Overview
Module Name: YuktaMedia Analytics Adapter

Module Type: Analytics Adapter

Maintainer: [email protected]

# Description

Analytics adapter for prebid provided by YuktaMedia. Contact [email protected] for information.

# Test Parameters

```
{
provider: 'yuktamedia',
options : {
pubId : 50357 //id provided by YuktaMedia LLP
pubKey: 'xxx' //key provided by YuktaMedia LLP
}
}
```
177 changes: 177 additions & 0 deletions test/spec/modules/yuktamediaAnalyticsAdaptor_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import yuktamediaAnalyticsAdapter from 'modules/yuktamediaAnalyticsAdapter';
import { expect } from 'chai';
let adaptermanager = require('src/adaptermanager');
let events = require('src/events');
let constants = require('src/constants.json');

describe('YuktaMedia analytics adapter', () => {
let xhr;
let requests;

beforeEach(() => {
xhr = sinon.useFakeXMLHttpRequest();
requests = [];
xhr.onCreate = request => requests.push(request);
sinon.stub(events, 'getEvents').returns([]);
});

afterEach(() => {
xhr.restore();
events.getEvents.restore();
});

describe('track', () => {
let initOptions = {
pubId: '1',
pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT=='
};

adaptermanager.registerAnalyticsAdapter({
code: 'yuktamedia',
adapter: yuktamediaAnalyticsAdapter
});

beforeEach(() => {
adaptermanager.enableAnalytics({
provider: 'yuktamedia',
options: initOptions
});
});

afterEach(() => {
yuktamediaAnalyticsAdapter.disableAnalytics();
});

it('builds and sends auction data', () => {
let auctionTimestamp = 1496510254313;
let bidRequest = {
'bidderCode': 'appnexus',
'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7',
'bidderRequestId': '173209942f8bdd',
'bids': [{
'bidder': 'appnexus',
'params': {
'placementId': '10433394'
},
'crumbs': {
'pubcid': '9a2a4e71-f39b-405f-aecc-19efc22b618d'
},
'adUnitCode': 'div-gpt-ad-1438287399331-0',
'transactionId': '2f481ff1-8d20-4c28-8e36-e384e9e3eec6',
'sizes': [
[300, 250],
[300, 600]
],
'bidId': '2eddfdc0c791dc',
'bidderRequestId': '173209942f8bdd',
'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
}
],
'auctionStart': 1522265863591,
'timeout': 3000,
'start': 1522265863600,
'doneCbCallCount': 1
};
let bidResponse = {
'height': 250,
'statusMessage': 'Bid available',
'adId': '2eddfdc0c791dc',
'mediaType': 'banner',
'source': 'client',
'requestId': '2eddfdc0c791dc',
'cpm': 0.5,
'creativeId': 29681110,
'currency': 'USD',
'netRevenue': true,
'ttl': 300,
'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7',
'responseTimestamp': 1522265866110,
'requestTimestamp': 1522265863600,
'bidder': 'appnexus',
'adUnitCode': 'div-gpt-ad-1438287399331-0',
'timeToRespond': 2510,
'size': '300x250'
};
let bidTimeoutArgsV1 = [
{
bidId: '2baa51527bd015',
bidder: 'bidderOne',
adUnitCode: '/19968336/header-bid-tag-0',
auctionId: '66529d4c-8998-47c2-ab3e-5b953490b98f'
},
{
bidId: '6fe3b4c2c23092',
bidder: 'bidderTwo',
adUnitCode: '/19968336/header-bid-tag-0',
auctionId: '66529d4c-8998-47c2-ab3e-5b953490b98f'
}
];
let bid = {
'bidderCode': 'appnexus',
'bidId': '2eddfdc0c791dc',
'adUnitCode': 'div-gpt-ad-1438287399331-0',
'requestId': '173209942f8bdd',
'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7',
'renderStatus': 2,
'cpm': 0.5,
'creativeId': 29681110,
'currency': 'USD',
'mediaType': 'banner',
'netRevenue': true,
'requestTimestamp': 1522265863600,
'responseTimestamp': 1522265866110,
'sizes': '300x250,300x600',
'statusMessage': 'Bid available',
'timeToRespond': 2510
}

// Step 1: Send auction init event
events.emit(constants.EVENTS.AUCTION_INIT, {
timestamp: auctionTimestamp
});

// Step 2: Send bid requested event
events.emit(constants.EVENTS.BID_REQUESTED, bidRequest);

// Step 3: Send bid response event
events.emit(constants.EVENTS.BID_RESPONSE, bidResponse);

// Step 4: Send bid time out event
events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeoutArgsV1);

// Step 5: Send auction end event
events.emit(constants.EVENTS.AUCTION_END, {}, 'auctionEnd');

expect(requests.length).to.equal(1);

let auctionEventData = JSON.parse(requests[0].requestBody);

expect(auctionEventData.bids.length).to.equal(1);
expect(auctionEventData.bids[0]).to.deep.equal(bid);

expect(auctionEventData.initOptions).to.deep.equal(initOptions);

// Step 6: Send auction bid won event
events.emit(constants.EVENTS.BID_WON, {
'bidderCode': 'appnexus',
'statusMessage': 'Bid available',
'adId': '108abedd106b669',
'auctionId': '6355d610-7cdc-4009-a866-f91997fd24bb',
'responseTimestamp': 1522144433058,
'requestTimestamp': 1522144432923,
'bidder': 'appnexus',
'adUnitCode': 'div-gpt-ad-1438287399331-0',
'timeToRespond': 135,
'size': '300x250',
'status': 'rendered'
}, 'won');

expect(requests.length).to.equal(2);

let winEventData = JSON.parse(requests[1].requestBody);

expect(winEventData.bidWon.status).to.equal('rendered');
expect(winEventData.initOptions).to.deep.equal(initOptions);
});
});
});

0 comments on commit 2e27a33

Please sign in to comment.