From 609ec1634719302f21bf0c242191445c9d54e764 Mon Sep 17 00:00:00 2001 From: pm-shashank-jain Date: Wed, 5 Dec 2018 18:29:04 +0530 Subject: [PATCH 01/30] changes to support native in pubmaticbid adapter --- modules/pubmaticBidAdapter.js | 238 +++++++++++++------ test/spec/modules/pubmaticBidAdapter_spec.js | 79 ++++++ 2 files changed, 240 insertions(+), 77 deletions(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 7203cee2391..00095ae2250 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -1,11 +1,19 @@ import * as utils from 'src/utils'; -import { registerBidder } from 'src/adapters/bidderFactory'; -import { BANNER, VIDEO } from 'src/mediaTypes'; -import {config} from 'src/config'; +import { + registerBidder +} from 'src/adapters/bidderFactory'; +import { + BANNER, + VIDEO, + NATIVE +} from 'src/mediaTypes'; +import { + config +} from 'src/config'; const constants = require('src/constants.json'); const BIDDER_CODE = 'pubmatic'; -const ENDPOINT = '//hbopenbid.pubmatic.com/translator?source=prebid-client'; +const ENDPOINT = 'https://hbopenbid.pubmatic.com:8080/translator?source=prebid-client'; const USYNCURL = '//ads.pubmatic.com/AdServer/js/showad.js#PIX&kdntuid=1&p='; const DEFAULT_CURRENCY = 'USD'; const AUCTION_TYPE = 1; @@ -25,7 +33,8 @@ const DATA_TYPES = { 'NUMBER': 'number', 'STRING': 'string', 'BOOLEAN': 'boolean', - 'ARRAY': 'array' + 'ARRAY': 'array', + 'OBJECT': 'object' }; const VIDEO_CUSTOM_PARAMS = { 'mimes': DATA_TYPES.ARRAY, @@ -43,6 +52,18 @@ const VIDEO_CUSTOM_PARAMS = { 'minbitrate': DATA_TYPES.NUMBER, 'maxbitrate': DATA_TYPES.NUMBER } +const NATIVE_CUSTOM_PARAMS = { + 'ver': DATA_TYPES.STRING, + 'layout': DATA_TYPES.NUMBER, + 'adUnit': DATA_TYPES.NUMBER, + 'context': DATA_TYPES.NUMBER, + 'contextsubtype': DATA_TYPES.NUMBER, + 'plcmttype': DATA_TYPES.NUMBER, + 'plcmtcnt': DATA_TYPES.NUMBER, + 'seq': DATA_TYPES.NUMBER, + 'assets': DATA_TYPES.ARRAY, + 'ext': DATA_TYPES.OBJECT +} const NET_REVENUE = false; const dealChannelValues = { 1: 'PMP', @@ -221,6 +242,7 @@ function _createImpressionObject(bid, conf) { var impObj = {}; var bannerObj = {}; var videoObj = {}; + var nativeObj = {}; var sizes = bid.hasOwnProperty('sizes') ? bid.sizes : []; impObj = { @@ -257,6 +279,17 @@ function _createImpressionObject(bid, conf) { } impObj.video = videoObj; + } else if (bid.params.hasOwnProperty('native')) { + var nativeData = bid.params.native; + for (var nativekey in NATIVE_CUSTOM_PARAMS) { + if (nativeData.hasOwnProperty(nativekey)) { + nativeObj[nativekey] = _checkParamDataType(nativekey, nativeData[nativekey], NATIVE_CUSTOM_PARAMS[nativekey]) + } + } + nativeObj.assets && nativeObj.assets.length > 0 && nativeObj.assets.forEach(function (element, idx) { + element.id = idx + 1; + }); + impObj.native = nativeObj; } else { bannerObj = { pos: 0, @@ -268,7 +301,10 @@ function _createImpressionObject(bid, conf) { sizes = sizes.splice(1, sizes.length - 1); var format = []; sizes.forEach(size => { - format.push({w: size[0], h: size[1]}); + format.push({ + w: size[0], + h: size[1] + }); }); bannerObj.format = format; } @@ -279,7 +315,9 @@ function _createImpressionObject(bid, conf) { function _getDigiTrustObject(key) { function getDigiTrustId() { - let digiTrustUser = window.DigiTrust && (config.getConfig('digiTrustId') || window.DigiTrust.getUser({member: key})); + let digiTrustUser = window.DigiTrust && (config.getConfig('digiTrustId') || window.DigiTrust.getUser({ + member: key + })); return (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || null; } let digiTrustId = getDigiTrustId(); @@ -295,15 +333,13 @@ function _handleDigitrustId(eids) { if (digiTrustId !== null) { eids.push({ 'source': 'digitru.st', - 'uids': [ - { - 'id': digiTrustId.id || '', - 'atype': 1, - 'ext': { - 'keyv': parseInt(digiTrustId.keyv) || 0 - } + 'uids': [{ + 'id': digiTrustId.id || '', + 'atype': 1, + 'ext': { + 'keyv': parseInt(digiTrustId.keyv) || 0 } - ] + }] }); } } @@ -313,15 +349,13 @@ function _handleTTDId(eids) { if (adsrvrOrgId && utils.isStr(adsrvrOrgId.TDID)) { eids.push({ 'source': 'adserver.org', - 'uids': [ - { - 'id': adsrvrOrgId.TDID, - 'atype': 1, - 'ext': { - 'rtiPartner': 'TDID' - } + 'uids': [{ + 'id': adsrvrOrgId.TDID, + 'atype': 1, + 'ext': { + 'rtiPartner': 'TDID' } - ] + }] }); } } @@ -337,27 +371,33 @@ function _handleEids(payload) { export const spec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER, VIDEO], + supportedMediaTypes: [BANNER, VIDEO, NATIVE], /** - * Determines whether or not the given bid request is valid. Valid bid request must have placementId and hbid - * - * @param {BidRequest} bid The bid params to validate. - * @return boolean True if this is a valid bid, and false otherwise. - */ + * Determines whether or not the given bid request is valid. Valid bid request must have placementId and hbid + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ isBidRequestValid: bid => { if (bid && bid.params) { if (!utils.isStr(bid.params.publisherId)) { - utils.logWarn(BIDDER_CODE + ' Error: publisherId is mandatory and cannot be numeric. Call to OpenBid will not be sent.'); + utils.logWarn(BIDDER_CODE + ' Error: publisherId is mandatory and cannot be numeric. Call to OpenBid will not be sent for ad unit:'); return false; } if (!utils.isStr(bid.params.adSlot)) { - utils.logWarn(BIDDER_CODE + ': adSlotId is mandatory and cannot be numeric. Call to OpenBid will not be sent.'); + utils.logWarn(BIDDER_CODE + ': adSlotId is mandatory and cannot be numeric. Call to OpenBid will not be sent for ad unit:'); return false; } // video ad validation if (bid.params.hasOwnProperty('video')) { if (!bid.params.video.hasOwnProperty('mimes') || !utils.isArray(bid.params.video.mimes) || bid.params.video.mimes.length === 0) { - utils.logWarn(BIDDER_CODE + ': For video ads, mimes is mandatory and must specify atlease 1 mime value. Call to OpenBid will not be sent.'); + utils.logWarn(BIDDER_CODE + ': For video ads, mimes is mandatory and must specify atlease 1 mime value. Call to OpenBid will not be sent for ad unit:'); + return false; + } + } + if (bid.params.hasOwnProperty('native')) { + if (!bid.params.native.hasOwnProperty('assets') || !utils.isArray(bid.params.native.assets) || bid.params.native.assets.length === 0) { + utils.logWarn(BIDDER_CODE + ': For native ads, assets is mandatory and must specify atleast 1 asset value. Call to OpenBid will not be sent for ad unit:'); return false; } } @@ -367,11 +407,11 @@ export const spec = { }, /** - * Make a server request from the list of BidRequests. - * - * @param {validBidRequests[]} - an array of bids - * @return ServerRequest Info describing the request to the server. - */ + * 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: (validBidRequests, bidderRequest) => { var conf = _initConf(); var payload = _createOrtbTemplate(conf); @@ -388,6 +428,12 @@ export const spec = { utils.logWarn(BIDDER_CODE + ': Skipping the non-standard adslot: ', bid.params.adSlot, bid); return; } + } else if (bid.params.hasOwnProperty('native')) { + // Check for valid ad slot in native + if (!bid.params.native.assets || bid.params.native.assets.length < 1) { + utils.logWarn(BIDDER_CODE + ': Skipping the non-standard adslot: ', bid.params.adSlot, bid); + return; + } } else { if (!(bid.params.adSlot && bid.params.adUnit && bid.params.adUnitIndex && bid.params.width && bid.params.height)) { utils.logWarn(BIDDER_CODE + ': Skipping the non-standard adslot: ', bid.params.adSlot, bid); @@ -484,11 +530,11 @@ export const spec = { }, /** - * Unpack the response from the server into a list of bids. - * - * @param {*} response A successful response from the server. - * @return {Bid[]} An array of bids which were nested inside the server. - */ + * Unpack the response from the server into a list of bids. + * + * @param {*} response A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ interpretResponse: (response, request) => { const bidResponses = []; var respCur = DEFAULT_CURRENCY; @@ -498,38 +544,76 @@ export const spec = { respCur = response.body.cur || respCur; response.body.seatbid.forEach(seatbidder => { seatbidder.bid && - utils.isArray(seatbidder.bid) && - seatbidder.bid.forEach(bid => { - let newBid = { - requestId: bid.impid, - cpm: (parseFloat(bid.price) || 0).toFixed(2), - width: bid.w, - height: bid.h, - creativeId: bid.crid || bid.id, - dealId: bid.dealid, - currency: respCur, - netRevenue: NET_REVENUE, - ttl: 300, - referrer: utils.getTopWindowUrl(), - ad: bid.adm - }; - let parsedRequest = JSON.parse(request.data); - if (parsedRequest.imp && parsedRequest.imp.length > 0) { - parsedRequest.imp.forEach(req => { - if (bid.impid === req.id && req.hasOwnProperty('video')) { - newBid.mediaType = 'video'; - newBid.width = bid.hasOwnProperty('w') ? bid.w : req.video.w; - newBid.height = bid.hasOwnProperty('h') ? bid.h : req.video.h; - newBid.vastXml = bid.adm; - } - }); - } - if (bid.ext && bid.ext.deal_channel) { - newBid['dealChannel'] = dealChannelValues[bid.ext.deal_channel] || null; - } - - bidResponses.push(newBid); - }); + utils.isArray(seatbidder.bid) && + seatbidder.bid.forEach(bid => { + let newBid = { + requestId: bid.impid, + cpm: (parseFloat(bid.price) || 0).toFixed(2), + width: bid.w, + height: bid.h, + creativeId: bid.crid || bid.id, + dealId: bid.dealid, + currency: respCur, + netRevenue: NET_REVENUE, + ttl: 300, + referrer: utils.getTopWindowUrl(), + ad: bid.adm + }; + let parsedRequest = JSON.parse(request.data); + if (parsedRequest.imp && parsedRequest.imp.length > 0) { + parsedRequest.imp.forEach(req => { + if (bid.impid === req.id && req.hasOwnProperty('video')) { + newBid.mediaType = 'video'; + newBid.width = bid.hasOwnProperty('w') ? bid.w : req.video.w; + newBid.height = bid.hasOwnProperty('h') ? bid.h : req.video.h; + newBid.vastXml = bid.adm; + } + if (bid.impid === req.id && req.hasOwnProperty('native')) { + newBid.mediaType = 'native'; + if (bid.hasOwnProperty('adm')) { + var adm = ''; + try { + adm = JSON.parse(bid.adm); + } catch (ex) { + adm = JSON.parse(bid.adm.replace(/\\/g, '')); + } + if (adm && adm.native && adm.native.assets && adm.native.assets.length > 0) { + const nativeAd = adm.native.assets[0]; + newBid[NATIVE] = { + title: nativeAd.title || '', + body: nativeAd.desc || '', + cta: nativeAd.ctatext || '', + sponsoredBy: adm.native.sponsored || 'PubMatic', + clickUrl: adm.native.link.url || 'www.pubmatic.com', + clickTrackers: adm.native.link.click_trackers || '', + impressionTrackers: adm.native.impression_trackers || '', + javascriptTrackers: adm.native.javascript_trackers || '', + }; + if (nativeAd.image) { + newBid['native'].image = { + url: nativeAd.image.url || '', + height: nativeAd.image.height || 150, + width: nativeAd.image.width || 150, + }; + } + if (nativeAd.icon) { + newBid['native'].icon = { + url: nativeAd.icon.url || '', + height: nativeAd.icon.height || '', + width: nativeAd.icon.width || '', + }; + } + } + } + } + }); + } + if (bid.ext && bid.ext.deal_channel) { + newBid['dealChannel'] = dealChannelValues[bid.ext.deal_channel] || null; + } + + bidResponses.push(newBid); + }); }); } } catch (error) { @@ -539,8 +623,8 @@ export const spec = { }, /** - * Register User Sync. - */ + * Register User Sync. + */ getUserSyncs: (syncOptions, responses, gdprConsent) => { let syncurl = USYNCURL + publisherId; @@ -566,7 +650,7 @@ export const spec = { * @param {Boolean} isOpenRtb boolean to check openrtb2 protocol * @return {Object} params bid params */ - transformBidParams: function(params, isOpenRtb) { + transformBidParams: function (params, isOpenRtb) { return utils.convertTypes({ 'publisherId': 'string', 'adSlot': 'string' diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index 05aaa191207..0e9d4942f9c 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -9,6 +9,8 @@ describe('PubMatic adapter', function () { let videoBidRequests; let multipleMediaRequests; let bidResponses; + let nativeBidRequests; + let nativeBidRequestsWithoutAsset; beforeEach(function () { bidRequests = [ @@ -124,6 +126,68 @@ describe('PubMatic adapter', function () { } ]; + nativeBidRequests = [{ + code: '/19968336/prebid_native_example_1', + sizes: [ + [300, 250] + ], + mediaTypes: { + native: { + title: { + required: true + }, + image: { + required: true + } + } + }, + bidder: 'pubmatic', + params: { + publisherId: '5670', + adSlot: 'div-1', + native: { + ver: '1.2', + layout: 3, + assets: [ + { + id: 1, + title: 'New Image', + img: { + h: 300, + w: 250, + } + } + ] + } + } + }]; + + nativeBidRequestsWithoutAsset = [{ + code: '/19968336/prebid_native_example_1', + sizes: [ + [300, 250] + ], + mediaTypes: { + native: { + title: { + required: true + }, + image: { + required: true + } + } + }, + bidder: 'pubmatic', + params: { + publisherId: '5670', + adSlot: 'div-1', + native: { + ver: '1.2', + layout: 3 + } + } + }] + bidResponses = { 'body': { 'id': '93D3BAD6-E2E2-49FB-9D89-920B1761C865', @@ -978,6 +1042,21 @@ describe('PubMatic adapter', function () { expect(data.imp[1]['video']['w']).to.equal(multipleMediaRequests[1].mediaTypes.video.playerSize[0]); expect(data.imp[1]['video']['h']).to.equal(multipleMediaRequests[1].mediaTypes.video.playerSize[1]); }); + + it('Request params check for native ad', function () { + let request = spec.buildRequests(nativeBidRequests); + let data = JSON.parse(request.data); + expect(data.imp[0].native).to.exist; + expect(data.imp[0].tagid).to.equal('div-1'); + expect(data.imp[0]['native']['assets']).to.exist.and.to.be.an('array'); + expect(data.imp[0]['native']['assets'][0]).to.eql(nativeBidRequests[0].params.native['assets'][0]); + }); + + it('Request object should not contain native request if assets is not provided', function () { + let request = spec.buildRequests(nativeBidRequestsWithoutAsset); + console.log(request); + expect(request).to.equal(undefined); + }); }); it('Request params dctr check', function () { From 792b854a93b8d0e239d1fc9a5ef4fdaf819c4c8c Mon Sep 17 00:00:00 2001 From: pm-shashank-jain Date: Wed, 5 Dec 2018 18:35:24 +0530 Subject: [PATCH 02/30] Removed port from endpoint --- modules/pubmaticBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 00095ae2250..7582d6164d8 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -13,7 +13,7 @@ import { const constants = require('src/constants.json'); const BIDDER_CODE = 'pubmatic'; -const ENDPOINT = 'https://hbopenbid.pubmatic.com:8080/translator?source=prebid-client'; +const ENDPOINT = 'https://hbopenbid.pubmatic.com/translator?source=prebid-client'; const USYNCURL = '//ads.pubmatic.com/AdServer/js/showad.js#PIX&kdntuid=1&p='; const DEFAULT_CURRENCY = 'USD'; const AUCTION_TYPE = 1; From b6740d0e27362044abd59039bfa25fc3f518dccc Mon Sep 17 00:00:00 2001 From: pm-shashank-jain Date: Wed, 5 Dec 2018 18:43:11 +0530 Subject: [PATCH 03/30] Removed protocol from endpoint --- modules/pubmaticBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 7582d6164d8..2fa3fc0ada0 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -13,7 +13,7 @@ import { const constants = require('src/constants.json'); const BIDDER_CODE = 'pubmatic'; -const ENDPOINT = 'https://hbopenbid.pubmatic.com/translator?source=prebid-client'; +const ENDPOINT = '//hbopenbid.pubmatic.com/translator?source=prebid-client'; const USYNCURL = '//ads.pubmatic.com/AdServer/js/showad.js#PIX&kdntuid=1&p='; const DEFAULT_CURRENCY = 'USD'; const AUCTION_TYPE = 1; From 0569f418d888d4ddd98e7e8fe698389e9c58f053 Mon Sep 17 00:00:00 2001 From: pm-shashank-jain Date: Wed, 5 Dec 2018 18:44:02 +0530 Subject: [PATCH 04/30] Formatting --- modules/pubmaticBidAdapter.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 2fa3fc0ada0..26029710cdd 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -1,15 +1,7 @@ import * as utils from 'src/utils'; -import { - registerBidder -} from 'src/adapters/bidderFactory'; -import { - BANNER, - VIDEO, - NATIVE -} from 'src/mediaTypes'; -import { - config -} from 'src/config'; +import { registerBidder } from 'src/adapters/bidderFactory'; +import { BANNER, VIDEO, NATIVE } from 'src/mediaTypes'; +import {config} from 'src/config'; const constants = require('src/constants.json'); const BIDDER_CODE = 'pubmatic'; From fd6bf0335fa0938be8a8544a3da9c93f30c44bdc Mon Sep 17 00:00:00 2001 From: pm-shashank-jain Date: Thu, 6 Dec 2018 17:23:58 +0530 Subject: [PATCH 05/30] Fix request payload --- modules/pubmaticBidAdapter.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 26029710cdd..0e2c8e25ee8 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -273,6 +273,7 @@ function _createImpressionObject(bid, conf) { impObj.video = videoObj; } else if (bid.params.hasOwnProperty('native')) { var nativeData = bid.params.native; + impObj.native = {}; for (var nativekey in NATIVE_CUSTOM_PARAMS) { if (nativeData.hasOwnProperty(nativekey)) { nativeObj[nativekey] = _checkParamDataType(nativekey, nativeData[nativekey], NATIVE_CUSTOM_PARAMS[nativekey]) @@ -281,7 +282,7 @@ function _createImpressionObject(bid, conf) { nativeObj.assets && nativeObj.assets.length > 0 && nativeObj.assets.forEach(function (element, idx) { element.id = idx + 1; }); - impObj.native = nativeObj; + impObj.native['request'] = nativeObj; } else { bannerObj = { pos: 0, From bd144204ac7d8b5e090854bc6b55d2227a89f0cc Mon Sep 17 00:00:00 2001 From: pm-shashank-jain Date: Thu, 6 Dec 2018 17:30:30 +0530 Subject: [PATCH 06/30] Updated test case --- test/spec/modules/pubmaticBidAdapter_spec.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index 0e9d4942f9c..27758ce9294 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -1047,9 +1047,10 @@ describe('PubMatic adapter', function () { let request = spec.buildRequests(nativeBidRequests); let data = JSON.parse(request.data); expect(data.imp[0].native).to.exist; + expect(data.imp[0].native['request']).to.exist; expect(data.imp[0].tagid).to.equal('div-1'); - expect(data.imp[0]['native']['assets']).to.exist.and.to.be.an('array'); - expect(data.imp[0]['native']['assets'][0]).to.eql(nativeBidRequests[0].params.native['assets'][0]); + expect(data.imp[0]['native']['request']['assets']).to.exist.and.to.be.an('array'); + expect(data.imp[0]['native']['request']['assets'][0]).to.eql(nativeBidRequests[0].params.native['assets'][0]); }); it('Request object should not contain native request if assets is not provided', function () { From 65e2f1effa83400dcbd5339542a280c0e5c18076 Mon Sep 17 00:00:00 2001 From: pm-shashank-jain Date: Fri, 7 Dec 2018 19:19:45 +0530 Subject: [PATCH 07/30] Changed request and response as per ortb spec --- modules/pubmaticBidAdapter.js | 221 ++++++++++++++----- test/spec/modules/pubmaticBidAdapter_spec.js | 34 +-- 2 files changed, 172 insertions(+), 83 deletions(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 0e2c8e25ee8..90e3e39358f 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -44,18 +44,7 @@ const VIDEO_CUSTOM_PARAMS = { 'minbitrate': DATA_TYPES.NUMBER, 'maxbitrate': DATA_TYPES.NUMBER } -const NATIVE_CUSTOM_PARAMS = { - 'ver': DATA_TYPES.STRING, - 'layout': DATA_TYPES.NUMBER, - 'adUnit': DATA_TYPES.NUMBER, - 'context': DATA_TYPES.NUMBER, - 'contextsubtype': DATA_TYPES.NUMBER, - 'plcmttype': DATA_TYPES.NUMBER, - 'plcmtcnt': DATA_TYPES.NUMBER, - 'seq': DATA_TYPES.NUMBER, - 'assets': DATA_TYPES.ARRAY, - 'ext': DATA_TYPES.OBJECT -} + const NET_REVENUE = false; const dealChannelValues = { 1: 'PMP', @@ -230,11 +219,120 @@ function _checkParamDataType(key, value, datatype) { } } +function _createNativeRequest(params) { + var nativeRequestObject = { + assets: [] + }; + for (var key in params) { + var assetObj = {}; + if (!(nativeRequestObject.assets && nativeRequestObject.assets.length > 0 && nativeRequestObject.assets.hasOwnProperty('key'))) { + switch (key) { + case 'title': + assetObj = { + id: 1, + req: params[key].required, + title: { + len: params[key].length, + ext: params[key].ext + } + }; + break; + case 'image': + assetObj = { + id: 2, + req: params[key].required, + img: { + type: params[key].type, + w: params[key].w || params[key].width || params[key].sizes[0], + h: params[key].h || params[key].height || params[key].sizes[1], + wmin: params[key].wmin || params[key].minimumWidth || (params[key].minsizes ? params[key].minsizes[0] : undefined), + hmin: params[key].hmin || params[key].minimumHeight || (params[key].minsizes ? params[key].minsizes[1] : undefined), + mimes: params[key].mimes, + ext: params[key].ext + } + }; + break; + case 'data': + assetObj = { + id: 9, + req: params[key].required, + data: { + type: params[key].type, + Len: params[key].length || params[key].len, + ext: params[key].ext + } + }; + break; + case 'video': + assetObj = { + id: 7, + req: params[key].required, + video: { + minduration: params[key].minduration, + maxduration: params[key].maxduration, + protocols: params[key].protocols, + mimes: params[key].mimes, + ext: params[key].ext + } + }; + break; + case 'ext': + assetObj = { + id: 8, + req: params[key].required + }; + break; + case 'sponsoredBy': + assetObj = { + id: 4, + req: params[key].required, + sponsoredBy: {} + }; + break; + case 'clickUrl': + assetObj = { + id: 6, + req: params[key].required, + clickUrl: {} + }; + break; + case 'body': + assetObj = { + id: 5, + req: params[key].required, + desc: {} + }; + break; + case 'icon': + assetObj = { + id: 3, + req: params[key].required, + icon: { + type: params[key].type, + w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : undefined), + h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : undefined) + } + }; + break; + case 'cta': + assetObj = { + id: 10, + req: params[key].required, + cta: {} + }; + break; + } + } + nativeRequestObject.assets[nativeRequestObject.assets.length] = assetObj; + }; + return nativeRequestObject; +} + function _createImpressionObject(bid, conf) { var impObj = {}; var bannerObj = {}; var videoObj = {}; - var nativeObj = {}; + // var nativeObj = {}; var sizes = bid.hasOwnProperty('sizes') ? bid.sizes : []; impObj = { @@ -271,18 +369,11 @@ function _createImpressionObject(bid, conf) { } impObj.video = videoObj; - } else if (bid.params.hasOwnProperty('native')) { - var nativeData = bid.params.native; + } else if (bid.nativeParams) { impObj.native = {}; - for (var nativekey in NATIVE_CUSTOM_PARAMS) { - if (nativeData.hasOwnProperty(nativekey)) { - nativeObj[nativekey] = _checkParamDataType(nativekey, nativeData[nativekey], NATIVE_CUSTOM_PARAMS[nativekey]) - } - } - nativeObj.assets && nativeObj.assets.length > 0 && nativeObj.assets.forEach(function (element, idx) { - element.id = idx + 1; - }); - impObj.native['request'] = nativeObj; + var nativeRequest = _createNativeRequest(bid.nativeParams) + impObj.native['request'] = JSON.stringify(nativeRequest); + console.log(impObj); } else { bannerObj = { pos: 0, @@ -388,12 +479,12 @@ export const spec = { return false; } } - if (bid.params.hasOwnProperty('native')) { - if (!bid.params.native.hasOwnProperty('assets') || !utils.isArray(bid.params.native.assets) || bid.params.native.assets.length === 0) { - utils.logWarn(BIDDER_CODE + ': For native ads, assets is mandatory and must specify atleast 1 asset value. Call to OpenBid will not be sent for ad unit:'); - return false; - } - } + // if (bid.params.hasOwnProperty('native')) { + // if (!bid.params.native.hasOwnProperty('assets') || !utils.isArray(bid.params.native.assets) || bid.params.native.assets.length === 0) { + // utils.logWarn(BIDDER_CODE + ': For native ads, assets is mandatory and must specify atleast 1 asset value. Call to OpenBid will not be sent for ad unit:'); + // return false; + // } + // } return true; } return false; @@ -421,18 +512,19 @@ export const spec = { utils.logWarn(BIDDER_CODE + ': Skipping the non-standard adslot: ', bid.params.adSlot, bid); return; } - } else if (bid.params.hasOwnProperty('native')) { - // Check for valid ad slot in native - if (!bid.params.native.assets || bid.params.native.assets.length < 1) { - utils.logWarn(BIDDER_CODE + ': Skipping the non-standard adslot: ', bid.params.adSlot, bid); - return; - } } else { if (!(bid.params.adSlot && bid.params.adUnit && bid.params.adUnitIndex && bid.params.width && bid.params.height)) { utils.logWarn(BIDDER_CODE + ': Skipping the non-standard adslot: ', bid.params.adSlot, bid); return; } } + // else if (bid.) { + // // Check for valid ad slot in native + // if (!bid.params.native.assets || bid.params.native.assets.length < 1) { + // utils.logWarn(BIDDER_CODE + ': Skipping the non-standard adslot: ', bid.params.adSlot, bid); + // return; + // } + // } conf.pubId = conf.pubId || bid.params.publisherId; conf = _handleCustomParams(bid.params, conf); conf.transactionId = bid.transactionId; @@ -563,6 +655,7 @@ export const spec = { } if (bid.impid === req.id && req.hasOwnProperty('native')) { newBid.mediaType = 'native'; + newBid.native = {}; if (bid.hasOwnProperty('adm')) { var adm = ''; try { @@ -571,31 +664,39 @@ export const spec = { adm = JSON.parse(bid.adm.replace(/\\/g, '')); } if (adm && adm.native && adm.native.assets && adm.native.assets.length > 0) { - const nativeAd = adm.native.assets[0]; - newBid[NATIVE] = { - title: nativeAd.title || '', - body: nativeAd.desc || '', - cta: nativeAd.ctatext || '', - sponsoredBy: adm.native.sponsored || 'PubMatic', - clickUrl: adm.native.link.url || 'www.pubmatic.com', - clickTrackers: adm.native.link.click_trackers || '', - impressionTrackers: adm.native.impression_trackers || '', - javascriptTrackers: adm.native.javascript_trackers || '', - }; - if (nativeAd.image) { - newBid['native'].image = { - url: nativeAd.image.url || '', - height: nativeAd.image.height || 150, - width: nativeAd.image.width || 150, - }; - } - if (nativeAd.icon) { - newBid['native'].icon = { - url: nativeAd.icon.url || '', - height: nativeAd.icon.height || '', - width: nativeAd.icon.width || '', - }; + for (let i = 0, len = adm.native.assets.length; i < len; i++) { + switch (adm.native.assets[i].id) { + case 1: + native.title = assets[i].title.text; + break; + case 2: + native.image = { + url: assets[i].img.url, + height: assets[i].img.h, + width: assets[i].img.w, + }; + break; + case 3: + native.icon = { + url: assets[i].img.url, + height: assets[i].img.h, + width: assets[i].img.w, + }; + break; + case 4: + native.sponsoredBy = assets[i].data.value; + break; + case 5: + native.body = assets[i].data.value; + break; + case 6: + native.cta = assets[i].data.value; + break; + } } + native.clickUrl = adm.native.link.url; + native.clickTrackers = adm.native.link.clicktrackers || []; + native.impressionTrackers = adm.native.imptrackers || []; } } } diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index 27758ce9294..1beb0acb630 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -134,10 +134,12 @@ describe('PubMatic adapter', function () { mediaTypes: { native: { title: { - required: true + required: true, + length: 50 }, image: { - required: true + required: true, + sizes: [300, 250] } } }, @@ -145,20 +147,6 @@ describe('PubMatic adapter', function () { params: { publisherId: '5670', adSlot: 'div-1', - native: { - ver: '1.2', - layout: 3, - assets: [ - { - id: 1, - title: 'New Image', - img: { - h: 300, - w: 250, - } - } - ] - } } }]; @@ -1046,18 +1034,18 @@ describe('PubMatic adapter', function () { it('Request params check for native ad', function () { let request = spec.buildRequests(nativeBidRequests); let data = JSON.parse(request.data); + console.log(data.imp[0]); expect(data.imp[0].native).to.exist; expect(data.imp[0].native['request']).to.exist; expect(data.imp[0].tagid).to.equal('div-1'); - expect(data.imp[0]['native']['request']['assets']).to.exist.and.to.be.an('array'); - expect(data.imp[0]['native']['request']['assets'][0]).to.eql(nativeBidRequests[0].params.native['assets'][0]); + expect(data.imp[0]['native']['request']).to.exist.and.to.be.an('string'); }); - it('Request object should not contain native request if assets is not provided', function () { - let request = spec.buildRequests(nativeBidRequestsWithoutAsset); - console.log(request); - expect(request).to.equal(undefined); - }); + // it('Request object should not contain native request if assets is not provided', function () { + // let request = spec.buildRequests(nativeBidRequestsWithoutAsset); + // console.log(request); + // expect(request).to.equal(undefined); + // }); }); it('Request params dctr check', function () { From 13c87de83d661729f0957ada629f210b73e6e466 Mon Sep 17 00:00:00 2001 From: pm-shashank-jain Date: Mon, 10 Dec 2018 14:38:15 +0530 Subject: [PATCH 08/30] Change in request and response --- modules/pubmaticBidAdapter.js | 100 +++++++++---------- test/spec/modules/pubmaticBidAdapter_spec.js | 3 + 2 files changed, 50 insertions(+), 53 deletions(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 90e3e39358f..63062103032 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -252,41 +252,29 @@ function _createNativeRequest(params) { } }; break; - case 'data': + case 'icon': assetObj = { - id: 9, + id: 3, req: params[key].required, - data: { + icon: { type: params[key].type, - Len: params[key].length || params[key].len, - ext: params[key].ext + w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : undefined), + h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : undefined) } }; break; - case 'video': + case 'sponsoredBy': assetObj = { - id: 7, + id: 4, req: params[key].required, - video: { - minduration: params[key].minduration, - maxduration: params[key].maxduration, - protocols: params[key].protocols, - mimes: params[key].mimes, - ext: params[key].ext - } - }; - break; - case 'ext': - assetObj = { - id: 8, - req: params[key].required + sponsoredBy: {} }; break; - case 'sponsoredBy': + case 'body': assetObj = { - id: 4, + id: 5, req: params[key].required, - sponsoredBy: {} + desc: {} }; break; case 'clickUrl': @@ -296,29 +284,34 @@ function _createNativeRequest(params) { clickUrl: {} }; break; - case 'body': + case 'video': assetObj = { - id: 5, + id: 7, req: params[key].required, - desc: {} + video: { + minduration: params[key].minduration, + maxduration: params[key].maxduration, + protocols: params[key].protocols, + mimes: params[key].mimes, + ext: params[key].ext + } }; break; - case 'icon': + case 'ext': assetObj = { - id: 3, - req: params[key].required, - icon: { - type: params[key].type, - w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : undefined), - h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : undefined) - } + id: 8, + req: params[key].required }; break; - case 'cta': + case 'data': assetObj = { - id: 10, + id: 9, req: params[key].required, - cta: {} + data: { + type: params[key].type, + Len: params[key].length || params[key].len, + ext: params[key].ext + } }; break; } @@ -372,7 +365,7 @@ function _createImpressionObject(bid, conf) { } else if (bid.nativeParams) { impObj.native = {}; var nativeRequest = _createNativeRequest(bid.nativeParams) - impObj.native['request'] = JSON.stringify(nativeRequest); + impObj.native['request'] = encodeURI(JSON.stringify(nativeRequest)); console.log(impObj); } else { bannerObj = { @@ -667,36 +660,37 @@ export const spec = { for (let i = 0, len = adm.native.assets.length; i < len; i++) { switch (adm.native.assets[i].id) { case 1: - native.title = assets[i].title.text; + newBid.native.title = adm.native.assets[i].title && adm.native.assets[i].title.text; break; case 2: - native.image = { - url: assets[i].img.url, - height: assets[i].img.h, - width: assets[i].img.w, + newBid.native.image = { + url: adm.native.assets[i].img && adm.native.assets[i].img.url, + height: adm.native.assets[i].img && adm.native.assets[i].img.h, + width: adm.native.assets[i].img && adm.native.assets[i].img.w, }; break; case 3: - native.icon = { - url: assets[i].img.url, - height: assets[i].img.h, - width: assets[i].img.w, + newBid.native.icon = { + url: adm.native.assets[i].img && adm.native.assets[i].img.url, + height: adm.native.assets[i].img && adm.native.assets[i].img.h, + width: adm.native.assets[i].img && adm.native.assets[i].img.w, }; break; case 4: - native.sponsoredBy = assets[i].data.value; + newBid.native.sponsoredBy = adm.native.assets[i].sponsored; break; case 5: - native.body = assets[i].data.value; + newBid.native.body = adm.native.assets[i].desc; break; case 6: - native.cta = assets[i].data.value; + newBid.native.cta = adm.native.assets[i].ctatext; break; } } - native.clickUrl = adm.native.link.url; - native.clickTrackers = adm.native.link.clicktrackers || []; - native.impressionTrackers = adm.native.imptrackers || []; + newBid.native.clickUrl = adm.native.link && adm.native.link.url; + newBid.native.clickTrackers = (adm.native.link && adm.native.link.clicktrackers) || []; + newBid.native.impressionTrackers = adm.native.imptrackers || []; + newBid.native.jstracker = adm.native.jstracker || []; } } } diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index 1beb0acb630..a3e1c5ef451 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -143,6 +143,9 @@ describe('PubMatic adapter', function () { } } }, + nativeParams: { + title: { required: true } + }, bidder: 'pubmatic', params: { publisherId: '5670', From d9f3562e894779b087df6c57d7af50a2cf0cbea9 Mon Sep 17 00:00:00 2001 From: pm-shashank-jain Date: Mon, 10 Dec 2018 18:46:31 +0530 Subject: [PATCH 09/30] Removed comments and extra code --- modules/pubmaticBidAdapter.js | 29 ++++---------------- test/spec/modules/pubmaticBidAdapter_spec.js | 7 ----- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 63062103032..6504931c7a8 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -325,7 +325,6 @@ function _createImpressionObject(bid, conf) { var impObj = {}; var bannerObj = {}; var videoObj = {}; - // var nativeObj = {}; var sizes = bid.hasOwnProperty('sizes') ? bid.sizes : []; impObj = { @@ -366,7 +365,6 @@ function _createImpressionObject(bid, conf) { impObj.native = {}; var nativeRequest = _createNativeRequest(bid.nativeParams) impObj.native['request'] = encodeURI(JSON.stringify(nativeRequest)); - console.log(impObj); } else { bannerObj = { pos: 0, @@ -392,9 +390,7 @@ function _createImpressionObject(bid, conf) { function _getDigiTrustObject(key) { function getDigiTrustId() { - let digiTrustUser = window.DigiTrust && (config.getConfig('digiTrustId') || window.DigiTrust.getUser({ - member: key - })); + let digiTrustUser = window.DigiTrust && (config.getConfig('digiTrustId') || window.DigiTrust.getUser({member: key})); return (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || null; } let digiTrustId = getDigiTrustId(); @@ -450,11 +446,11 @@ export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO, NATIVE], /** - * Determines whether or not the given bid request is valid. Valid bid request must have placementId and hbid - * - * @param {BidRequest} bid The bid params to validate. - * @return boolean True if this is a valid bid, and false otherwise. - */ + * Determines whether or not the given bid request is valid. Valid bid request must have placementId and hbid + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ isBidRequestValid: bid => { if (bid && bid.params) { if (!utils.isStr(bid.params.publisherId)) { @@ -472,12 +468,6 @@ export const spec = { return false; } } - // if (bid.params.hasOwnProperty('native')) { - // if (!bid.params.native.hasOwnProperty('assets') || !utils.isArray(bid.params.native.assets) || bid.params.native.assets.length === 0) { - // utils.logWarn(BIDDER_CODE + ': For native ads, assets is mandatory and must specify atleast 1 asset value. Call to OpenBid will not be sent for ad unit:'); - // return false; - // } - // } return true; } return false; @@ -511,13 +501,6 @@ export const spec = { return; } } - // else if (bid.) { - // // Check for valid ad slot in native - // if (!bid.params.native.assets || bid.params.native.assets.length < 1) { - // utils.logWarn(BIDDER_CODE + ': Skipping the non-standard adslot: ', bid.params.adSlot, bid); - // return; - // } - // } conf.pubId = conf.pubId || bid.params.publisherId; conf = _handleCustomParams(bid.params, conf); conf.transactionId = bid.transactionId; diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index a3e1c5ef451..fd4ac851075 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -1037,18 +1037,11 @@ describe('PubMatic adapter', function () { it('Request params check for native ad', function () { let request = spec.buildRequests(nativeBidRequests); let data = JSON.parse(request.data); - console.log(data.imp[0]); expect(data.imp[0].native).to.exist; expect(data.imp[0].native['request']).to.exist; expect(data.imp[0].tagid).to.equal('div-1'); expect(data.imp[0]['native']['request']).to.exist.and.to.be.an('string'); }); - - // it('Request object should not contain native request if assets is not provided', function () { - // let request = spec.buildRequests(nativeBidRequestsWithoutAsset); - // console.log(request); - // expect(request).to.equal(undefined); - // }); }); it('Request params dctr check', function () { From adbc774618654a6feb7dbd2e59b9af0b14146375 Mon Sep 17 00:00:00 2001 From: pm-shashank-jain Date: Tue, 11 Dec 2018 19:10:52 +0530 Subject: [PATCH 10/30] Code Review comments --- modules/pubmaticBidAdapter.js | 369 ++++++++++++++++++++++++++-------- 1 file changed, 287 insertions(+), 82 deletions(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 6504931c7a8..f04055d7a68 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -45,6 +45,76 @@ const VIDEO_CUSTOM_PARAMS = { 'maxbitrate': DATA_TYPES.NUMBER } +const NATIVE_ASSET_ID = { + 'TITLE': 1, + 'IMAGE': 2, + 'ICON': 3, + 'SPONSOREDBY': 4, + 'BODY': 5, + 'CLICKURL': 6, + 'VIDEO': 7, + 'EXT': 8, + 'DATA': 9, + 'LOGO': 10, + 'SPONSORED': 11, + 'DESC': 12, + 'RATING': 13, + 'LIKES': 14, + 'DOWNLOADS': 15, + 'PRICE': 16, + 'SALEPRICE': 17, + 'PHONE': 18, + 'ADDRESS': 19, + 'DESC2': 20, + 'DISPLAYURL': 21, + 'CTATEXT': 22 +} + +const NATIVE_ASSET_IMAGE_TYPE = { + 'ICON': 1, + 'LOGO': 2, + 'IMAGE': 3 +} + +const NATIVE_ASSET_DATA_TYPE = { + 'sponsored': 1, + 'desc': 2, + 'rating': 3, + 'likes': 4, + 'downloads': 5, + 'price': 6, + 'saleprice': 7, + 'phone': 8, + 'address': 9, + 'desc2': 10, + 'displayurl': 11, + 'ctatext': 12 +} + +const NATIVE_MINIMUM_REQUIRED_IMAGE_ASSETS = [ + { + id: NATIVE_ASSET_ID.TITLE, + required: 1, + title: { + + } + }, + { + id: NATIVE_ASSET_ID.IMAGE, + required: true, + img: { + type: 3 + } + }, + { + id: NATIVE_ASSET_ID.SPONSOREDBY, + required: true, + data: { + type: 1 + } + } +] + const NET_REVENUE = false; const dealChannelValues = { 1: 'PMP', @@ -225,12 +295,12 @@ function _createNativeRequest(params) { }; for (var key in params) { var assetObj = {}; - if (!(nativeRequestObject.assets && nativeRequestObject.assets.length > 0 && nativeRequestObject.assets.hasOwnProperty('key'))) { + if (!(nativeRequestObject.assets && nativeRequestObject.assets.length > 0 && nativeRequestObject.assets.hasOwnProperty(key))) { switch (key) { case 'title': assetObj = { - id: 1, - req: params[key].required, + id: NATIVE_ASSET_ID.TITLE, + required: params[key].required ? 1 : 0, title: { len: params[key].length, ext: params[key].ext @@ -239,55 +309,52 @@ function _createNativeRequest(params) { break; case 'image': assetObj = { - id: 2, - req: params[key].required, + id: NATIVE_ASSET_ID.IMAGE, + required: params[key].required ? 1 : 0, img: { - type: params[key].type, + type: NATIVE_ASSET_IMAGE_TYPE.IMAGE, w: params[key].w || params[key].width || params[key].sizes[0], h: params[key].h || params[key].height || params[key].sizes[1], wmin: params[key].wmin || params[key].minimumWidth || (params[key].minsizes ? params[key].minsizes[0] : undefined), hmin: params[key].hmin || params[key].minimumHeight || (params[key].minsizes ? params[key].minsizes[1] : undefined), mimes: params[key].mimes, - ext: params[key].ext + ext: params[key].ext, } }; break; case 'icon': assetObj = { - id: 3, - req: params[key].required, - icon: { - type: params[key].type, + id: NATIVE_ASSET_ID.ICON, + required: params[key].required ? 1 : 0, + img: { + type: NATIVE_ASSET_IMAGE_TYPE.ICON, w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : undefined), - h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : undefined) + h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : undefined), } }; break; case 'sponsoredBy': assetObj = { - id: 4, - req: params[key].required, - sponsoredBy: {} + id: NATIVE_ASSET_ID.SPONSOREDBY, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.sponsored + } }; break; case 'body': assetObj = { - id: 5, - req: params[key].required, - desc: {} - }; - break; - case 'clickUrl': - assetObj = { - id: 6, - req: params[key].required, - clickUrl: {} + id: NATIVE_ASSET_ID.BODY, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.desc + } }; break; case 'video': assetObj = { - id: 7, - req: params[key].required, + id: NATIVE_ASSET_ID.VIDEO, + required: params[key].required ? 1 : 0, video: { minduration: params[key].minduration, maxduration: params[key].maxduration, @@ -299,25 +366,138 @@ function _createNativeRequest(params) { break; case 'ext': assetObj = { - id: 8, - req: params[key].required + id: NATIVE_ASSET_ID.EXT, + required: params[key].required ? 1 : 0, }; break; case 'data': assetObj = { - id: 9, - req: params[key].required, + id: NATIVE_ASSET_ID.DATA, + required: params[key].required ? 1 : 0, data: { type: params[key].type, - Len: params[key].length || params[key].len, + len: params[key].length || params[key].len, ext: params[key].ext } }; break; + case 'logo': + assetObj = { + id: NATIVE_ASSET_ID.LOGO, + required: params[key].required ? 1 : 0, + img: { + type: NATIVE_ASSET_IMAGE_TYPE.LOGO, + w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : undefined), + h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : undefined) + } + }; + break; + case 'rating': + assetObj = { + id: NATIVE_ASSET_ID.RATING, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.rating, + } + }; + break; + case 'likes': + assetObj = { + id: NATIVE_ASSET_ID.LIKES, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.likes, + } + }; + break; + case 'downloads': + assetObj = { + id: NATIVE_ASSET_ID.DOWNLOADS, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.downloads, + } + }; + break; + case 'price': + assetObj = { + id: NATIVE_ASSET_ID.PRICE, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.price, + } + }; + break; + case 'saleprice': + assetObj = { + id: NATIVE_ASSET_ID.SALEPRICE, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.saleprice, + } + }; + break; + case 'phone': + assetObj = { + id: NATIVE_ASSET_ID.PHONE, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.phone, + } + }; + break; + case 'address': + assetObj = { + id: NATIVE_ASSET_ID.DATA, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.address, + } + }; + break; + case 'desc2': + assetObj = { + id: NATIVE_ASSET_ID.DESC2, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.desc2, + } + }; + break; + case 'displayurl': + assetObj = { + id: NATIVE_ASSET_ID.DISPLAYURL, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.displayurl, + } + }; + break; + case 'ctatext': + assetObj = { + id: NATIVE_ASSET_ID.CTATEXT, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.ctatext, + } + }; + break; } } nativeRequestObject.assets[nativeRequestObject.assets.length] = assetObj; }; + NATIVE_MINIMUM_REQUIRED_IMAGE_ASSETS.forEach(ele => { + var isRequiredAsset = false; + for (var i = 0; i < nativeRequestObject.assets.length; i++) { + if (ele.id == nativeRequestObject.assets[i].id) { + isRequiredAsset = true; + break; + } + } + if (!isRequiredAsset) { + nativeRequestObject.assets.push(ele); + } + }); return nativeRequestObject; } @@ -363,8 +543,7 @@ function _createImpressionObject(bid, conf) { impObj.video = videoObj; } else if (bid.nativeParams) { impObj.native = {}; - var nativeRequest = _createNativeRequest(bid.nativeParams) - impObj.native['request'] = encodeURI(JSON.stringify(nativeRequest)); + impObj.native['request'] = JSON.stringify(_createNativeRequest(bid.nativeParams)); } else { bannerObj = { pos: 0, @@ -442,6 +621,77 @@ function _handleEids(payload) { } } +function _parseNativeResponse(bid, newBid) { + newBid.mediaType = 'native'; + newBid.native = {}; + if (bid.hasOwnProperty('adm')) { + var adm = ''; + try { + adm = JSON.parse(bid.adm.replace(/\\/g, '')); + } catch (ex) { + utils.logWarn(BIDDER_CODE + ' Error: Cannot parse native reponse for ad slot: ' + bid.params.adSlot); + return; + } + if (adm && adm.native && adm.native.assets && adm.native.assets.length > 0) { + for (let i = 0, len = adm.native.assets.length; i < len; i++) { + switch (adm.native.assets[i].id) { + case NATIVE_ASSET_ID.TITLE: + newBid.native.title = adm.native.assets[i].title && adm.native.assets[i].title.text; + break; + case NATIVE_ASSET_ID.IMAGE: + newBid.native.image = { + url: adm.native.assets[i].img && adm.native.assets[i].img.url, + height: adm.native.assets[i].img && adm.native.assets[i].img.h, + width: adm.native.assets[i].img && adm.native.assets[i].img.w, + }; + break; + case NATIVE_ASSET_ID.ICON: + newBid.native.icon = { + url: adm.native.assets[i].img && adm.native.assets[i].img.url, + height: adm.native.assets[i].img && adm.native.assets[i].img.h, + width: adm.native.assets[i].img && adm.native.assets[i].img.w, + }; + break; + case NATIVE_ASSET_ID.SPONSOREDBY: + newBid.native.sponsoredBy = adm.native.assets[i].data && adm.native.assets[i].data.value; + break; + case NATIVE_ASSET_ID.BODY: + newBid.native.body = adm.native.assets[i].data && adm.native.assets[i].data.value; + break; + case NATIVE_ASSET_ID.LIKES: + newBid.native.likes = adm.native.assets[i].data && adm.native.assets[i].data.value; + break; + case NATIVE_ASSET_ID.DOWNLOADS: + newBid.native.downloads = adm.native.assets[i].data && adm.native.assets[i].data.value; + break; + case NATIVE_ASSET_ID.PRICE: + newBid.native.price = adm.native.assets[i].data && adm.native.assets[i].data.value; + break; + case NATIVE_ASSET_ID.SALEPRICE: + newBid.native.saleprice = adm.native.assets[i].data && adm.native.assets[i].data.value; + break; + case NATIVE_ASSET_ID.PHONE: + newBid.native.phone = adm.native.assets[i].data && adm.native.assets[i].data.value; + break; + case NATIVE_ASSET_ID.ADDRESS: + newBid.native.address = adm.native.assets[i].data && adm.native.assets[i].data.value; + break; + case NATIVE_ASSET_ID.DESC2: + newBid.native.desc2 = adm.native.assets[i].data && adm.native.assets[i].data.value; + break; + case NATIVE_ASSET_ID.CTATEXT: + newBid.native.ctatext = adm.native.assets[i].data && adm.native.assets[i].data.value; + break; + } + } + newBid.native.clickUrl = adm.native.link && adm.native.link.url; + newBid.native.clickTrackers = (adm.native.link && adm.native.link.clicktrackers) || []; + newBid.native.impressionTrackers = adm.native.imptrackers || []; + newBid.native.jstracker = adm.native.jstracker || []; + } + } +} + export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO, NATIVE], @@ -454,11 +704,11 @@ export const spec = { isBidRequestValid: bid => { if (bid && bid.params) { if (!utils.isStr(bid.params.publisherId)) { - utils.logWarn(BIDDER_CODE + ' Error: publisherId is mandatory and cannot be numeric. Call to OpenBid will not be sent for ad unit:'); + utils.logWarn(BIDDER_CODE + ' Error: publisherId is mandatory and cannot be numeric. Call to OpenBid will not be sent for ad unit: ' + bid.params.adSlot); return false; } if (!utils.isStr(bid.params.adSlot)) { - utils.logWarn(BIDDER_CODE + ': adSlotId is mandatory and cannot be numeric. Call to OpenBid will not be sent for ad unit:'); + utils.logWarn(BIDDER_CODE + ': adSlotId is mandatory and cannot be numeric. Call to OpenBid will not be sent for ad unit: ' + bid.params.adSlot); return false; } // video ad validation @@ -630,52 +880,7 @@ export const spec = { newBid.vastXml = bid.adm; } if (bid.impid === req.id && req.hasOwnProperty('native')) { - newBid.mediaType = 'native'; - newBid.native = {}; - if (bid.hasOwnProperty('adm')) { - var adm = ''; - try { - adm = JSON.parse(bid.adm); - } catch (ex) { - adm = JSON.parse(bid.adm.replace(/\\/g, '')); - } - if (adm && adm.native && adm.native.assets && adm.native.assets.length > 0) { - for (let i = 0, len = adm.native.assets.length; i < len; i++) { - switch (adm.native.assets[i].id) { - case 1: - newBid.native.title = adm.native.assets[i].title && adm.native.assets[i].title.text; - break; - case 2: - newBid.native.image = { - url: adm.native.assets[i].img && adm.native.assets[i].img.url, - height: adm.native.assets[i].img && adm.native.assets[i].img.h, - width: adm.native.assets[i].img && adm.native.assets[i].img.w, - }; - break; - case 3: - newBid.native.icon = { - url: adm.native.assets[i].img && adm.native.assets[i].img.url, - height: adm.native.assets[i].img && adm.native.assets[i].img.h, - width: adm.native.assets[i].img && adm.native.assets[i].img.w, - }; - break; - case 4: - newBid.native.sponsoredBy = adm.native.assets[i].sponsored; - break; - case 5: - newBid.native.body = adm.native.assets[i].desc; - break; - case 6: - newBid.native.cta = adm.native.assets[i].ctatext; - break; - } - } - newBid.native.clickUrl = adm.native.link && adm.native.link.url; - newBid.native.clickTrackers = (adm.native.link && adm.native.link.clicktrackers) || []; - newBid.native.impressionTrackers = adm.native.imptrackers || []; - newBid.native.jstracker = adm.native.jstracker || []; - } - } + _parseNativeResponse(bid, newBid); } }); } From 21fe846c92f6e09f7f15b62ab93c0aebdc5b42f8 Mon Sep 17 00:00:00 2001 From: pm-shashank-jain Date: Thu, 13 Dec 2018 18:11:24 +0530 Subject: [PATCH 11/30] Code Review Comments and Test cases for request and response --- modules/pubmaticBidAdapter.js | 443 ++++++++++--------- test/spec/modules/pubmaticBidAdapter_spec.js | 153 ++++++- 2 files changed, 362 insertions(+), 234 deletions(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index f04055d7a68..7e3df4e136c 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -77,35 +77,22 @@ const NATIVE_ASSET_IMAGE_TYPE = { } const NATIVE_ASSET_DATA_TYPE = { - 'sponsored': 1, - 'desc': 2, - 'rating': 3, - 'likes': 4, - 'downloads': 5, - 'price': 6, - 'saleprice': 7, - 'phone': 8, - 'address': 9, - 'desc2': 10, - 'displayurl': 11, - 'ctatext': 12 + 'SPONSORED': 1, + 'DESC': 2, + 'RATING': 3, + 'LIKES': 4, + 'DOWNLOADS': 5, + 'PRICE': 6, + 'SALEPRICE': 7, + 'PHONE': 8, + 'ADDRESS': 9, + 'DESC2': 10, + 'DISPLAYURL': 11, + 'CTATEXT': 12 } +// check if title, image can be added with mandatory field default values const NATIVE_MINIMUM_REQUIRED_IMAGE_ASSETS = [ - { - id: NATIVE_ASSET_ID.TITLE, - required: 1, - title: { - - } - }, - { - id: NATIVE_ASSET_ID.IMAGE, - required: true, - img: { - type: 3 - } - }, { id: NATIVE_ASSET_ID.SPONSOREDBY, required: true, @@ -294,207 +281,221 @@ function _createNativeRequest(params) { assets: [] }; for (var key in params) { - var assetObj = {}; - if (!(nativeRequestObject.assets && nativeRequestObject.assets.length > 0 && nativeRequestObject.assets.hasOwnProperty(key))) { - switch (key) { - case 'title': - assetObj = { - id: NATIVE_ASSET_ID.TITLE, - required: params[key].required ? 1 : 0, - title: { - len: params[key].length, - ext: params[key].ext - } - }; - break; - case 'image': - assetObj = { - id: NATIVE_ASSET_ID.IMAGE, - required: params[key].required ? 1 : 0, - img: { - type: NATIVE_ASSET_IMAGE_TYPE.IMAGE, - w: params[key].w || params[key].width || params[key].sizes[0], - h: params[key].h || params[key].height || params[key].sizes[1], - wmin: params[key].wmin || params[key].minimumWidth || (params[key].minsizes ? params[key].minsizes[0] : undefined), - hmin: params[key].hmin || params[key].minimumHeight || (params[key].minsizes ? params[key].minsizes[1] : undefined), - mimes: params[key].mimes, - ext: params[key].ext, - } - }; - break; - case 'icon': - assetObj = { - id: NATIVE_ASSET_ID.ICON, - required: params[key].required ? 1 : 0, - img: { - type: NATIVE_ASSET_IMAGE_TYPE.ICON, - w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : undefined), - h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : undefined), - } - }; - break; - case 'sponsoredBy': - assetObj = { - id: NATIVE_ASSET_ID.SPONSOREDBY, - required: params[key].required ? 1 : 0, - data: { - type: NATIVE_ASSET_DATA_TYPE.sponsored - } - }; - break; - case 'body': - assetObj = { - id: NATIVE_ASSET_ID.BODY, - required: params[key].required ? 1 : 0, - data: { - type: NATIVE_ASSET_DATA_TYPE.desc - } - }; - break; - case 'video': - assetObj = { - id: NATIVE_ASSET_ID.VIDEO, - required: params[key].required ? 1 : 0, - video: { - minduration: params[key].minduration, - maxduration: params[key].maxduration, - protocols: params[key].protocols, - mimes: params[key].mimes, - ext: params[key].ext - } - }; - break; - case 'ext': - assetObj = { - id: NATIVE_ASSET_ID.EXT, - required: params[key].required ? 1 : 0, - }; - break; - case 'data': - assetObj = { - id: NATIVE_ASSET_ID.DATA, - required: params[key].required ? 1 : 0, - data: { - type: params[key].type, - len: params[key].length || params[key].len, - ext: params[key].ext - } - }; - break; - case 'logo': - assetObj = { - id: NATIVE_ASSET_ID.LOGO, - required: params[key].required ? 1 : 0, - img: { - type: NATIVE_ASSET_IMAGE_TYPE.LOGO, - w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : undefined), - h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : undefined) - } - }; - break; - case 'rating': - assetObj = { - id: NATIVE_ASSET_ID.RATING, - required: params[key].required ? 1 : 0, - data: { - type: NATIVE_ASSET_DATA_TYPE.rating, - } - }; - break; - case 'likes': - assetObj = { - id: NATIVE_ASSET_ID.LIKES, - required: params[key].required ? 1 : 0, - data: { - type: NATIVE_ASSET_DATA_TYPE.likes, - } - }; - break; - case 'downloads': - assetObj = { - id: NATIVE_ASSET_ID.DOWNLOADS, - required: params[key].required ? 1 : 0, - data: { - type: NATIVE_ASSET_DATA_TYPE.downloads, - } - }; - break; - case 'price': - assetObj = { - id: NATIVE_ASSET_ID.PRICE, - required: params[key].required ? 1 : 0, - data: { - type: NATIVE_ASSET_DATA_TYPE.price, - } - }; - break; - case 'saleprice': - assetObj = { - id: NATIVE_ASSET_ID.SALEPRICE, - required: params[key].required ? 1 : 0, - data: { - type: NATIVE_ASSET_DATA_TYPE.saleprice, - } - }; - break; - case 'phone': - assetObj = { - id: NATIVE_ASSET_ID.PHONE, - required: params[key].required ? 1 : 0, - data: { - type: NATIVE_ASSET_DATA_TYPE.phone, - } - }; - break; - case 'address': - assetObj = { - id: NATIVE_ASSET_ID.DATA, - required: params[key].required ? 1 : 0, - data: { - type: NATIVE_ASSET_DATA_TYPE.address, - } - }; - break; - case 'desc2': - assetObj = { - id: NATIVE_ASSET_ID.DESC2, - required: params[key].required ? 1 : 0, - data: { - type: NATIVE_ASSET_DATA_TYPE.desc2, - } - }; - break; - case 'displayurl': - assetObj = { - id: NATIVE_ASSET_ID.DISPLAYURL, - required: params[key].required ? 1 : 0, - data: { - type: NATIVE_ASSET_DATA_TYPE.displayurl, + if (params.hasOwnProperty(key)) { + var assetObj = {}; + if (!(nativeRequestObject.assets && nativeRequestObject.assets.length > 0 && nativeRequestObject.assets.hasOwnProperty(key))) { + switch (key) { + case 'title': + if (params[key].length) { + assetObj = { + id: NATIVE_ASSET_ID.TITLE, + required: params[key].required ? 1 : 0, + title: { + len: params[key].length, + ext: params[key].ext + } + }; } - }; - break; - case 'ctatext': - assetObj = { - id: NATIVE_ASSET_ID.CTATEXT, - required: params[key].required ? 1 : 0, - data: { - type: NATIVE_ASSET_DATA_TYPE.ctatext, + break; + case 'image': + if (params[key].sizes && params[key].sizes.length > 0) { + assetObj = { + id: NATIVE_ASSET_ID.IMAGE, + required: params[key].required ? 1 : 0, + img: { + type: NATIVE_ASSET_IMAGE_TYPE.IMAGE, + w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : undefined), + h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : undefined), + wmin: params[key].wmin || params[key].minimumWidth || (params[key].minsizes ? params[key].minsizes[0] : undefined), + hmin: params[key].hmin || params[key].minimumHeight || (params[key].minsizes ? params[key].minsizes[1] : undefined), + mimes: params[key].mimes, + ext: params[key].ext, + } + }; } - }; - break; + break; + case 'icon': + if (params[key].sizes && params[key].sizes.length > 0) { + assetObj = { + id: NATIVE_ASSET_ID.ICON, + required: params[key].required ? 1 : 0, + img: { + type: NATIVE_ASSET_IMAGE_TYPE.ICON, + w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : undefined), + h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : undefined), + } + }; + }; + break; + case 'sponsoredBy': + assetObj = { + id: NATIVE_ASSET_ID.SPONSOREDBY, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.SPONSORED + } + }; + break; + case 'body': + assetObj = { + id: NATIVE_ASSET_ID.BODY, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.DESC + } + }; + break; + case 'video': + assetObj = { + id: NATIVE_ASSET_ID.VIDEO, + required: params[key].required ? 1 : 0, + video: { + minduration: params[key].minduration, + maxduration: params[key].maxduration, + protocols: params[key].protocols, + mimes: params[key].mimes, + ext: params[key].ext + } + }; + break; + case 'ext': + assetObj = { + id: NATIVE_ASSET_ID.EXT, + required: params[key].required ? 1 : 0, + }; + break; + case 'data': + assetObj = { + id: NATIVE_ASSET_ID.DATA, + required: params[key].required ? 1 : 0, + data: { + type: params[key].type, + len: params[key].length || params[key].len, + ext: params[key].ext + } + }; + break; + case 'logo': + assetObj = { + id: NATIVE_ASSET_ID.LOGO, + required: params[key].required ? 1 : 0, + img: { + type: NATIVE_ASSET_IMAGE_TYPE.LOGO, + w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : undefined), + h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : undefined) + } + }; + break; + case 'rating': + assetObj = { + id: NATIVE_ASSET_ID.RATING, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.RATING, + } + }; + break; + case 'likes': + assetObj = { + id: NATIVE_ASSET_ID.LIKES, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.LIKES, + } + }; + break; + case 'downloads': + assetObj = { + id: NATIVE_ASSET_ID.DOWNLOADS, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.DOWNLOADS, + } + }; + break; + case 'price': + assetObj = { + id: NATIVE_ASSET_ID.PRICE, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.PRICE, + } + }; + break; + case 'saleprice': + assetObj = { + id: NATIVE_ASSET_ID.SALEPRICE, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.SALEPRICE, + } + }; + break; + case 'phone': + assetObj = { + id: NATIVE_ASSET_ID.PHONE, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.PHONE, + } + }; + break; + case 'address': + assetObj = { + id: NATIVE_ASSET_ID.DATA, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.ADDRESS, + } + }; + break; + case 'desc2': + assetObj = { + id: NATIVE_ASSET_ID.DESC2, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.DESC2, + } + }; + break; + case 'displayurl': + assetObj = { + id: NATIVE_ASSET_ID.DISPLAYURL, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.DISPLAYURL, + } + }; + break; + case 'ctatext': + assetObj = { + id: NATIVE_ASSET_ID.CTATEXT, + required: params[key].required ? 1 : 0, + data: { + type: NATIVE_ASSET_DATA_TYPE.CTATEXT, + } + }; + break; + } } } - nativeRequestObject.assets[nativeRequestObject.assets.length] = assetObj; + if (assetObj && assetObj.id) { + nativeRequestObject.assets[nativeRequestObject.assets.length] = assetObj; + } }; + + // for native image adtype prebid has to have few required assests i.e. title,sponsoredBy, image + // if any of these are missing from the request then it will be added to the request NATIVE_MINIMUM_REQUIRED_IMAGE_ASSETS.forEach(ele => { - var isRequiredAsset = false; - for (var i = 0; i < nativeRequestObject.assets.length; i++) { + var isRequiredAssetPresent = false; + var lengthOfExistingAssets = nativeRequestObject.assets.length; + for (var i = 0; i < lengthOfExistingAssets; i++) { if (ele.id == nativeRequestObject.assets[i].id) { - isRequiredAsset = true; + isRequiredAssetPresent = true; break; } } - if (!isRequiredAsset) { + if (!isRequiredAssetPresent) { nativeRequestObject.assets.push(ele); } }); @@ -622,7 +623,6 @@ function _handleEids(payload) { } function _parseNativeResponse(bid, newBid) { - newBid.mediaType = 'native'; newBid.native = {}; if (bid.hasOwnProperty('adm')) { var adm = ''; @@ -704,17 +704,17 @@ export const spec = { isBidRequestValid: bid => { if (bid && bid.params) { if (!utils.isStr(bid.params.publisherId)) { - utils.logWarn(BIDDER_CODE + ' Error: publisherId is mandatory and cannot be numeric. Call to OpenBid will not be sent for ad unit: ' + bid.params.adSlot); + utils.logWarn(BIDDER_CODE + ' Error: publisherId is mandatory and cannot be numeric. Call to OpenBid will not be sent for ad unit: ' + bid); return false; } if (!utils.isStr(bid.params.adSlot)) { - utils.logWarn(BIDDER_CODE + ': adSlotId is mandatory and cannot be numeric. Call to OpenBid will not be sent for ad unit: ' + bid.params.adSlot); + utils.logWarn(BIDDER_CODE + ': adSlotId is mandatory and cannot be numeric. Call to OpenBid will not be sent for ad unit: ' + bid); return false; } // video ad validation if (bid.params.hasOwnProperty('video')) { if (!bid.params.video.hasOwnProperty('mimes') || !utils.isArray(bid.params.video.mimes) || bid.params.video.mimes.length === 0) { - utils.logWarn(BIDDER_CODE + ': For video ads, mimes is mandatory and must specify atlease 1 mime value. Call to OpenBid will not be sent for ad unit:'); + utils.logWarn(BIDDER_CODE + ': For video ads, mimes is mandatory and must specify atlease 1 mime value. Call to OpenBid will not be sent for ad unit:' + bid); return false; } } @@ -880,6 +880,7 @@ export const spec = { newBid.vastXml = bid.adm; } if (bid.impid === req.id && req.hasOwnProperty('native')) { + newBid.mediaType = 'native'; _parseNativeResponse(bid, newBid); } }); diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index fd4ac851075..27154bdd592 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -11,6 +11,11 @@ describe('PubMatic adapter', function () { let bidResponses; let nativeBidRequests; let nativeBidRequestsWithoutAsset; + let nativeBidRequestsWithRequiredParam; + let nativeBidResponse; + let validnativeBidImpression; + let validnativeBidImpressionWithRequiredParam; + let nativeBidImpressionWithoutRequiredParams; beforeEach(function () { bidRequests = [ @@ -135,25 +140,56 @@ describe('PubMatic adapter', function () { native: { title: { required: true, - length: 50 + length: 80 }, image: { required: true, sizes: [300, 250] + }, + sponsoredBy: { + required: true } } }, nativeParams: { - title: { required: true } + title: { required: true, length: 80 }, + image: { required: true, sizes: [300, 250] }, + sponsoredBy: { required: true } }, bidder: 'pubmatic', params: { publisherId: '5670', - adSlot: 'div-1', - } + adSlot: '/43743431/NativeAutomationPrebid@1x1', + }, + bidId: '2a5571261281d4', + requestId: 'B68287E1-DC39-4B38-9790-FE4F179739D6', + bidderRequestId: '1c56ad30b9b8ca8', }]; nativeBidRequestsWithoutAsset = [{ + code: '/19968336/prebid_native_example_1', + sizes: [ + [300, 250] + ], + mediaTypes: { + native: { + type: 'image' + } + }, + nativeParams: { + title: { required: true }, + image: { required: true }, + sponsoredBy: { required: true }, + clickUrl: { required: true } + }, + bidder: 'pubmatic', + params: { + publisherId: '5670', + adSlot: '/43743431/NativeAutomationPrebid@1x1', + } + }]; + + nativeBidRequestsWithRequiredParam = [{ code: '/19968336/prebid_native_example_1', sizes: [ [300, 250] @@ -161,23 +197,29 @@ describe('PubMatic adapter', function () { mediaTypes: { native: { title: { - required: true + required: false, + length: 80 }, image: { + required: false, + sizes: [300, 250] + }, + sponsoredBy: { required: true } } }, + nativeParams: { + title: { required: false, length: 80 }, + image: { required: false, sizes: [300, 250] }, + sponsoredBy: { required: true } + }, bidder: 'pubmatic', params: { publisherId: '5670', - adSlot: 'div-1', - native: { - ver: '1.2', - layout: 3 - } + adSlot: '/43743431/NativeAutomationPrebid@1x1', } - }] + }]; bidResponses = { 'body': { @@ -209,6 +251,46 @@ describe('PubMatic adapter', function () { }] } }; + + nativeBidResponse = { + 'body': { + 'id': '1544691825939', + 'seatbid': [{ + 'bid': [{ + 'id': 'B68287E1-DC39-4B38-9790-FE4F179739D6', + 'impid': '2a5571261281d4', + 'price': 0.01, + 'adm': "{\"native\":{\"assets\":[{\"id\":1,\"title\":{\"text\":\"Native Test Title\"}},{\"id\":2,\"img\":{\"h\":627,\"url\":\"http://stagingpub.net/native_ads/PM-Native-Ad-1200x627.png\",\"w\":1200}},{\"data\":{\"value\":\"Sponsored By PubMatic\"},\"id\":4}],\"imptrackers\":[\"http://imptracker.com/main/9bde02d0-6017-11e4-9df7-005056967c35\",\"http://172.16.4.213/AdServer/AdDisplayTrackerServlet?operId=1&pubId=5890&siteId=5892&adId=6016&adType=12&adServerId=243&kefact=0.010000&kaxefact=0.010000&kadNetFrequecy=0&kadwidth=0&kadheight=0&kadsizeid=7&kltstamp=1544692761&indirectAdId=0&adServerOptimizerId=2&ranreq=0.1&kpbmtpfact=1.000000&dcId=1&tldId=0&passback=0&svr=MADS1107&ekefact=GSQSXOLKDgBAvRnoiNj0LxtpAnNEO30u1ZI5sITloOsP7gzh&ekaxefact=GSQSXAXLDgD0fOZLCjgbnVJiyS3D65dqDkxfs2ArpC3iugXw&ekpbmtpfact=GSQSXCDLDgB5mcooOvXtCKmx7TnNDJDY2YuHFOL3o9ceoU4H&crID=campaign111&lpu=advertiserdomain.com&ucrid=273354366805642829&campaignId=16981&creativeId=0&pctr=0.000000&wDSPByrId=511&wDspId=6&wbId=0&wrId=0&wAdvID=1&isRTB=1&rtbId=C09BB577-B8C1-4C3E-A0FF-73F6F631C80A&imprId=B68287E1-DC39-4B38-9790-FE4F179739D6&oid=B68287E1-DC39-4B38-9790-FE4F179739D6&pageURL=http%3A%2F%2Ftest.com%2FTestPages%2Fnativead.html\"],\"jstracker\":\"