From e539c6821400a9b945bffbebb3fd4103305aca2e Mon Sep 17 00:00:00 2001 From: Matt Lane Date: Wed, 27 Sep 2017 18:07:45 -0700 Subject: [PATCH] Support aspect ratio specification for native images --- modules/appnexusAstBidAdapter.js | 69 ++++++++++++------- .../modules/appnexusAstBidAdapter_spec.js | 32 ++++++++- 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/modules/appnexusAstBidAdapter.js b/modules/appnexusAstBidAdapter.js index 50fb328b35d..d956b5f2dfd 100644 --- a/modules/appnexusAstBidAdapter.js +++ b/modules/appnexusAstBidAdapter.js @@ -14,13 +14,15 @@ const NATIVE_MAPPING = { cta: 'ctatext', image: { serverName: 'main_image', - serverParams: { required: true, sizes: [{}] } + requiredParams: { required: true }, + minimumParams: { sizes: [{}] }, }, icon: { serverName: 'icon', - serverParams: { required: true, sizes: [{}] } + requiredParams: { required: true }, + minimumParams: { sizes: [{}] }, }, - sponsoredBy: 'sponsored_by' + sponsoredBy: 'sponsored_by', }; const SOURCE = 'pbjs'; @@ -264,28 +266,7 @@ function bidToTag(bid) { tag.ad_types = ['native']; if (bid.nativeParams) { - const nativeRequest = {}; - - // map standard prebid native asset identifier to /ut parameters - // e.g., tag specifies `body` but /ut only knows `description` - // mapping may be in form {tag: ''} or - // {tag: {serverName: '', serverParams: {...}}} - Object.keys(bid.nativeParams).forEach(key => { - // check if one of the forms is used, otherwise - // a mapping wasn't specified so pass the key straight through - const requestKey = - (NATIVE_MAPPING[key] && NATIVE_MAPPING[key].serverName) || - NATIVE_MAPPING[key] || - key; - - // if the mapping for this identifier specifies required server - // params via the `serverParams` object, merge that in - nativeRequest[requestKey] = Object.assign({}, - NATIVE_MAPPING[key] && NATIVE_MAPPING[key].serverParams, - bid.nativeParams[key] - ); - }); - + const nativeRequest = buildNativeRequest(bid.nativeParams); tag['native'] = {layouts: [nativeRequest]}; } } @@ -343,6 +324,44 @@ function getRtbBid(tag) { return tag && tag.ads && tag.ads.length && tag.ads.find(ad => ad.rtb); } +function buildNativeRequest(params) { + const request = {}; + + // map standard prebid native asset identifier to /ut parameters + // e.g., tag specifies `body` but /ut only knows `description`. + // mapping may be in form {tag: ''} or + // {tag: {serverName: '', requiredParams: {...}}} + Object.keys(params).forEach(key => { + // check if one of the forms is used, otherwise + // a mapping wasn't specified so pass the key straight through + const requestKey = + (NATIVE_MAPPING[key] && NATIVE_MAPPING[key].serverName) || + NATIVE_MAPPING[key] || + key; + + // required params are always passed on request + const requiredParams = NATIVE_MAPPING[key] && NATIVE_MAPPING[key].requiredParams; + request[requestKey] = Object.assign({}, requiredParams, params[key]); + + // minimum params are passed if no non-required params given on adunit + const minimumParams = NATIVE_MAPPING[key] && NATIVE_MAPPING[key].minimumParams; + + if (requiredParams && minimumParams) { + // subtract required keys from adunit keys + const adunitKeys = Object.keys(params[key]); + const requiredKeys = Object.keys(requiredParams); + const remaining = adunitKeys.filter(key => !requiredKeys.includes(key)); + + // if none are left over, the minimum params needs to be sent + if (remaining.length === 0) { + request[requestKey] = Object.assign({}, request[requestKey], minimumParams); + } + } + }); + + return request; +} + function outstreamRender(bid) { // push to render queue because ANOutstreamVideo may not be loaded yet bid.renderer.push(() => { diff --git a/test/spec/modules/appnexusAstBidAdapter_spec.js b/test/spec/modules/appnexusAstBidAdapter_spec.js index eea8c55882b..61745697f3a 100644 --- a/test/spec/modules/appnexusAstBidAdapter_spec.js +++ b/test/spec/modules/appnexusAstBidAdapter_spec.js @@ -164,7 +164,7 @@ describe('AppNexusAdapter', () => { delete REQUEST.bids[0].params.nativeParams; }); - it('sets required native asset params when not provided on adunit', () => { + it('sets minimum native asset params when not provided on adunit', () => { REQUEST.bids[0].mediaType = 'native'; REQUEST.bids[0].nativeParams = { image: {required: true}, @@ -181,6 +181,36 @@ describe('AppNexusAdapter', () => { delete REQUEST.bids[0].params.nativeParams; }); + it('does not overwrite native ad unit params with mimimum params', () => { + REQUEST.bids[0].mediaType = 'native'; + REQUEST.bids[0].nativeParams = { + image: { + aspect_ratios: [{ + min_width: 100, + ratio_width: 2, + ratio_height: 3, + }] + }, + }; + + adapter.callBids(REQUEST); + + const request = JSON.parse(requests[0].requestBody); + expect(request.tags[0].native.layouts[0]).to.deep.equal({ + main_image: { + required: true, + aspect_ratios: [{ + min_width: 100, + ratio_width: 2, + ratio_height: 3, + }] + }, + }); + + delete REQUEST.bids[0].mediaType; + delete REQUEST.bids[0].params.nativeParams; + }); + it('sends bid request to ENDPOINT via POST', () => { adapter.callBids(REQUEST); expect(requests[0].url).to.equal(ENDPOINT);