diff --git a/integrationExamples/gpt/pbjs_example_gpt.html b/integrationExamples/gpt/pbjs_example_gpt.html index f1ec912fd265..e54a604e2817 100644 --- a/integrationExamples/gpt/pbjs_example_gpt.html +++ b/integrationExamples/gpt/pbjs_example_gpt.html @@ -269,6 +269,13 @@ placement_id: 0 } }, + { + bidder: 'weborama', + params: { + placementId: 0, + traffic: 'banner' + } + }, { bidder: 'pollux', params: { diff --git a/modules/weboramaBidAdapter.js b/modules/weboramaBidAdapter.js new file mode 100644 index 000000000000..2fe6f30b361e --- /dev/null +++ b/modules/weboramaBidAdapter.js @@ -0,0 +1,117 @@ +import { registerBidder } from 'src/adapters/bidderFactory'; +import { BANNER, NATIVE, VIDEO } from 'src/mediaTypes'; +import * as utils from 'src/utils'; + +const BIDDER_CODE = 'weborama'; +const URL = '//supply.nl.weborama.fr/?c=o&m=multi'; +const URL_SYNC = '//supply.nl.weborama.fr/?c=o&m=cookie'; + +function isBidResponseValid(bid) { + if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) { + return false; + } + switch (bid.mediaType) { + case BANNER: + return Boolean(bid.width && bid.height && bid.ad); + case VIDEO: + return Boolean(bid.vastUrl); + case NATIVE: + return Boolean(bid.native); + default: + return false; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + + /** + * Determines whether or not the given bid request is valid. + * + * @param {object} bid The bid to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: (bid) => { + return Boolean(bid.bidId && + bid.params && + !isNaN(bid.params.placementId) && + spec.supportedMediaTypes.indexOf(bid.params.traffic) !== -1 + ); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} validBidRequests A non-empty list of valid bid requests that should be sent to the Server. + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: (validBidRequests) => { + let winTop; + try { + winTop = utils.getWindowTop(); + winTop.location.toString(); + } catch (e) { + utils.logMessage(e); + winTop = window; + }; + + const location = utils.getTopWindowLocation(); + const placements = []; + const request = { + 'secure': (location.protocol === 'https:') ? 1 : 0, + 'deviceWidth': winTop.screen.width, + 'deviceHeight': winTop.screen.height, + 'host': location.host, + 'page': location.pathname, + 'placements': placements + }; + + for (let i = 0; i < validBidRequests.length; i++) { + const bid = validBidRequests[i]; + const params = bid.params; + placements.push({ + placementId: params.placementId, + bidId: bid.bidId, + sizes: bid.sizes, + traffic: params.traffic + }); + } + return { + method: 'POST', + url: URL, + data: request + }; + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: (serverResponse) => { + let response = []; + try { + serverResponse = serverResponse.body; + for (let i = 0; i < serverResponse.length; i++) { + let resItem = serverResponse[i]; + if (isBidResponseValid(resItem)) { + response.push(resItem); + } + } + } catch (e) { + utils.logMessage(e); + }; + return response; + }, + + getUserSyncs: () => { + return [{ + type: 'image', + url: URL_SYNC + }]; + } +}; + +registerBidder(spec); diff --git a/modules/weboramaBidAdapter.md b/modules/weboramaBidAdapter.md new file mode 100644 index 000000000000..5bdca0bfcd14 --- /dev/null +++ b/modules/weboramaBidAdapter.md @@ -0,0 +1,27 @@ +# Overview + +``` +Module Name: Weborama SSP Bidder Adapter +Module Type: Bidder Adapter +Maintainer: devweborama@gmail.com +``` + +# Description + +Module that connects to Weborama SSP demand sources + +# Test Parameters +``` + var adUnits = [{ + code: 'placementCode', + sizes: [[300, 250]], + bids: [{ + bidder: 'weborama', + params: { + placementId: 0, + traffic: 'banner' + } + }] + } + ]; +``` diff --git a/test/spec/modules/weboramaBidAdapter_spec.js b/test/spec/modules/weboramaBidAdapter_spec.js new file mode 100644 index 000000000000..ef8414eb487d --- /dev/null +++ b/test/spec/modules/weboramaBidAdapter_spec.js @@ -0,0 +1,118 @@ +import {expect} from 'chai'; +import {spec} from '../../../modules/weboramaBidAdapter'; + +describe('WeboramaAdapter', () => { + let bid = { + bidId: '2dd581a2b6281d', + bidder: 'weborama', + bidderRequestId: '145e1d6a7837c9', + params: { + placementId: 123, + traffic: 'banner' + }, + placementCode: 'placement_0', + auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', + sizes: [[300, 250]], + transactionId: '3bb2f6da-87a6-4029-aeb0-bfe951372e62' + }; + + describe('isBidRequestValid', () => { + it('Should return true when placementId can be cast to a number', () => { + expect(spec.isBidRequestValid(bid)).to.be.true; + }); + it('Should return false when placementId is not a number', () => { + bid.params.placementId = 'aaa'; + expect(spec.isBidRequestValid(bid)).to.be.false; + }); + }); + + describe('buildRequests', () => { + let serverRequest = spec.buildRequests([bid]); + it('Creates a ServerRequest object with method, URL and data', () => { + expect(serverRequest).to.exist; + expect(serverRequest.method).to.exist; + expect(serverRequest.url).to.exist; + expect(serverRequest.data).to.exist; + }); + it('Returns POST method', () => { + expect(serverRequest.method).to.equal('POST'); + }); + it('Returns valid URL', () => { + expect(serverRequest.url).to.equal('//supply.nl.weborama.fr/?c=o&m=multi'); + }); + it('Returns valid data if array of bids is valid', () => { + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'secure', 'host', 'page', 'placements'); + expect(data.deviceWidth).to.be.a('number'); + expect(data.deviceHeight).to.be.a('number'); + expect(data.secure).to.be.within(0, 1); + expect(data.host).to.be.a('string'); + expect(data.page).to.be.a('string'); + let placements = data['placements']; + for (let i = 0; i < placements.length; i++) { + let placement = placements[i]; + expect(placement).to.have.all.keys('placementId', 'bidId', 'traffic', 'sizes'); + expect(placement.placementId).to.be.a('number'); + expect(placement.bidId).to.be.a('string'); + expect(placement.traffic).to.be.a('string'); + expect(placement.sizes).to.be.an('array'); + } + }); + it('Returns empty data if no valid requests are passed', () => { + serverRequest = spec.buildRequests([]); + let data = serverRequest.data; + expect(data.placements).to.be.an('array').that.is.empty; + }); + }); + describe('interpretResponse', () => { + let resObject = { + body: [ { + requestId: '123', + mediaType: 'banner', + cpm: 0.3, + width: 320, + height: 50, + ad: '