From 1cfc0c9f07ff50f1beb76efe2130de69124a824e Mon Sep 17 00:00:00 2001 From: yehonatanshac Date: Thu, 16 Nov 2017 20:38:02 +0200 Subject: [PATCH] Kumma adapter updated for Prebid 1.0 (#1766) * kumma adapter for prebid.js 1.0 * add prebid 1.0 example * changing default ad + supporting bidfloor+function for top window referrer --- modules/kummaBidAdapter.js | 176 ++++++++++------ modules/kummaBidAdapter.md | 28 +++ test/spec/modules/kummaBidAdapter_spec.js | 235 ++++++++-------------- 3 files changed, 230 insertions(+), 209 deletions(-) create mode 100644 modules/kummaBidAdapter.md diff --git a/modules/kummaBidAdapter.js b/modules/kummaBidAdapter.js index b65b80c5a1a8..f819ec1dc44d 100644 --- a/modules/kummaBidAdapter.js +++ b/modules/kummaBidAdapter.js @@ -1,63 +1,113 @@ -var bidfactory = require('src/bidfactory.js'); -var bidmanager = require('src/bidmanager.js'); -var adloader = require('src/adloader.js'); -var utils = require('src/utils.js'); -var CONSTANTS = require('src/constants.json'); -var adaptermanager = require('src/adaptermanager'); - -var KummaAdapter = function KummaAdapter() { - function _callBids(params) { - var bidURL; - var bids = params.bids || []; - var requestURL = window.location.protocol + '//cdn.kumma.com/pb_ortb.js?cb=' + new Date().getTime() + '&ver=1&'; - - for (var i = 0; i < bids.length; i++) { - var requestParams = {}; - var bid = bids[i]; - - requestParams.pub_id = bid.params.pubId; - requestParams.site_id = bid.params.siteId; - requestParams.placement_id = bid.placementCode; - - var parseSized = utils.parseSizesInput(bid.sizes); - var arrSize = parseSized[0].split('x'); - - requestParams.width = arrSize[0]; - requestParams.height = arrSize[1]; - requestParams.callback = '$$PREBID_GLOBAL$$._doKummaCallback'; - requestParams.callback_uid = bid.bidId; - bidURL = requestURL + utils.parseQueryStringParameters(requestParams); - - utils.logMessage('Kumma.prebid, Bid ID: ' + bid.bidId + ', Pub ID: ' + bid.params.pubId); - adloader.loadScript(bidURL); - } - } - - $$PREBID_GLOBAL$$._doKummaCallback = function (response) { - var bidObject; - var bidRequest; - var callbackID; - callbackID = response.callback_uid; - bidRequest = utils.getBidRequest(callbackID); - if (response.cpm > 0) { - bidObject = bidfactory.createBid(CONSTANTS.STATUS.GOOD, bidRequest); - bidObject.bidderCode = 'kumma'; - bidObject.cpm = response.cpm; - bidObject.ad = response.tag; - bidObject.width = response.width; - bidObject.height = response.height; - } else { - bidObject = bidfactory.createBid(CONSTANTS.STATUS.NO_BID, bidRequest); - bidObject.bidderCode = 'kumma'; - utils.logMessage('No Bid response from Kumma request: ' + callbackID); - } - bidmanager.addBidResponse(bidRequest.placementCode, bidObject); - }; - - return { - callBids: _callBids - }; -}; -adaptermanager.registerBidAdapter(new KummaAdapter(), 'kumma'); - -module.exports = KummaAdapter; + +import {logError, getTopWindowLocation, getTopWindowReferrer} from 'src/utils'; +import { registerBidder } from 'src/adapters/bidderFactory'; + +export const spec = { + + code: 'kumma', + + isBidRequestValid: bid => ( + !!(bid && bid.params && bid.params.pubId && bid.params.siteId) + ), + buildRequests: bidRequests => { + const request = { + id: bidRequests[0].bidderRequestId, + at: 2, + imp: bidRequests.map(slot => impression(slot)), + site: site(bidRequests), + device: device(), + }; + return { + method: 'POST', + url: '//hb.kumma.com/', + data: JSON.stringify(request), + }; + }, + interpretResponse: (response, request) => ( + bidResponseAvailable(request, response.body) + ), +}; +function bidResponseAvailable(bidRequest, bidResponse) { + const idToImpMap = {}; + const idToBidMap = {}; + let ortbRequest = null; + try { + ortbRequest = JSON.parse(bidRequest.data); + } catch (ex) { + logError('kumma.parse', 'ERROR', ex); + } + ortbRequest.imp.forEach(imp => { + idToImpMap[imp.id] = imp; + }); + if (bidResponse) { + bidResponse.seatbid.forEach(seatBid => seatBid.bid.forEach(bid => { + idToBidMap[bid.impid] = bid; + })); + } + const bids = []; + Object.keys(idToImpMap).forEach(id => { + if (idToBidMap[id]) { + const bid = {}; + bid.requestId = id; + bid.creativeId = idToBidMap[id].adid; + bid.cpm = idToBidMap[id].price; + bid.currency = bidResponse.cur; + bid.ttl = 360; + bid.netRevenue = true; + bid.ad = idToBidMap[id].adm; + bid.ad = bid.ad.replace(/\$(%7B|\{)AUCTION_IMP_ID(%7D|\})/gi, idToBidMap[id].impid); + bid.ad = bid.ad.replace(/\$(%7B|\{)AUCTION_AD_ID(%7D|\})/gi, idToBidMap[id].adid); + bid.ad = bid.ad.replace(/\$(%7B|\{)AUCTION_PRICE(%7D|\})/gi, idToBidMap[id].price); + bid.ad = bid.ad.replace(/\$(%7B|\{)AUCTION_CURRENCY(%7D|\})/gi, bidResponse.cur); + bid.ad = bid.ad.replace(/\$(%7B|\{)AUCTION_BID_ID(%7D|\})/gi, bidResponse.bidid); + bid.width = idToImpMap[id].banner.w; + bid.height = idToImpMap[id].banner.h; + bids.push(bid); + } + }); + return bids; +} +function impression(slot) { + return { + id: slot.bidId, + banner: banner(slot), + bidfloor: slot.params.bidFloor || '0.000001', + tagid: slot.params.placementId.toString(), + }; +} +function banner(slot) { + const size = slot.params.size.toUpperCase().split('X'); + const width = parseInt(size[0]); + const height = parseInt(size[1]); + return { + w: width, + h: height, + }; +} +function site(bidderRequest) { + const pubId = bidderRequest && bidderRequest.length > 0 ? bidderRequest[0].params.pubId : '0'; + const siteId = bidderRequest && bidderRequest.length > 0 ? bidderRequest[0].params.siteId : '0'; + const appParams = bidderRequest[0].params.app; + if (!appParams) { + return { + publisher: { + id: pubId.toString(), + domain: getTopWindowLocation().hostname, + }, + id: siteId.toString(), + ref: getTopWindowReferrer(), + page: getTopWindowLocation().href, + } + } + return null; +} +function device() { + return { + ua: navigator.userAgent, + language: (navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage), + w: (window.screen.width || window.innerWidth), + h: (window.screen.height || window.innerHeigh), + }; +} + +registerBidder(spec); diff --git a/modules/kummaBidAdapter.md b/modules/kummaBidAdapter.md new file mode 100644 index 000000000000..3ec4aff73f71 --- /dev/null +++ b/modules/kummaBidAdapter.md @@ -0,0 +1,28 @@ +# Overview + +**Module Name**: Kumma Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: yehonatan@kumma.com + +# Description + +Connects to Kumma demand source to fetch bids. +Please use ```kumma``` as the bidder code. + +# Test Parameters +``` + var adUnits = [{ + code: 'banner-ad-div', + sizes: [[300, 250]], + bids: [{ + bidder: 'kumma', + params: { + pubId: '55879', // required + siteId: '26047', // required + size: '300X250', // required + placementId: '123', + bidFloor: '0.001' + } + }] + }]; +``` diff --git a/test/spec/modules/kummaBidAdapter_spec.js b/test/spec/modules/kummaBidAdapter_spec.js index 82a2823efd7f..3b58ee256627 100644 --- a/test/spec/modules/kummaBidAdapter_spec.js +++ b/test/spec/modules/kummaBidAdapter_spec.js @@ -1,156 +1,99 @@ -describe('kumma adapter tests', function () { - var expect = require('chai').expect; - var urlParse = require('url-parse'); - var querystringify = require('querystringify'); - var adapter = require('modules/kummaBidAdapter'); - var adLoader = require('src/adloader'); - var bidmanager = require('src/bidmanager'); - - var stubLoadScript; - - beforeEach(function () { - stubLoadScript = sinon.stub(adLoader, 'loadScript'); - }); - - afterEach(function () { - stubLoadScript.restore(); - }); - - describe('creation of bid url', function () { - if (typeof ($$PREBID_GLOBAL$$._bidsReceived) === 'undefined') { - $$PREBID_GLOBAL$$._bidsReceived = []; +import {expect} from 'chai'; +import {spec} from 'modules/kummaBidAdapter'; +import {getTopWindowLocation, getTopWindowReferrer} from 'src/utils'; + +describe('Kumma Adapter Tests', () => { + const slotConfigs = [{ + placementCode: '/DfpAccount1/slot1', + sizes: [[300, 250]], + bidId: 'bid12345', + params: { + pubId: '55879', + siteId: '26047', + placementId: '123', + size: '300x250', + bidFloor: '0.001' } - if (typeof ($$PREBID_GLOBAL$$._bidsRequested) === 'undefined') { - $$PREBID_GLOBAL$$._bidsRequested = []; + }, { + placementCode: '/DfpAccount2/slot2', + sizes: [[250, 250]], + bidId: 'bid23456', + params: { + pubId: '55879', + siteId: '26047', + placementId: '456', + size: '250x250' } - - it('bid request for single placement', function () { - var params = { - bids: [{ - placementCode: '/19968336/header-bid-tag-0', - sizes: [[300, 250]], - bidId: 'bid1111', - bidder: 'kumma', - params: { pubId: '37054', siteId: '123' } - }] - }; - - adapter().callBids(params); - - var bidUrl = stubLoadScript.getCall(0).args[0]; - - sinon.assert.calledOnce(stubLoadScript); - - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - expect(parsedBidUrlQueryString).to.have.property('pub_id').and.to.equal('37054'); - expect(parsedBidUrlQueryString).to.have.property('site_id').and.to.equal('123'); - expect(parsedBidUrlQueryString).to.have.property('width').and.to.equal('300'); - expect(parsedBidUrlQueryString).to.have.property('height').and.to.equal('250'); - }); + }]; + it('Verify build request', () => { + const request = spec.buildRequests(slotConfigs); + expect(request.url).to.equal('//hb.kumma.com/'); + expect(request.method).to.equal('POST'); + const ortbRequest = JSON.parse(request.data); + // site object + expect(ortbRequest.site).to.not.equal(null); + expect(ortbRequest.site.publisher).to.not.equal(null); + expect(ortbRequest.site.publisher.id).to.equal('55879'); + expect(ortbRequest.site.ref).to.equal(getTopWindowReferrer()); + expect(ortbRequest.site.page).to.equal(getTopWindowLocation().href); + expect(ortbRequest.imp).to.have.lengthOf(2); + // device object + expect(ortbRequest.device).to.not.equal(null); + expect(ortbRequest.device.ua).to.equal(navigator.userAgent); + // slot 1 + expect(ortbRequest.imp[0].tagid).to.equal('123'); + expect(ortbRequest.imp[0].banner).to.not.equal(null); + expect(ortbRequest.imp[0].banner.w).to.equal(300); + expect(ortbRequest.imp[0].banner.h).to.equal(250); + expect(ortbRequest.imp[0].bidfloor).to.equal('0.001'); + // slot 2 + expect(ortbRequest.imp[1].tagid).to.equal('456'); + expect(ortbRequest.imp[1].banner).to.not.equal(null); + expect(ortbRequest.imp[1].banner.w).to.equal(250); + expect(ortbRequest.imp[1].banner.h).to.equal(250); + expect(ortbRequest.imp[1].bidfloor).to.equal('0.000001'); }); - describe('handling bid response', function () { - it('should return complete bid response', function() { - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - - var params = { - bids: [{ - placementCode: '/19968336/header-bid-tag-0', - sizes: [[300, 250]], - bidId: 'bid1111', - bidder: 'kumma', - params: { pubId: '37054', siteId: '123' } - }] - }; - - var response = { - cpm: 1, - width: 300, - height: 250, - callback_uid: 'bid1111', - tag: '