From 442484d839deba1053ab673cea561179ab57777d Mon Sep 17 00:00:00 2001 From: Max Crawford Date: Fri, 22 Jun 2018 15:08:35 -0400 Subject: [PATCH] Refactored URL query parameter passthrough for additional values, changed SSP endpoint to v.lkqd.net, and updated associated unit tests (#2758) --- modules/lkqdBidAdapter.js | 183 +++++++++++++---------- modules/lkqdBidAdapter.md | 16 +- test/spec/modules/lkqdBidAdapter_spec.js | 68 +++++---- 3 files changed, 157 insertions(+), 110 deletions(-) diff --git a/modules/lkqdBidAdapter.js b/modules/lkqdBidAdapter.js index cb4ffef73ee3..e9ebae4f26b2 100644 --- a/modules/lkqdBidAdapter.js +++ b/modules/lkqdBidAdapter.js @@ -4,41 +4,13 @@ import { VIDEO } from 'src/mediaTypes'; const BIDDER_CODE = 'lkqd'; const BID_TTL_DEFAULT = 300; -const ENDPOINT = 'https://ssp.lkqd.net/ad?pid=[PLACEMENT_ID]&sid=[SITE_ID]&output=[OUTPUT]&execution=[EXECUTION]&placement=[PLACEMENT]&playinit=[PLAY_INIT]&volume=[VOLUME]&timeout=[TIMEOUT]&width=[WIDTH]‌&height=[HEIGHT]&pbt=[PREBID_TOKEN]‌&dnt=[DO_NOT_TRACK]‌&pageurl=[PAGEURL]‌&contentid=[CONTENT_ID]‌&contenttitle=[CONTENT_TITLE]‌&contentlength=[CONTENT_LENGTH]‌&contenturl=[CONTENT_URL]&prebid=true'; - -const PID_KEY = '[PLACEMENT_ID]'; -const SID_KEY = '[SITE_ID]'; -const OUTPUT_KEY = '[OUTPUT]'; -const EXECUTION_KEY = '[EXECUTION]'; -const PLACEMENT_KEY = '[PLACEMENT]'; -const PLAYINIT_KEY = '[PLAY_INIT]'; -const VOLUME_KEY = '[VOLUME]'; -const TIMEOUT_KEY = '[TIMEOUT]'; -const WIDTH_KEY = '[WIDTH]'; -const HEIGHT_KEY = '[HEIGHT]'; -const DNT_KEY = '[DO_NOT_TRACK]'; -const PAGEURL_KEY = '[PAGEURL]'; -const CONTENTID_KEY = '[CONTENT_ID]'; -const CONTENTTITLE_KEY = '[CONTENT_TITLE]'; -const CONTENTLENGTH_KEY = '[CONTENT_LENGTH]'; -const CONTENTURL_KEY = '[CONTENT_URL]'; - -const PID_DEFAULT = null; -const SID_DEFAULT = null; -const OUTPUT_DEFAULT = 'vast'; -const EXECUTION_DEFAULT = 'any'; -const PLACEMENT_DEFAULT = ''; -const PLAYINIT_DEFAULT = 'auto'; -const VOLUME_DEFAULT = '100'; -const TIMEOUT_DEFAULT = ''; -const WIDTH_DEFAULT = null; -const HEIGHT_DEFAULT = null; -const DNT_DEFAULT = null; -const PAGEURL_DEFAULT = null; -const CONTENTID_DEFAULT = null; -const CONTENTTITLE_DEFAULT = null; -const CONTENTLENGTH_DEFAULT = null; -const CONTENTURL_DEFAULT = null; +const ENDPOINT = 'https://v.lkqd.net/ad'; + +const PARAM_OUTPUT_DEFAULT = 'vast'; +const PARAM_EXECUTION_DEFAULT = 'any'; +const PARAM_SUPPORT_DEFAULT = 'html5'; +const PARAM_PLAYINIT_DEFAULT = 'auto'; +const PARAM_VOLUME_DEFAULT = '100'; function _validateId(id) { if (id && typeof id !== 'undefined' && parseInt(id) > 0) { @@ -58,18 +30,6 @@ function isBidRequestValid(bidRequest) { return false; } -function _replaceMacro(key, paramValue, defaultValue, url) { - if (url && typeof url === 'string' && url !== '' && url.indexOf(key) > 0) { - if (paramValue) { - url = url.replace(key, paramValue); - } else if (defaultValue || defaultValue == '') { - url = url.replace(key, defaultValue); - } - } - - return url; -} - function buildRequests(validBidRequests) { let bidRequests = []; @@ -101,29 +61,101 @@ function buildRequests(validBidRequests) { } let sspUrl = ENDPOINT.concat(); + let sspData = {}; // required parameters - sspUrl = _replaceMacro(PID_KEY, bidRequest.params.placementId, PID_DEFAULT, sspUrl); - sspUrl = _replaceMacro(SID_KEY, bidRequest.params.siteId, SID_DEFAULT, sspUrl); + sspData.pid = bidRequest.params.placementId; + sspData.sid = bidRequest.params.siteId; + sspData.prebid = true; + // optional parameters - sspUrl = _replaceMacro(OUTPUT_KEY, bidRequest.params.output, OUTPUT_DEFAULT, sspUrl); - sspUrl = _replaceMacro(EXECUTION_KEY, bidRequest.params.execution, EXECUTION_DEFAULT, sspUrl); - sspUrl = _replaceMacro(PLACEMENT_KEY, bidRequest.params.placement, PLACEMENT_DEFAULT, sspUrl); - sspUrl = _replaceMacro(PLAYINIT_KEY, bidRequest.params.playinit, PLAYINIT_DEFAULT, sspUrl); - sspUrl = _replaceMacro(VOLUME_KEY, bidRequest.params.volume, VOLUME_DEFAULT, sspUrl); - sspUrl = _replaceMacro(TIMEOUT_KEY, bidRequest.params.timeout, TIMEOUT_DEFAULT, sspUrl); - sspUrl = _replaceMacro(WIDTH_KEY, playerWidth, WIDTH_DEFAULT, sspUrl); - sspUrl = _replaceMacro(HEIGHT_KEY, playerHeight, HEIGHT_DEFAULT, sspUrl); - sspUrl = _replaceMacro(DNT_KEY, bidRequest.params.dnt, DNT_DEFAULT, sspUrl); - sspUrl = _replaceMacro(PAGEURL_KEY, bidRequest.params.pageurl, PAGEURL_DEFAULT, sspUrl); - sspUrl = _replaceMacro(CONTENTID_KEY, bidRequest.params.contentId, CONTENTID_DEFAULT, sspUrl); - sspUrl = _replaceMacro(CONTENTTITLE_KEY, bidRequest.params.contentTitle, CONTENTTITLE_DEFAULT, sspUrl); - sspUrl = _replaceMacro(CONTENTLENGTH_KEY, bidRequest.params.contentLength, CONTENTLENGTH_DEFAULT, sspUrl); - sspUrl = _replaceMacro(CONTENTURL_KEY, bidRequest.params.contentUrl, CONTENTURL_DEFAULT, sspUrl); + if (bidRequest.params.hasOwnProperty('output') && bidRequest.params.output != null) { + sspData.output = bidRequest.params.output; + } else { + sspData.output = PARAM_OUTPUT_DEFAULT; + } + if (bidRequest.params.hasOwnProperty('execution') && bidRequest.params.execution != null) { + sspData.execution = bidRequest.params.execution; + } else { + sspData.execution = PARAM_EXECUTION_DEFAULT; + } + if (bidRequest.params.hasOwnProperty('support') && bidRequest.params.support != null) { + sspData.support = bidRequest.params.support; + } else { + sspData.support = PARAM_SUPPORT_DEFAULT; + } + if (bidRequest.params.hasOwnProperty('playinit') && bidRequest.params.playinit != null) { + sspData.playinit = bidRequest.params.playinit; + } else { + sspData.playinit = PARAM_PLAYINIT_DEFAULT; + } + if (bidRequest.params.hasOwnProperty('volume') && bidRequest.params.volume != null) { + sspData.volume = bidRequest.params.volume; + } else { + sspData.volume = PARAM_VOLUME_DEFAULT; + } + if (playerWidth) { + sspData.width = playerWidth; + } + if (playerHeight) { + sspData.height = playerHeight; + } + if (bidRequest.params.hasOwnProperty('vpaidmode') && bidRequest.params.vpaidmode != null) { + sspData.vpaidmode = bidRequest.params.vpaidmode; + } + if (bidRequest.params.hasOwnProperty('appname') && bidRequest.params.appname != null) { + sspData.appname = bidRequest.params.appname; + } + if (bidRequest.params.hasOwnProperty('bundleid') && bidRequest.params.bundleid != null) { + sspData.bundleid = bidRequest.params.bundleid; + } + if (bidRequest.params.hasOwnProperty('aid') && bidRequest.params.aid != null) { + sspData.aid = bidRequest.params.aid; + } + if (bidRequest.params.hasOwnProperty('idfa') && bidRequest.params.idfa != null) { + sspData.idfa = bidRequest.params.idfa; + } + if (bidRequest.params.hasOwnProperty('gdpr') && bidRequest.params.gdpr != null) { + sspData.gdpr = bidRequest.params.gdpr; + } + if (bidRequest.params.hasOwnProperty('gdprcs') && bidRequest.params.gdprcs != null) { + sspData.gdprcs = bidRequest.params.gdprcs; + } + if (bidRequest.params.hasOwnProperty('flrd') && bidRequest.params.flrd != null) { + sspData.flrd = bidRequest.params.flrd; + } + if (bidRequest.params.hasOwnProperty('flrmp') && bidRequest.params.flrmp != null) { + sspData.flrmp = bidRequest.params.flrmp; + } + if (bidRequest.params.hasOwnProperty('placement') && bidRequest.params.placement != null) { + sspData.placement = bidRequest.params.placement; + } + if (bidRequest.params.hasOwnProperty('timeout') && bidRequest.params.timeout != null) { + sspData.timeout = bidRequest.params.timeout; + } + if (bidRequest.params.hasOwnProperty('dnt') && bidRequest.params.dnt != null) { + sspData.dnt = bidRequest.params.dnt; + } + if (bidRequest.params.hasOwnProperty('pageurl') && bidRequest.params.pageurl != null) { + sspData.pageurl = bidRequest.params.pageurl; + } + if (bidRequest.params.hasOwnProperty('contentId') && bidRequest.params.contentId != null) { + sspData.contentid = bidRequest.params.contentId; + } + if (bidRequest.params.hasOwnProperty('contentTitle') && bidRequest.params.contentTitle != null) { + sspData.contenttitle = bidRequest.params.contentTitle; + } + if (bidRequest.params.hasOwnProperty('contentLength') && bidRequest.params.contentLength != null) { + sspData.contentlength = bidRequest.params.contentLength; + } + if (bidRequest.params.hasOwnProperty('contentUrl') && bidRequest.params.contentUrl != null) { + sspData.contenturl = bidRequest.params.contentUrl; + } + // random number to prevent caching - sspUrl = sspUrl + '‌&rnd=' + Math.floor(Math.random() * 999999999); + sspData.rnd = Math.floor(Math.random() * 999999999); - let sspData = {}; + // Prebid.js required properties sspData.bidId = bidRequest.bidId; sspData.bidWidth = playerWidth; sspData.bidHeight = playerHeight; @@ -149,26 +181,10 @@ function interpretResponse(serverResponse, bidRequest) { try { let bidResponse = {}; if (bidRequest && bidRequest.data && bidRequest.data.bidId && bidRequest.data.bidId !== '') { - let sspXml = new window.DOMParser().parseFromString(serverResponse.body, 'text/xml'); + let sspXmlString = serverResponse.body; + let sspXml = new window.DOMParser().parseFromString(sspXmlString, 'text/xml'); if (sspXml && sspXml.getElementsByTagName('parsererror').length == 0) { let sspUrl = bidRequest.url.concat(); - let prebidToken; - let extensions = sspXml.getElementsByTagName('Extension'); - - if (extensions && extensions.length) { - for (let i = 0; i < extensions.length; i++) { - if (extensions[i].getAttribute('id') === 'prebidToken') { - prebidToken = extensions[i] - } - } - if (prebidToken) { - sspUrl = sspUrl + '&pbt' + prebidToken; - } else { - utils.logWarn('Warning: Could not determine token, cannot guarantee same ad will be received after auctionEnd'); - } - } else { - utils.logWarn('Warning: Response did not contain a token, cannot guarantee same ad will be received after auctionEnd'); - } bidResponse.requestId = bidRequest.data.bidId; bidResponse.bidderCode = BIDDER_CODE; @@ -181,6 +197,7 @@ function interpretResponse(serverResponse, bidRequest) { bidResponse.currency = sspXml.getElementsByTagName('Pricing')[0].getAttribute('currency'); bidResponse.netRevenue = true; bidResponse.vastUrl = sspUrl; + bidResponse.vastXml = sspXmlString; bidResponse.mediaType = VIDEO; bidResponses.push(bidResponse); diff --git a/modules/lkqdBidAdapter.md b/modules/lkqdBidAdapter.md index 22bff449befe..2ea2ef95b4ba 100644 --- a/modules/lkqdBidAdapter.md +++ b/modules/lkqdBidAdapter.md @@ -15,7 +15,7 @@ LKQD bid adapter supports Video ads currently. For more information about [LKQD Ad Serving and Management](http://www.lkqd.com/ad-serving-and-management/), please contact [info@lkqd.com](info@lkqd.com). # Sample Ad Unit: For Publishers -``` +```javascript var videoAdUnit = [ { code: 'video1', @@ -31,3 +31,17 @@ var videoAdUnit = [ } }] }]; +``` + +# Configuration + +The LKQD Bidder Adapter expects Prebid Cache to be enabled so that we can store and retrieve a single vastXml. If this value is not set it will have to use vastUrl to make a duplicate call to the SSP and cannot guarantee the same ad will be received after auctionEnd. + +```javascript +pbjs.setConfig({ + usePrebidCache: true, + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + } +}); +``` diff --git a/test/spec/modules/lkqdBidAdapter_spec.js b/test/spec/modules/lkqdBidAdapter_spec.js index d3e16f0c99a2..a5e750862293 100644 --- a/test/spec/modules/lkqdBidAdapter_spec.js +++ b/test/spec/modules/lkqdBidAdapter_spec.js @@ -41,7 +41,7 @@ describe('LKQD Bid Adapter Test', () => { }); describe('buildRequests', () => { - const ENDPOINT = 'https://ssp.lkqd.net/ad?'; + const ENDPOINT = 'https://v.lkqd.net/ad'; let bidRequests = [ { 'bidder': 'lkqd', @@ -76,41 +76,57 @@ describe('LKQD Bid Adapter Test', () => { it('should populate available parameters', () => { const requests = spec.buildRequests(bidRequests); expect(requests.length).to.equal(2); - const r1 = requests[0].url; - expect(r1).to.contain('?pid=263'); - expect(r1).to.contain('&sid=662921'); - expect(r1).to.contain('&width=300'); - expect(r1).to.contain('&height=250'); - const r2 = requests[1].url; - expect(r2).to.contain('?pid=263'); - expect(r2).to.contain('&sid=662921'); - expect(r2).to.contain('&width=640'); - expect(r2).to.contain('&height=480'); + const r1 = requests[0].data; + expect(r1).to.have.property('pid'); + expect(r1.pid).to.equal('263'); + expect(r1).to.have.property('sid'); + expect(r1.sid).to.equal('662921'); + expect(r1).to.have.property('width'); + expect(r1.width).to.equal(300); + expect(r1).to.have.property('height'); + expect(r1.height).to.equal(250); + const r2 = requests[1].data; + expect(r2).to.have.property('pid'); + expect(r2.pid).to.equal('263'); + expect(r2).to.have.property('sid'); + expect(r2.sid).to.equal('662921'); + expect(r2).to.have.property('width'); + expect(r2.width).to.equal(640); + expect(r2).to.have.property('height'); + expect(r2.height).to.equal(480); }); it('should not populate unspecified parameters', () => { const requests = spec.buildRequests(bidRequests); expect(requests.length).to.equal(2); - const r1 = requests[0].url; - expect(r1).to.contain('‌&contentid=[CONTENT_ID]'); - expect(r1).to.contain('‌&contenttitle=[CONTENT_TITLE]'); - expect(r1).to.contain('‌&contentlength=[CONTENT_LENGTH]'); - expect(r1).to.contain('&height=250'); - const r2 = requests[1].url; - expect(r2).to.contain('‌&contentid=[CONTENT_ID]'); - expect(r2).to.contain('‌&contenttitle=[CONTENT_TITLE]'); - expect(r2).to.contain('‌&contentlength=[CONTENT_LENGTH]'); - expect(r2).to.contain('‌&contenturl=[CONTENT_URL]'); + const r1 = requests[0].data; + expect(r1).to.not.have.property('dnt'); + expect(r1).to.not.have.property('pageurl'); + expect(r1).to.not.have.property('contentid'); + expect(r1).to.not.have.property('contenttitle'); + expect(r1).to.not.have.property('contentlength'); + expect(r1).to.not.have.property('contenturl'); + const r2 = requests[1].data; + expect(r2).to.not.have.property('dnt'); + expect(r2).to.not.have.property('pageurl'); + expect(r2).to.not.have.property('contentid'); + expect(r2).to.not.have.property('contenttitle'); + expect(r2).to.not.have.property('contentlength'); + expect(r2).to.not.have.property('contenturl'); }); it('should handle single size request', () => { const requests = spec.buildRequests(bidRequest); expect(requests.length).to.equal(1); - const r1 = requests[0].url; - expect(r1).to.contain('?pid=263'); - expect(r1).to.contain('&sid=662921'); - expect(r1).to.contain('&width=640'); - expect(r1).to.contain('&height=480'); + const r1 = requests[0].data; + expect(r1).to.have.property('pid'); + expect(r1.pid).to.equal('263'); + expect(r1).to.have.property('sid'); + expect(r1.sid).to.equal('662921'); + expect(r1).to.have.property('width'); + expect(r1.width).to.equal(640); + expect(r1).to.have.property('height'); + expect(r1.height).to.equal(480); }); it('sends bid request to ENDPOINT via GET', () => {