From d241df72b804afe94d45c5351c4f160392de8504 Mon Sep 17 00:00:00 2001 From: Daniel Liebner Date: Mon, 27 May 2019 19:29:18 -0400 Subject: [PATCH 1/3] Added bidglass adapter + test --- modules/bidglassBidAdapter.js | 185 ++++++++++++++++++++++ modules/bidglassBidAdapter.md | 34 ++++ test/spec/modules/bidglassAdapter_spec.js | 103 ++++++++++++ 3 files changed, 322 insertions(+) create mode 100644 modules/bidglassBidAdapter.js create mode 100644 modules/bidglassBidAdapter.md create mode 100644 test/spec/modules/bidglassAdapter_spec.js diff --git a/modules/bidglassBidAdapter.js b/modules/bidglassBidAdapter.js new file mode 100644 index 00000000000..400c413d1a2 --- /dev/null +++ b/modules/bidglassBidAdapter.js @@ -0,0 +1,185 @@ +import * as utils from 'src/utils'; +// import {config} from 'src/config'; +import {registerBidder} from 'src/adapters/bidderFactory'; + +const BIDDER_CODE = 'bidglass'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['bg'], // 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.params.adUnitId && !isNaN(parseFloat(bid.params.adUnitId)) && isFinite(bid.params.adUnitId)); + }, + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(validBidRequests, bidderRequest) { + /* + Use `bidderRequest.bids[]` to get bidder-dependent + request info. + + If your bidder supports multiple currencies, use + `config.getConfig(currency)` to find which one the ad + server needs. + */ + + /* + Sample array entry for validBidRequests[]: + [{ + "bidder": "bidglass", + "bidId": "51ef8751f9aead", + "params": { + "adUnitId": 11, + ... + }, + "adUnitCode": "div-gpt-ad-1460505748561-0", + "transactionId": "d7b773de-ceaa-484d-89ca-d9f51b8d61ec", + "sizes": [[320,50],[300,250],[300,600]], + "bidderRequestId": "418b37f85e772c", + "auctionId": "18fd8b8b0bd757", + "bidRequestsCount": 1 + }] + */ + + let imps = []; + let getReferer = function() { + if (window === window.top) { + return window.location.href; + } else if (window.parent === window.top) { + return document.referrer; + } else { + return null; + } + }; + let getOrigins = function() { + var ori = [window.location.protocol + '//' + window.location.hostname]; + + if (window.location.ancestorOrigins) { + for (var i = 0; i < window.location.ancestorOrigins.length; i++) { + ori.push(window.location.ancestorOrigins[i]); + } + } else if (window !== window.top) { + // Derive the parent origin + var parts = document.referrer.split('/'); + + ori.push(parts[0] + '//' + parts[2]); + + if (window.parent !== window.top) { + // Additional unknown origins exist + ori.push('null'); + } + } + + return ori; + }; + + utils._each(validBidRequests, function(bid) { + bid.sizes = ((utils.isArray(bid.sizes) && utils.isArray(bid.sizes[0])) ? bid.sizes : [bid.sizes]); + bid.sizes = bid.sizes.filter(size => utils.isArray(size)); + + // Stuff to send: [bid id, sizes, adUnitId] + imps.push({ + bidId: bid.bidId, + sizes: bid.sizes, + adUnitId: utils.getBidIdParameter('adUnitId', bid.params) + }); + }); + + // Stuff to send: page URL + const bidReq = { + reqId: utils.getUniqueIdentifierStr(), + imps: imps, + ref: getReferer(), + ori: getOrigins() + }; + + let url = 'https://bid.glass/ad/hb.php?' + + `src=$$REPO_AND_VERSION$$`; + + return { + method: 'POST', + url: url, + data: JSON.stringify(bidReq), + options: { + contentType: 'text/plain', + withCredentials: false + } + } + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse) { + // const serverBody = serverResponse.body; + // const headerValue = serverResponse.headers.get('some-response-header'); + + const bidResponses = []; + + utils._each(serverResponse.body.bidResponses, function(bid) { + bidResponses.push({ + requestId: bid.requestId, + cpm: parseFloat(bid.cpm), + width: parseInt(bid.width), + height: parseInt(bid.height), + creativeId: bid.creativeId, + dealId: bid.dealId || null, + currency: bid.currency || 'USD', + mediaType: bid.mediaType || 'banner', + netRevenue: true, + ttl: bid.ttl || 10, + ad: bid.ad + }); + }); + + return bidResponses; + }, + + /** + * Register the user sync pixels which should be dropped after the auction. + * + * @param {SyncOptions} syncOptions Which user syncs are allowed? + * @param {ServerResponse[]} serverResponses List of server's responses. + * @return {UserSync[]} The user syncs which should be dropped. + */ + getUserSyncs: function() {}, + + /** + * Register bidder specific code, which will execute if bidder timed out after an auction + * @param {data} Containing timeout specific data + */ + onTimeout: function(data) { + // Bidder specifc code + }, + + /** + * Register bidder specific code, which will execute if a bid from this bidder won the auction + * @param {Bid} The bid that won the auction + */ + onBidWon: function(bid) { + // Bidder specific code + }, + + /** + * Register bidder specific code, which will execute when the adserver targeting has been set for a bid from this bidder + * @param {Bid} The bid of which the targeting has been set + */ + onSetTargeting: function(bid) { + // Bidder specific code + } + +} + +registerBidder(spec); diff --git a/modules/bidglassBidAdapter.md b/modules/bidglassBidAdapter.md new file mode 100644 index 00000000000..5384a095314 --- /dev/null +++ b/modules/bidglassBidAdapter.md @@ -0,0 +1,34 @@ +# Overview + +``` +Module Name: Bid Glass Bid Adapter +Module Type: Bidder Adapter +Maintainer: dliebner@gmail.com +``` + +# Description + +Connects to Bid Glass and allows bids on ad units to compete within prebid. + +# Sample Ad Unit: For Publishers +``` +var adUnits = [{ + code: 'bg-test-rectangle', + sizes: [[300, 250]], + bids: [{ + bidder: 'bidglass', + params: { + adUnitId: '-1' + } + }] +},{ + code: 'bg-test-leaderboard', + sizes: [[728, 90]], + bids: [{ + bidder: 'bidglass', + params: { + adUnitId: '-1' + } + }] +}] +``` \ No newline at end of file diff --git a/test/spec/modules/bidglassAdapter_spec.js b/test/spec/modules/bidglassAdapter_spec.js new file mode 100644 index 00000000000..00a47fc997a --- /dev/null +++ b/test/spec/modules/bidglassAdapter_spec.js @@ -0,0 +1,103 @@ +import { expect } from 'chai'; +import { spec } from 'modules/bidglassBidAdapter'; +import { newBidder } from 'src/adapters/bidderFactory'; + +describe('Bid Glass Adapter', function () { + const adapter = newBidder(spec); + + describe('isBidRequestValid', function () { + let bid = { + 'bidder': 'bidglass', + 'params': { + 'adUnitId': '3' + }, + 'adUnitCode': 'bidglass-testunit', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }; + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params are not passed', function () { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + const bidRequests = [{ + 'bidder': 'bidglass', + 'params': { + 'adUnitId': '3' + }, + 'adUnitCode': 'bidglass-testunit', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }]; + + const request = spec.buildRequests(bidRequests); + + it('sends bid request to our endpoint via POST', function () { + expect(request.method).to.equal('POST'); + }); + + it('sets withCredentials to false', function () { + expect(request.options.withCredentials).to.equal(false); + }); + }); + + describe('interpretResponse', function () { + let response; + beforeEach(function () { + response = { + body: { + 'bidResponses': [{ + 'ad': '', + 'cpm': '0.01', + 'creativeId': '-1', + 'width': '300', + 'height': '250', + 'requestId': '30b31c1838de1e' + }] + } + }; + }); + + it('should get the correct bid response', function () { + let expectedResponse = [{ + 'requestId': '30b31c1838de1e', + 'cpm': 0.01, + 'width': 300, + 'height': 250, + 'creativeId': '-1', + 'dealId': null, + 'currency': 'USD', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 10, + 'ad': '' + }]; + + let result = spec.interpretResponse(response); + expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); + }); + + it('handles empty bid response', function () { + let response = { + body: { + 'bidResponses': [] + } + }; + let result = spec.interpretResponse(response); + expect(result.length).to.equal(0); + }); + }); +}); From ca16df083dea442848c58e691850ab7ee9d5a976 Mon Sep 17 00:00:00 2001 From: Daniel Liebner Date: Thu, 13 Jun 2019 00:16:05 -0400 Subject: [PATCH 2/3] PR Review Updates: - Added formal params to getUserSyncs function definition - getUserSyncs now always returns an array - Improved unit test coverage --- modules/bidglassBidAdapter.js | 4 +++- test/spec/modules/bidglassAdapter_spec.js | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/modules/bidglassBidAdapter.js b/modules/bidglassBidAdapter.js index 400c413d1a2..e522acdb8e1 100644 --- a/modules/bidglassBidAdapter.js +++ b/modules/bidglassBidAdapter.js @@ -154,7 +154,9 @@ export const spec = { * @param {ServerResponse[]} serverResponses List of server's responses. * @return {UserSync[]} The user syncs which should be dropped. */ - getUserSyncs: function() {}, + getUserSyncs: function(syncOptions, serverResponses) { + return []; + }, /** * Register bidder specific code, which will execute if bidder timed out after an auction diff --git a/test/spec/modules/bidglassAdapter_spec.js b/test/spec/modules/bidglassAdapter_spec.js index 00a47fc997a..b588192f203 100644 --- a/test/spec/modules/bidglassAdapter_spec.js +++ b/test/spec/modules/bidglassAdapter_spec.js @@ -100,4 +100,15 @@ describe('Bid Glass Adapter', function () { expect(result.length).to.equal(0); }); }); + + describe('getUserSyncs', function () { + let syncOptions = {iframeEnabled: true, pixelEnabled: true}; + let emptyServerResponse = { + bidResponses: [] + }; + it('should return an array', function () { + let result = spec.getUserSyncs(syncOptions, emptyServerResponse); + expect(result).to.be.an('array'); + }); + }); }); From c8900913c94b4a36f8ef2b720dce813e61fb45c1 Mon Sep 17 00:00:00 2001 From: Daniel Liebner Date: Thu, 13 Jun 2019 17:03:40 -0400 Subject: [PATCH 3/3] PR Review Updates: - Removed unused methods: getUserSyncs, onTimeout, onBidWon, onSetTargeting - Removed getUserSyncs unit test - Removed "dead code" - Removed some unnecessary comments - Fixed usage of parseInt --- modules/bidglassBidAdapter.js | 59 ++--------------------- test/spec/modules/bidglassAdapter_spec.js | 11 ----- 2 files changed, 3 insertions(+), 67 deletions(-) diff --git a/modules/bidglassBidAdapter.js b/modules/bidglassBidAdapter.js index e522acdb8e1..1898d1220fa 100644 --- a/modules/bidglassBidAdapter.js +++ b/modules/bidglassBidAdapter.js @@ -23,15 +23,6 @@ export const spec = { * @return ServerRequest Info describing the request to the server. */ buildRequests: function(validBidRequests, bidderRequest) { - /* - Use `bidderRequest.bids[]` to get bidder-dependent - request info. - - If your bidder supports multiple currencies, use - `config.getConfig(currency)` to find which one the ad - server needs. - */ - /* Sample array entry for validBidRequests[]: [{ @@ -52,13 +43,7 @@ export const spec = { let imps = []; let getReferer = function() { - if (window === window.top) { - return window.location.href; - } else if (window.parent === window.top) { - return document.referrer; - } else { - return null; - } + return window === window.top ? window.location.href : window.parent === window.top ? document.referrer : null; }; let getOrigins = function() { var ori = [window.location.protocol + '//' + window.location.hostname]; @@ -123,17 +108,14 @@ export const spec = { * @return {Bid[]} An array of bids which were nested inside the server. */ interpretResponse: function(serverResponse) { - // const serverBody = serverResponse.body; - // const headerValue = serverResponse.headers.get('some-response-header'); - const bidResponses = []; utils._each(serverResponse.body.bidResponses, function(bid) { bidResponses.push({ requestId: bid.requestId, cpm: parseFloat(bid.cpm), - width: parseInt(bid.width), - height: parseInt(bid.height), + width: parseInt(bid.width, 10), + height: parseInt(bid.height, 10), creativeId: bid.creativeId, dealId: bid.dealId || null, currency: bid.currency || 'USD', @@ -145,41 +127,6 @@ export const spec = { }); return bidResponses; - }, - - /** - * Register the user sync pixels which should be dropped after the auction. - * - * @param {SyncOptions} syncOptions Which user syncs are allowed? - * @param {ServerResponse[]} serverResponses List of server's responses. - * @return {UserSync[]} The user syncs which should be dropped. - */ - getUserSyncs: function(syncOptions, serverResponses) { - return []; - }, - - /** - * Register bidder specific code, which will execute if bidder timed out after an auction - * @param {data} Containing timeout specific data - */ - onTimeout: function(data) { - // Bidder specifc code - }, - - /** - * Register bidder specific code, which will execute if a bid from this bidder won the auction - * @param {Bid} The bid that won the auction - */ - onBidWon: function(bid) { - // Bidder specific code - }, - - /** - * Register bidder specific code, which will execute when the adserver targeting has been set for a bid from this bidder - * @param {Bid} The bid of which the targeting has been set - */ - onSetTargeting: function(bid) { - // Bidder specific code } } diff --git a/test/spec/modules/bidglassAdapter_spec.js b/test/spec/modules/bidglassAdapter_spec.js index b588192f203..00a47fc997a 100644 --- a/test/spec/modules/bidglassAdapter_spec.js +++ b/test/spec/modules/bidglassAdapter_spec.js @@ -100,15 +100,4 @@ describe('Bid Glass Adapter', function () { expect(result.length).to.equal(0); }); }); - - describe('getUserSyncs', function () { - let syncOptions = {iframeEnabled: true, pixelEnabled: true}; - let emptyServerResponse = { - bidResponses: [] - }; - it('should return an array', function () { - let result = spec.getUserSyncs(syncOptions, emptyServerResponse); - expect(result).to.be.an('array'); - }); - }); });