From 1c6318e8352f55869714493217d570d2f08b6b1a Mon Sep 17 00:00:00 2001 From: Luca Corbo Date: Thu, 14 Nov 2024 15:36:55 +0100 Subject: [PATCH 1/6] WURFL RTD Module: enrich the ortb2.device object with WURFL data (#12442) This commit updates the WURFL RTD Module to enrich the ortb2.device object with WURFL data. --- modules/wurflRtdProvider.js | 84 +++++++- test/spec/modules/wurflRtdProvider_spec.js | 237 ++++++++++++++++----- 2 files changed, 261 insertions(+), 60 deletions(-) diff --git a/modules/wurflRtdProvider.js b/modules/wurflRtdProvider.js index f019d2dbe52..dbf50744d25 100644 --- a/modules/wurflRtdProvider.js +++ b/modules/wurflRtdProvider.js @@ -101,13 +101,12 @@ function enrichBidderRequests(reqBidsConfigObj, bidders, wjsResponse) { // inject WURFL data enrichedBidders.add(bidderCode); const data = bidderData(wjsResponse.WURFL, caps, authBidders[bidderCode]); - logger.logMessage(`injecting data for ${bidderCode}: `, data); + data['enrich_device'] = true; enrichBidderRequest(reqBidsConfigObj, bidderCode, data); return; } // inject WURFL low entropy data const data = lowEntropyData(wjsResponse.WURFL, wjsResponse.wurfl_pbjs?.low_entropy_caps); - logger.logMessage(`injecting low entropy data for ${bidderCode}: `, data); enrichBidderRequest(reqBidsConfigObj, bidderCode, data); }); } @@ -147,9 +146,14 @@ export const lowEntropyData = (wurflData, lowEntropyCaps) => { } data[cap] = value; }); + if ('model_name' in wurflData) { + data['model_name'] = wurflData.model_name.replace(/(iP(hone|ad|od)).*/, 'iP$2'); + } + if ('brand_name' in wurflData) { + data['brand_name'] = wurflData.brand_name; + } return data; } - /** * enrichBidderRequest enriches the bidder request with WURFL data * @param {Object} reqBidsConfigObj Bid request configuration object @@ -159,14 +163,82 @@ export const lowEntropyData = (wurflData, lowEntropyCaps) => { export const enrichBidderRequest = (reqBidsConfigObj, bidderCode, wurflData) => { const ortb2data = { 'device': { - 'ext': { - 'wurfl': wurflData, - } + 'ext': {}, }, }; + + const device = reqBidsConfigObj.ortb2Fragments.global.device; + enrichOrtb2DeviceData('make', wurflData.brand_name, device, ortb2data); + enrichOrtb2DeviceData('model', wurflData.model_name, device, ortb2data); + if (wurflData.enrich_device) { + delete wurflData.enrich_device; + enrichOrtb2DeviceData('devicetype', makeOrtb2DeviceType(wurflData), device, ortb2data); + enrichOrtb2DeviceData('os', wurflData.advertised_device_os, device, ortb2data); + enrichOrtb2DeviceData('osv', wurflData.advertised_device_os_version, device, ortb2data); + enrichOrtb2DeviceData('hwv', wurflData.model_name, device, ortb2data); + enrichOrtb2DeviceData('h', wurflData.resolution_height, device, ortb2data); + enrichOrtb2DeviceData('w', wurflData.resolution_width, device, ortb2data); + enrichOrtb2DeviceData('ppi', wurflData.pixel_density, device, ortb2data); + enrichOrtb2DeviceData('pxratio', wurflData.density_class, device, ortb2data); + enrichOrtb2DeviceData('js', wurflData.ajax_support_javascript, device, ortb2data); + } + ortb2data.device.ext['wurfl'] = wurflData mergeDeep(reqBidsConfigObj.ortb2Fragments.bidder, { [bidderCode]: ortb2data }); } +/** + * makeOrtb2DeviceType returns the ortb2 device type based on WURFL data + * @param {Object} wurflData WURFL data + * @returns {Number} ortb2 device type + * @see https://www.scientiamobile.com/how-to-populate-iab-openrtb-device-object/ + */ +export function makeOrtb2DeviceType(wurflData) { + if (wurflData.is_mobile) { + if (!('is_phone' in wurflData) || !('is_tablet' in wurflData)) { + return undefined; + } + if (wurflData.is_phone || wurflData.is_tablet) { + return 1; + } + return 6; + } + if (wurflData.is_full_desktop) { + return 2; + } + if (wurflData.is_connected_tv) { + return 3; + } + if (wurflData.is_phone) { + return 4; + } + if (wurflData.is_tablet) { + return 5; + } + if (wurflData.is_ott) { + return 7; + } + return undefined; +} + +/** + * enrichOrtb2DeviceData enriches the ortb2data device data with WURFL data. + * Note: it does not overrides properties set by Prebid.js + * @param {String} key the device property key + * @param {any} value the value of the device property + * @param {Object} device the ortb2 device object from Prebid.js + * @param {Object} ortb2data the ortb2 device data enrchiced with WURFL data + */ +function enrichOrtb2DeviceData(key, value, device, ortb2data) { + if (device?.[key] !== undefined) { + // value already defined by Prebid.js, do not overrides + return; + } + if (value === undefined) { + return; + } + ortb2data.device[key] = value; +} + /** * onAuctionEndEvent is called when the auction ends * @param {Object} auctionDetails Auction details diff --git a/test/spec/modules/wurflRtdProvider_spec.js b/test/spec/modules/wurflRtdProvider_spec.js index 434abfc4e22..0ac324ef8b2 100644 --- a/test/spec/modules/wurflRtdProvider_spec.js +++ b/test/spec/modules/wurflRtdProvider_spec.js @@ -3,6 +3,7 @@ import { enrichBidderRequest, lowEntropyData, wurflSubmodule, + makeOrtb2DeviceType, } from 'modules/wurflRtdProvider'; import * as ajaxModule from 'src/ajax'; import { loadExternalScriptStub } from 'test/mocks/adloaderStub.js'; @@ -10,50 +11,49 @@ import { loadExternalScriptStub } from 'test/mocks/adloaderStub.js'; describe('wurflRtdProvider', function () { describe('wurflSubmodule', function () { const altHost = 'http://example.local/wurfl.js'; + const wurfl_pbjs = { - low_entropy_caps: ['complete_device_name', 'form_factor', 'is_mobile'], - caps: [ - 'advertised_browser', - 'advertised_browser_version', - 'advertised_device_os', - 'advertised_device_os_version', - 'brand_name', - 'complete_device_name', - 'form_factor', - 'is_app_webview', - 'is_full_desktop', - 'is_mobile', - 'is_robot', - 'is_smartphone', - 'is_smarttv', - 'is_tablet', - 'manufacturer_name', - 'marketing_name' - ], + low_entropy_caps: ['is_mobile', 'complete_device_name', 'form_factor'], + caps: ['advertised_browser', 'advertised_browser_version', 'advertised_device_os', 'advertised_device_os_version', 'ajax_support_javascript', 'brand_name', 'complete_device_name', 'density_class', 'form_factor', 'is_android', 'is_app_webview', 'is_connected_tv', 'is_full_desktop', 'is_ios', 'is_mobile', 'is_ott', 'is_phone', 'is_robot', 'is_smartphone', 'is_smarttv', 'is_tablet', 'manufacturer_name', 'marketing_name', 'max_image_height', 'max_image_width', 'model_name', 'physical_screen_height', 'physical_screen_width', 'pixel_density', 'pointing_method', 'resolution_height', 'resolution_width'], authorized_bidders: { - 'bidder1': [0, 1, 2, 3, 4, 5, 6, 7, 10, 13, 15], - 'bidder2': [5, 6, 7, 8, 9, 10, 11, 12, 13, 14], + bidder1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], + bidder2: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 21, 25, 28, 30, 31] } } - const WURFL = { - advertised_browser: 'Chrome', - advertised_browser_version: '125.0.6422.76', - advertised_device_os: 'Linux', - advertised_device_os_version: '6.5.0', + advertised_browser: 'Chrome Mobile', + advertised_browser_version: '130.0.0.0', + advertised_device_os: 'Android', + advertised_device_os_version: '6.0', + ajax_support_javascript: !0, brand_name: 'Google', - complete_device_name: 'Google Chrome', - form_factor: 'Desktop', + complete_device_name: 'Google Nexus 5', + density_class: '3.0', + form_factor: 'Feature Phone', + is_android: !0, is_app_webview: !1, - is_full_desktop: !0, - is_mobile: !1, + is_connected_tv: !1, + is_full_desktop: !1, + is_ios: !1, + is_mobile: !0, + is_ott: !1, + is_phone: !0, is_robot: !1, is_smartphone: !1, is_smarttv: !1, is_tablet: !1, - manufacturer_name: '', + manufacturer_name: 'LG', marketing_name: '', - } + max_image_height: 640, + max_image_width: 360, + model_name: 'Nexus 5', + physical_screen_height: 110, + physical_screen_width: 62, + pixel_density: 443, + pointing_method: 'touchscreen', + resolution_height: 1920, + resolution_width: 1080 + }; // expected analytics values const expectedStatsURL = 'https://prebid.wurflcloud.com/v1/prebid/stats'; @@ -61,11 +61,11 @@ describe('wurflRtdProvider', function () { let sandbox; - beforeEach(function() { + beforeEach(function () { sandbox = sinon.createSandbox(); window.WURFLPromises = { - init: new Promise(function(resolve, reject) { resolve({ WURFL, wurfl_pbjs }) }), - complete: new Promise(function(resolve, reject) { resolve({ WURFL, wurfl_pbjs }) }), + init: new Promise(function (resolve, reject) { resolve({ WURFL, wurfl_pbjs }) }), + complete: new Promise(function (resolve, reject) { resolve({ WURFL, wurfl_pbjs }) }), }; }); @@ -85,6 +85,9 @@ describe('wurflRtdProvider', function () { ] }], ortb2Fragments: { + global: { + device: {}, + }, bidder: {}, } }; @@ -99,56 +102,113 @@ describe('wurflRtdProvider', function () { expectedURL.searchParams.set('mode', 'prebid'); const callback = () => { - expect(reqBidsConfigObj.ortb2Fragments.bidder).to.deep.equal({ + const v = { bidder1: { device: { + make: 'Google', + model: 'Nexus 5', + devicetype: 1, + os: 'Android', + osv: '6.0', + hwv: 'Nexus 5', + h: 1920, + w: 1080, + ppi: 443, + pxratio: '3.0', + js: true, ext: { wurfl: { - advertised_browser: 'Chrome', - advertised_browser_version: '125.0.6422.76', - advertised_device_os: 'Linux', - advertised_device_os_version: '6.5.0', + advertised_browser: 'Chrome Mobile', + advertised_browser_version: '130.0.0.0', + advertised_device_os: 'Android', + advertised_device_os_version: '6.0', + ajax_support_javascript: !0, brand_name: 'Google', - complete_device_name: 'Google Chrome', - form_factor: 'Desktop', + complete_device_name: 'Google Nexus 5', + density_class: '3.0', + form_factor: 'Feature Phone', is_app_webview: !1, + is_connected_tv: !1, + is_full_desktop: !1, + is_mobile: !0, + is_ott: !1, + is_phone: !0, is_robot: !1, + is_smartphone: !1, + is_smarttv: !1, is_tablet: !1, + manufacturer_name: 'LG', marketing_name: '', + max_image_height: 640, + max_image_width: 360, + model_name: 'Nexus 5', + physical_screen_height: 110, + physical_screen_width: 62, + pixel_density: 443, + pointing_method: 'touchscreen', + resolution_height: 1920, + resolution_width: 1080 }, }, }, }, bidder2: { device: { + make: 'Google', + model: 'Nexus 5', + devicetype: 1, + os: 'Android', + osv: '6.0', + hwv: 'Nexus 5', + h: 1920, + w: 1080, + ppi: 443, + pxratio: '3.0', + js: true, ext: { wurfl: { - complete_device_name: 'Google Chrome', - form_factor: 'Desktop', + advertised_device_os: 'Android', + advertised_device_os_version: '6.0', + ajax_support_javascript: !0, + brand_name: 'Google', + complete_device_name: 'Google Nexus 5', + density_class: '3.0', + form_factor: 'Feature Phone', + is_android: !0, is_app_webview: !1, - is_full_desktop: !0, - is_mobile: !1, - is_robot: !1, - is_smartphone: !1, - is_smarttv: !1, + is_connected_tv: !1, + is_full_desktop: !1, + is_ios: !1, + is_mobile: !0, + is_ott: !1, + is_phone: !0, is_tablet: !1, - manufacturer_name: '', + manufacturer_name: 'LG', + model_name: 'Nexus 5', + pixel_density: 443, + resolution_height: 1920, + resolution_width: 1080 }, }, }, }, bidder3: { device: { + make: 'Google', + model: 'Nexus 5', ext: { wurfl: { - complete_device_name: 'Google Chrome', - form_factor: 'Desktop', - is_mobile: !1, + complete_device_name: 'Google Nexus 5', + form_factor: 'Feature Phone', + is_mobile: !0, + model_name: 'Nexus 5', + brand_name: 'Google', }, }, }, }, - }); + }; + expect(reqBidsConfigObj.ortb2Fragments.bidder).to.deep.equal(v); done(); }; @@ -245,12 +305,16 @@ describe('wurflRtdProvider', function () { complete_device_name: 'Apple iPhone X', form_factor: 'Smartphone', is_mobile: !0, + brand_name: 'Apple', + model_name: 'iPhone X', }; const lowEntropyCaps = ['complete_device_name', 'form_factor', 'is_mobile']; const expectedData = { complete_device_name: 'Apple iPhone', form_factor: 'Smartphone', is_mobile: !0, + brand_name: 'Apple', + model_name: 'iPhone', }; const result = lowEntropyData(wjsData, lowEntropyCaps); expect(result).to.deep.equal(expectedData); @@ -289,6 +353,9 @@ describe('wurflRtdProvider', function () { it('should enrich the bidder request with WURFL data', () => { const reqBidsConfigObj = { ortb2Fragments: { + global: { + device: {}, + }, bidder: { exampleBidder: { device: { @@ -321,4 +388,66 @@ describe('wurflRtdProvider', function () { }); }); }); + + describe('makeOrtb2DeviceType', function () { + it('should return 1 when wurflData is_mobile and is_phone is true', function () { + const wurflData = { is_mobile: true, is_phone: true, is_tablet: false }; + const result = makeOrtb2DeviceType(wurflData); + expect(result).to.equal(1); + }); + + it('should return 1 when wurflData is_mobile and is_tablet is true', function () { + const wurflData = { is_mobile: true, is_phone: false, is_tablet: true }; + const result = makeOrtb2DeviceType(wurflData); + expect(result).to.equal(1); + }); + + it('should return 6 when wurflData is_mobile but is_phone and is_tablet are false', function () { + const wurflData = { is_mobile: true, is_phone: false, is_tablet: false }; + const result = makeOrtb2DeviceType(wurflData); + expect(result).to.equal(6); + }); + + it('should return 2 when wurflData is_full_desktop is true', function () { + const wurflData = { is_full_desktop: true }; + const result = makeOrtb2DeviceType(wurflData); + expect(result).to.equal(2); + }); + + it('should return 3 when wurflData is_connected_tv is true', function () { + const wurflData = { is_connected_tv: true }; + const result = makeOrtb2DeviceType(wurflData); + expect(result).to.equal(3); + }); + + it('should return 4 when wurflData is_phone is true and is_mobile is false or undefined', function () { + const wurflData = { is_phone: true }; + const result = makeOrtb2DeviceType(wurflData); + expect(result).to.equal(4); + }); + + it('should return 5 when wurflData is_tablet is true and is_mobile is false or undefined', function () { + const wurflData = { is_tablet: true }; + const result = makeOrtb2DeviceType(wurflData); + expect(result).to.equal(5); + }); + + it('should return 7 when wurflData is_ott is true', function () { + const wurflData = { is_ott: true }; + const result = makeOrtb2DeviceType(wurflData); + expect(result).to.equal(7); + }); + + it('should return undefined when wurflData is_mobile is true but is_phone and is_tablet are missing', function () { + const wurflData = { is_mobile: true }; + const result = makeOrtb2DeviceType(wurflData); + expect(result).to.be.undefined; + }); + + it('should return undefined when no conditions are met', function () { + const wurflData = {}; + const result = makeOrtb2DeviceType(wurflData); + expect(result).to.be.undefined; + }); + }); }); From b941544ab1482205add62b315ed197d2bed17fe5 Mon Sep 17 00:00:00 2001 From: SmartHubSolutions <87376145+SmartHubSolutions@users.noreply.github.com> Date: Thu, 14 Nov 2024 16:37:56 +0200 Subject: [PATCH 2/6] Smarthub: renaming Smarthub to Attekmi (#12432) * update adapter SmartHub: add aliases * Smarthub: renaming Smarthub to Attekmi * fix tests * add attekmi alias --------- Co-authored-by: Victor --- modules/smarthubBidAdapter.js | 14 ++++++++------ modules/smarthubBidAdapter.md | 10 +++++----- test/spec/modules/smarthubBidAdapter_spec.js | 4 ++-- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/modules/smarthubBidAdapter.js b/modules/smarthubBidAdapter.js index 367011d68d5..c9cc737fac7 100644 --- a/modules/smarthubBidAdapter.js +++ b/modules/smarthubBidAdapter.js @@ -9,6 +9,7 @@ import { const BIDDER_CODE = 'smarthub'; const ALIASES = [ + {code: 'attekmi', skipPbsAliasing: true}, {code: 'markapp', skipPbsAliasing: true}, {code: 'jdpmedia', skipPbsAliasing: true}, {code: 'tredio', skipPbsAliasing: true}, @@ -16,12 +17,13 @@ const ALIASES = [ {code: 'vimayx', skipPbsAliasing: true}, ]; const BASE_URLS = { - smarthub: 'https://prebid.smart-hub.io/pbjs', - markapp: 'https://markapp-prebid.smart-hub.io/pbjs', - jdpmedia: 'https://jdpmedia-prebid.smart-hub.io/pbjs', - tredio: 'https://tredio-prebid.smart-hub.io/pbjs', - felixads: 'https://felixads-prebid.smart-hub.io/pbjs', - vimayx: 'https://vimayx-prebid.smart-hub.io/pbjs', + attekmi: 'https://prebid.attekmi.com/pbjs', + smarthub: 'https://prebid.attekmi.com/pbjs', + markapp: 'https://markapp-prebid.attekmi.com/pbjs', + jdpmedia: 'https://jdpmedia-prebid.attekmi.com/pbjs', + tredio: 'https://tredio-prebid.attekmi.com/pbjs', + felixads: 'https://felixads-prebid.attekmi.com/pbjs', + vimayx: 'https://vimayx-prebid.attekmi.com/pbjs', }; const _getUrl = (partnerName) => { diff --git a/modules/smarthubBidAdapter.md b/modules/smarthubBidAdapter.md index c09855303e2..dbdae927097 100644 --- a/modules/smarthubBidAdapter.md +++ b/modules/smarthubBidAdapter.md @@ -1,16 +1,16 @@ # Overview ``` -Module Name: SmartHub Bidder Adapter -Module Type: SmartHub Bidder Adapter -Maintainer: support@smart-hub.io +Module Name: Attekmi Bidder Adapter +Module Type: Attekmi Bidder Adapter +Maintainer: prebid@attekmi.com ``` # Description -Connects to SmartHub exchange for bids. +Connects to Attekmi exchange for bids. -SmartHub bid adapter supports Banner, Video (instream and outstream) and Native. +Attekmi bid adapter supports Banner, Video (instream and outstream) and Native. # Test Parameters ``` diff --git a/test/spec/modules/smarthubBidAdapter_spec.js b/test/spec/modules/smarthubBidAdapter_spec.js index eb5fe58093d..302195ea944 100644 --- a/test/spec/modules/smarthubBidAdapter_spec.js +++ b/test/spec/modules/smarthubBidAdapter_spec.js @@ -139,11 +139,11 @@ describe('SmartHubBidAdapter', function () { }); it('Returns valid URL', function () { - expect(serverRequest.url).to.equal(`https://prebid.smart-hub.io/pbjs?partnerName=testname`); + expect(serverRequest.url).to.equal(`https://prebid.attekmi.com/pbjs?partnerName=testname`); }); it('Returns valid URL if alias', function () { - expect(requestAlias.url).to.equal(`https://${bidderAlias}-prebid.smart-hub.io/pbjs`); + expect(requestAlias.url).to.equal(`https://${bidderAlias}-prebid.attekmi.com/pbjs`); }); it('Returns general data valid', function () { From 62307a390a8c2be42f534840369a302b8fcb1c89 Mon Sep 17 00:00:00 2001 From: Pranav Sheth <57259342+pranavsheth@users.noreply.github.com> Date: Thu, 14 Nov 2024 20:16:05 +0530 Subject: [PATCH 3/6] ehealthcaresolutions Bid Adapter : initial release (#12384) * New Bidder:tapnative * removed duplicate * new bidder:ehealthcaresolutions --- modules/ehealthcaresolutionsBidAdapter.js | 41 +++ modules/ehealthcaresolutionsBidAdapter.md | 61 ++++ .../ehealthcaresolutionsBidAdapter_spec.js | 322 ++++++++++++++++++ 3 files changed, 424 insertions(+) create mode 100644 modules/ehealthcaresolutionsBidAdapter.js create mode 100644 modules/ehealthcaresolutionsBidAdapter.md create mode 100644 test/spec/modules/ehealthcaresolutionsBidAdapter_spec.js diff --git a/modules/ehealthcaresolutionsBidAdapter.js b/modules/ehealthcaresolutionsBidAdapter.js new file mode 100644 index 00000000000..9df4c38e4f2 --- /dev/null +++ b/modules/ehealthcaresolutionsBidAdapter.js @@ -0,0 +1,41 @@ +import { + BANNER, + NATIVE +} from '../src/mediaTypes.js'; +import { + registerBidder +} from '../src/adapters/bidderFactory.js'; +import { + getBannerRequest, + getBannerResponse, + getNativeResponse, +} from '../libraries/audUtils/bidderUtils.js'; + +const ENDPOINT_URL = 'https://rtb.ehealthcaresolutions.com/hb'; +// Export const spec +export const spec = { + code: 'ehealthcaresolutions', + supportedMediaTypes: [BANNER, NATIVE], + // Determines whether or not the given bid request is valid + isBidRequestValid: (bParam) => { + return !!(bParam.params.placement_id); + }, + // Make a server request from the list of BidRequests + buildRequests: (bidRequests, serverRequest) => { + // Get Requests based on media types + return getBannerRequest(bidRequests, serverRequest, ENDPOINT_URL); + }, + // Unpack the response from the server into a list of bids. + interpretResponse: (bResponse, bRequest) => { + let Response = {}; + const mediaType = JSON.parse(bRequest.data)[0].MediaType; + if (mediaType == BANNER) { + Response = getBannerResponse(bResponse, BANNER); + } else if (mediaType == NATIVE) { + Response = getNativeResponse(bResponse, bRequest, NATIVE); + } + return Response; + } +} + +registerBidder(spec); diff --git a/modules/ehealthcaresolutionsBidAdapter.md b/modules/ehealthcaresolutionsBidAdapter.md new file mode 100644 index 00000000000..fdf859404d2 --- /dev/null +++ b/modules/ehealthcaresolutionsBidAdapter.md @@ -0,0 +1,61 @@ +# Overview + +``` +Module Name: eHealthcareSolutions Bidder Adapter +Module Type: Bidder Adapter +Maintainer: info@ehsmail.com +``` + +# Description + +eHealthcareSolutions currently supports the BANNER and NATIVE type ads through prebid js + +Module that connects to eHealthcareSolutions's demand sources. + +# Test Request +``` + var adUnits = [ + { + code: 'display-ad', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + } + bids: [ + { + bidder: 'ehealthcaresolutions', + params: { + placement_id: 111519, // Required parameter + width: 300, // Optional parameter + height: 250, // Optional parameter + bid_floor: 0.5 // Optional parameter + } + } + ] + }, + { + code: 'native-ad-container', + mediaTypes: { + native: { + title: { required: true, len: 100 }, + image: { required: true, sizes: [300, 250] }, + sponsored: { required: false }, + clickUrl: { required: true }, + desc: { required: true }, + icon: { required: false, sizes: [50, 50] }, + cta: { required: false } + } + }, + bids: [ + { + bidder: 'eHealthcareSolutions', + params: { + placement_id: 111519, // Required parameter + bid_floor: 1 // Optional parameter + } + } + ] + } + ]; +``` diff --git a/test/spec/modules/ehealthcaresolutionsBidAdapter_spec.js b/test/spec/modules/ehealthcaresolutionsBidAdapter_spec.js new file mode 100644 index 00000000000..c420c387598 --- /dev/null +++ b/test/spec/modules/ehealthcaresolutionsBidAdapter_spec.js @@ -0,0 +1,322 @@ +import { expect } from 'chai'; +import { spec } from '../../../modules/ehealthcaresolutionsBidAdapter.js'; +import * as utils from '../../../src/utils.js'; + +describe('ehealthcaresolutions adapter', function () { + let bannerRequest, nativeRequest; + let bannerResponse, nativeResponse, invalidBannerResponse, invalidNativeResponse; + + beforeEach(function () { + bannerRequest = [ + { + bidder: 'ehealthcaresolutions', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + params: { + placement_id: 111520, + bid_floor: 0.5 + } + } + ]; + nativeRequest = [ + { + bidder: 'ehealthcaresolutions', + mediaTypes: { + native: { + title: { required: true, len: 100 }, + image: { required: true, sizes: [300, 250] }, + sponsored: { required: false }, + clickUrl: { required: true }, + desc: { required: true }, + icon: { required: false, sizes: [50, 50] }, + cta: { required: false } + } + }, + params: { + placement_id: 111519, + bid_floor: 1 + } + } + ]; + bannerResponse = { + 'body': { + 'id': '006ac3b3-67f0-43bf-a33a-388b2f869fef', + 'seatbid': [{ + 'bid': [{ + 'id': '049d07ed-c07e-4890-9f19-5cf41406a42d', + 'impid': '286e606ac84a09', + 'price': 0.11, + 'adid': '368853', + 'adm': "", + 'adomain': ['google.com'], + 'iurl': 'https://cdn.ehealthcaresolutions.com/1_368853_1.png', + 'cid': '468133/368853', + 'crid': '368853', + 'w': 300, + 'h': 250, + 'cat': ['IAB7-19'] + }], + 'seat': 'ehealthcaresolutions', + 'group': 0 + }], + 'cur': 'USD', + 'bidid': 'BIDDER_-1' + } + }; + nativeResponse = { + 'body': { + 'id': '453ade66-9113-4944-a674-5bbdcb9808ac', + 'seatbid': [{ + 'bid': [{ + 'id': '652c9a4c-66ea-4579-998b-cefe7b4cfecd', + 'impid': '2c3875bdbb1893', + 'price': 1.1, + 'adid': '368852', + 'adm': '{\"native\":{\"ver\":\"1.1\",\"assets\": [{\"id\":1,\"required\":1,\"title\":{\"text\":\"Integrative Approaches: Merging Traditional and Alternative \"}},{\"id\":2,\"required\":1,\"img\":{\"url\":\"https://cdn.ehealthcaresolutions.com/1_368852_0.png\",\"w\":500,\"h\":300,\"type\":\"3\"}},{\"id\":3,\"required\":0,\"data\":{\"value\":\"Diabetes In Control. A free weekly diabetes newsletter for Medical Professionals.\"}},{\"id\":4,\"required\":1,\"data\":{\"value\":\"Integrative Approaches: Merging Traditional and Alternative \"}},{\"id\":6,\"required\":1,\"data\":{\"value\":\"URL\"}}],\"link\":{\"url\":\"https://r.ehealthcaresolutions.com/adx-rtb-d/servlet/WebF_AdManager.AdLinkManager?qs=H4sIAAAAAAAAAx2U2QHDIAxDVwKDr3F84P1HqNLPtMSRpSeG9RiPXH+5a474KzO/47YX7UoP50m61fLujlNjb76/8ZiblkimHq5nL/ZRedp3031x1tnk55LjSNN6h9/Zq+qmaLLuWTl74m1ZJKnb+m2OtQm/3L4sb933pM92qMOgjJ41MYmPXKnndRVKs+9bfSEumoZIFpTXuXbCP+WXuzl725E3O+9odi5OJrnBzhwjx9+UnFN3nTNt1/HY5aeljKtvZYpoJHNXr8BWa8ysKQY7ZmNA3DHK2qRwY7+zLu+xm9z5eheJ4Pv2usSptvO3p7JHrnXn0T5yVWdccp9Yz7hhoz2iu2zqsXsGFZ9hh14J6yU4TkJ0BgnOY8tY3tS+n2qsw7xZfKuanSNbAo+9nkJ83i20+FwhfbJeDVOllXsdxmDWauYcSRgS9+yG5qHwUDjAxxA0iZnOjlsnI+y09+ATeTEwbAVGgp0Qu/ceP0kjUvpu1Ty7O9MoegfrmLPxdjUh3mJL+XhARby+Ax8iBckf6BQdn9W+DMlvmlzYLuLlIy7YociFOIvXvEiYYCMboVk8BLHbnw3Zmr5us3xbjtXL67L96F15acJXkM5BOmTaUbBkYGdCI+Et8XmlpbuE3xVQwmxryc2y4wP3ByuuP8GogPZz8OpPaBv8diWWUTrC2nnLhdNUrJRTKc9FepDvwHTDwfbbMCTSb4LhUIFkyFrw/i7GtkPi6NCCai6N47TgNsTnzZWRoVtOSLq7FsLiF29y0Gj0GHVPVYG3QOPS7Swc3UuiFAQZJx3YvpHA2geUgVBASMEL4vcDi2Dw3NPtBSC4EQEvH/uMILu6WyUwraywTeVpoqoHTqOoD84FzReKoWemJy6jyuiBieGlQIe6wY2elTaMOwEUFF5NagzPj6nauc0+aXzQN3Q72hxFAgtfORK60RRAHYZLYymIzSJcXLgRFsqrb1UoD+5Atq7TWojaLTfOyUvH9EeJvZEOilQAXrf/ALoI8ZhABQAA\"},\"imptrackers\":[\"https://i.ehealthcaresolutions.com/adx-rtb-d/servlet/WebF_AdManager.ImpCounter?price=${AUCTION_PRICE}&ids=111519,16703,468132,368852,211356,233,13,16704,1&cb=1728409547&ap=5.00000&vd=223.233.85.189,14,8&nm=0.00&GUIDs=[adx_guid],652c9a4c-66ea-4579-998b-cefe7b4cfecd,652c9a4c-66ea-4579-998b-cefe7b4cfecd,999999,-1_&info=2,-1,IN&adx_custom=&adx_custom_ex=~~~-1~~~0&cat=-1&ref=https%3A%2F%2Fqa-jboss.audiencelogy.com%2Ftn_native_prod.html\",\"https://i.ehealthcaresolutions.com/adx-rtb-d/servlet/WebF_AdManager.ImpTracker?price=${AUCTION_PRICE}&ids=111519,16703,468132,368852,211356,233,13,16704,1&cb=1728409547&ap=5.00000&vd=223.233.85.189,14,8&nm=0.00&GUIDs=[adx_guid],652c9a4c-66ea-4579-998b-cefe7b4cfecd,652c9a4c-66ea-4579-998b-cefe7b4cfecd,999999,-1_&info=2,-1,IN&adx_custom=&adx_custom_ex=~~~-1~~~0&cat=-1&ref=\",\"https://rtb-east.ehealthcaresolutions.com:9001/beacon?uid=44636f6605b06ec6d4389d6efb7e5054&cc=468132&fccap=5&nid=1\"]}}', + 'adomain': ['www.diabetesincontrol.com'], + 'iurl': 'https://cdn.ehealthcaresolutions.com/1_368852_0.png', + 'cid': '468132/368852', + 'crid': '368852', + 'cat': ['IAB7'] + }], + 'seat': 'ehealthcaresolutions', + 'group': 0 + }], + 'cur': 'USD', + 'bidid': 'BIDDER_-1' + } + }; + invalidBannerResponse = { + 'body': { + 'id': '006ac3b3-67f0-43bf-a33a-388b2f869fef', + 'seatbid': [{ + 'bid': [{ + 'id': '049d07ed-c07e-4890-9f19-5cf41406a42d', + 'impid': '286e606ac84a09', + 'price': 0.11, + 'adid': '368853', + 'adm': 'invalid response', + 'adomain': ['google.com'], + 'iurl': 'https://cdn.ehealthcaresolutions.com/1_368853_1.png', + 'cid': '468133/368853', + 'crid': '368853', + 'w': 300, + 'h': 250, + 'cat': ['IAB7-19'] + }], + 'seat': 'ehealthcaresolutions', + 'group': 0 + }], + 'cur': 'USD', + 'bidid': 'BIDDER_-1' + } + }; + invalidNativeResponse = { + 'body': { + 'id': '453ade66-9113-4944-a674-5bbdcb9808ac', + 'seatbid': [{ + 'bid': [{ + 'id': '652c9a4c-66ea-4579-998b-cefe7b4cfecd', + 'impid': '2c3875bdbb1893', + 'price': 1.1, + 'adid': '368852', + 'adm': 'invalid response', + 'adomain': ['www.diabetesincontrol.com'], + 'iurl': 'https://cdn.ehealthcaresolutions.com/1_368852_0.png', + 'cid': '468132/368852', + 'crid': '368852', + 'cat': ['IAB7'] + }], + 'seat': 'ehealthcaresolutions', + 'group': 0 + }], + 'cur': 'USD', + 'bidid': 'BIDDER_-1' + } + }; + }); + + describe('validations', function () { + it('isBidValid : placement_id is passed', function () { + let bid = { + bidder: 'ehealthcaresolutions', + params: { + placement_id: 111520 + } + }, + isValid = spec.isBidRequestValid(bid); + expect(isValid).to.equals(true); + }); + it('isBidValid : placement_id is not passed', function () { + let bid = { + bidder: 'ehealthcaresolutions', + params: { + width: 300, + height: 250, + domain: '', + bid_floor: 0.5 + } + }, + isValid = spec.isBidRequestValid(bid); + expect(isValid).to.equals(false); + }); + }); + describe('Validate Banner Request', function () { + it('Immutable bid request validate', function () { + let _Request = utils.deepClone(bannerRequest), + bidRequest = spec.buildRequests(bannerRequest); + expect(bannerRequest).to.deep.equal(_Request); + }); + it('Validate bidder connection', function () { + let _Request = spec.buildRequests(bannerRequest); + expect(_Request.url).to.equal('https://rtb.ehealthcaresolutions.com/hb'); + expect(_Request.method).to.equal('POST'); + expect(_Request.options.contentType).to.equal('application/json'); + }); + it('Validate bid request : Impression', function () { + let _Request = spec.buildRequests(bannerRequest); + let data = JSON.parse(_Request.data); + // expect(data.at).to.equal(1); // auction type + expect(data[0].imp[0].id).to.equal(bannerRequest[0].bidId); + expect(data[0].placementId).to.equal(111520); + }); + it('Validate bid request : ad size', function () { + let _Request = spec.buildRequests(bannerRequest); + let data = JSON.parse(_Request.data); + expect(data[0].imp[0].banner).to.be.a('object'); + expect(data[0].imp[0].banner.w).to.equal(300); + expect(data[0].imp[0].banner.h).to.equal(250); + }); + it('Validate bid request : user object', function () { + let _Request = spec.buildRequests(bannerRequest); + let data = JSON.parse(_Request.data); + expect(data[0].user).to.be.a('object'); + expect(data[0].user.id).to.be.a('string'); + }); + it('Validate bid request : CCPA Check', function () { + let bidRequest = { + uspConsent: '1NYN' + }; + let _Request = spec.buildRequests(bannerRequest, bidRequest); + let data = JSON.parse(_Request.data); + expect(data[0].regs.ext.us_privacy).to.equal('1NYN'); + // let _bidRequest = {}; + // let _Request1 = spec.buildRequests(request, _bidRequest); + // let data1 = JSON.parse(_Request1.data); + // expect(data1.regs).to.equal(undefined); + }); + }); + describe('Validate banner response ', function () { + it('Validate bid response : valid bid response', function () { + let _Request = spec.buildRequests(bannerRequest); + let bResponse = spec.interpretResponse(bannerResponse, _Request); + expect(bResponse).to.be.an('array').with.length.above(0); + expect(bResponse[0].requestId).to.equal(bannerResponse.body.seatbid[0].bid[0].impid); + expect(bResponse[0].width).to.equal(bannerResponse.body.seatbid[0].bid[0].w); + expect(bResponse[0].height).to.equal(bannerResponse.body.seatbid[0].bid[0].h); + expect(bResponse[0].currency).to.equal('USD'); + expect(bResponse[0].netRevenue).to.equal(false); + expect(bResponse[0].mediaType).to.equal('banner'); + expect(bResponse[0].meta.advertiserDomains).to.deep.equal(['google.com']); + expect(bResponse[0].ttl).to.equal(300); + expect(bResponse[0].creativeId).to.equal(bannerResponse.body.seatbid[0].bid[0].crid); + expect(bResponse[0].dealId).to.equal(bannerResponse.body.seatbid[0].bid[0].dealId); + }); + it('Invalid bid response check ', function () { + let bRequest = spec.buildRequests(bannerRequest); + let response = spec.interpretResponse(invalidBannerResponse, bRequest); + expect(response[0].ad).to.equal('invalid response'); + }); + }); + describe('Validate Native Request', function () { + it('Immutable bid request validate', function () { + let _Request = utils.deepClone(nativeRequest), + bidRequest = spec.buildRequests(nativeRequest); + expect(nativeRequest).to.deep.equal(_Request); + }); + it('Validate bidder connection', function () { + let _Request = spec.buildRequests(nativeRequest); + expect(_Request.url).to.equal('https://rtb.ehealthcaresolutions.com/hb'); + expect(_Request.method).to.equal('POST'); + expect(_Request.options.contentType).to.equal('application/json'); + }); + it('Validate bid request : Impression', function () { + let _Request = spec.buildRequests(nativeRequest); + let data = JSON.parse(_Request.data); + // expect(data.at).to.equal(1); // auction type + expect(data[0].imp[0].id).to.equal(nativeRequest[0].bidId); + expect(data[0].placementId).to.equal(111519); + }); + it('Validate bid request : user object', function () { + let _Request = spec.buildRequests(nativeRequest); + let data = JSON.parse(_Request.data); + expect(data[0].user).to.be.a('object'); + expect(data[0].user.id).to.be.a('string'); + }); + it('Validate bid request : CCPA Check', function () { + let bidRequest = { + uspConsent: '1NYN' + }; + let _Request = spec.buildRequests(nativeRequest, bidRequest); + let data = JSON.parse(_Request.data); + expect(data[0].regs.ext.us_privacy).to.equal('1NYN'); + // let _bidRequest = {}; + // let _Request1 = spec.buildRequests(request, _bidRequest); + // let data1 = JSON.parse(_Request1.data); + // expect(data1.regs).to.equal(undefined); + }); + }); + describe('Validate native response ', function () { + it('Validate bid response : valid bid response', function () { + let _Request = spec.buildRequests(nativeRequest); + let bResponse = spec.interpretResponse(nativeResponse, _Request); + expect(bResponse).to.be.an('array').with.length.above(0); + expect(bResponse[0].requestId).to.equal(nativeResponse.body.seatbid[0].bid[0].impid); + // expect(bResponse[0].width).to.equal(bannerResponse.body.seatbid[0].bid[0].w); + // expect(bResponse[0].height).to.equal(bannerResponse.body.seatbid[0].bid[0].h); + expect(bResponse[0].currency).to.equal('USD'); + expect(bResponse[0].netRevenue).to.equal(false); + expect(bResponse[0].mediaType).to.equal('native'); + expect(bResponse[0].native.clickUrl).to.be.a('string').and.not.be.empty; + expect(bResponse[0].native.impressionTrackers).to.be.an('array').with.length.above(0); + expect(bResponse[0].native.title).to.be.a('string').and.not.be.empty; + expect(bResponse[0].native.image.url).to.be.a('string').and.not.be.empty; + expect(bResponse[0].meta.advertiserDomains).to.deep.equal(['www.diabetesincontrol.com']); + expect(bResponse[0].ttl).to.equal(300); + expect(bResponse[0].creativeId).to.equal(nativeResponse.body.seatbid[0].bid[0].crid); + expect(bResponse[0].dealId).to.equal(nativeResponse.body.seatbid[0].bid[0].dealId); + }); + }); + describe('GPP and coppa', function () { + it('Request params check with GPP Consent', function () { + let bidderReq = { gppConsent: { gppString: 'gpp-string-test', applicableSections: [5] } }; + let _Request = spec.buildRequests(bannerRequest, bidderReq); + let data = JSON.parse(_Request.data); + expect(data[0].regs.gpp).to.equal('gpp-string-test'); + expect(data[0].regs.gpp_sid[0]).to.equal(5); + }); + it('Request params check with GPP Consent read from ortb2', function () { + let bidderReq = { + ortb2: { + regs: { + gpp: 'gpp-test-string', + gpp_sid: [5] + } + } + }; + let _Request = spec.buildRequests(bannerRequest, bidderReq); + let data = JSON.parse(_Request.data); + expect(data[0].regs.gpp).to.equal('gpp-test-string'); + expect(data[0].regs.gpp_sid[0]).to.equal(5); + }); + it(' Bid request should have coppa flag if its true', () => { + let bidderReq = { ortb2: { regs: { coppa: 1 } } }; + let _Request = spec.buildRequests(bannerRequest, bidderReq); + let data = JSON.parse(_Request.data); + expect(data[0].regs.coppa).to.equal(1); + }); + }); +}); From fee94cde778c71cd2f84539f79e454df9d71066f Mon Sep 17 00:00:00 2001 From: vdo-ai-tech <126867429+vdo-ai-tech@users.noreply.github.com> Date: Fri, 15 Nov 2024 02:06:35 +0530 Subject: [PATCH 4/6] Vdo.ai Bid Adapter : update to prebid version 9 (#12284) * upgraded vdo.ai prebid adapter to prebid version 9 * linting issues fixed * refactored code * removed page visibility and timing function since they are no longer required * getting coppa from ortb2 object, then fallback to config * lint issue fixed * refactored just to rerun CI/CD build --------- Co-authored-by: rishabhsehrawat1 --- modules/vdoaiBidAdapter.js | 179 +++++++++++-- test/spec/modules/vdoaiBidAdapter_spec.js | 311 ++++++++++++++++++++-- 2 files changed, 442 insertions(+), 48 deletions(-) diff --git a/modules/vdoaiBidAdapter.js b/modules/vdoaiBidAdapter.js index f375e161f88..8fda9cba593 100644 --- a/modules/vdoaiBidAdapter.js +++ b/modules/vdoaiBidAdapter.js @@ -1,6 +1,8 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {getAdUnitSizes} from '../libraries/sizeUtils/sizeUtils.js'; +import { deepClone, logError, deepAccess } from '../src/utils.js'; +import { config } from '../src/config.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -9,7 +11,86 @@ import {getAdUnitSizes} from '../libraries/sizeUtils/sizeUtils.js'; */ const BIDDER_CODE = 'vdoai'; -const ENDPOINT_URL = 'https://prebid.vdo.ai/auction'; +const ENDPOINT_URL = 'https://prebid-v2.vdo.ai/auction'; + +function getFrameNesting() { + let topmostFrame = window; + let parent = window.parent; + try { + while (topmostFrame !== topmostFrame.parent) { + parent = topmostFrame.parent; + // eslint-disable-next-line no-unused-expressions + parent.location.href; + topmostFrame = topmostFrame.parent; + } + } catch (e) { } + return topmostFrame; +} + +/** + * Returns information about the page needed by the server in an object to be converted in JSON + * + * @returns {{location: *, referrer: (*|string), stack: (*|Array.), numIframes: (*|Number), wWidth: (*|Number), wHeight: (*|Number), sWidth, sHeight, date: string, timeOffset: number}} + */ +function getPageInfo(bidderRequest) { + const topmostFrame = getFrameNesting(); + return { + referrer: deepAccess(bidderRequest, 'refererInfo.ref', null), + stack: deepAccess(bidderRequest, 'refererInfo.stack', []), + numIframes: deepAccess(bidderRequest, 'refererInfo.numIframes', 0), + wWidth: topmostFrame.innerWidth, + location: deepAccess(bidderRequest, 'refererInfo.page', null), + wHeight: topmostFrame.innerHeight, + aWidth: topmostFrame.screen.availWidth, + aHeight: topmostFrame.screen.availHeight, + oWidth: topmostFrame.outerWidth, + oHeight: topmostFrame.outerHeight, + sWidth: topmostFrame.screen.width, + sHeight: topmostFrame.screen.height, + sLeft: 'screenLeft' in topmostFrame ? topmostFrame.screenLeft : topmostFrame.screenX, + sTop: 'screenTop' in topmostFrame ? topmostFrame.screenTop : topmostFrame.screenY, + xOffset: topmostFrame.pageXOffset, + docHeight: topmostFrame.document.body ? topmostFrame.document.body.scrollHeight : null, + hLength: history.length, + yOffset: topmostFrame.pageYOffset, + version: { + prebid_version: '$prebid.version$', + adapter_version: '1.0.0', + vendor: '$$PREBID_GLOBAL$$', + } + }; +} + +export function isSchainValid(schain) { + let isValid = false; + const requiredFields = ['asi', 'sid', 'hp']; + if (!schain || !schain.nodes) return isValid; + isValid = schain.nodes.reduce((status, node) => { + if (!status) return status; + return requiredFields.every(field => node.hasOwnProperty(field)); + }, true); + if (!isValid) { + logError('VDO.AI: required schain params missing'); + } + return isValid; +} + +function parseVideoSize(bid) { + const playerSize = bid.mediaTypes.video.playerSize; + if (typeof playerSize !== 'undefined' && Array.isArray(playerSize) && playerSize.length > 0) { + return getSizes(playerSize) + } + return []; +} + +function getSizes(sizes) { + const ret = []; + for (let i = 0; i < sizes.length; i++) { + const size = sizes[i]; + ret.push({ width: size[0], height: size[1] }) + } + return ret; +} export const spec = { code: BIDDER_CODE, @@ -21,7 +102,7 @@ export const spec = { * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: function (bid) { - return !!(bid.params.placementId); + return !!(bid.params.placementId) && typeof bid.params.placementId === 'string'; }, /** @@ -31,23 +112,82 @@ export const spec = { * @param validBidRequests * @param bidderRequest */ + buildRequests: function (validBidRequests, bidderRequest) { if (validBidRequests.length === 0) { return []; } - return validBidRequests.map(bidRequest => { const sizes = getAdUnitSizes(bidRequest); - const payload = { + let payload = { placementId: bidRequest.params.placementId, sizes: sizes, bidId: bidRequest.bidId, - // TODO: is 'page' the right value here? - referer: bidderRequest.refererInfo.page, - // TODO: fix auctionId leak: https://github.com/prebid/Prebid.js/issues/9781 - id: bidRequest.auctionId, - mediaType: bidRequest.mediaTypes.video ? 'video' : 'banner' + mediaType: bidRequest.mediaTypes.video ? 'video' : 'banner', + domain: bidderRequest.ortb2.site.domain, + publisherDomain: bidderRequest.ortb2.site.publisher.domain, + adUnitCode: bidRequest.adUnitCode, + bidder: bidRequest.bidder, + tmax: bidderRequest.timeout }; + + payload.bidderRequestId = bidRequest.bidderRequestId; + payload.auctionId = deepAccess(bidRequest, 'ortb2.source.tid'); + payload.transactionId = deepAccess(bidRequest, 'ortb2Imp.ext.tid'); + payload.gpid = deepAccess(bidRequest, 'ortb2Imp.ext.gpid') || deepAccess(bidRequest, 'ortb2Imp.ext.data.pbadslot'); + payload.ortb2Imp = deepAccess(bidRequest, 'ortb2Imp'); + + if (payload.mediaType === 'video') { + payload.context = bidRequest.mediaTypes.video.context; + payload.playerSize = parseVideoSize(bidRequest); + payload.mediaTypeInfo = deepClone(bidRequest.mediaTypes.video); + } + + if (typeof bidRequest.getFloor === 'function') { + let floor = bidRequest.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*' + }); + if (floor && floor.floor && floor.currency === 'USD') { + payload.bidFloor = floor.floor; + } + } else if (bidRequest.params.bidFloor) { + payload.bidFloor = bidRequest.params.bidFloor; + } + + payload.pageInfo = getPageInfo(bidderRequest); + + if (bidderRequest && bidderRequest.gdprConsent) { + payload.gdprConsent = { + consentRequired: bidderRequest.gdprConsent.gdprApplies, + consentString: bidderRequest.gdprConsent.consentString, + addtlConsent: bidderRequest.gdprConsent.addtlConsent + }; + } + if (bidderRequest && bidderRequest.gppConsent) { + payload.gppConsent = { + applicableSections: bidderRequest.gppConsent.applicableSections, + consentString: bidderRequest.gppConsent.gppString, + } + } + if (bidderRequest && bidderRequest.ortb2) { + payload.ortb2 = bidderRequest.ortb2; + } + if (bidderRequest && bidderRequest.uspConsent) { + payload.usPrivacy = bidderRequest.uspConsent; + } + if (validBidRequests && validBidRequests.length !== 0 && validBidRequests[0].schain && isSchainValid(validBidRequests[0].schain)) { + payload.schain = validBidRequests[0].schain; + } + if (validBidRequests && validBidRequests.length !== 0 && validBidRequests[0].userIdAsEids) { + payload.userId = validBidRequests[0].userIdAsEids; + } + let coppaOrtb2 = !!deepAccess(bidderRequest, 'ortb2.regs.coppa'); + let coppaConfig = config.getConfig('coppa'); + if (coppaOrtb2 === true || coppaConfig === true) { + payload.coppa = true; + } return { method: 'POST', url: ENDPOINT_URL, @@ -67,35 +207,24 @@ export const spec = { const bidResponses = []; const response = serverResponse.body; const creativeId = response.adid || 0; - // const width = response.w || 0; - const width = response.width; - // const height = response.h || 0; - const height = response.height; + const width = response.w; + const height = response.h; const cpm = response.price || 0; - response.rWidth = width; - response.rHeight = height; - const adCreative = response.vdoCreative; if (width !== 0 && height !== 0 && cpm !== 0 && creativeId !== 0) { - // const dealId = response.dealid || ''; const currency = response.cur || 'USD'; const netRevenue = true; - // const referrer = bidRequest.data.referer; const bidResponse = { requestId: response.bidId, cpm: cpm, width: width, height: height, creativeId: creativeId, - // dealId: dealId, currency: currency, netRevenue: netRevenue, ttl: 60, - // referrer: referrer, - // ad: response.adm - // ad: adCreative, mediaType: response.mediaType }; @@ -104,9 +233,9 @@ export const spec = { } else { bidResponse.ad = adCreative; } - if (response.adDomain) { + if (response.adomain) { bidResponse.meta = { - advertiserDomains: response.adDomain + advertiserDomains: response.adomain }; } bidResponses.push(bidResponse); @@ -130,7 +259,7 @@ export const spec = { return []; }, - onTImeout: function(data) {}, + onTimeout: function(data) {}, onBidWon: function(bid) {}, onSetTargeting: function(bid) {} }; diff --git a/test/spec/modules/vdoaiBidAdapter_spec.js b/test/spec/modules/vdoaiBidAdapter_spec.js index b1cfa606d84..e7f153fa237 100644 --- a/test/spec/modules/vdoaiBidAdapter_spec.js +++ b/test/spec/modules/vdoaiBidAdapter_spec.js @@ -1,11 +1,19 @@ import {assert, expect} from 'chai'; import {spec} from 'modules/vdoaiBidAdapter.js'; import {newBidder} from 'src/adapters/bidderFactory.js'; +import { config } from 'src/config.js'; -const ENDPOINT_URL = 'https://prebid.vdo.ai/auction'; +const ENDPOINT_URL = 'https://prebid-v2.vdo.ai/auction'; describe('vdoaiBidAdapter', function () { const adapter = newBidder(spec); + const sandbox = sinon.sandbox.create(); + beforeEach(function() { + sandbox.stub(config, 'getConfig').withArgs('coppa').returns(true); + }); + afterEach(function() { + sandbox.restore(); + }); describe('isBidRequestValid', function () { let bid = { 'bidder': 'vdoai', @@ -20,16 +28,33 @@ describe('vdoaiBidAdapter', function () { 'bidderRequestId': '1234asdf1234asdf', 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf120' }; + let invalidParams = { + 'bidder': 'vdoai', + 'params': { + placementId: false + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250] + ], + 'bidId': '1234asdf1234', + 'bidderRequestId': '1234asdf1234asdf', + 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf120' + }; it('should return true where required params found', function () { expect(spec.isBidRequestValid(bid)).to.equal(true); }); + it('should return false where required params not found', function () { + expect(spec.isBidRequestValid(invalidParams)).to.equal(false); + }); }); describe('buildRequests', function () { let bidRequests = [ { 'bidder': 'vdoai', 'params': { - placementId: 'testPlacementId' + placementId: 'testPlacementId', + bidFloor: 0.1 }, 'sizes': [ [300, 250] @@ -37,16 +62,84 @@ describe('vdoaiBidAdapter', function () { 'bidId': '23beaa6af6cdde', 'bidderRequestId': '19c0c1efdf37e7', 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1', - 'mediaTypes': 'banner' + 'mediaType': 'banner', + 'adUnitCode': '1234', + 'mediaTypes': { + banner: { + sizes: [300, 250] + } + } + }, + { + 'bidder': 'vdoai', + 'params': { + placementId: 'testPlacementId', + bidFloor: 0.1 + }, + 'width': '300', + 'height': '200', + 'bidId': 'bidId123', + 'referer': 'www.example.com', + 'mediaType': 'video', + 'mediaTypes': { + video: { + context: 'instream', + playerSize: [[640, 360]] + } + } } ]; let bidderRequests = { + timeout: 3000, 'refererInfo': { 'numIframes': 0, 'reachedTop': true, 'referer': 'https://example.com', - 'stack': ['https://example.com'] + 'stack': ['https://example.com'], + 'page': 'example.com', + 'ref': 'example2.com' + }, + 'ortb2': { + source: { + tid: 123456789 + }, + 'site': { + 'domain': 'abc.com', + 'publisher': { + 'domain': 'abc.com' + } + } + }, + 'ortb2Imp': { + ext: { + tid: '12345', + gpid: '1234' + } + }, + gdprConsent: { + consentString: 'abc', + gdprApplies: true, + addtlConsent: 'xyz' + }, + gppConsent: { + gppString: 'abcd', + applicableSections: '' + }, + uspConsent: { + uspConsent: '12345' + }, + userIdAsEids: {}, + schain: { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'vdo.ai', + 'sid': '4359', + 'hp': 1 + } + ] } }; @@ -57,6 +150,44 @@ describe('vdoaiBidAdapter', function () { it('attaches source and version to endpoint URL as query params', function () { expect(request[0].url).to.equal(ENDPOINT_URL); }); + it('should contain all keys', function() { + expect(request[0].data.pageInfo).to.include.all.keys('location', 'referrer', 'stack', 'numIframes', 'sHeight', 'sWidth', 'docHeight', 'wHeight', 'wWidth', 'oHeight', 'oWidth', 'aWidth', 'aHeight', 'sLeft', 'sTop', 'hLength', 'xOffset', 'yOffset', 'version'); + }) + it('should return empty array if no valid bid was passed', function () { + expect(spec.buildRequests([], bidderRequests)).to.be.empty; + }); + it('should not send invalid schain', function () { + delete bidderRequests.schain.nodes[0].asi; + let result = spec.buildRequests(bidRequests, bidderRequests); + expect(result[0].data.schain).to.be.undefined; + }); + it('should not send invalid schain', function () { + delete bidderRequests.schain; + let result = spec.buildRequests(bidRequests, bidderRequests); + expect(result[0].data.schain).to.be.undefined; + }); + it('should check for correct sizes', function () { + delete bidRequests[1].mediaTypes.video.playerSize; + let result = spec.buildRequests(bidRequests, bidderRequests); + expect(result[1].data.playerSize).to.be.empty; + }); + it('should not pass undefined in GDPR string', function () { + delete bidderRequests.gdprConsent; + let result = spec.buildRequests(bidRequests, bidderRequests); + expect(result[0].data.gdprConsent).to.be.undefined; + }); + + it('should not pass undefined in gppConsent', function () { + delete bidderRequests.gppConsent; + let result = spec.buildRequests(bidRequests, bidderRequests); + expect(result[0].data.gppConsent).to.be.undefined; + }); + + it('should not pass undefined in uspConsent', function () { + delete bidderRequests.uspConsent; + let result = spec.buildRequests(bidRequests, bidderRequests); + expect(result[0].data.uspConsent).to.be.undefined; + }); }); describe('interpretResponse', function () { @@ -75,29 +206,31 @@ describe('vdoaiBidAdapter', function () { } ]; let serverResponse = { - body: { - 'vdoCreative': '

I am an ad

', - 'price': 4.2, - 'adid': '12345asdfg', - 'currency': 'EUR', - 'statusMessage': 'Bid available', - 'requestId': 'bidId123', - 'width': 300, - 'height': 250, - 'netRevenue': true, - 'adDomain': ['text.abc'] + body: + { + 'price': 2, + 'adid': 'test-ad', + 'adomain': [ + 'text.abc' + ], + 'w': 300, + 'h': 250, + 'vdoCreative': '

I am an ad

', + 'bidId': '31d1375caab87a', + 'mediaType': 'banner' } }; + it('should get the correct bid response', function () { let expectedResponse = [{ - 'requestId': 'bidId123', - 'cpm': 4.2, + 'requestId': '31d1375caab87a', + 'cpm': 2, 'width': 300, 'height': 250, - 'creativeId': '12345asdfg', - 'currency': 'EUR', + 'creativeId': 'test-ad', + 'currency': 'USD', 'netRevenue': true, - 'ttl': 3000, + 'ttl': 60, 'ad': '

I am an ad

', 'meta': { 'advertiserDomains': ['text.abc'] @@ -112,9 +245,9 @@ describe('vdoaiBidAdapter', function () { let serverResponse = { body: { 'vdoCreative': '', - 'price': 4.2, + 'price': 2, 'adid': '12345asdfg', - 'currency': 'EUR', + 'currency': 'USD', 'statusMessage': 'Bid available', 'requestId': 'bidId123', 'width': 300, @@ -133,7 +266,13 @@ describe('vdoaiBidAdapter', function () { 'height': '200', 'bidId': 'bidId123', 'referer': 'www.example.com', - 'mediaType': 'video' + 'mediaType': 'video', + 'mediaTypes': { + video: { + context: 'instream', + playerSize: [[640, 360]] + } + } } } ]; @@ -142,5 +281,131 @@ describe('vdoaiBidAdapter', function () { expect(result[0]).to.have.property('vastXml'); expect(result[0]).to.have.property('mediaType', 'video'); }); + it('should not return invalid responses', function() { + serverResponse.body.w = 0; + let result = spec.interpretResponse(serverResponse, bidRequest[0]); + expect(result).to.be.empty; + }); + it('should not return invalid responses with invalid height', function() { + serverResponse.body.w = 300; + serverResponse.body.h = 0; + let result = spec.interpretResponse(serverResponse, bidRequest[0]); + expect(result).to.be.empty; + }); + it('should not return invalid responses with invalid cpm', function() { + serverResponse.body.h = 250; + serverResponse.body.price = 0; + let result = spec.interpretResponse(serverResponse, bidRequest[0]); + expect(result).to.be.empty; + }); + it('should not return invalid responses with invalid creative ID', function() { + serverResponse.body.price = 2; + serverResponse.body.adid = undefined; + let result = spec.interpretResponse(serverResponse, bidRequest[0]); + expect(result).to.be.empty; + }); + }); + describe('getUserSyncs', function() { + it('should return correct sync urls', function() { + let serverResponse = [{ + body: { + 'vdoCreative': '', + 'price': 2, + 'adid': '12345asdfg', + 'currency': 'USD', + 'statusMessage': 'Bid available', + 'requestId': 'bidId123', + 'width': 300, + 'height': 250, + 'netRevenue': true, + 'mediaType': 'video', + 'cookiesync': { + 'status': 'no_cookie', + 'bidder_status': [ + { + 'bidder': 'vdoai', + 'no_cookie': true, + 'usersync': { + 'url': 'https://rtb.vdo.ai/setuid/', + 'type': 'iframe' + } + } + ] + } + } + }]; + + let syncUrls = spec.getUserSyncs({ + iframeEnabled: true + }, serverResponse); + expect(syncUrls[0].url).to.be.equal(serverResponse[0].body.cookiesync.bidder_status[0].usersync.url); + + syncUrls = spec.getUserSyncs({ + iframeEnabled: false + }, serverResponse); + expect(syncUrls[0]).to.be.undefined; + }); + it('should not return invalid sync urls', function() { + let serverResponse = [{ + body: { + 'vdoCreative': '', + 'price': 2, + 'adid': '12345asdfg', + 'currency': 'USD', + 'statusMessage': 'Bid available', + 'requestId': 'bidId123', + 'width': 300, + 'height': 250, + 'netRevenue': true, + 'mediaType': 'video', + 'cookiesync': { + 'status': 'no_cookie', + 'bidder_status': [ + ] + } + } + }]; + + var syncUrls = spec.getUserSyncs({ + iframeEnabled: true + }, serverResponse); + expect(syncUrls[0]).to.be.undefined; + + delete serverResponse[0].body.cookiesync.bidder_status; + syncUrls = spec.getUserSyncs({ + iframeEnabled: true + }, serverResponse); + expect(syncUrls[0]).to.be.undefined; + + delete serverResponse[0].body.cookiesync; + syncUrls = spec.getUserSyncs({ + iframeEnabled: true + }, serverResponse); + expect(syncUrls[0]).to.be.undefined; + + delete serverResponse[0].body; + syncUrls = spec.getUserSyncs({ + iframeEnabled: true + }, serverResponse); + expect(syncUrls[0]).to.be.undefined; + }); + }); + + describe('onTimeout', function() { + it('should run without errors', function() { + spec.onTimeout(); + }); + }); + + describe('onBidWon', function() { + it('should run without errors', function() { + spec.onBidWon(); + }); + }); + + describe('onSetTargeting', function() { + it('should run without errors', function() { + spec.onSetTargeting(); + }); }); }); From bb586b85fb59424d366808d1dad82b2602ee0fc8 Mon Sep 17 00:00:00 2001 From: Dejan Grbavcic Date: Thu, 14 Nov 2024 23:22:51 +0100 Subject: [PATCH 5/6] Brid Bid Adapter : user sync and response changes (#12248) * TargetVideo bid adapter * TargetVideo bid adapter * TargetVideo bid adapter * TargetVideo Bid Adapter: Add GDPR/USP support * TargetVideo Bid Adapter: Add GDPR/USP support tests * TargetVideo Bid Adapter: Updating margin rule * Add Brid bid adapter * Brid adapter requested changes * BridBidAdapter: switching to plcmt * Brid Bid Adapter: getUserSyncs method and interpretResponse updates * Adding missing semicolon --- libraries/targetVideoUtils/constants.js | 2 + modules/bridBidAdapter.js | 175 +++++++++++------------ test/spec/modules/bridBidAdapter_spec.js | 20 +++ 3 files changed, 103 insertions(+), 94 deletions(-) diff --git a/libraries/targetVideoUtils/constants.js b/libraries/targetVideoUtils/constants.js index 8ce94c0eaeb..1f47846eba4 100644 --- a/libraries/targetVideoUtils/constants.js +++ b/libraries/targetVideoUtils/constants.js @@ -6,6 +6,7 @@ const BIDDER_CODE = 'targetVideo'; const TIME_TO_LIVE = 300; const BANNER_ENDPOINT_URL = 'https://ib.adnxs.com/ut/v3/prebid'; const VIDEO_ENDPOINT_URL = 'https://pbs.prebrid.tv/openrtb2/auction'; +const SYNC_URL = 'https://bppb.link/static/'; const VIDEO_PARAMS = [ 'api', 'linearity', 'maxduration', 'mimes', 'minduration', 'plcmt', 'playbackmethod', 'protocols', 'startdelay' @@ -16,6 +17,7 @@ export { GVLID, MARGIN, BIDDER_CODE, + SYNC_URL, TIME_TO_LIVE, BANNER_ENDPOINT_URL, VIDEO_ENDPOINT_URL, diff --git a/modules/bridBidAdapter.js b/modules/bridBidAdapter.js index 527cb9d5d5d..74f5e66b90b 100644 --- a/modules/bridBidAdapter.js +++ b/modules/bridBidAdapter.js @@ -1,27 +1,17 @@ -import {_each, deepAccess, getDefinedParams, parseGPTSingleSizeArrayToRtbSize} from '../src/utils.js'; +import {_each, deepAccess, formatQS, getDefinedParams, parseGPTSingleSizeArrayToRtbSize} from '../src/utils.js'; import {VIDEO} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {getAd, getSiteObj} from '../libraries/targetVideoUtils/bidderUtils.js' +import {GVLID, SOURCE, SYNC_URL, TIME_TO_LIVE, VIDEO_ENDPOINT_URL, VIDEO_PARAMS} from '../libraries/targetVideoUtils/constants.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest */ - -const SOURCE = 'pbjs'; -const BIDDER_CODE = 'brid'; -const ENDPOINT_URL = 'https://pbs.prebrid.tv/openrtb2/auction'; -const GVLID = 934; -const TIME_TO_LIVE = 300; -const VIDEO_PARAMS = [ - 'api', 'linearity', 'maxduration', 'mimes', 'minduration', 'plcmt', - 'playbackmethod', 'protocols', 'startdelay' -]; - export const spec = { - code: BIDDER_CODE, + code: 'brid', gvlid: GVLID, supportedMediaTypes: [VIDEO], @@ -117,7 +107,7 @@ export const spec = { requests.push({ method: 'POST', - url: ENDPOINT_URL, + url: VIDEO_ENDPOINT_URL, data: JSON.stringify(postBody), options: { withCredentials: true @@ -138,92 +128,89 @@ export const spec = { */ interpretResponse: function(serverResponse, bidRequest) { const response = serverResponse.body; - const bidResponses = []; - - _each(response.seatbid, (resp) => { - _each(resp.bid, (bid) => { - const requestId = bidRequest.bidId; - const params = bidRequest.params; - - const {ad, adUrl, vastUrl, vastXml} = getAd(bid); - - const bidResponse = { - requestId, - params, - cpm: bid.price, - width: bid.w, - height: bid.h, - creativeId: bid.adid, - currency: response.cur, - netRevenue: false, - ttl: TIME_TO_LIVE, - meta: { - advertiserDomains: bid.adomain || [] - } - }; + let highestBid = null; + + if (response && response.seatbid && response.seatbid.length && response.seatbid[0].bid && response.seatbid[0].bid.length) { + _each(response.seatbid, (resp) => { + _each(resp.bid, (bid) => { + const requestId = bidRequest.bidId; + const params = bidRequest.params; + + const {ad, adUrl, vastUrl, vastXml} = getAd(bid); + + const bidResponse = { + requestId, + params, + cpm: bid.price, + width: bid.w, + height: bid.h, + creativeId: bid.crid || bid.adid, + currency: response.cur, + netRevenue: false, + ttl: TIME_TO_LIVE, + meta: { + advertiserDomains: bid.adomain || [] + } + }; - if (vastUrl || vastXml) { - bidResponse.mediaType = VIDEO; - if (vastUrl) bidResponse.vastUrl = vastUrl; - if (vastXml) bidResponse.vastXml = vastXml; - } else { - bidResponse.ad = ad; - bidResponse.adUrl = adUrl; - }; + if (vastUrl || vastXml) { + bidResponse.mediaType = VIDEO; + if (vastUrl) bidResponse.vastUrl = vastUrl; + if (vastXml) bidResponse.vastXml = vastXml; + } else { + bidResponse.ad = ad; + bidResponse.adUrl = adUrl; + }; - bidResponses.push(bidResponse); + if (!highestBid || highestBid.cpm < bidResponse.cpm) { + highestBid = bidResponse; + } + }); }); - }); + } - return bidResponses; + return highestBid ? [highestBid] : []; }, -} + /** + * Determine the user sync type (either 'iframe' or 'image') based on syncOptions. + * Construct the sync URL by appending required query parameters such as gdpr, ccpa, and coppa consents. + * Return an array containing an object with the sync type and the constructed URL. + */ + getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) => { + const params = { + endpoint: 'brid' + }; + + // Attaching GDPR Consent Params in UserSync url + if (gdprConsent) { + params.gdpr = (gdprConsent.gdprApplies ? 1 : 0); + params.gdpr_consent = encodeURIComponent(gdprConsent.consentString || ''); + } + + // CCPA + if (uspConsent && typeof uspConsent === 'string') { + params.us_privacy = encodeURIComponent(uspConsent); + } + + // GPP Consent + if (gppConsent?.gppString && gppConsent?.applicableSections?.length) { + params.gpp = encodeURIComponent(gppConsent.gppString); + params.gpp_sid = encodeURIComponent(gppConsent?.applicableSections?.join(',')); + } + + const queryParams = Object.keys(params).length > 0 ? formatQS(params) : ''; + let response = []; + if (syncOptions.iframeEnabled) { + response = [{ + type: 'iframe', + url: SYNC_URL + 'load-cookie.html?' + queryParams + }]; + } + + return response; + } -// /** -// * Helper function to get ad -// * -// * @param {object} bid The bid. -// * @return {object} ad object. -// */ -// function getAd(bid) { -// let ad, adUrl, vastXml, vastUrl; - -// switch (deepAccess(bid, 'ext.prebid.type')) { -// case VIDEO: -// if (bid.adm.substr(0, 4) === 'http') { -// vastUrl = bid.adm; -// } else { -// vastXml = bid.adm; -// }; -// break; -// default: -// if (bid.adm && bid.nurl) { -// ad = bid.adm; -// ad += createTrackPixelHtml(decodeURIComponent(bid.nurl)); -// } else if (bid.adm) { -// ad = bid.adm; -// } else if (bid.nurl) { -// adUrl = bid.nurl; -// }; -// } - -// return {ad, adUrl, vastXml, vastUrl}; -// } - -// /** -// * Helper function to get site object -// * -// * @return {object} siteObj. -// */ -// function getSiteObj() { -// const refInfo = (getRefererInfo && getRefererInfo()) || {}; - -// return { -// page: refInfo.page, -// ref: refInfo.ref, -// domain: refInfo.domain -// }; -// } +} registerBidder(spec); diff --git a/test/spec/modules/bridBidAdapter_spec.js b/test/spec/modules/bridBidAdapter_spec.js index 7503c748999..fdda6d840e8 100644 --- a/test/spec/modules/bridBidAdapter_spec.js +++ b/test/spec/modules/bridBidAdapter_spec.js @@ -1,4 +1,5 @@ import { spec } from '../../../modules/bridBidAdapter.js' +import { SYNC_URL } from '../../../libraries/targetVideoUtils/constants.js'; describe('Brid Bid Adapter', function() { const videoRequest = [{ @@ -126,4 +127,23 @@ describe('Brid Bid Adapter', function() { expect(payload.regs.ext.gdpr).to.be.undefined; expect(payload.regs.ext.us_privacy).to.equal(uspConsentString); }); + + it('Test userSync have only one object and it should have a property type=iframe', function () { + let userSync = spec.getUserSyncs({ iframeEnabled: true }); + expect(userSync).to.be.an('array'); + expect(userSync.length).to.be.equal(1); + expect(userSync[0]).to.have.property('type'); + expect(userSync[0].type).to.be.equal('iframe'); + }); + + it('Test userSync valid sync url for iframe', function () { + let [userSync] = spec.getUserSyncs({ iframeEnabled: true }, {}, {consentString: 'anyString'}); + expect(userSync.url).to.contain(SYNC_URL + 'load-cookie.html?endpoint=brid&gdpr=0&gdpr_consent=anyString'); + expect(userSync.type).to.be.equal('iframe'); + }); + + it('Test userSyncs iframeEnabled=false', function () { + let userSyncs = spec.getUserSyncs({iframeEnabled: false}); + expect(userSyncs).to.have.lengthOf(0); + }); }); From ee12e82f4b3891a1b786a16f3899633c855b41ed Mon Sep 17 00:00:00 2001 From: Fatih Kaya Date: Fri, 15 Nov 2024 18:04:43 +0300 Subject: [PATCH 6/6] AdMatic Bid Adapter : add adt alias (#12451) * Admatic Bidder Adaptor * Update admaticBidAdapter.md * Update admaticBidAdapter.md * remove floor parameter * Update admaticBidAdapter.js * Admatic Bid Adapter: alias and bid floor features activated * Admatic adapter: host param control changed * Alias name changed. * Revert "Admatic adapter: host param control changed" This reverts commit de7ac85981b1ba3ad8c5d1dc95c5dadbdf5b9895. * added alias feature and host param * Revert "added alias feature and host param" This reverts commit 6ec8f4539ea6be403a0d7e08dad5c7a5228f28a1. * Revert "Alias name changed." This reverts commit 661c54f9b2397e8f25c257144d73161e13466281. * Revert "Admatic Bid Adapter: alias and bid floor features activated" This reverts commit 7a2e0e29c49e2f876b68aafe886b336fe2fe6fcb. * Revert "Update admaticBidAdapter.js" This reverts commit 7a845b7151bbb08addfb58ea9bd5b44167cc8a4e. * Revert "remove floor parameter" This reverts commit 7a23b055ccd4ea23d23e73248e82b21bc6f69d90. * Admatic adapter: host param control && Add new Bidder * Revert "Admatic adapter: host param control && Add new Bidder" This reverts commit 3c797b120c8e0fe2b851381300ac5c4b1f92c6e2. * commit new features * Update admaticBidAdapter.js * updated for coverage * sync updated * Update adloader.js * AdMatic Bidder: development of user sync url * Update admaticBidAdapter.js * Set currency for AdserverCurrency: bug fix * Update admaticBidAdapter.js * update * admatic adapter video params update * Update admaticBidAdapter.js * update * Update admaticBidAdapter.js * update * update * Update admaticBidAdapter_spec.js * Update admaticBidAdapter.js * Update admaticBidAdapter.js * Revert "Update admaticBidAdapter.js" This reverts commit 1216892fe55e5ab24dda8e045ea007ee6bb40ff8. * Revert "Update admaticBidAdapter.js" This reverts commit b1929ece33bb4040a3bcd6b9332b50335356829c. * Revert "Update admaticBidAdapter_spec.js" This reverts commit 1ca659798b0c9b912634b1673e15e54e547b81e7. * Revert "update" This reverts commit 689ce9d21e08c27be49adb35c5fd5205aef5c35c. * Revert "update" This reverts commit f381a453f9389bebd58dcfa719e9ec17f939f338. * Revert "Update admaticBidAdapter.js" This reverts commit 38fd7abec701d8a4750f9e95eaeb40fb67e9f0e6. * Revert "update" This reverts commit a5316e74b612a5b2cd16cf42586334321fc87770. * Revert "Update admaticBidAdapter.js" This reverts commit 60a28cae302b711366dab0bff9f49b11862fb8ee. * Revert "admatic adapter video params update" This reverts commit 31e69e88fd9355e143f736754ac2e47fe49b65b6. * update * Update admaticBidAdapter.js * Update admaticBidAdapter_spec.js * mime_type add * add native adapter * AdMatic Adapter: Consent Management * added gvlid * Update admaticBidAdapter.js * admatic cur update * Update admaticBidAdapter.js * Update admaticBidAdapter.js * Update admaticBidAdapter.js --- modules/admaticBidAdapter.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/admaticBidAdapter.js b/modules/admaticBidAdapter.js index 78e76651177..ed38cc975e8 100644 --- a/modules/admaticBidAdapter.js +++ b/modules/admaticBidAdapter.js @@ -23,7 +23,8 @@ export const spec = { {code: 'admaticde', gvlid: 1281}, {code: 'pixad', gvlid: 1281}, {code: 'monetixads', gvlid: 1281}, - {code: 'netaddiction', gvlid: 1281} + {code: 'netaddiction', gvlid: 1281}, + {code: 'adt', gvlid: 779} ], supportedMediaTypes: [BANNER, VIDEO, NATIVE], /** @@ -54,7 +55,7 @@ export const spec = { const bids = validBidRequests.map(buildRequestObject); const ortb = bidderRequest.ortb2; const networkId = getValue(validBidRequests[0].params, 'networkId'); - const host = getValue(validBidRequests[0].params, 'host'); + let host = getValue(validBidRequests[0].params, 'host'); const bidderName = validBidRequests[0].bidder; const payload = { @@ -137,11 +138,15 @@ export const spec = { case 'admaticde': SYNC_URL = 'https://static.cdn.admatic.de/admaticde/sync.html'; break; + case 'adt': + SYNC_URL = 'https://static.cdn.adtarget.org/adt/sync.html'; + break; default: SYNC_URL = 'https://static.cdn.admatic.com.tr/sync.html'; break; } + host = host?.replace('https://', '')?.replace('http://', '')?.replace('/', ''); return { method: 'POST', url: `https://${host}/pb`, data: payload, options: { contentType: 'application/json' } }; } }, @@ -150,7 +155,7 @@ export const spec = { if (!hasSynced && syncOptions.iframeEnabled) { // data is only assigned if params are available to pass to syncEndpoint let params = getUserSyncParams(gdprConsent, uspConsent, gppConsent); - params = Object.keys(params).length ? `?${formatQS(params)}` : ''; + params = Object.keys(params).length ? `&${formatQS(params)}` : ''; hasSynced = true; return {