-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Yieldmo bid adapter #1415
Yieldmo bid adapter #1415
Changes from 16 commits
11b6a54
4e782b0
5e1a577
28d584d
5a31918
4068db6
420910f
5428371
0419c0f
22768d2
50e9087
2838948
8c1b0d6
53063a7
308cbe1
8cfc236
2bf6d29
525f1a9
517536b
39bfc99
2776712
59ce30b
37124fc
fce2a4c
5c7d3a7
98b1589
a5f8ed1
06bda89
b5b9d1f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
var utils = require('src/utils.js'); | ||
var adloader = require('src/adloader.js'); | ||
var bidmanager = require('src/bidmanager.js'); | ||
var bidfactory = require('src/bidfactory.js'); | ||
var adaptermanager = require('src/adaptermanager'); | ||
|
||
/** | ||
* Adapter for requesting bids from Yieldmo. | ||
* | ||
* @returns {{callBids: _callBids}} | ||
* @constructor | ||
*/ | ||
|
||
var YieldmoAdapter = function YieldmoAdapter() { | ||
function _callBids(params) { | ||
var bids = params.bids; | ||
adloader.loadScript(buildYieldmoCall(bids)); | ||
} | ||
|
||
function buildYieldmoCall(bids) { | ||
// build our base tag, based on if we are http or https | ||
var ymURI = '//ads.yieldmo.com/ads?'; | ||
var ymCall = document.location.protocol + ymURI; | ||
|
||
// Placement specific information | ||
ymCall = _appendPlacementInformation(ymCall, bids); | ||
|
||
// General impression params | ||
ymCall = _appendImpressionInformation(ymCall); | ||
|
||
// remove the trailing "&" | ||
if (ymCall.lastIndexOf('&') === ymCall.length - 1) { | ||
ymCall = ymCall.substring(0, ymCall.length - 1); | ||
} | ||
|
||
// @if NODE_ENV='debug' | ||
// utils.logMessage('ymCall request built: ' + ymCall); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be commented out? |
||
// @endif | ||
|
||
return ymCall; | ||
} | ||
|
||
function _appendPlacementInformation(url, bids) { | ||
var placements = []; | ||
var placement; | ||
var bid; | ||
|
||
for (var i = 0; i < bids.length; i++) { | ||
bid = bids[i]; | ||
|
||
placement = {}; | ||
placement.callback_id = bid.bidId; | ||
placement.placement_id = bid.placementCode; | ||
placement.sizes = bid.sizes; | ||
|
||
placements.push(placement); | ||
} | ||
|
||
url = utils.tryAppendQueryString(url, 'p', JSON.stringify(placements)); | ||
return url; | ||
} | ||
|
||
function _appendImpressionInformation(url) { | ||
var page_url = document.location; // page url | ||
var pr = document.referrer || ''; // page's referrer | ||
var dnt = (navigator.doNotTrack || false).toString(); // true if user enabled dnt (false by default) | ||
var _s = document.location.protocol === 'https:' ? 1 : 0; // 1 if page is secure | ||
var description = _getPageDescription(); | ||
var title = document.title || ''; // Value of the title from the publisher's page. | ||
var e = 4; // 0 (COP) or 4 (DFP) for now -- ad server should reject other environments (TODO: validate that it will always be the case) | ||
var bust = new Date().getTime().toString(); // cache buster | ||
var scrd = window.devicePixelRatio || 0; // screen pixel density | ||
var ae = 0; // prebid adapter version | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need to send this (per Rahul Jain) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also misleading comment 😸 |
||
|
||
url = utils.tryAppendQueryString(url, 'callback', '$$PREBID_GLOBAL$$.YMCB'); | ||
url = utils.tryAppendQueryString(url, 'page_url', page_url); | ||
url = utils.tryAppendQueryString(url, 'pr', pr); | ||
url = utils.tryAppendQueryString(url, 'bust', bust); | ||
url = utils.tryAppendQueryString(url, '_s', _s); | ||
url = utils.tryAppendQueryString(url, 'scrd', scrd); | ||
url = utils.tryAppendQueryString(url, 'dnt', dnt); | ||
url = utils.tryAppendQueryString(url, 'ae', ae); | ||
url = utils.tryAppendQueryString(url, 'description', description); | ||
url = utils.tryAppendQueryString(url, 'title', title); | ||
|
||
return url; | ||
} | ||
|
||
function _getPageDescription() { | ||
if (document.querySelector('meta[name="description"]')) { | ||
return document.querySelector('meta[name="description"]').getAttribute('content'); // Value of the description metadata from the publisher's page. | ||
} else { | ||
return ''; | ||
} | ||
} | ||
|
||
// expose the callback to the global object: | ||
$$PREBID_GLOBAL$$.YMCB = function(ymResponses) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is fine for right now... but beware that Prebid will be dropping support for JSONP in version 1.0, which should be coming in the next few months. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, I'll make a note for us to update this. Do you know if any existing adapters are a good example to look at for 1.0 compatible callback? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We won't be letting servers respond with code in 1.0--just data. So you'll be making a GET/POST request, and then unpacking bids from the JSON (or XML, plain text, etc) in the response body. The exact API for adapters in 1.0 is still under discussion in #1494, if you want to take a look and make suggestions over there. I'm updating the |
||
if (ymResponses) { | ||
for (var i = 0; i < ymResponses.length; i++) { | ||
_registerPlacementBid(ymResponses[i]); | ||
} | ||
} else { | ||
// no response data | ||
// @if NODE_ENV='debug' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can also be removed |
||
utils.logMessage('No prebid response for placement %%PLACEMENT%%'); | ||
// @endif | ||
} | ||
}; | ||
|
||
function _registerPlacementBid(response) { | ||
var bidObj = utils.getBidRequest(response.callback_id); | ||
var placementCode = bidObj && bidObj.placementCode; | ||
var bid = []; | ||
|
||
if (response && response.cpm && response.cpm !== 0) { | ||
bid = bidfactory.createBid(1, bidObj); | ||
bid.bidderCode = 'yieldmo'; | ||
bid.cpm = response.cpm; | ||
bid.ad = response.ad; | ||
bid.width = response.width; | ||
bid.height = response.height; | ||
bidmanager.addBidResponse(placementCode, bid); | ||
} else { | ||
// no response data | ||
// @if NODE_ENV='debug' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prebid isn't using The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
if (bidObj) { utils.logMessage('No prebid response from yieldmo for placementCode: ' + bidObj.placementCode); } | ||
// @endif | ||
bid = bidfactory.createBid(2, bidObj); | ||
bid.bidderCode = 'yieldmo'; | ||
bidmanager.addBidResponse(placementCode, bid); | ||
} | ||
} | ||
|
||
return { | ||
callBids: _callBids | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
}; | ||
|
||
adaptermanager.registerBidAdapter(new YieldmoAdapter(), 'yieldmo'); | ||
|
||
module.exports = YieldmoAdapter; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
import {expect} from 'chai'; | ||
import Adapter from '../../../modules/yieldmoBidAdapter'; | ||
import bidManager from '../../../src/bidmanager'; | ||
import adLoader from '../../../src/adloader'; | ||
import {parse as parseURL} from '../../../src/url'; | ||
|
||
describe('Yieldmo adapter', () => { | ||
let bidsRequestedOriginal; | ||
let adapter; | ||
let sandbox; | ||
|
||
const bidderRequest = { | ||
bidderCode: 'yieldmo', | ||
bids: [ | ||
{ | ||
bidId: 'bidId1', | ||
bidder: 'yieldmo', | ||
placementCode: 'foo', | ||
sizes: [[728, 90]] | ||
}, | ||
{ | ||
bidId: 'bidId2', | ||
bidder: 'yieldmo', | ||
placementCode: 'bar', | ||
sizes: [[300, 600], [300, 250]] | ||
} | ||
] | ||
}; | ||
|
||
beforeEach(() => { | ||
bidsRequestedOriginal = $$PREBID_GLOBAL$$._bidsRequested; | ||
$$PREBID_GLOBAL$$._bidsRequested = []; | ||
|
||
adapter = new Adapter(); | ||
sandbox = sinon.sandbox.create(); | ||
}); | ||
|
||
afterEach(() => { | ||
sandbox.restore(); | ||
|
||
$$PREBID_GLOBAL$$._bidsRequested = bidsRequestedOriginal; | ||
}); | ||
|
||
describe('callBids', () => { | ||
let bidRequestURL; | ||
|
||
beforeEach(() => { | ||
sandbox.stub(adLoader, 'loadScript'); | ||
adapter.callBids(bidderRequest); | ||
|
||
bidRequestURL = adLoader.loadScript.firstCall.args[0]; | ||
}); | ||
|
||
it('should load a script with passed bid params', () => { | ||
let route = 'http://ads.yieldmo.com/ads?'; | ||
let requestParams = parseURL(bidRequestURL).search; | ||
let parsedPlacementParams = JSON.parse(decodeURIComponent(requestParams.p)); | ||
|
||
sinon.assert.calledOnce(adLoader.loadScript); | ||
expect(bidRequestURL).to.contain(route); | ||
|
||
// placement 1 | ||
expect(parsedPlacementParams[0]).to.have.property('callback_id', 'bidId1'); | ||
expect(parsedPlacementParams[0]).to.have.property('placement_id', 'foo'); | ||
expect(parsedPlacementParams[0].sizes[0][0]).to.equal(728); | ||
expect(parsedPlacementParams[0].sizes[0][1]).to.equal(90); | ||
|
||
// placement 2 | ||
expect(parsedPlacementParams[1]).to.have.property('callback_id', 'bidId2'); | ||
expect(parsedPlacementParams[1]).to.have.property('placement_id', 'bar'); | ||
expect(parsedPlacementParams[1].sizes[0][0]).to.equal(300); | ||
expect(parsedPlacementParams[1].sizes[0][1]).to.equal(600); | ||
expect(parsedPlacementParams[1].sizes[1][0]).to.equal(300); | ||
expect(parsedPlacementParams[1].sizes[1][1]).to.equal(250); | ||
|
||
// impression information | ||
expect(requestParams).to.have.property('callback', '$$PREBID_GLOBAL$$.YMCB'); | ||
expect(requestParams).to.have.property('page_url'); | ||
}); | ||
}); | ||
|
||
describe('YMCB', () => { | ||
it('should exist and be a function', () => { | ||
expect($$PREBID_GLOBAL$$.YMCB).to.exist.and.to.be.a('function'); | ||
}); | ||
}); | ||
|
||
describe('add bids to the manager', () => { | ||
let firstBid; | ||
let secondBid; | ||
|
||
beforeEach(() => { | ||
sandbox.stub(bidManager, 'addBidResponse'); | ||
|
||
$$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); | ||
|
||
// respond | ||
let bidderReponse = [{ | ||
'cpm': 3.45455, | ||
'width': 300, | ||
'height': 250, | ||
'callback_id': 'bidId1', | ||
'ad': '<html><head></head><body>HELLO YIELDMO AD</body></html>' | ||
}, { | ||
'cpm': 4.35455, | ||
'width': 400, | ||
'height': 350, | ||
'callback_id': 'bidId2', | ||
'ad': '<html><head></head><body>HELLO YIELDMO AD</body></html>' | ||
}]; | ||
|
||
$$PREBID_GLOBAL$$.YMCB(bidderReponse); | ||
|
||
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 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', 3.45455); | ||
expect(secondBid).to.have.property('cpm', 4.35455); | ||
}); | ||
|
||
it('should add the bidder code to the bid object', () => { | ||
expect(firstBid).to.have.property('bidderCode', 'yieldmo'); | ||
expect(secondBid).to.have.property('bidderCode', 'yieldmo'); | ||
}); | ||
|
||
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', 300); | ||
expect(firstBid).to.have.property('height', 250); | ||
expect(secondBid).to.have.property('width', 400); | ||
expect(secondBid).to.have.property('height', 350); | ||
}); | ||
}); | ||
|
||
describe('add empty bids if no bid returned', () => { | ||
let firstBid; | ||
let secondBid; | ||
|
||
beforeEach(() => { | ||
sandbox.stub(bidManager, 'addBidResponse'); | ||
|
||
$$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); | ||
|
||
// respond | ||
let bidderReponse = [{ | ||
'status': 'no_bid', | ||
'callback_id': 'bidId1' | ||
}, { | ||
'status': 'no_bid', | ||
'callback_id': 'bidId2' | ||
}]; | ||
|
||
$$PREBID_GLOBAL$$.YMCB(bidderReponse); | ||
|
||
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 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 an error statusCode', () => { | ||
expect(firstBid.getStatusCode()).to.eql(2); | ||
expect(secondBid.getStatusCode()).to.eql(2); | ||
}); | ||
|
||
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 add the bidder code to the bid object', () => { | ||
expect(firstBid).to.have.property('bidderCode', 'yieldmo'); | ||
expect(secondBid).to.have.property('bidderCode', 'yieldmo'); | ||
}); | ||
}); | ||
}); |
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.
Can also be removed