From 60b81b4949ee6be6103224ce7d9a96a759de1b45 Mon Sep 17 00:00:00 2001 From: David Andersen Date: Thu, 2 Jan 2020 15:56:09 -0500 Subject: [PATCH 01/11] Add triplelift adapter --- triple-lift/CHANGES.md | 0 triple-lift/DOCUMENTATION.md | 69 ++++ triple-lift/triple-lift-htb-exports.js | 9 + triple-lift/triple-lift-htb-system-tests.js | 121 ++++++ triple-lift/triple-lift-htb-validator.js | 78 ++++ triple-lift/triple-lift-htb.js | 415 ++++++++++++++++++++ 6 files changed, 692 insertions(+) create mode 100644 triple-lift/CHANGES.md create mode 100644 triple-lift/DOCUMENTATION.md create mode 100644 triple-lift/triple-lift-htb-exports.js create mode 100644 triple-lift/triple-lift-htb-system-tests.js create mode 100644 triple-lift/triple-lift-htb-validator.js create mode 100644 triple-lift/triple-lift-htb.js diff --git a/triple-lift/CHANGES.md b/triple-lift/CHANGES.md new file mode 100644 index 00000000..e69de29b diff --git a/triple-lift/DOCUMENTATION.md b/triple-lift/DOCUMENTATION.md new file mode 100644 index 00000000..d2178611 --- /dev/null +++ b/triple-lift/DOCUMENTATION.md @@ -0,0 +1,69 @@ +# TripleLift +## General Compatibility +|Feature| | +|---|---| +| Consent | | +| Native Ad Support | | +| SafeFrame Support | | +| PMP Support | | + +## Browser Compatibility +| Browser | | +|--- |---| +| Chrome | | +| Edge | | +| Firefox | | +| Internet Explorer 9 | | +| Internet Explorer 10 | | +| Internet Explorer 11 | | +| Safari | | +| Mobile Chrome | | +| Mobile Safari | | +| UC Browser | | +| Samsung Internet | | +| Opera | | + +## Adapter Information +| Info | | +|---|---| +| Partner Id | TripleLiftHtb | +| Ad Server Responds in (Cents, Dollars, etc) | | +| Bid Type (Gross / Net) | | +| GAM Key (Open Market) | | +| GAM Key (Private Market) | | +| Ad Server URLs | | +| Slot Mapping Sytle (Size / Multiple Sizes / Slot) | | +| Request Architecture (MRA / SRA) | | + +## Currencies Supported + +## Bid Request Information +### Parameters +| Key | Required | Type | Description | +|---|---|---|---| +| | | | | + +### Example +```javascript + +``` + +## Bid Response Information +### Bid Example +```javascript + +``` +### Pass Example +```javascript + +``` + +## Configuration Information +### Configuration Keys +| Key | Required | Type | Description | +|---|---|---|---| +| | | | | +### Example +```javascript + +``` diff --git a/triple-lift/triple-lift-htb-exports.js b/triple-lift/triple-lift-htb-exports.js new file mode 100644 index 00000000..c9420203 --- /dev/null +++ b/triple-lift/triple-lift-htb-exports.js @@ -0,0 +1,9 @@ +//? if(FEATURES.GPT_LINE_ITEMS) { +shellInterface.TripleLiftHtb = { + render: SpaceCamp.services.RenderService.renderDfpAd.bind(null, 'TripleLiftHtb') +}; + +shellInterface.TPL = { + render: SpaceCamp.services.RenderService.renderDfpAd.bind(null, 'TripleLiftHtb') +}; +//? } \ No newline at end of file diff --git a/triple-lift/triple-lift-htb-system-tests.js b/triple-lift/triple-lift-htb-system-tests.js new file mode 100644 index 00000000..35711466 --- /dev/null +++ b/triple-lift/triple-lift-htb-system-tests.js @@ -0,0 +1,121 @@ +'use strict'; + +function getPartnerId() { + return 'TripleLiftHtb'; +} + +function getStatsId() { + return 'TPL'; +} + +function getCallbackType() { + return 'NONE'; +} + +function getArchitecture() { + return 'MRA'; +} + +function getConfig() { + return { + xSlots: { + 1: { + inventoryCode: 'test', + sizes: [[300, 250]] + } + } + }; +} + +function getBidRequestRegex() { + return { + method: 'GET', + urlRegex: /tlx\.3lift\.com\/header\/auction/ + }; +} + +function validateBidRequest(request) { + var r = request.query; + expect(r.v).toBe('2.1'); + expect(r.lib).toBe('ix'); + expect(r.inv_code).toBe('test'); + expect(r.size).toBe('300x250'); + expect(r.fe).toBe('0'); + expect(r.cmp_cs).toBe(''); + expect(r.gdpr).toBe('false'); + expect(r.referrer).toBe(document.URL); +} + +function validateBidRequestWithPrivacy(request) { + var r = request.query; + expect(r.v).toBe('2.1'); + expect(r.lib).toBe('ix'); + expect(r.inv_code).toBe('test'); + expect(r.size).toBe('300x250'); + expect(r.fe).toBe('0'); + expect(r.gdpr).toBe('true'); + expect(r.cmp_cs).toBe('TEST_GDPR_CONSENT_STRING'); + expect(r.referrer).toBe(document.URL); +} + +function getValidResponse(request, creative) { + return JSON.stringify({ + ad: creative, + cpm: 2.00, + crid: '3898_17463_747551', + width: 300, + height: 250, + imp_id: '1', + tl_source: 'hdx' + }); +} + +function validateTargeting(targetingMap) { + expect(targetingMap).toEqual(jasmine.objectContaining({ + ix_tpl_cpm: jasmine.arrayContaining(['300x250_200']), + ix_tpl_id: jasmine.arrayContaining([jasmine.any(String)]) + })); +} + +function getPassResponse() { + return JSON.stringify({ + status: 'no_bid' + }); +} + +function getValidResponseWithDeal(request, creative) { + return JSON.stringify({ + ad: creative, + cpm: 2.00, + crid: '3898_17463_747551', + width: 300, + height: 250, + imp_id: '1', + deal_id: 'TEST_DEAL_ID', + tl_source: 'hdx' + }); +} + +function validateTargetingWithDeal(targetingMap) { + expect(targetingMap).toEqual(jasmine.objectContaining({ + ix_tpl_cpm: jasmine.arrayContaining(['300x250_200']), + ix_tpl_dealid: jasmine.arrayContaining(['TEST_DEAL_ID']), + ix_tpl_id: jasmine.arrayContaining([jasmine.any(String)]) + })); +} + +module.exports = { + getPartnerId: getPartnerId, + getStatsId: getStatsId, + getCallbackType: getCallbackType, + getArchitecture: getArchitecture, + getConfig: getConfig, + getBidRequestRegex: getBidRequestRegex, + validateBidRequest: validateBidRequest, + validateBidRequestWithPrivacy: validateBidRequestWithPrivacy, + getValidResponse: getValidResponse, + validateTargeting: validateTargeting, + getPassResponse: getPassResponse, + getValidResponseWithDeal: getValidResponseWithDeal, + validateTargetingWithDeal: validateTargetingWithDeal +}; diff --git a/triple-lift/triple-lift-htb-validator.js b/triple-lift/triple-lift-htb-validator.js new file mode 100644 index 00000000..8e99a99e --- /dev/null +++ b/triple-lift/triple-lift-htb-validator.js @@ -0,0 +1,78 @@ +/** + * @author: Partner + * @license: UNLICENSED + * + * @copyright: Copyright (c) 2017 by Index Exchange. All rights reserved. + * + * The information contained within this document is confidential, copyrighted + * and or a trade secret. No part of this document may be reproduced or + * distributed in any form or by any means, in whole or in part, without the + * prior written permission of Index Exchange. + */ + +'use strict'; + +//////////////////////////////////////////////////////////////////////////////// +// Dependencies //////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +var Inspector = require('../../../libs/external/schema-inspector.js'); + +//////////////////////////////////////////////////////////////////////////////// +// Main //////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +/* ============================================================================= + * STEP 0 | Config Validation + * ----------------------------------------------------------------------------- + * This file contains the necessary validation for the partner configuration. + * This validation will be performed on the partner specific configuration object + * that is passed into the wrapper. The wrapper uses an outside library called + * schema-insepctor to perform the validation. Information about it can be found here: + * https://atinux.fr/schema-inspector/. + */ + +var partnerValidator = function (configs) { + var result = Inspector.validate({ + type: 'object', + properties: { + xSlots: { + type: 'object', + properties: { + '*': { + type: 'object', + properties: { + inventoryCode: { + type: 'string', + minLength: 1 + }, + sizes: { + type: 'array', + items: { + type: 'array', + exactLength: 2, + items: { + type: 'integer', + } + } + }, + floor: { + type: 'number', + optional: true, + gt: 0 + } + } + } + } + } + } + }, configs); + + if (!result.valid) { + return result.format(); + } + + return null; +}; + +module.exports = partnerValidator; diff --git a/triple-lift/triple-lift-htb.js b/triple-lift/triple-lift-htb.js new file mode 100644 index 00000000..7a90573b --- /dev/null +++ b/triple-lift/triple-lift-htb.js @@ -0,0 +1,415 @@ +/** + * @author: Partner + * @license: UNLICENSED + * + * @copyright: Copyright (c) 2017 by Index Exchange. All rights reserved. + * + * The information contained within this document is confidential, copyrighted + * and or a trade secret. No part of this document may be reproduced or + * distributed in any form or by any means, in whole or in part, without the + * prior written permission of Index Exchange. + */ + +'use strict'; + +//////////////////////////////////////////////////////////////////////////////// +// Dependencies //////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +var Browser = require('browser.js'); +var Classify = require('classify.js'); +var Constants = require('constants.js'); +var Partner = require('partner.js'); +var Size = require('size.js'); +var SpaceCamp = require('space-camp.js'); +var System = require('system.js'); +var Network = require('network.js'); + +var ComplianceService; +var EventsService; +var RenderService; + +//? if (DEBUG) { +var ConfigValidators = require('config-validators.js'); +var PartnerSpecificValidator = require('triple-lift-htb-validator.js'); +var Scribe = require('scribe.js'); +var Whoopsie = require('whoopsie.js'); +//? } + +//////////////////////////////////////////////////////////////////////////////// +// Main //////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Triple Lift Header Tag Bidder module. + * + * @class + */ +function TripleLiftHtb(configs) { + /* TripleLift endpoint only works with AJAX */ + if (!Network.isXhrSupported()) { + //? if (DEBUG) { + Scribe.warn('Partner TripleLift requires AJAX support. Aborting instantiation.'); + //? } + + return null; + } + + /* ===================================== + * Data + * ---------------------------------- */ + + /* Private + * ---------------------------------- */ + + /** + * Reference to the partner base class. + * + * @private {object} + */ + var __baseClass; + + /** + * Profile for this partner. + * + * @private {object} + */ + var __profile; + + /** + * Base url for bid requests. + * + * @private {object} + */ + var __baseUrl; + + /* ===================================== + * Functions + * ---------------------------------- */ + + /* Utilities + * ---------------------------------- */ + + /** + * Generates the request URL to the endpoint for the xSlots in the given + * returnParcels. + * + * @param {object[]} returnParcels + * @return {object} the request object + */ + function __generateRequestObj(returnParcels) { + /* ============================================================================= + * STEP 2 | Generate Request URL + * ----------------------------------------------------------------------------- + * + * Generate the URL to request demand from the partner endpoint using the provided + * returnParcels. The returnParcels is an array of objects each object containing + * an .xSlotRef which is a reference to the xSlot object from the partner configuration. + * Use this to retrieve the placements/xSlots you need to request for. + * + * If your partner is MRA, returnParcels will be an array of length one. If your + * partner is SRA, it will contain any number of entities. In any event, the full + * contents of the array should be able to fit into a single request and the + * return value of this function should similarly represent a single request to the + * endpoint. + * + * Return an object containing: + * queryUrl: the url for the request + * data: the query object containing a map of the query string paramaters + * + * callbackId: + * + * arbitrary id to match the request with the response in the callback function. If + * your endpoint supports passing in an arbitrary ID and returning as part of the response + * please use the callbackType: Partner.CallbackTypes.ID and fill out the adResponseCallback. + * Also please provide this adResponseCallback to your bid request here so that the JSONP + * response calls it once it has completed. + * + * If your endpoint does not support passing in an ID, simply use + * Partner.CallbackTypes.CALLBACK_NAME and the wrapper will take care of handling request + * matching by generating unique callbacks for each request using the callbackId. + * + * If your endpoint is ajax only, please set the appropriate values in your profile for this, + * i.e. Partner.CallbackTypes.NONE and Partner.Requesttypes.AJAX + * + * The return object should look something like this: + * { + * url: 'http://bidserver.com/api/bids' // base request url for a GET/POST request + * data: { // query string object that will be attached to the base url + * slots: [ + * { + * placementId: 54321, + * sizes: [[300, 250]] + * },{ + * placementId: 12345, + * sizes: [[300, 600]] + * },{ + * placementId: 654321, + * sizes: [[728, 90]] + * } + * ], + * site: 'http://google.com' + * }, + * callbackId: '_23sd2ij4i1' //unique id used for pairing requests and responses + * } + */ + + var gdprStatus = ComplianceService.gdpr.getConsent(); + var privacyEnabled = ComplianceService.isPrivacyEnabled(); + + /* MRA partners receive only one parcel in the array. */ + var returnParcel = returnParcels[0]; + var xSlot = returnParcel.xSlotRef; + + /* request params */ + var requestParams = { + inv_code: xSlot.inventoryCode, // jshint ignore:line + lib: 'ix', + fe: Browser.isFlashSupported() ? 1 : 0, + size: Size.arrayToString(xSlot.sizes), + referrer: Browser.getPageUrl(), + v: '2.1' + }; + + if (privacyEnabled) { + requestParams.gdpr = gdprStatus.applies; + requestParams.cmp_cs = gdprStatus.consentString; + } + if (xSlot.floor) { + requestParams.floor = xSlot.floor; + } + + return { + url: __baseUrl, + data: requestParams + }; + } + + /* Helpers + * ---------------------------------- */ + + /* Parse adResponse, put demand into outParcels. + * Triple-Lift response contains a single result object. + */ + function __parseResponse(sessionId, responseObj, returnParcels) { + /* ============================================================================= + * STEP 4 | Parse & store demand response + * ----------------------------------------------------------------------------- + * + * Fill the below variables with information about the bid from the partner, using + * the adResponse variable that contains your module adResponse. + */ + + /* This an array of all the bids in your response that will be iterated over below. Each of + * these will be mapped back to a returnParcel object using some criteria explained below. + * The following variables will also be parsed and attached to that returnParcel object as + * returned demand. + * + * Use the adResponse variable to extract your bid information and insert it into the + * bids array. Each element in the bids array should represent a single bid and should + * match up to a single element from the returnParcel array. + * + */ + + /* ---------- Process adResponse and extract the bids into the bids array ------------*/ + + /* there is only one bid because mra */ + var bid = responseObj; + + /* --------------------------------------------------------------------------------- */ + + /* MRA partners receive only one parcel in the array. */ + var returnParcel = returnParcels[0]; + + /* header stats information */ + var headerStatsInfo = { + sessionId: sessionId, + statsId: __profile.statsId, + htSlotId: returnParcel.htSlot.getId(), + requestId: returnParcel.requestId, + xSlotNames: [returnParcel.xSlotName] + }; + + /* If not a pass */ + if (!bid.status && bid.cpm && bid.cpm > 0) { + if (__profile.enabledAnalytics.requestTime) { + EventsService.emit('hs_slot_bid', headerStatsInfo); + } + + /* ---------- Fill the bid variables with data from the bid response here. ------------*/ + /* Using the above variable, curBid, extract various information about the bid and assign it to + * these local variables */ + + var bidPrice = bid.cpm; /* the bid price for the given slot */ + var bidCreative = bid.ad; /* the creative/adm for the given slot that will be rendered if is the winner. */ + var bidSize = [Number(bid.width), Number(bid.height)]; /* the size of the given slot */ + + /* the dealId if applicable for this slot. */ + var bidDealId = bid.deal_id; // jshint ignore:line + + /* ---------------------------------------------------------------------------------------*/ + + returnParcel.targetingType = 'slot'; + returnParcel.targeting = {}; + returnParcel.size = bidSize; + + var targetingCpm = ''; + + //? if(FEATURES.GPT_LINE_ITEMS) { + targetingCpm = __baseClass._bidTransformers.targeting.apply(bidPrice); + var sizeKey = Size.arrayToString(bidSize); + + if (bidDealId) { + returnParcel.targeting[__baseClass._configs.targetingKeys.pmid] = [bidDealId]; + returnParcel.targeting[__baseClass._configs.targetingKeys.pm] = [sizeKey + '_' + targetingCpm]; + } else { + returnParcel.targeting[__baseClass._configs.targetingKeys.om] = [sizeKey + '_' + targetingCpm]; + } + + returnParcel.targeting[__baseClass._configs.targetingKeys.id] = [returnParcel.requestId]; + //? } + + //? if(FEATURES.RETURN_CREATIVE) { + returnParcel.adm = bidCreative; + //? } + + //? if(FEATURES.RETURN_PRICE) { + returnParcel.price = Number(__baseClass._bidTransformers.price.apply(bidPrice)); + //? } + + var pubKitAdId = RenderService.registerAd({ + sessionId: sessionId, + partnerId: __profile.partnerId, + adm: bidCreative, + requestId: returnParcel.requestId, + size: returnParcel.size, + price: targetingCpm ? targetingCpm : undefined, + dealId: bidDealId ? bidDealId : undefined, + timeOfExpiry: __profile.features.demandExpiry.enabled ? (__profile.features.demandExpiry.value + System.now()) : 0 + }); + + //? if(FEATURES.INTERNAL_RENDER) { + returnParcel.targeting.pubKitAdId = pubKitAdId; + //? } + } else { + //? if (DEBUG) { + Scribe.info(__profile.partnerId + ' no bid response for { id: ' + returnParcel.xSlotRef.inventoryCode + ' }.'); + //? } + + if (__profile.enabledAnalytics.requestTime) { + EventsService.emit('hs_slot_pass', headerStatsInfo); + } + + returnParcel.pass = true; + } + + } + + /* ===================================== + * Constructors + * ---------------------------------- */ + + (function __constructor() { + ComplianceService = SpaceCamp.services.ComplianceService; + EventsService = SpaceCamp.services.EventsService; + RenderService = SpaceCamp.services.RenderService; + + /* ============================================================================= + * STEP 1 | Partner Configuration + * ----------------------------------------------------------------------------- + * + * Please review below partner profile according to the steps in the README doc. + */ + + __profile = { + partnerId: 'TripleLiftHtb', + namespace: 'TripleLiftHtb', + statsId: 'TPL', + version: '2.1.1', + targetingType: 'slot', + enabledAnalytics: { + requestTime: true + }, + features: { + demandExpiry: { + enabled: false, + value: 0 + }, + rateLimiting: { + enabled: false, + value: 0 + } + }, + targetingKeys: { + om: 'ix_tpl_cpm', + pm: 'ix_tpl_cpm', + pmid: 'ix_tpl_dealid', + id: 'ix_tpl_id' + }, + bidUnitInCents: 100, + lineItemType: Constants.LineItemTypes.ID_AND_SIZE, + callbackType: Partner.CallbackTypes.NONE, + architecture: Partner.Architectures.MRA, + requestType: Partner.RequestTypes.AJAX + }; + + /* ---------------------------------------------------------------------------------------*/ + + //? if (DEBUG) { + var results = ConfigValidators.partnerBaseConfig(configs) || PartnerSpecificValidator(configs); + + if (results) { + throw Whoopsie('INVALID_CONFIG', results); + } + //? } + + /* build base bid request url */ + __baseUrl = Browser.getProtocol() + '//tlx.3lift.com/header/auction'; + + __baseClass = Partner(__profile, configs, null, { + parseResponse: __parseResponse, + generateRequestObj: __generateRequestObj + }); + })(); + + /* ===================================== + * Public Interface + * ---------------------------------- */ + + var derivedClass = { + /* Class Information + * ---------------------------------- */ + + //? if (DEBUG) { + __type__: 'TripleLiftHtb', + //? } + + //? if (TEST) { + __baseClass: __baseClass, + //? } + + /* Data + * ---------------------------------- */ + + //? if (TEST) { + __profile: __profile, + __baseUrl: __baseUrl, + //? } + + /* Functions + * ---------------------------------- */ + + //? if (TEST) { + __generateRequestObj: __generateRequestObj, + __parseResponse: __parseResponse + //? } + }; + + return Classify.derive(__baseClass, derivedClass); +} + +//////////////////////////////////////////////////////////////////////////////// +// Exports ///////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +module.exports = TripleLiftHtb; From d803d45d6f748324f9cf3dc5a94b522e3316772b Mon Sep 17 00:00:00 2001 From: David Andersen Date: Thu, 2 Jan 2020 16:17:32 -0500 Subject: [PATCH 02/11] Add tmax query param --- triple-lift/triple-lift-htb-system-tests.js | 2 ++ triple-lift/triple-lift-htb.js | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/triple-lift/triple-lift-htb-system-tests.js b/triple-lift/triple-lift-htb-system-tests.js index 35711466..3242eb8f 100644 --- a/triple-lift/triple-lift-htb-system-tests.js +++ b/triple-lift/triple-lift-htb-system-tests.js @@ -44,6 +44,7 @@ function validateBidRequest(request) { expect(r.cmp_cs).toBe(''); expect(r.gdpr).toBe('false'); expect(r.referrer).toBe(document.URL); + expect(r.tmax).toBe('0'); } function validateBidRequestWithPrivacy(request) { @@ -56,6 +57,7 @@ function validateBidRequestWithPrivacy(request) { expect(r.gdpr).toBe('true'); expect(r.cmp_cs).toBe('TEST_GDPR_CONSENT_STRING'); expect(r.referrer).toBe(document.URL); + expect(r.tmax).toBe('0'); } function getValidResponse(request, creative) { diff --git a/triple-lift/triple-lift-htb.js b/triple-lift/triple-lift-htb.js index 7a90573b..85938998 100644 --- a/triple-lift/triple-lift-htb.js +++ b/triple-lift/triple-lift-htb.js @@ -168,7 +168,8 @@ function TripleLiftHtb(configs) { fe: Browser.isFlashSupported() ? 1 : 0, size: Size.arrayToString(xSlot.sizes), referrer: Browser.getPageUrl(), - v: '2.1' + v: '2.1', + tmax: configs.timeout || 0 }; if (privacyEnabled) { From 5e4efe9b4513318cd661dccc3059ae0705a100c1 Mon Sep 17 00:00:00 2001 From: David Andersen Date: Thu, 2 Jan 2020 16:28:35 -0500 Subject: [PATCH 03/11] Hardcode HTTPS protocol for API request --- triple-lift/triple-lift-htb-system-tests.js | 2 +- triple-lift/triple-lift-htb.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/triple-lift/triple-lift-htb-system-tests.js b/triple-lift/triple-lift-htb-system-tests.js index 3242eb8f..45313edc 100644 --- a/triple-lift/triple-lift-htb-system-tests.js +++ b/triple-lift/triple-lift-htb-system-tests.js @@ -30,7 +30,7 @@ function getConfig() { function getBidRequestRegex() { return { method: 'GET', - urlRegex: /tlx\.3lift\.com\/header\/auction/ + urlRegex: /https:\/\/tlx\.3lift\.com\/header\/auction/ }; } diff --git a/triple-lift/triple-lift-htb.js b/triple-lift/triple-lift-htb.js index 85938998..8ab9ef90 100644 --- a/triple-lift/triple-lift-htb.js +++ b/triple-lift/triple-lift-htb.js @@ -365,7 +365,7 @@ function TripleLiftHtb(configs) { //? } /* build base bid request url */ - __baseUrl = Browser.getProtocol() + '//tlx.3lift.com/header/auction'; + __baseUrl = 'https://tlx.3lift.com/header/auction'; __baseClass = Partner(__profile, configs, null, { parseResponse: __parseResponse, From 4076aa40a3423b61b0af5aa6b4bcf67f9ef58110 Mon Sep 17 00:00:00 2001 From: David Andersen Date: Thu, 2 Jan 2020 16:42:39 -0500 Subject: [PATCH 04/11] Add CCPA query param --- triple-lift/triple-lift-htb.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/triple-lift/triple-lift-htb.js b/triple-lift/triple-lift-htb.js index 8ab9ef90..22acc86d 100644 --- a/triple-lift/triple-lift-htb.js +++ b/triple-lift/triple-lift-htb.js @@ -156,6 +156,7 @@ function TripleLiftHtb(configs) { var gdprStatus = ComplianceService.gdpr.getConsent(); var privacyEnabled = ComplianceService.isPrivacyEnabled(); + var uspConsent = ComplianceService.usp && ComplianceService.usp.getConsent(); /* MRA partners receive only one parcel in the array. */ var returnParcel = returnParcels[0]; @@ -175,6 +176,10 @@ function TripleLiftHtb(configs) { if (privacyEnabled) { requestParams.gdpr = gdprStatus.applies; requestParams.cmp_cs = gdprStatus.consentString; + + if (uspConsent) { + requestParams.us_privacy = uspConsent.uspString; + } } if (xSlot.floor) { requestParams.floor = xSlot.floor; From 3f4ba06be7636f5c2971aafb2b0ad5d63d339560 Mon Sep 17 00:00:00 2001 From: David Andersen Date: Thu, 2 Jan 2020 16:50:39 -0500 Subject: [PATCH 05/11] Update adapter version --- triple-lift/CHANGES.md | 4 ++++ triple-lift/triple-lift-htb.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/triple-lift/CHANGES.md b/triple-lift/CHANGES.md index e69de29b..39c1b001 100644 --- a/triple-lift/CHANGES.md +++ b/triple-lift/CHANGES.md @@ -0,0 +1,4 @@ +# 2.1.2 +- Added tmax support +- Added CCPA support +- Hardcoded HTTPS protocol for API endpoint diff --git a/triple-lift/triple-lift-htb.js b/triple-lift/triple-lift-htb.js index 22acc86d..b21aed87 100644 --- a/triple-lift/triple-lift-htb.js +++ b/triple-lift/triple-lift-htb.js @@ -331,7 +331,7 @@ function TripleLiftHtb(configs) { partnerId: 'TripleLiftHtb', namespace: 'TripleLiftHtb', statsId: 'TPL', - version: '2.1.1', + version: '2.1.2', targetingType: 'slot', enabledAnalytics: { requestTime: true From 0e5b78ab4d6fb3ee85c3df838f166412b64d1c80 Mon Sep 17 00:00:00 2001 From: David Andersen Date: Thu, 9 Jan 2020 15:40:22 -0500 Subject: [PATCH 06/11] Consolidate version information --- triple-lift/triple-lift-htb-system-tests.js | 4 ++-- triple-lift/triple-lift-htb.js | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/triple-lift/triple-lift-htb-system-tests.js b/triple-lift/triple-lift-htb-system-tests.js index 45313edc..09ca4a0c 100644 --- a/triple-lift/triple-lift-htb-system-tests.js +++ b/triple-lift/triple-lift-htb-system-tests.js @@ -36,7 +36,7 @@ function getBidRequestRegex() { function validateBidRequest(request) { var r = request.query; - expect(r.v).toBe('2.1'); + expect(r.v).toBe('2.1.2'); expect(r.lib).toBe('ix'); expect(r.inv_code).toBe('test'); expect(r.size).toBe('300x250'); @@ -49,7 +49,7 @@ function validateBidRequest(request) { function validateBidRequestWithPrivacy(request) { var r = request.query; - expect(r.v).toBe('2.1'); + expect(r.v).toBe('2.1.2'); expect(r.lib).toBe('ix'); expect(r.inv_code).toBe('test'); expect(r.size).toBe('300x250'); diff --git a/triple-lift/triple-lift-htb.js b/triple-lift/triple-lift-htb.js index b21aed87..d61ca3f3 100644 --- a/triple-lift/triple-lift-htb.js +++ b/triple-lift/triple-lift-htb.js @@ -40,6 +40,8 @@ var Whoopsie = require('whoopsie.js'); // Main //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// +var CURRENT_VERSION = '2.1.2'; + /** * Triple Lift Header Tag Bidder module. * @@ -169,7 +171,7 @@ function TripleLiftHtb(configs) { fe: Browser.isFlashSupported() ? 1 : 0, size: Size.arrayToString(xSlot.sizes), referrer: Browser.getPageUrl(), - v: '2.1', + v: CURRENT_VERSION, tmax: configs.timeout || 0 }; @@ -331,7 +333,7 @@ function TripleLiftHtb(configs) { partnerId: 'TripleLiftHtb', namespace: 'TripleLiftHtb', statsId: 'TPL', - version: '2.1.2', + version: CURRENT_VERSION, targetingType: 'slot', enabledAnalytics: { requestTime: true From 0ac6a101271de3e424fad255b013984df0e3980c Mon Sep 17 00:00:00 2001 From: David Andersen Date: Thu, 9 Jan 2020 15:44:26 -0500 Subject: [PATCH 07/11] Remove obsolete query param --- triple-lift/triple-lift-htb-system-tests.js | 2 -- triple-lift/triple-lift-htb.js | 1 - 2 files changed, 3 deletions(-) diff --git a/triple-lift/triple-lift-htb-system-tests.js b/triple-lift/triple-lift-htb-system-tests.js index 09ca4a0c..2fe958f4 100644 --- a/triple-lift/triple-lift-htb-system-tests.js +++ b/triple-lift/triple-lift-htb-system-tests.js @@ -40,7 +40,6 @@ function validateBidRequest(request) { expect(r.lib).toBe('ix'); expect(r.inv_code).toBe('test'); expect(r.size).toBe('300x250'); - expect(r.fe).toBe('0'); expect(r.cmp_cs).toBe(''); expect(r.gdpr).toBe('false'); expect(r.referrer).toBe(document.URL); @@ -53,7 +52,6 @@ function validateBidRequestWithPrivacy(request) { expect(r.lib).toBe('ix'); expect(r.inv_code).toBe('test'); expect(r.size).toBe('300x250'); - expect(r.fe).toBe('0'); expect(r.gdpr).toBe('true'); expect(r.cmp_cs).toBe('TEST_GDPR_CONSENT_STRING'); expect(r.referrer).toBe(document.URL); diff --git a/triple-lift/triple-lift-htb.js b/triple-lift/triple-lift-htb.js index d61ca3f3..8fcb6c49 100644 --- a/triple-lift/triple-lift-htb.js +++ b/triple-lift/triple-lift-htb.js @@ -168,7 +168,6 @@ function TripleLiftHtb(configs) { var requestParams = { inv_code: xSlot.inventoryCode, // jshint ignore:line lib: 'ix', - fe: Browser.isFlashSupported() ? 1 : 0, size: Size.arrayToString(xSlot.sizes), referrer: Browser.getPageUrl(), v: CURRENT_VERSION, From 843c8f40478199123fe8fca249527691dce59cdf Mon Sep 17 00:00:00 2001 From: David Andersen Date: Thu, 9 Jan 2020 16:46:35 -0500 Subject: [PATCH 08/11] Add documentation --- triple-lift/DOCUMENTATION.md | 76 ++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/triple-lift/DOCUMENTATION.md b/triple-lift/DOCUMENTATION.md index d2178611..85f7e6de 100644 --- a/triple-lift/DOCUMENTATION.md +++ b/triple-lift/DOCUMENTATION.md @@ -2,38 +2,38 @@ ## General Compatibility |Feature| | |---|---| -| Consent | | -| Native Ad Support | | -| SafeFrame Support | | -| PMP Support | | +| Consent | yes | +| Native Ad Support | No | +| SafeFrame Support | No | +| PMP Support | yes | ## Browser Compatibility | Browser | | |--- |---| -| Chrome | | -| Edge | | -| Firefox | | -| Internet Explorer 9 | | -| Internet Explorer 10 | | -| Internet Explorer 11 | | -| Safari | | -| Mobile Chrome | | -| Mobile Safari | | -| UC Browser | | -| Samsung Internet | | -| Opera | | +| Chrome | yes | +| Edge | yes | +| Firefox | yes | +| Internet Explorer 9 | yes | +| Internet Explorer 10 | yes | +| Internet Explorer 11 | yes | +| Safari | yes | +| Mobile Chrome | yes | +| Mobile Safari | yes | +| UC Browser | yes | +| Samsung Internet | yes | +| Opera | yes | ## Adapter Information | Info | | |---|---| | Partner Id | TripleLiftHtb | -| Ad Server Responds in (Cents, Dollars, etc) | | -| Bid Type (Gross / Net) | | -| GAM Key (Open Market) | | -| GAM Key (Private Market) | | -| Ad Server URLs | | -| Slot Mapping Sytle (Size / Multiple Sizes / Slot) | | -| Request Architecture (MRA / SRA) | | +| Ad Server Responds in (Cents, Dollars, etc) | cents | +| Bid Type (Gross / Net) | net | +| GAM Key (Open Market) | ix_tpl_cpm | +| GAM Key (Private Market) | ix_tpl_cpm | +| Ad Server URLs | https://tlx.3lift.com/header/auction | +| Slot Mapping Style (Size / Multiple Sizes / Slot) | slot | +| Request Architecture (MRA / SRA) | MRA | ## Currencies Supported @@ -41,29 +41,45 @@ ### Parameters | Key | Required | Type | Description | |---|---|---|---| -| | | | | +| inv_code | true | string | supply inventory code | +| lib | true | string | supply source ("ix") | +| size | true | string | supply dimensions (e.g. "300x250") | +| referrer | true | string | document referrer URL | +| v | true | number | adapter version number | ### Example -```javascript - +``` +HTTP GET https://tlx.3lift.com/header/auction?inv_code=DailyBeast_ROS_Desktop_728x90&lib=ix&fe=0&size=728x90&referrer=https%3A%2F%2Fwww.thedailybeast.com%2Fukrainian-plane-crash-in-iran-raises-issue-of-flaw-in-another-boeing-737-model%3Fref%3Dwrap&v=2.1 ``` ## Bid Response Information ### Bid Example ```javascript - +{ + "ad": "[HTML AD MARKUP]", + "cpm": 3.651, + "crid": "3335_18160_T4915441", + "height": 250, + "imp_id": "1", + "tl_source": "tlx", + "width": 300 +} ``` ### Pass Example ```javascript - + {"status":"no_bid"} ``` ## Configuration Information ### Configuration Keys | Key | Required | Type | Description | |---|---|---|---| -| | | | | +| inventoryCode | yes | string | placement identifier | +| sizes | yes | array | ad slot dimensions | ### Example ```javascript - +{ + "inventoryCode": "DailyBeast_ROS_Desktop_300x250", + "sizes": [[300, 250]] +} ``` From 1fda9e16fd35d996dea45e469ba6152736243e10 Mon Sep 17 00:00:00 2001 From: David Andersen Date: Thu, 9 Jan 2020 16:48:36 -0500 Subject: [PATCH 09/11] Correct formatting --- triple-lift/DOCUMENTATION.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/triple-lift/DOCUMENTATION.md b/triple-lift/DOCUMENTATION.md index 85f7e6de..97129f11 100644 --- a/triple-lift/DOCUMENTATION.md +++ b/triple-lift/DOCUMENTATION.md @@ -3,8 +3,8 @@ |Feature| | |---|---| | Consent | yes | -| Native Ad Support | No | -| SafeFrame Support | No | +| Native Ad Support | no | +| SafeFrame Support | no | | PMP Support | yes | ## Browser Compatibility From b92f73784ad5c1960c4d9fe75bb82090f8b7141e Mon Sep 17 00:00:00 2001 From: David Andersen Date: Wed, 15 Jan 2020 17:55:23 -0500 Subject: [PATCH 10/11] Enable linter and fix errors --- .eslintignore | 1 - triple-lift/triple-lift-htb-validator.js | 6 +- triple-lift/triple-lift-htb.js | 71 +++++++++++++++--------- 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/.eslintignore b/.eslintignore index 3642ec6c..2d81151e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -6,4 +6,3 @@ just-premium/ kargo/ rtk/ share-through/ -triple-lift/ diff --git a/triple-lift/triple-lift-htb-validator.js b/triple-lift/triple-lift-htb-validator.js index 8e99a99e..56683d2a 100644 --- a/triple-lift/triple-lift-htb-validator.js +++ b/triple-lift/triple-lift-htb-validator.js @@ -32,7 +32,7 @@ var Inspector = require('../../../libs/external/schema-inspector.js'); * https://atinux.fr/schema-inspector/. */ -var partnerValidator = function (configs) { +function partnerValidator(configs) { var result = Inspector.validate({ type: 'object', properties: { @@ -52,7 +52,7 @@ var partnerValidator = function (configs) { type: 'array', exactLength: 2, items: { - type: 'integer', + type: 'integer' } } }, @@ -73,6 +73,6 @@ var partnerValidator = function (configs) { } return null; -}; +} module.exports = partnerValidator; diff --git a/triple-lift/triple-lift-htb.js b/triple-lift/triple-lift-htb.js index 8fcb6c49..60fd478b 100644 --- a/triple-lift/triple-lift-htb.js +++ b/triple-lift/triple-lift-htb.js @@ -164,9 +164,9 @@ function TripleLiftHtb(configs) { var returnParcel = returnParcels[0]; var xSlot = returnParcel.xSlotRef; - /* request params */ + /* Request params */ var requestParams = { - inv_code: xSlot.inventoryCode, // jshint ignore:line + inv_code: xSlot.inventoryCode, // eslint-disable-line camelcase lib: 'ix', size: Size.arrayToString(xSlot.sizes), referrer: Browser.getPageUrl(), @@ -175,13 +175,14 @@ function TripleLiftHtb(configs) { }; if (privacyEnabled) { - requestParams.gdpr = gdprStatus.applies; - requestParams.cmp_cs = gdprStatus.consentString; + requestParams.gdpr = gdprStatus.applies; + requestParams.cmp_cs = gdprStatus.consentString; // eslint-disable-line camelcase - if (uspConsent) { - requestParams.us_privacy = uspConsent.uspString; - } + if (uspConsent) { + requestParams.us_privacy = uspConsent.uspString; // eslint-disable-line camelcase + } } + if (xSlot.floor) { requestParams.floor = xSlot.floor; } @@ -218,9 +219,9 @@ function TripleLiftHtb(configs) { * */ - /* ---------- Process adResponse and extract the bids into the bids array ------------*/ + /* ---------- Process adResponse and extract the bids into the bids array ------------ */ - /* there is only one bid because mra */ + /* There is only one bid because mra */ var bid = responseObj; /* --------------------------------------------------------------------------------- */ @@ -228,7 +229,7 @@ function TripleLiftHtb(configs) { /* MRA partners receive only one parcel in the array. */ var returnParcel = returnParcels[0]; - /* header stats information */ + /* Header stats information */ var headerStatsInfo = { sessionId: sessionId, statsId: __profile.statsId, @@ -243,18 +244,23 @@ function TripleLiftHtb(configs) { EventsService.emit('hs_slot_bid', headerStatsInfo); } - /* ---------- Fill the bid variables with data from the bid response here. ------------*/ + /* ---------- Fill the bid variables with data from the bid response here. ------------ */ /* Using the above variable, curBid, extract various information about the bid and assign it to * these local variables */ - var bidPrice = bid.cpm; /* the bid price for the given slot */ - var bidCreative = bid.ad; /* the creative/adm for the given slot that will be rendered if is the winner. */ - var bidSize = [Number(bid.width), Number(bid.height)]; /* the size of the given slot */ + /* The bid price for the given slot */ + var bidPrice = bid.cpm; + + /* The creative/adm for the given slot that will be rendered if it is the winner */ + var bidCreative = bid.ad; + + /* The size of the given slot */ + var bidSize = [Number(bid.width), Number(bid.height)]; - /* the dealId if applicable for this slot. */ - var bidDealId = bid.deal_id; // jshint ignore:line + /* The dealId if applicable for this slot. */ + var bidDealId = bid.deal_id; - /* ---------------------------------------------------------------------------------------*/ + /* --------------------------------------------------------------------------------------- */ returnParcel.targetingType = 'slot'; returnParcel.targeting = {}; @@ -284,23 +290,35 @@ function TripleLiftHtb(configs) { returnParcel.price = Number(__baseClass._bidTransformers.price.apply(bidPrice)); //? } - var pubKitAdId = RenderService.registerAd({ + var demandExpiryEnabled = __profile.features.demandExpiry.enabled; + + var adConfig = { sessionId: sessionId, partnerId: __profile.partnerId, adm: bidCreative, requestId: returnParcel.requestId, size: returnParcel.size, - price: targetingCpm ? targetingCpm : undefined, - dealId: bidDealId ? bidDealId : undefined, - timeOfExpiry: __profile.features.demandExpiry.enabled ? (__profile.features.demandExpiry.value + System.now()) : 0 - }); + timeOfExpiry: demandExpiryEnabled ? __profile.features.demandExpiry.value + System.now() : 0 + }; + + if (targetingCpm) { + adConfig.price = targetingCpm; + } + + if (bidDealId) { + adConfig.dealId = bidDealId; + } + + var pubKitAdId = RenderService.registerAd(adConfig); //? if(FEATURES.INTERNAL_RENDER) { returnParcel.targeting.pubKitAdId = pubKitAdId; //? } } else { //? if (DEBUG) { - Scribe.info(__profile.partnerId + ' no bid response for { id: ' + returnParcel.xSlotRef.inventoryCode + ' }.'); + var partnerId = __profile.partnerId; + var invCode = returnParcel.xSlotRef.inventoryCode; + Scribe.info(partnerId + ' no bid response for { id: ' + invCode + ' }.'); //? } if (__profile.enabledAnalytics.requestTime) { @@ -309,7 +327,6 @@ function TripleLiftHtb(configs) { returnParcel.pass = true; } - } /* ===================================== @@ -360,7 +377,7 @@ function TripleLiftHtb(configs) { requestType: Partner.RequestTypes.AJAX }; - /* ---------------------------------------------------------------------------------------*/ + /* --------------------------------------------------------------------------------------- */ //? if (DEBUG) { var results = ConfigValidators.partnerBaseConfig(configs) || PartnerSpecificValidator(configs); @@ -370,7 +387,7 @@ function TripleLiftHtb(configs) { } //? } - /* build base bid request url */ + /* Build base bid request url */ __baseUrl = 'https://tlx.3lift.com/header/auction'; __baseClass = Partner(__profile, configs, null, { @@ -409,7 +426,7 @@ function TripleLiftHtb(configs) { //? if (TEST) { __generateRequestObj: __generateRequestObj, __parseResponse: __parseResponse - //? } + //? } }; return Classify.derive(__baseClass, derivedClass); From bb7fd099c8767157e8b7958673d687489f205644 Mon Sep 17 00:00:00 2001 From: David Andersen Date: Fri, 17 Jan 2020 11:19:30 -0500 Subject: [PATCH 11/11] Update timeout value --- triple-lift/triple-lift-htb-system-tests.js | 4 ++-- triple-lift/triple-lift-htb.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/triple-lift/triple-lift-htb-system-tests.js b/triple-lift/triple-lift-htb-system-tests.js index 2fe958f4..cd3d42c1 100644 --- a/triple-lift/triple-lift-htb-system-tests.js +++ b/triple-lift/triple-lift-htb-system-tests.js @@ -43,7 +43,7 @@ function validateBidRequest(request) { expect(r.cmp_cs).toBe(''); expect(r.gdpr).toBe('false'); expect(r.referrer).toBe(document.URL); - expect(r.tmax).toBe('0'); + expect(r.tmax).toBe('100000'); } function validateBidRequestWithPrivacy(request) { @@ -55,7 +55,7 @@ function validateBidRequestWithPrivacy(request) { expect(r.gdpr).toBe('true'); expect(r.cmp_cs).toBe('TEST_GDPR_CONSENT_STRING'); expect(r.referrer).toBe(document.URL); - expect(r.tmax).toBe('0'); + expect(r.tmax).toBe('100000'); } function getValidResponse(request, creative) { diff --git a/triple-lift/triple-lift-htb.js b/triple-lift/triple-lift-htb.js index 60fd478b..e92d545b 100644 --- a/triple-lift/triple-lift-htb.js +++ b/triple-lift/triple-lift-htb.js @@ -171,7 +171,7 @@ function TripleLiftHtb(configs) { size: Size.arrayToString(xSlot.sizes), referrer: Browser.getPageUrl(), v: CURRENT_VERSION, - tmax: configs.timeout || 0 + tmax: SpaceCamp.globalTimeout || 0 }; if (privacyEnabled) {