From 16aad1f564c3e4d33e358b22aa485b69ab02ad87 Mon Sep 17 00:00:00 2001 From: songtungmtp <57524426+songtungmtp@users.noreply.github.com> Date: Thu, 21 Nov 2019 05:25:37 +0900 Subject: [PATCH] add smms adapter (#4439) * add smms adapter * re-run ci, why adigo adapter failed?? * review comments fix, remove deprecated functions, fix unit test --- modules/smmsBidAdapter.js | 155 ++++++++++++++++++++++ modules/smmsBidAdapter.md | 60 +++++++++ test/spec/modules/smmsBidAdapter_spec.js | 161 +++++++++++++++++++++++ 3 files changed, 376 insertions(+) create mode 100644 modules/smmsBidAdapter.js create mode 100644 modules/smmsBidAdapter.md create mode 100644 test/spec/modules/smmsBidAdapter_spec.js diff --git a/modules/smmsBidAdapter.js b/modules/smmsBidAdapter.js new file mode 100644 index 00000000000..dafd4aba734 --- /dev/null +++ b/modules/smmsBidAdapter.js @@ -0,0 +1,155 @@ +import * as utils from '../src/utils'; +import { registerBidder } from '../src/adapters/bidderFactory'; + +const BIDDER_CODE = 'smms'; +const ENDPOINT_BANNER = 'https://bidder.mediams.mb.softbank.jp/api/v1/prebid/banner'; +const ENDPOINT_NATIVE = 'https://bidder.mediams.mb.softbank.jp/api/v1/prebid/native'; +const COOKIE_SYNC_URL = 'https://bidder.mediams.mb.softbank.jp/api/v1/cookie/gen'; +const SUPPORTED_MEDIA_TYPES = ['banner', 'native']; +const SUPPORTED_CURRENCIES = ['USD', 'JPY']; +const DEFAULT_CURRENCY = 'JPY'; +const NET_REVENUE = true; + +function _encodeURIComponent(a) { + let b = window.encodeURIComponent(a); + b = b.replace(/'/g, '%27'); + return b; +} + +export function _getUrlVars(url) { + let hash; + const myJson = {}; + const hashes = url.slice(url.indexOf('?') + 1).split('&'); + for (let i = 0; i < hashes.length; i++) { + hash = hashes[i].split('='); + myJson[hash[0]] = hash[1]; + } + return myJson; +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: SUPPORTED_MEDIA_TYPES, + isBidRequestValid: function(bid) { + let valid = !!(bid.params.placementId); + if (valid && bid.params.hasOwnProperty('currency')) { + if (SUPPORTED_CURRENCIES.indexOf(bid.params.currency) === -1) { + utils.logError('Invalid currency type, we support only JPY and USD!'); + valid = false; + } + } + + return valid; + }, + /** + * 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) { + const serverRequests = []; + let refererInfo; + if (bidderRequest && bidderRequest.refererInfo) { + refererInfo = bidderRequest.refererInfo; + } + + const g = (typeof (geparams) !== 'undefined' && typeof (geparams) == 'object' && geparams) ? geparams : {}; + validBidRequests.forEach((bid, i) => { + let endpoint = ENDPOINT_BANNER; + let data = { + 'placementid': bid.params.placementId, + 'cur': bid.params.hasOwnProperty('currency') ? bid.params.currency : DEFAULT_CURRENCY, + 'ua': navigator.userAgent, + 'adtk': _encodeURIComponent(g.lat ? '0' : '1'), + 'loc': (refererInfo && refererInfo.referer) ? refererInfo.referer : '', + 'topframe': (window.parent == window.self) ? 1 : 0, + 'sw': screen && screen.width, + 'sh': screen && screen.height, + 'cb': Math.floor(Math.random() * 99999999999), + 'tpaf': 1, + 'cks': 1, + 'requestid': bid.bidId, + 'referer': (refererInfo && refererInfo.referer) ? refererInfo.referer : '' + }; + + if (bid.hasOwnProperty('nativeParams')) { + endpoint = ENDPOINT_NATIVE; + data.tkf = 1; // return url tracker + data.ad_track = '1'; + data.apiv = '1.1.0'; + } + + serverRequests.push({ + method: 'GET', + url: endpoint, + data: utils.parseQueryStringParameters(data) + }); + }); + + return serverRequests; + }, + interpretResponse: function(serverResponse, request) { + const data = _getUrlVars(request.data) + const successBid = serverResponse.body || {}; + let bidResponses = []; + if (successBid.hasOwnProperty(data.placementid)) { + let bid = successBid[data.placementid] + let bidResponse = { + requestId: bid.requestid, + cpm: bid.price, + creativeId: bid.creativeId, + currency: bid.cur, + netRevenue: NET_REVENUE, + ttl: 700 + }; + + if (bid.hasOwnProperty('title')) { // it is native ad response + bidResponse.mediaType = 'native' + bidResponse.native = { + title: bid.title, + body: bid.description, + cta: bid.cta, + sponsoredBy: bid.advertiser, + clickUrl: _encodeURIComponent(bid.landingURL), + impressionTrackers: bid.trackings, + } + if (bid.screenshots) { + bidResponse.native.image = { + url: bid.screenshots.url, + height: bid.screenshots.height, + width: bid.screenshots.width, + } + } + if (bid.icon) { + bidResponse.native.icon = { + url: bid.icon.url, + height: bid.icon.height, + width: bid.icon.width, + } + } + } else { + bidResponse.ad = bid.adm + bidResponse.width = bid.width + bidResponse.height = bid.height + } + + bidResponses.push(bidResponse); + } + + return bidResponses; + }, + getUserSyncs: function(syncOptions, serverResponses) { + let syncs = [] + syncs.push({ + type: 'image', + url: COOKIE_SYNC_URL + }) + + return syncs; + }, + onTimeout: function(timeoutData) {}, + onBidWon: function(bid) {}, + onSetTargeting: function(bid) {} +} +registerBidder(spec); diff --git a/modules/smmsBidAdapter.md b/modules/smmsBidAdapter.md new file mode 100644 index 00000000000..f1d6e233f96 --- /dev/null +++ b/modules/smmsBidAdapter.md @@ -0,0 +1,60 @@ +# Overview + +Module Name: SMMS Bid Adapter + +Maintainer: SBBGRP-SSP-PMP@g.softbank.co.jp + +# Description + +Module that connects to softbank's demand sources + +# Test Parameters + +```javascript + var adUnits = [ + { + code: 'test', + mediaTypes: { + banner: { + sizes: [[300, 250], [300,600]], + } + }, + bids: [ + { + bidder: 'smms', + params: { + placementId: 1440837, + currency: 'USD' + } + } + ] + }, + { + code: 'test', + mediaTypes: { + native: { + title: { + required: true, + len: 80 + }, + image: { + required: true, + sizes: [150, 50] + }, + sponsoredBy: { + required: true + } + } + }, + bids: [ + { + bidder: 'smms', + params: { + placementId: 1440838, + currency: 'USD' + } + }, + ], + } + ]; +``` diff --git a/test/spec/modules/smmsBidAdapter_spec.js b/test/spec/modules/smmsBidAdapter_spec.js new file mode 100644 index 00000000000..3ed952811ea --- /dev/null +++ b/test/spec/modules/smmsBidAdapter_spec.js @@ -0,0 +1,161 @@ +import {expect} from 'chai'; +import {spec, _getUrlVars} from 'modules/smmsBidAdapter'; +import * as utils from 'src/utils'; + +const BASE_URI = 'https://bidder.mediams.mb.softbank.jp/api/v1/prebid/banner' +const NATIVE_BASE_URI = 'https://bidder.mediams.mb.softbank.jp/api/v1/prebid/native' + +describe('smms adapter', function() { + let bidRequests; + let nativeBidRequests; + + beforeEach(function() { + bidRequests = [ + { + bidder: 'smms', + params: { + placementId: 1440837, + currency: 'USD' + } + } + ] + + nativeBidRequests = [ + { + bidder: 'smms', + params: { + placementId: 1440838, + currency: 'USD' + }, + nativeParams: { + title: { + required: true, + len: 80 + }, + image: { + required: true, + sizes: [150, 50] + }, + sponsoredBy: { + required: true + } + } + } + ] + }) + + describe('isBidRequestValid', function () { + it('valid bid case: required params found', function () { + let validBid = { + bidder: 'smms', + params: { + placementId: 1440837, + currency: 'USD' + } + } + let isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(true); + }); + + it('invalid bid case: placementId is not passed', function() { + let validBid = { + bidder: 'smms', + params: { + } + } + let isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(false); + }) + + it('invalid bid case: currency is not support', function() { + let validBid = { + bidder: 'smms', + params: { + placementId: 1440837, + currency: 'AUD' + } + } + let isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(false); + }) + }) + + describe('buildRequests', function () { + it('sends bid request to ENDPOINT via GET', function () { + const request = spec.buildRequests(bidRequests)[0]; + expect(request.url).to.equal(BASE_URI); + expect(request.method).to.equal('GET'); + }); + + it('sends native bid request to ENDPOINT via GET', function () { + const request = spec.buildRequests(nativeBidRequests)[0]; + expect(request.url).to.equal(NATIVE_BASE_URI); + expect(request.method).to.equal('GET'); + }); + + it('buildRequests function should not modify original bidRequests object', function () { + let originalBidRequests = utils.deepClone(bidRequests); + spec.buildRequests(bidRequests); + expect(bidRequests).to.deep.equal(originalBidRequests); + }); + + it('buildRequests function should not modify original nativeBidRequests object', function () { + let originalBidRequests = utils.deepClone(nativeBidRequests); + spec.buildRequests(nativeBidRequests); + expect(nativeBidRequests).to.deep.equal(originalBidRequests); + }); + + it('Request params check', function() { + let request = spec.buildRequests(bidRequests)[0]; + const data = _getUrlVars(request.data) + expect(parseInt(data.placementid)).to.exist.and.to.equal(bidRequests[0].params.placementId); + expect(data.cur).to.exist.and.to.equal(bidRequests[0].params.currency); + }) + + it('Native request params check', function() { + let request = spec.buildRequests(nativeBidRequests)[0]; + const data = _getUrlVars(request.data) + expect(parseInt(data.placementid)).to.exist.and.to.equal(nativeBidRequests[0].params.placementId); + expect(data.cur).to.exist.and.to.equal(nativeBidRequests[0].params.currency); + }) + }) + + describe('interpretResponse', function () { + let response = { + 1440837: + { + 'creativeId': '', + 'cur': 'USD', + 'price': 0.0920, + 'width': 300, + 'height': 250, + 'requestid': '2e42361a6172bf', + 'adm': '' + } + } + + it('should get correct bid response', function () { + let expectedResponse = [ + { + 'requestId': '2e42361a6172bf', + 'cpm': 0.0920, + 'width': 300, + 'height': 250, + 'netRevenue': true, + 'currency': 'USD', + 'creativeId': '', + 'ttl': 700, + 'ad': '' + } + ]; + let request = spec.buildRequests(bidRequests)[0]; + let result = spec.interpretResponse({body: response}, request); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + expect(result[0].cpm).to.not.equal(null); + expect(result[0].creativeId).to.not.equal(null); + expect(result[0].ad).to.not.equal(null); + expect(result[0].currency).to.equal('USD'); + expect(result[0].netRevenue).to.equal(true); + }); + }) +})