diff --git a/modules/orbitsoftBidAdapter.js b/modules/orbitsoftBidAdapter.js new file mode 100644 index 00000000000..d72a8719bd8 --- /dev/null +++ b/modules/orbitsoftBidAdapter.js @@ -0,0 +1,150 @@ +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {config} from '../src/config.js'; + +const BIDDER_CODE = 'orbitsoft'; +let styleParamsMap = { + 'title.family': 'f1', // headerFont + 'title.size': 'fs1', // headerFontSize + 'title.weight': 'w1', // headerWeight + 'title.style': 's1', // headerStyle + 'title.color': 'c3', // headerColor + 'description.family': 'f2', // descriptionFont + 'description.size': 'fs2', // descriptionFontSize + 'description.weight': 'w2', // descriptionWeight + 'description.style': 's2', // descriptionStyle + 'description.color': 'c4', // descriptionColor + 'url.family': 'f3', // urlFont + 'url.size': 'fs3', // urlFontSize + 'url.weight': 'w3', // urlWeight + 'url.style': 's3', // urlStyle + 'url.color': 'c5', // urlColor + 'colors.background': 'c2', // borderColor + 'colors.border': 'c1', // borderColor + 'colors.link': 'c6', // lnkColor +}; +export const spec = { + code: BIDDER_CODE, + aliases: ['oas', '152media'], // short code and customer aliases + isBidRequestValid: function (bid) { + switch (true) { + case !('params' in bid): + utils.logError(bid.bidder + ': No required params'); + return false; + case !(bid.params.placementId): + utils.logError(bid.bidder + ': No required param placementId'); + return false; + case !(bid.params.requestUrl): + utils.logError(bid.bidder + ': No required param requestUrl'); + return false; + } + return true; + }, + buildRequests: function (validBidRequests) { + let bidRequest; + let serverRequests = []; + for (let i = 0; i < validBidRequests.length; i++) { + bidRequest = validBidRequests[i]; + let bidRequestParams = bidRequest.params; + let placementId = utils.getBidIdParameter('placementId', bidRequestParams); + let requestUrl = utils.getBidIdParameter('requestUrl', bidRequestParams); + let referrer = utils.getBidIdParameter('ref', bidRequestParams); + let location = utils.getBidIdParameter('loc', bidRequestParams); + // Append location & referrer + if (location === '') { + location = utils.getWindowLocation(); + } + if (referrer === '' && bidRequest && bidRequest.refererInfo) { + referrer = bidRequest.refererInfo.referer; + } + + // Styles params + let stylesParams = utils.getBidIdParameter('style', bidRequestParams); + let stylesParamsArray = {}; + for (let currentValue in stylesParams) { + if (stylesParams.hasOwnProperty(currentValue)) { + let currentStyle = stylesParams[currentValue]; + for (let field in currentStyle) { + if (currentStyle.hasOwnProperty(field)) { + let styleField = styleParamsMap[currentValue + '.' + field]; + if (typeof styleField !== 'undefined') { + stylesParamsArray[styleField] = currentStyle[field]; + } + } + } + } + } + // Custom params + let customParams = utils.getBidIdParameter('customParams', bidRequestParams); + let customParamsArray = {}; + for (let customField in customParams) { + if (customParams.hasOwnProperty(customField)) { + customParamsArray['c.' + customField] = customParams[customField]; + } + } + + // Sizes params (not supports by server, for future features) + let sizesParams = bidRequest.sizes; + let parsedSizes = utils.parseSizesInput(sizesParams); + let requestData = Object.assign({ + 'scid': placementId, + 'callback_uid': utils.generateUUID(), + 'loc': location, + 'ref': referrer, + 'size': parsedSizes + }, stylesParamsArray, customParamsArray); + + serverRequests.push({ + method: 'POST', + url: requestUrl, + data: requestData, + options: {withCredentials: false}, + bidRequest: bidRequest + }); + } + return serverRequests; + }, + interpretResponse: function (serverResponse, request) { + let bidResponses = []; + if (!serverResponse || serverResponse.error) { + utils.logError(BIDDER_CODE + ': Server response error'); + return bidResponses; + } + + const serverBody = serverResponse.body; + if (!serverBody) { + utils.logError(BIDDER_CODE + ': Empty bid response'); + return bidResponses; + } + + const CPM = serverBody.cpm; + const WIDTH = serverBody.width; + const HEIGHT = serverBody.height; + const CREATIVE = serverBody.content_url; + const CALLBACK_UID = serverBody.callback_uid; + const TIME_TO_LIVE = config.getConfig('_bidderTimeout'); + const REFERER = utils.getWindowTop(); + let bidRequest = request.bidRequest; + if (CPM > 0 && WIDTH > 0 && HEIGHT > 0) { + let bidResponse = { + requestId: bidRequest.bidId, + cpm: CPM, + width: WIDTH, + height: HEIGHT, + creativeId: CALLBACK_UID, + ttl: TIME_TO_LIVE, + referrer: REFERER, + currency: 'USD', + netRevenue: true, + adUrl: CREATIVE, + meta: { + advertiserDomains: serverBody.adomain ? serverBody.adomain : [] + } + }; + bidResponses.push(bidResponse); + } + + return bidResponses; + } +}; +registerBidder(spec); diff --git a/test/spec/modules/orbitsoftBidAdapter_spec.js b/test/spec/modules/orbitsoftBidAdapter_spec.js new file mode 100644 index 00000000000..8c3187e9324 --- /dev/null +++ b/test/spec/modules/orbitsoftBidAdapter_spec.js @@ -0,0 +1,255 @@ +import {expect} from 'chai'; +import {spec} from 'modules/orbitsoftBidAdapter.js'; + +const ENDPOINT_URL = 'https://orbitsoft.com/php/ads/hb.phps'; +const REFERRER_URL = 'http://referrer.url/?_='; + +describe('Orbitsoft adapter', function () { + describe('implementation', function () { + describe('for requests', function () { + it('should accept valid bid', function () { + let validBid = { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL + } + }, + isValid = spec.isBidRequestValid(validBid); + + expect(isValid).to.equal(true); + }); + + it('should reject invalid bid', function () { + let invalidBid = { + bidder: 'orbitsoft' + }, + isValid = spec.isBidRequestValid(invalidBid); + + expect(isValid).to.equal(false); + }); + }); + describe('for requests', function () { + it('should accept valid bid with styles', function () { + let validBid = { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL, + style: { + title: { + family: 'Tahoma', + size: 'medium', + weight: 'normal', + style: 'normal', + color: '0053F9' + }, + description: { + family: 'Tahoma', + size: 'medium', + weight: 'normal', + style: 'normal', + color: '0053F9' + }, + url: { + family: 'Tahoma', + size: 'medium', + weight: 'normal', + style: 'normal', + color: '0053F9' + }, + colors: { + background: 'ffffff', + border: 'E0E0E0', + link: '5B99FE' + } + } + }, + refererInfo: {referer: REFERRER_URL}, + }, + isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(true); + + let buildRequest = spec.buildRequests([validBid])[0]; + let requestUrl = buildRequest.url; + let requestUrlParams = buildRequest.data; + expect(requestUrl).to.equal(ENDPOINT_URL); + expect(requestUrlParams).have.property('f1', 'Tahoma'); + expect(requestUrlParams).have.property('fs1', 'medium'); + expect(requestUrlParams).have.property('w1', 'normal'); + expect(requestUrlParams).have.property('s1', 'normal'); + expect(requestUrlParams).have.property('c3', '0053F9'); + expect(requestUrlParams).have.property('f2', 'Tahoma'); + expect(requestUrlParams).have.property('fs2', 'medium'); + expect(requestUrlParams).have.property('w2', 'normal'); + expect(requestUrlParams).have.property('s2', 'normal'); + expect(requestUrlParams).have.property('c4', '0053F9'); + expect(requestUrlParams).have.property('f3', 'Tahoma'); + expect(requestUrlParams).have.property('fs3', 'medium'); + expect(requestUrlParams).have.property('w3', 'normal'); + expect(requestUrlParams).have.property('s3', 'normal'); + expect(requestUrlParams).have.property('c5', '0053F9'); + expect(requestUrlParams).have.property('c2', 'ffffff'); + expect(requestUrlParams).have.property('c1', 'E0E0E0'); + expect(requestUrlParams).have.property('c6', '5B99FE'); + }); + + it('should accept valid bid with custom params', function () { + let validBid = { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL, + customParams: { + cacheBuster: 'bf4d7c1', + clickUrl: 'http://testclickurl.com' + } + }, + refererInfo: {referer: REFERRER_URL}, + }, + isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(true); + + let buildRequest = spec.buildRequests([validBid])[0]; + let requestUrlCustomParams = buildRequest.data; + expect(requestUrlCustomParams).have.property('c.cacheBuster', 'bf4d7c1'); + expect(requestUrlCustomParams).have.property('c.clickUrl', 'http://testclickurl.com'); + }); + + it('should reject invalid bid without requestUrl', function () { + let invalidBid = { + bidder: 'orbitsoft', + params: { + placementId: '123' + } + }, + isValid = spec.isBidRequestValid(invalidBid); + + expect(isValid).to.equal(false); + }); + + it('should reject invalid bid without placementId', function () { + let invalidBid = { + bidder: 'orbitsoft', + params: { + requestUrl: ENDPOINT_URL + } + }, + isValid = spec.isBidRequestValid(invalidBid); + + expect(isValid).to.equal(false); + }); + }); + describe('bid responses', function () { + it('should return complete bid response', function () { + let serverResponse = { + body: { + callback_uid: '265b29b70cc106', + cpm: 0.5, + width: 240, + height: 240, + content_url: 'https://orbitsoft.com/php/ads/hb.html', + adomain: ['test.adomain.tld'] + } + }; + + let bidRequests = [ + { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL + } + } + ]; + let bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); + expect(bids).to.be.lengthOf(1); + expect(bids[0].cpm).to.equal(serverResponse.body.cpm); + expect(bids[0].width).to.equal(serverResponse.body.width); + expect(bids[0].height).to.equal(serverResponse.body.height); + expect(bids[0].currency).to.equal('USD'); + expect(bids[0].netRevenue).to.equal(true); + expect(bids[0].adUrl).to.have.length.above(1); + expect(bids[0].adUrl).to.have.string('https://orbitsoft.com/php/ads/hb.html'); + expect(Object.keys(bids[0].meta)).to.include.members(['advertiserDomains']); + expect(bids[0].meta.advertiserDomains).to.deep.equal(serverResponse.body.adomain); + }); + + it('should return empty bid response', function () { + let bidRequests = [ + { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL + } + } + ]; + let serverResponse = { + body: { + callback_uid: '265b29b70cc106', + cpm: 0 + } + }, + bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); + + expect(bids).to.be.lengthOf(0); + }); + + it('should return empty bid response on incorrect size', function () { + let bidRequests = [ + { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL + } + } + ]; + let serverResponse = { + body: { + callback_uid: '265b29b70cc106', + cpm: 1.5, + width: 0, + height: 0 + } + }, + bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); + + expect(bids).to.be.lengthOf(0); + }); + + it('should return empty bid response with error', function () { + let bidRequests = [ + { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL + } + } + ]; + let serverResponse = {error: 'error'}, + bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); + + expect(bids).to.be.lengthOf(0); + }); + + it('should return empty bid response on empty body', function () { + let bidRequests = [ + { + bidder: 'orbitsoft', + params: { + placementId: '123', + requestUrl: ENDPOINT_URL + } + } + ]; + let serverResponse = {}, + bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); + + expect(bids).to.be.lengthOf(0); + }); + }); + }); +});