forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Sharethrough adapter (prebid#865)
* Rz/submit to prebid (#4) Added Sharethrough Adapter * fix warnings * added beacons * made compatible with chrome 37. other minor changes * win beacon fired in analytics adapter * specs for new analytics adapter * add try catch blocks. misc refactor * removed test page * remove debugger * refactor analytics adapter * removed test endpoint * analytics url parameter is empty * removed bidwon listener on adapter * removed analytics from package.json
- Loading branch information
1 parent
0853677
commit a42655b
Showing
5 changed files
with
468 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 |
---|---|---|
|
@@ -38,6 +38,7 @@ | |
"underdogmedia", | ||
"memeglobal", | ||
"centro", | ||
"sharethrough", | ||
"roxot", | ||
"vertoz", | ||
"widespace", | ||
|
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,63 @@ | ||
import adapter from 'AnalyticsAdapter'; | ||
const utils = require('../../utils'); | ||
|
||
const emptyUrl = ''; | ||
const analyticsType = 'endpoint'; | ||
const STR_BIDDER_CODE = "sharethrough"; | ||
const STR_VERSION = "0.1.0"; | ||
|
||
export default utils.extend(adapter( | ||
{ | ||
emptyUrl, | ||
analyticsType | ||
} | ||
), | ||
{ | ||
STR_BEACON_HOST: document.location.protocol + "//b.sharethrough.com/butler?", | ||
placementCodeSet: {}, | ||
|
||
track({ eventType, args }) { | ||
if(eventType === 'bidRequested' && args.bidderCode === 'sharethrough') { | ||
var bids = args.bids; | ||
var keys = Object.keys(bids); | ||
for(var i = 0; i < keys.length; i++) { | ||
this.placementCodeSet[bids[keys[i]].placementCode] = args.bids[keys[i]]; | ||
} | ||
} | ||
|
||
if(eventType === 'bidWon') { | ||
this.bidWon(args); | ||
} | ||
}, | ||
|
||
bidWon(args) { | ||
const curBidderCode = args.bidderCode; | ||
|
||
if(curBidderCode !== STR_BIDDER_CODE && (args.adUnitCode in this.placementCodeSet)) { | ||
let strBid = this.placementCodeSet[args.adUnitCode]; | ||
this.fireLoseBeacon(curBidderCode, args.cpm, strBid.adserverRequestId, "headerBidLose"); | ||
} | ||
}, | ||
|
||
fireLoseBeacon(winningBidderCode, winningCPM, arid, type) { | ||
let loseBeaconUrl = this.STR_BEACON_HOST; | ||
loseBeaconUrl = utils.tryAppendQueryString(loseBeaconUrl, "winnerBidderCode", winningBidderCode); | ||
loseBeaconUrl = utils.tryAppendQueryString(loseBeaconUrl, "winnerCpm", winningCPM); | ||
loseBeaconUrl = utils.tryAppendQueryString(loseBeaconUrl, "arid", arid); | ||
loseBeaconUrl = utils.tryAppendQueryString(loseBeaconUrl, "type", type); | ||
loseBeaconUrl = this.appendEnvFields(loseBeaconUrl); | ||
|
||
this.fireBeacon(loseBeaconUrl); | ||
}, | ||
appendEnvFields(url) { | ||
url = utils.tryAppendQueryString(url, 'hbVersion', '$prebid.version$'); | ||
url = utils.tryAppendQueryString(url, 'strVersion', STR_VERSION); | ||
url = utils.tryAppendQueryString(url, 'hbSource', 'prebid'); | ||
|
||
return url; | ||
}, | ||
fireBeacon(theUrl) { | ||
const img = new Image(); | ||
img.src = theUrl; | ||
} | ||
}); |
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,127 @@ | ||
var utils = require('../utils.js'); | ||
var bidmanager = require('../bidmanager.js'); | ||
var bidfactory = require('../bidfactory.js'); | ||
|
||
const STR_BIDDER_CODE = "sharethrough"; | ||
const STR_VERSION = "0.1.0"; //Need to check analytics too for version | ||
|
||
var SharethroughAdapter = function SharethroughAdapter() { | ||
|
||
const str = {}; | ||
str.STR_BTLR_HOST = document.location.protocol + "//btlr.sharethrough.com"; | ||
str.STR_BEACON_HOST = document.location.protocol + "//b.sharethrough.com/butler?"; | ||
str.placementCodeSet = {}; | ||
|
||
function _callBids(params) { | ||
const bids = params.bids; | ||
|
||
addEventListener("message", _receiveMessage, false); | ||
|
||
// cycle through bids | ||
for (let i = 0; i < bids.length; i += 1) { | ||
const bidRequest = bids[i]; | ||
str.placementCodeSet[bidRequest.placementCode] = bidRequest; | ||
const scriptUrl = _buildSharethroughCall(bidRequest); | ||
str.loadIFrame(scriptUrl); | ||
} | ||
} | ||
|
||
function _buildSharethroughCall(bid) { | ||
const testPkey = 'test'; | ||
const pkey = utils.getBidIdParameter('pkey', bid.params); | ||
|
||
let host = str.STR_BTLR_HOST; | ||
|
||
let url = host + "/header-bid/v1?"; | ||
url = utils.tryAppendQueryString(url, 'bidId', bid.bidId); | ||
|
||
if(pkey !== testPkey) { | ||
url = utils.tryAppendQueryString(url, 'placement_key', pkey); | ||
url = utils.tryAppendQueryString(url, 'ijson', '$$PREBID_GLOBAL$$.strcallback'); | ||
url = appendEnvFields(url); | ||
} else { | ||
url = url.substring(0, url.length - 1); | ||
} | ||
|
||
return url; | ||
} | ||
|
||
str.loadIFrame = function(url) { | ||
const iframe = document.createElement("iframe"); | ||
iframe.src = url; | ||
iframe.style.cssText = 'display:none;'; | ||
|
||
document.body.appendChild(iframe); | ||
}; | ||
|
||
function _receiveMessage(event) { | ||
if(event.origin === str.STR_BTLR_HOST) { | ||
try { | ||
$$PREBID_GLOBAL$$.strcallback(JSON.parse(event.data).response); | ||
} catch(e) { | ||
console.log(e); | ||
} | ||
} | ||
} | ||
|
||
$$PREBID_GLOBAL$$.strcallback = function(bidResponse) { | ||
const bidId = bidResponse.bidId; | ||
const bidObj = utils.getBidRequest(bidId); | ||
try { | ||
const bid = bidfactory.createBid(1, bidObj); | ||
bid.bidderCode = STR_BIDDER_CODE; | ||
bid.cpm = bidResponse.creatives[0].cpm; | ||
const size = bidObj.sizes[0]; | ||
bid.width = size[0]; | ||
bid.height = size[1]; | ||
bid.adserverRequestId = bidResponse.adserverRequestId; | ||
str.placementCodeSet[bidObj.placementCode].adserverRequestId = bidResponse.adserverRequestId; | ||
|
||
bid.pkey = utils.getBidIdParameter('pkey', bidObj.params); | ||
|
||
const windowLocation = `str_response_${bidId}`; | ||
const bidJsonString = JSON.stringify(bidResponse); | ||
bid.ad = `<div data-str-native-key="${bid.pkey}" data-stx-response-name='${windowLocation}'> | ||
</div> | ||
<script>var ${windowLocation} = ${bidJsonString}</script> | ||
<script src="//native.sharethrough.com/assets/sfp-set-targeting.js"></script> | ||
<script type='text/javascript'> | ||
(function() { | ||
var sfp_js = document.createElement('script'); | ||
sfp_js.src = "//native.sharethrough.com/assets/sfp.js"; | ||
sfp_js.type = 'text/javascript'; | ||
sfp_js.charset = 'utf-8'; | ||
try { | ||
window.top.document.getElementsByTagName('body')[0].appendChild(sfp_js); | ||
} catch (e) { | ||
console.log(e); | ||
} | ||
})(); | ||
</script>`; | ||
bidmanager.addBidResponse(bidObj.placementCode, bid); | ||
} catch (e) { | ||
_handleInvalidBid(bidObj); | ||
} | ||
}; | ||
|
||
function _handleInvalidBid(bidObj) { | ||
const bid = bidfactory.createBid(2, bidObj); | ||
bidmanager.addBidResponse(bidObj.placementCode, bid); | ||
} | ||
|
||
function appendEnvFields(url) { | ||
url = utils.tryAppendQueryString(url, 'hbVersion', '$prebid.version$'); | ||
url = utils.tryAppendQueryString(url, 'strVersion', STR_VERSION); | ||
url = utils.tryAppendQueryString(url, 'hbSource', 'prebid'); | ||
|
||
return url; | ||
} | ||
|
||
return { | ||
callBids: _callBids, | ||
str : str, | ||
}; | ||
}; | ||
|
||
module.exports = SharethroughAdapter; | ||
|
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,178 @@ | ||
import { expect } from 'chai'; | ||
import Adapter from '../../../src/adapters/sharethrough'; | ||
import bidManager from '../../../src/bidmanager'; | ||
|
||
describe('sharethrough adapter', () => { | ||
|
||
let adapter; | ||
let sandbox; | ||
let bidsRequestedOriginal; | ||
|
||
const bidderRequest = { | ||
bidderCode: 'sharethrough', | ||
bids: [ | ||
{ | ||
bidder: 'sharethrough', | ||
bidId: 'bidId1', | ||
sizes: [[600,300]], | ||
placementCode: 'foo', | ||
params: { | ||
pkey: 'aaaa1111' | ||
} | ||
}, | ||
{ | ||
bidder: 'sharethrough', | ||
bidId: 'bidId2', | ||
sizes: [[700,400]], | ||
placementCode: 'bar', | ||
params: { | ||
pkey: 'bbbb2222' | ||
} | ||
} | ||
] | ||
}; | ||
|
||
beforeEach(() => { | ||
adapter = new Adapter(); | ||
sandbox = sinon.sandbox.create(); | ||
bidsRequestedOriginal = pbjs._bidsRequested; | ||
pbjs._bidsRequested = []; | ||
}); | ||
|
||
afterEach(() => { | ||
sandbox.restore(); | ||
|
||
pbjs._bidsRequested = bidsRequestedOriginal; | ||
}); | ||
|
||
describe('callBids', () => { | ||
|
||
let firstBidUrl; | ||
let secondBidUrl; | ||
|
||
beforeEach(() => { | ||
sandbox.spy(adapter.str, 'loadIFrame'); | ||
}); | ||
|
||
it('should call loadIFrame on the adloader for each bid', () => { | ||
|
||
adapter.callBids(bidderRequest); | ||
|
||
firstBidUrl = adapter.str.loadIFrame.firstCall.args[0]; | ||
secondBidUrl = adapter.str.loadIFrame.secondCall.args[0]; | ||
|
||
sinon.assert.calledTwice(adapter.str.loadIFrame); | ||
|
||
expect(firstBidUrl).to.contain(adapter.str.STR_BTLR_HOST + '/header-bid/v1?bidId=bidId1&placement_key=aaaa1111&ijson=pbjs.strcallback&hbVersion=%24prebid.version%24&strVersion=0.1.0&hbSource=prebid&'); | ||
expect(secondBidUrl).to.contain(adapter.str.STR_BTLR_HOST + '/header-bid/v1?bidId=bidId2&placement_key=bbbb2222&ijson=pbjs.strcallback&hbVersion=%24prebid.version%24&strVersion=0.1.0&hbSource=prebid&'); | ||
}); | ||
|
||
}); | ||
|
||
describe('strcallback', () => { | ||
|
||
it('should exist and be a function', () => { | ||
let shit = sandbox.stub(pbjs, 'strcallback'); | ||
expect(pbjs.strcallback).to.exist.and.to.be.a('function'); | ||
}); | ||
|
||
}); | ||
|
||
describe('bid requests', () => { | ||
|
||
let firstBid; | ||
let secondBid; | ||
|
||
beforeEach(() => { | ||
sandbox.stub(bidManager, 'addBidResponse'); | ||
|
||
pbjs._bidsRequested.push(bidderRequest); | ||
adapter.str.placementCodeSet['foo'] = {}; | ||
adapter.str.placementCodeSet['bar'] = {}; | ||
// respond | ||
|
||
let bidderReponse1 = { | ||
"adserverRequestId": "40b6afd5-6134-4fbb-850a-bb8972a46994", | ||
"bidId": "bidId1", | ||
"creatives": [ | ||
{ | ||
"cpm": 12.34, | ||
"auctionWinId": "b2882d5e-bf8b-44da-a91c-0c11287b8051", | ||
"version": 1 | ||
} | ||
], | ||
"stxUserId": "" | ||
}; | ||
|
||
let bidderReponse2 = { | ||
"adserverRequestId": "40b6afd5-6134-4fbb-850a-bb8972a46994", | ||
"bidId": "bidId2", | ||
"creatives": [ | ||
{ | ||
"cpm": 12.35, | ||
"auctionWinId": "b2882d5e-bf8b-44da-a91c-0c11287b8051", | ||
"version": 1 | ||
} | ||
], | ||
"stxUserId": "" | ||
}; | ||
|
||
pbjs.strcallback(bidderReponse1); | ||
pbjs.strcallback(bidderReponse2); | ||
|
||
firstBid = bidManager.addBidResponse.firstCall.args[1]; | ||
secondBid = bidManager.addBidResponse.secondCall.args[1]; | ||
}); | ||
|
||
it('should add a bid object for each bid', () => { | ||
sinon.assert.calledTwice(bidManager.addBidResponse); | ||
}); | ||
|
||
it('should pass the correct placement code as first param', () => { | ||
let firstPlacementCode = bidManager.addBidResponse.firstCall.args[0]; | ||
let secondPlacementCode = bidManager.addBidResponse.secondCall.args[0]; | ||
|
||
expect(firstPlacementCode).to.eql('foo'); | ||
expect(secondPlacementCode).to.eql('bar'); | ||
}); | ||
|
||
it('should include the bid request bidId as the adId', () => { | ||
expect(firstBid).to.have.property('adId', 'bidId1'); | ||
expect(secondBid).to.have.property('adId', 'bidId2'); | ||
}); | ||
|
||
it('should have a good statusCode', () => { | ||
expect(firstBid.getStatusCode()).to.eql(1); | ||
expect(secondBid.getStatusCode()).to.eql(1); | ||
}); | ||
|
||
it('should add the CPM to the bid object', () => { | ||
expect(firstBid).to.have.property('cpm', 12.34); | ||
expect(secondBid).to.have.property('cpm', 12.35); | ||
}); | ||
|
||
it('should add the bidder code to the bid object', () => { | ||
expect(firstBid).to.have.property('bidderCode', 'sharethrough'); | ||
expect(secondBid).to.have.property('bidderCode', 'sharethrough'); | ||
}); | ||
|
||
it('should include the ad on the bid object', () => { | ||
expect(firstBid).to.have.property('ad'); | ||
expect(secondBid).to.have.property('ad'); | ||
}); | ||
|
||
it('should include the size on the bid object', () => { | ||
expect(firstBid).to.have.property('width', 600); | ||
expect(firstBid).to.have.property('height', 300); | ||
expect(secondBid).to.have.property('width', 700); | ||
expect(secondBid).to.have.property('height', 400); | ||
}); | ||
|
||
it('should include the pkey', () => { | ||
expect(firstBid).to.have.property('pkey', 'aaaa1111'); | ||
expect(secondBid).to.have.property('pkey', 'bbbb2222'); | ||
}); | ||
|
||
}); | ||
|
||
}); |
Oops, something went wrong.