-
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.
Added iQM Bid Adapter for Prebid.js 1.0 (#1880)
* Added iQM Bid Adapter for Prebid.js 1.0 * Modified URL from http to https * Removed geo function which was fetching user location.
- Loading branch information
1 parent
b738584
commit f1f18e1
Showing
3 changed files
with
397 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,137 @@ | ||
import * as utils from 'src/utils'; | ||
// import {config} from 'src/config'; | ||
import {registerBidder} from 'src/adapters/bidderFactory'; | ||
const BIDDER_CODE = 'iqm'; | ||
const ENDPOINT_URL = 'https://pbd.bids.iqm.com'; | ||
const VERSION = 'v.1.0.0'; | ||
|
||
export const spec = { | ||
code: BIDDER_CODE, | ||
aliases: ['iqm'], // short code | ||
/** | ||
* Determines whether or not the given bid request is valid. | ||
* | ||
* @param {BidRequest} bid The bid params to validate. | ||
* @return boolean True if this is a valid bid, and false otherwise. | ||
*/ | ||
isBidRequestValid: function(bid) { | ||
return !!(bid && bid.params && bid.params.publisherId && bid.params.placementId && bid.params.tagId); | ||
}, | ||
/** | ||
* Make a server request from the list of BidRequests. | ||
* | ||
* @return ServerRequest Info describing the request to the server. | ||
* @param validBidRequests - an array of bids | ||
*/ | ||
buildRequests: function(validBidRequests) { | ||
let requestId = ''; | ||
let siteId = ''; | ||
let device = getDevice(); | ||
return validBidRequests.map(bid => { | ||
requestId = bid.requestId; | ||
let bidfloor = utils.getBidIdParameter('bidfloor', bid.params); | ||
siteId = utils.getBidIdParameter('tagId', bid.params); | ||
const imp = { | ||
id: bid.bidId, | ||
secure: 1, | ||
bidfloor: bidfloor || 0, | ||
displaymanager: 'Prebid.js', | ||
displaymanagerver: VERSION, | ||
mediatype: 'banner' | ||
}; | ||
imp.banner = getSize(bid.sizes); | ||
let data = { | ||
id: requestId, | ||
publisherId: utils.getBidIdParameter('publisherId', bid.params), | ||
tagId: utils.getBidIdParameter('tagId', bid.params), | ||
placementId: utils.getBidIdParameter('placementId', bid.params), | ||
device: device, | ||
site: { | ||
id: siteId, | ||
page: utils.getTopWindowLocation().href, | ||
domain: utils.getTopWindowLocation().host | ||
}, | ||
imp: imp | ||
}; | ||
return { | ||
method: 'POST', | ||
url: ENDPOINT_URL, | ||
data: data | ||
}; | ||
}); | ||
}, | ||
/** | ||
* Unpack the response from the server into a list of bids. | ||
* | ||
* @param {*} serverResponse A successful response from the server. | ||
* @param bidRequest | ||
* @return {Bid[]} An array of bids which were nested inside the server. | ||
*/ | ||
interpretResponse: function(serverResponse, bidRequest) { | ||
// const serverBody = serverResponse.body; | ||
// const headerValue = serverResponse.headers.get('some-response-header') | ||
const bidResponses = []; | ||
serverResponse = serverResponse.body; | ||
if (serverResponse && utils.isArray(serverResponse.seatbid)) { | ||
utils._each(serverResponse.seatbid, function(bidList) { | ||
utils._each(bidList.bid, function(bid) { | ||
const responseCPM = parseFloat(bid.price); | ||
if (responseCPM > 0.0 && bid.impid) { | ||
// const responseNurl = bid.nurl || ''; | ||
const bidResponse = { | ||
requestId: bid.impid, | ||
currency: serverResponse.cur || 'USD', | ||
cpm: responseCPM, | ||
netRevenue: true, | ||
creativeId: bid.crid || '', | ||
ad: bid.adm || '', | ||
width: bid.w || bidRequest.data.imp.banner.w, | ||
height: bid.h || bidRequest.data.imp.banner.h, | ||
ttl: bid.ttl || 300 | ||
}; | ||
|
||
bidResponses.push(bidResponse); | ||
} | ||
}) | ||
}); | ||
} | ||
return bidResponses; | ||
} | ||
}; | ||
|
||
let getDevice = function () { | ||
const language = navigator.language ? 'language' : 'userLanguage'; | ||
return { | ||
h: screen.height, | ||
w: screen.width, | ||
dnt: _getDNT() ? 1 : 0, | ||
language: navigator[language].split('-')[0], | ||
make: navigator.vendor ? navigator.vendor : '', | ||
ua: navigator.userAgent, | ||
devicetype: _isMobile() ? 1 : _isConnectedTV() ? 3 : 2 | ||
}; | ||
}; | ||
|
||
let _getDNT = function () { | ||
return navigator.doNotTrack === '1' || window.doNotTrack === '1' || navigator.msDoNotTrack === '1' || navigator.doNotTrack === 'yes'; | ||
}; | ||
|
||
let getSize = function (sizes) { | ||
let sizeMap; | ||
if (sizes.length === 2 && typeof sizes[0] === 'number' && typeof sizes[1] === 'number') { | ||
sizeMap = {w: sizes[0], h: sizes[1]}; | ||
} else { | ||
sizeMap = {w: sizes[0][0], h: sizes[0][1]}; | ||
} | ||
return sizeMap; | ||
}; | ||
|
||
function _isMobile() { | ||
return (/(ios|ipod|ipad|iphone|android)/i).test(global.navigator.userAgent); | ||
} | ||
|
||
function _isConnectedTV() { | ||
return (/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(global.navigator.userAgent); | ||
} | ||
|
||
registerBidder(spec); |
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,41 @@ | ||
#Overview | ||
|
||
``` | ||
Module Name: iQM Bidder Adapter | ||
Module Type: Bidder Adapter | ||
Maintainer: hbteam@iqm.com | ||
``` | ||
|
||
# Parameters | ||
|
||
| Name | Scope | Description | Example | | ||
| :------------ | :------- | :------------------------ | :------------------- | | ||
| `publisherId` | required | The Publisher ID from iQM | "df5fd732-c5f3-11e7" | | ||
| `tagId` | required | The tag ID from iQM | "1c5c9ec2-c5f4-11e7" | | ||
| `placementId` | required | The Placement ID from iQM | "50cc36fe-c5f4-11e7" | | ||
| `bidfloor` | optional | Bid Floor | 0.50 | | ||
|
||
# Description | ||
|
||
Module that connects to iQM demand sources | ||
|
||
# Test Parameters | ||
``` | ||
var adUnits = [ | ||
{ | ||
code: 'test-div1', | ||
sizes: [[320, 50]], // display 320x50 | ||
bids: [ | ||
{ | ||
bidder: 'iqm', | ||
params: { | ||
publisherId: 'df5fd732-c5f3-11e7-abc4-cec278b6b50a', | ||
tagId: '1c5c9ec2-c5f4-11e7-abc4-cec278b6b50a', | ||
placementId: '50cc36fe-c5f4-11e7-abc4-cec278b6b50a', | ||
bidfloor: 0.50, | ||
} | ||
} | ||
] | ||
} | ||
]; | ||
``` |
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,219 @@ | ||
import {expect} from 'chai'; | ||
import {spec} from 'modules/iqmBidAdapter' | ||
import * as utils from 'src/utils'; | ||
|
||
describe('iqmBidAdapter', () => { | ||
const ENDPOINT_URL = 'https://pbd.bids.iqm.com'; | ||
const bidRequests = [{ | ||
bidder: 'iqm', | ||
params: { | ||
position: 1, | ||
tagId: 'tagId-1', | ||
placementId: 'placementId-1', | ||
pubId: 'pubId-1', | ||
secure: true, | ||
bidfloor: 0.5 | ||
}, | ||
placementCode: 'pcode000', | ||
transactionId: 'tx000', | ||
sizes: [[300, 250]], | ||
bidId: 'bid000', | ||
bidderRequestId: '117d765b87bed38', | ||
requestId: 'req000' | ||
}]; | ||
|
||
const bidResponses = { | ||
body: { | ||
id: 'req000', | ||
seatbid: [{ | ||
bid: [{ | ||
nurl: 'nurl', | ||
adm: '<img src"http://www.imgurl.com" />', | ||
crid: 'cr-65981', | ||
impid: 'bid000', | ||
price: 0.99, | ||
w: 300, | ||
h: 250, | ||
adomain: ['https://example.com'], | ||
id: 'bid000', | ||
ttl: 300 | ||
}] | ||
}] | ||
}, | ||
headers: {}}; | ||
|
||
const bidResponseEmptySeat = { | ||
body: { | ||
id: 'req000', | ||
seatbid: [] | ||
}, | ||
headers: {} | ||
}; | ||
|
||
const bidResponseEmptyBid = { | ||
body: { | ||
id: 'req000', | ||
seatbid: [{ | ||
bid: [] | ||
}] | ||
}, | ||
headers: {} | ||
}; | ||
|
||
const bidResponseNoImpId = { | ||
body: { | ||
id: 'req000', | ||
seatbid: [{ | ||
bid: [{ | ||
nurl: 'nurl', | ||
adm: '<img src"http://www.imgurl.com" />', | ||
crid: 'cr-65981', | ||
price: 0.99, | ||
w: 300, | ||
h: 250, | ||
adomain: ['https://example.com'], | ||
id: 'bid000', | ||
ttl: 300 | ||
}] | ||
}] | ||
}, | ||
headers: {} | ||
}; | ||
|
||
describe('Request verification', () => { | ||
it('basic property verification', () => { | ||
expect(spec.code).to.equal('iqm'); | ||
expect(spec.aliases).to.be.an('array'); | ||
// expect(spec.aliases).to.be.ofSize(1); | ||
expect(spec.aliases).to.have.lengthOf(1); | ||
}); | ||
|
||
describe('isBidRequestValid', () => { | ||
let bid = { | ||
'bidder': 'iqm', | ||
'params': { | ||
'placementId': 'placementId', | ||
'tagId': 'tagId', | ||
'publisherId': 'pubId' | ||
}, | ||
'adUnitCode': 'ad-unit-code', | ||
'sizes': [[300, 250], [300, 600]], | ||
'bidId': '30b31c1838de1e', | ||
'bidderRequestId': '22edbae2733bf6', | ||
'auctionId': '1d1a030790a475' | ||
}; | ||
|
||
it('should return false for empty object', () => { | ||
expect(spec.isBidRequestValid({})).to.equal(false); | ||
}); | ||
|
||
it('should return false for request without param', () => { | ||
let bid = Object.assign({}, bid); | ||
delete bid.params; | ||
expect(spec.isBidRequestValid(bid)).to.equal(false); | ||
}); | ||
|
||
it('should return false for invalid params', () => { | ||
let bid = Object.assign({}, bid); | ||
delete bid.params; | ||
bid.params = { | ||
'placementId': 'placementId' | ||
}; | ||
expect(spec.isBidRequestValid(bid)).to.equal(false); | ||
}); | ||
|
||
it('should return true for proper request', () => { | ||
expect(spec.isBidRequestValid(bid)).to.equal(true); | ||
}); | ||
}); | ||
|
||
describe('buildRequests', () => { | ||
it('sends every bid request to ENDPOINT_URL via POST method', () => { | ||
const requests = spec.buildRequests(bidRequests); | ||
expect(requests[0].method).to.equal('POST'); | ||
expect(requests[0].url).to.equal(ENDPOINT_URL); | ||
// expect(requests[1].method).to.equal('POST'); | ||
// expect(requests[1].url).to.equal(ENDPOINT_URL); | ||
}); | ||
|
||
it('should send request data with every request', () => { | ||
const requests = spec.buildRequests(bidRequests); | ||
const data = requests[0].data; | ||
expect(data.id).to.equal(bidRequests[0].requestId); | ||
|
||
expect(data.imp.id).to.equal(bidRequests[0].bidId); | ||
expect(data.imp.bidfloor).to.equal(bidRequests[0].params.bidfloor); | ||
expect(data.imp.secure).to.equal(1); | ||
expect(data.imp.displaymanager).to.equal('Prebid.js'); | ||
expect(data.imp.displaymanagerver).to.equal('v.1.0.0'); | ||
expect(data.imp.mediatype).to.equal('banner'); | ||
expect(data.imp.banner).to.deep.equal({ | ||
w: 300, | ||
h: 250 | ||
}); | ||
expect(data.publisherId).to.equal(utils.getBidIdParameter('publisherId', bidRequests[0].params)); | ||
expect(data.tagId).to.equal(utils.getBidIdParameter('tagId', bidRequests[0].params)); | ||
expect(data.placementId).to.equal(utils.getBidIdParameter('placementId', bidRequests[0].params)); | ||
expect(data.device.w).to.equal(screen.width); | ||
expect(data.device.h).to.equal(screen.height); | ||
expect(data.device.make).to.equal(navigator.vendor ? navigator.vendor : ''); | ||
expect(data.device.ua).to.equal(navigator.userAgent); | ||
expect(data.device.dnt).to.equal(navigator.doNotTrack === '1' || window.doNotTrack === '1' || navigator.msDoNotTrack === '1' || navigator.doNotTrack === 'yes' ? 1 : 0); | ||
expect(data.site).to.deep.equal({ | ||
id: utils.getBidIdParameter('tagId', bidRequests[0].params), | ||
page: utils.getTopWindowLocation().href, | ||
domain: utils.getTopWindowLocation().host | ||
}); | ||
|
||
expect(data.device.ua).to.equal(navigator.userAgent); | ||
expect(data.device.h).to.equal(screen.height); | ||
expect(data.device.w).to.equal(screen.width); | ||
|
||
expect(data.site.id).to.equal(bidRequests[0].params.tagId); | ||
expect(data.site.page).to.equal(utils.getTopWindowLocation().href); | ||
expect(data.site.domain).to.equal(utils.getTopWindowLocation().host); | ||
}); | ||
}); | ||
|
||
describe('interpretResponse', () => { | ||
it('should handle no bid response', () => { | ||
const response = spec.interpretResponse({ body: null }, { bidRequests }); | ||
expect(response.length).to.equal(0); | ||
}); | ||
|
||
it('should have at least one Seat Object', () => { | ||
const request = spec.buildRequests(bidRequests); | ||
const response = spec.interpretResponse(bidResponseEmptySeat, request); | ||
expect(response.length).to.equal(0); | ||
}); | ||
|
||
it('should have at least one Bid Object', () => { | ||
const request = spec.buildRequests(bidRequests); | ||
const response = spec.interpretResponse(bidResponseEmptyBid, request); | ||
expect(response.length).to.equal(0); | ||
}); | ||
|
||
it('should have impId in Bid Object', () => { | ||
const request = spec.buildRequests(bidRequests); | ||
const response = spec.interpretResponse(bidResponseNoImpId, request); | ||
expect(response.length).to.equal(0); | ||
}); | ||
|
||
it('should handle valid response', () => { | ||
const request = spec.buildRequests(bidRequests); | ||
const response = spec.interpretResponse(bidResponses, request); | ||
expect(response).to.be.an('array').to.have.lengthOf(1); | ||
|
||
let bid = response[0]; | ||
expect(bid).to.have.property('requestId', 'bid000'); | ||
expect(bid).to.have.property('currency', 'USD'); | ||
expect(bid).to.have.property('cpm', 0.99); | ||
expect(bid).to.have.property('creativeId', 'cr-65981'); | ||
expect(bid).to.have.property('width', 300); | ||
expect(bid).to.have.property('height', 250); | ||
expect(bid).to.have.property('ttl', 300); | ||
expect(bid).to.have.property('ad', '<img src"http://www.imgurl.com" />'); | ||
}); | ||
}); | ||
}); | ||
}); |