From 6abd25e9c40dc7e11ed82f030f11298c675b4672 Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Wed, 20 Mar 2024 17:58:59 +0530 Subject: [PATCH 1/8] add support for: - dsa - us_privacy/ccpa - gpp - gppSid --- modules/insticatorBidAdapter.js | 63 +++++++- .../spec/modules/insticatorBidAdapter_spec.js | 151 +++++++++++++++++- 2 files changed, 205 insertions(+), 9 deletions(-) diff --git a/modules/insticatorBidAdapter.js b/modules/insticatorBidAdapter.js index 4d9b95e5948..2d93c0b3e8d 100644 --- a/modules/insticatorBidAdapter.js +++ b/modules/insticatorBidAdapter.js @@ -190,17 +190,59 @@ function buildDevice(bidRequest) { return device; } +function _getCoppa() { + return config.getConfig('coppa') === true ? 1 : 0; +} + +function _getGppConsent(bidderRequest) { + let gpp = deepAccess(bidderRequest, 'gppConsent.gppString') + let gppSid = deepAccess(bidderRequest, 'gppConsent.applicableSections') + + if (!gpp || !gppSid) { + gpp = deepAccess(bidderRequest, 'ortb2.regs.gpp', '') + gppSid = deepAccess(bidderRequest, 'ortb2.regs.gpp_sid', []) + } + return { gpp, gppSid } +} + +function _getUspConsent(bidderRequest) { + return (deepAccess(bidderRequest, 'uspConsent')) ? { uspConsent: bidderRequest.uspConsent } : false; +} + function buildRegs(bidderRequest) { + let regs = { + ext: {}, + }; if (bidderRequest.gdprConsent) { - return { - ext: { - gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0, - gdprConsentString: bidderRequest.gdprConsent.consentString, - }, - }; + regs.ext.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; + regs.ext.gdprConsentString = bidderRequest.gdprConsent.consentString; } - return {}; + regs.coppa = _getCoppa(); + + const { gpp, gppSid } = _getGppConsent(bidderRequest); + + if (gpp) { + regs.ext.gpp = gpp; + } + + if (gppSid) { + regs.ext.gppSid = gppSid; + } + + const usp = _getUspConsent(bidderRequest); + + if (usp) { + regs.ext.us_privacy = usp.uspConsent; + regs.ext.ccpa = usp.uspConsent + } + + const dsa = deepAccess(bidderRequest, 'ortb2.regs.ext.dsa'); + if (dsa) { + regs.ext.dsa = dsa; + } + + return regs; } function buildUser(bid) { @@ -326,6 +368,13 @@ function buildBid(bid, bidderRequest) { bidResponse.vastUrl = 'data:text/xml;charset=utf-8;base64,' + window.btoa(bidResponse.vastXml.replace(/\\"/g, '"')); } + if (bid.ext && bid.ext.dsa) { + bidResponse.ext = { + ...bidResponse.ext, + dsa: bid.ext.dsa, + } + } + return bidResponse; } diff --git a/test/spec/modules/insticatorBidAdapter_spec.js b/test/spec/modules/insticatorBidAdapter_spec.js index 86f96834547..18e27df53b1 100644 --- a/test/spec/modules/insticatorBidAdapter_spec.js +++ b/test/spec/modules/insticatorBidAdapter_spec.js @@ -497,11 +497,57 @@ describe('InsticatorBidAdapter', function () { expect(data.user.id).to.equal(USER_ID_STUBBED); }); - it('should return empty regs object if no gdprConsent is passed', function () { + it('should return with coppa regs object if no gdprConsent is passed', function () { const requests = spec.buildRequests([bidRequest], { ...bidderRequest, ...{ gdprConsent: false } }); const data = JSON.parse(requests[0].data); - expect(data.regs).to.be.an('object').that.is.empty; + expect(data.regs).to.be.an('object'); + expect(data.regs.coppa).to.be.oneOf([0, 1]); + }); + + it('should return with us_privacy string if uspConsent is passed', function () { + const requests = spec.buildRequests([bidRequest], { ...bidderRequest, ...{ uspConsent: '1YNN' } }); + const data = JSON.parse(requests[0].data); + expect(data.regs).to.be.an('object'); + expect(data.regs.ext).to.be.an('object'); + expect(data.regs.ext.us_privacy).to.equal('1YNN'); + expect(data.regs.ext.ccpa).to.equal('1YNN'); + }); + + it('should return with gpp if gppConsent is passed', function () { + const requests = spec.buildRequests([bidRequest], { ...bidderRequest, ...{ gppConsent: { gppString: '1YNN', applicableSections: ['1', '2'] } } }); + const data = JSON.parse(requests[0].data); + expect(data.regs).to.be.an('object'); + expect(data.regs.ext).to.be.an('object'); + expect(data.regs.ext.gppSid).to.deep.equal(['1', '2']); + }); + + it('should create the request with dsa data and return with dsa object', function() { + const dsa = { + dsarequired: 2, + pubrender: 1, + datatopub: 2, + transparency: [{ + domain: 'google.com', + dsaparams: [1, 2] + }] + } + const bidRequestWithDsa = { + ...bidderRequest, + ortb2: { + regs: { + ext: { + dsa: dsa + } + } + } + } + const requests = spec.buildRequests([bidRequest], {...bidRequestWithDsa}); + const data = JSON.parse(requests[0].data); + expect(data.regs).to.be.an('object'); + expect(data.regs.ext).to.be.an('object'); + expect(data.regs.ext.dsa).to.deep.equal(dsa); }); + it('should return empty array if no valid requests are passed', function () { expect(spec.buildRequests([], bidderRequest)).to.be.an('array').that.have.lengthOf(0); }); @@ -837,4 +883,105 @@ describe('InsticatorBidAdapter', function () { expect(bidResponse.vastUrl).to.match(/^data:text\/xml;charset=utf-8;base64,[\w+/=]+$/) }); }) + + describe(`Response with DSA data`, function() { + const bidRequestDsa = { + method: 'POST', + url: 'https://ex.ingage.tech/v1/openrtb', + options: { + contentType: 'application/json', + withCredentials: true, + }, + data: '', + bidderRequest: { + bidderRequestId: '22edbae2733bf6', + auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', + timeout: 300, + bids: [ + { + bidder: 'insticator', + params: { + adUnitId: '1a2b3c4d5e6f1a2b3c4d' + }, + adUnitCode: 'adunit-code-1', + mediaTypes: { + video: { + mimes: [ + 'video/mp4', + 'video/mpeg', + ], + playerSize: [[250, 300]], + placement: 2, + plcmt: 2, + } + }, + bidId: 'bid1', + } + ], + ortb2: { + regs: { + ext: { + dsa: { + dsarequired: 2, + pubrender: 1, + datatopub: 2, + transparency: [{ + domain: 'google.com', + dsaparams: [1, 2] + }] + } + }} + }, + } + }; + + const bidResponseDsa = { + body: { + id: '22edbae2733bf6', + bidid: 'foo9876', + cur: 'USD', + seatbid: [ + { + seat: 'some-dsp', + bid: [ + { + ad: '', + impid: 'bid1', + crid: 'crid1', + price: 0.5, + w: 300, + h: 250, + adm: '', + exp: 60, + adomain: ['test1.com'], + ext: { + meta: { + test: 1, + }, + dsa: { + behalf: 'Advertiser', + paid: 'Advertiser', + transparency: [{ + domain: 'google.com', + dsaparams: [1, 2] + }], + adrender: 1 + } + }, + } + ], + }, + ] + } + }; + const bidRequestWithDsa = utils.deepClone(bidRequestDsa); + it('should have related properties for DSA data', function() { + const serverResponseWithDsa = utils.deepClone(bidResponseDsa); + const bidResponse = spec.interpretResponse(serverResponseWithDsa, bidRequestWithDsa)[0]; + expect(bidResponse).to.have.any.keys('ext'); + expect(bidResponse.ext.dsa).to.have.property('behalf', 'Advertiser'); + expect(bidResponse.ext.dsa).to.have.property('paid', 'Advertiser'); + expect(bidResponse.ext.dsa).to.have.property('adrender', 1); + }); + }); }); From 89de802c4de6ce0be535b8819c976bc72f2642fb Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Wed, 20 Mar 2024 18:47:47 +0530 Subject: [PATCH 2/8] video validation fix --- modules/insticatorBidAdapter.js | 39 +++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/modules/insticatorBidAdapter.js b/modules/insticatorBidAdapter.js index 2d93c0b3e8d..ec31298b560 100644 --- a/modules/insticatorBidAdapter.js +++ b/modules/insticatorBidAdapter.js @@ -12,33 +12,41 @@ const USER_ID_COOKIE_EXP = 2592000000; // 30 days const BID_TTL = 300; // 5 minutes const GVLID = 910; -const isSubarray = (arr, target) => { +const filterArray = (arr, target) => { if (!isArrayOfNums(arr) || arr.length === 0) { - return false; + return []; } const targetSet = new Set(target); - return arr.every(el => targetSet.has(el)); + return arr.filter(el => targetSet.has(el)); }; +const VIDEO_NUM_ARRAY_PARAMS = { + 'protocols': [2, 3, 5, 6, 7, 8], + 'api': [1, 2, 3, 4, 5, 6, 7], + 'playbackmethod': [1, 2, 3, 4, 5, 6, 7], + 'delivery': [1, 2, 3], + 'battr': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], +} + export const OPTIONAL_VIDEO_PARAMS = { 'minduration': (value) => isInteger(value), 'maxduration': (value) => isInteger(value), - 'protocols': (value) => isSubarray(value, [2, 3, 5, 6, 7, 8]), // protocols values supported by Inticator, according to the OpenRTB spec + 'protocols': (value) => isArrayOfNums(value), // protocols values supported by Inticator, according to the OpenRTB spec 'startdelay': (value) => isInteger(value), 'linearity': (value) => isInteger(value) && [1].includes(value), 'skip': (value) => isInteger(value) && [1, 0].includes(value), 'skipmin': (value) => isInteger(value), 'skipafter': (value) => isInteger(value), 'sequence': (value) => isInteger(value), - 'battr': (value) => isSubarray(value, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]), + 'battr': (value) => isArrayOfNums(value), 'maxextended': (value) => isInteger(value), 'minbitrate': (value) => isInteger(value), 'maxbitrate': (value) => isInteger(value), - 'playbackmethod': (value) => isSubarray(value, [1, 2, 3, 4]), + 'playbackmethod': (value) => isArrayOfNums(value), 'playbackend': (value) => isInteger(value) && [1, 2, 3].includes(value), - 'delivery': (value) => isSubarray(value, [1, 2, 3]), + 'delivery': (value) => isArrayOfNums(value), 'pos': (value) => isInteger(value) && [0, 1, 2, 3, 4, 5, 6, 7].includes(value), - 'api': (value) => isSubarray(value, [1, 2, 3, 4, 5, 6, 7]), + 'api': (value) => isArrayOfNums(value), }; export const storage = getStorageManager({bidderCode: BIDDER_CODE}); @@ -121,10 +129,18 @@ function buildVideo(bidRequest) { const bidRequestVideo = deepAccess(bidRequest, 'mediaTypes.video'); const videoBidderParams = deepAccess(bidRequest, 'params.video', {}); + const videoParams = { + ...bidRequestVideo, + ...videoBidderParams // bidder specific overrides for video + } let optionalParams = {}; for (const param in OPTIONAL_VIDEO_PARAMS) { - if (bidRequestVideo[param]) { - optionalParams[param] = bidRequestVideo[param]; + if (videoParams[param]) { + if (param in VIDEO_NUM_ARRAY_PARAMS) { + optionalParams[param] = filterArray(videoParams[param], VIDEO_NUM_ARRAY_PARAMS[param]); + } else { + optionalParams[param] = videoParams[param]; + } } } @@ -137,8 +153,7 @@ function buildVideo(bidRequest) { mimes, w, h, - ...optionalParams, - ...videoBidderParams // bidder specific overrides for video + ...videoParams // bidder specific overrides for video } return videoObj From 78df3ed8ab1d85b55663714a8fd47735287cb1f9 Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Thu, 21 Mar 2024 20:32:52 +0530 Subject: [PATCH 3/8] support first part site details --- modules/insticatorBidAdapter.js | 19 ++++++++++ .../spec/modules/insticatorBidAdapter_spec.js | 38 ++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/modules/insticatorBidAdapter.js b/modules/insticatorBidAdapter.js index ec31298b560..9bdb8a96ad1 100644 --- a/modules/insticatorBidAdapter.js +++ b/modules/insticatorBidAdapter.js @@ -49,6 +49,16 @@ export const OPTIONAL_VIDEO_PARAMS = { 'api': (value) => isArrayOfNums(value), }; +const ORTB_SITE_FIRST_PARTY_DATA = { + 'cat': v => Array.isArray(v) && v.every(c => typeof c === 'string'), + 'sectioncat': v => Array.isArray(v) && v.every(c => typeof c === 'string'), + 'pagecat': v => Array.isArray(v) && v.every(c => typeof c === 'string'), + 'search': v => typeof v === 'string', + 'mobile': v => isInteger(), + 'content': v => typeof v === 'object', + 'keywords': v => typeof v === 'string', +} + export const storage = getStorageManager({bidderCode: BIDDER_CODE}); config.setDefaults({ @@ -340,6 +350,15 @@ function buildRequest(validBidRequests, bidderRequest) { req.user.ext = { eids }; } + const ortb2SiteData = deepAccess(bidderRequest, 'ortb2.site'); + if (ortb2SiteData) { + for (const key in ORTB_SITE_FIRST_PARTY_DATA) { + const value = ortb2SiteData[key]; + if (value && ORTB_SITE_FIRST_PARTY_DATA[key](value)) { + req.site[key] = value; + } + } + } return req; } diff --git a/test/spec/modules/insticatorBidAdapter_spec.js b/test/spec/modules/insticatorBidAdapter_spec.js index 18e27df53b1..c18e9d04105 100644 --- a/test/spec/modules/insticatorBidAdapter_spec.js +++ b/test/spec/modules/insticatorBidAdapter_spec.js @@ -75,7 +75,7 @@ describe('InsticatorBidAdapter', function () { ortb2: { source: { tid: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', - } + }, }, timeout: 300, gdprConsent: { @@ -497,6 +497,7 @@ describe('InsticatorBidAdapter', function () { expect(data.user.id).to.equal(USER_ID_STUBBED); }); + it('should return with coppa regs object if no gdprConsent is passed', function () { const requests = spec.buildRequests([bidRequest], { ...bidderRequest, ...{ gdprConsent: false } }); const data = JSON.parse(requests[0].data); @@ -585,6 +586,41 @@ describe('InsticatorBidAdapter', function () { expect(data.imp[0].video.w).to.equal(640); expect(data.imp[0].video.h).to.equal(480); }); + + it('should have sites first party data if present in bidderRequest ortb2', function () { + bidderRequest = { + ...bidderRequest, + ortb2: { + ...bidderRequest.ortb2, + site: { + keywords: 'keyword1,keyword2', + search: 'search', + content: { + title: 'title', + keywords: 'keyword3,keyword4', + genre: 'rock' + }, + cat: ['IAB1', 'IAB2'] + } + } + } + const requests = spec.buildRequests([bidRequest], bidderRequest); + const data = JSON.parse(requests[0].data); + expect(data).to.have.property('site'); + expect(data.site).to.have.property('keywords'); + expect(data.site.keywords).to.equal('keyword1,keyword2'); + expect(data.site).to.have.property('search'); + expect(data.site.search).to.equal('search'); + expect(data.site).to.have.property('content'); + expect(data.site.content).to.have.property('title'); + expect(data.site.content.title).to.equal('title'); + expect(data.site.content).to.have.property('keywords'); + expect(data.site.content.keywords).to.equal('keyword3,keyword4'); + expect(data.site.content).to.have.property('genre'); + expect(data.site.content.genre).to.equal('rock'); + expect(data.site).to.have.property('cat'); + expect(data.site.cat).to.deep.equal(['IAB1', 'IAB2']); + }); }); describe('interpretResponse', function () { From 9a34ff6f8a74e1e81ef5c665229c2bb100abaccd Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Fri, 22 Mar 2024 23:16:01 +0530 Subject: [PATCH 4/8] support user data from bidder, and update server endpoint for alternative bidder configs --- modules/insticatorBidAdapter.js | 33 ++++++++++++-- .../spec/modules/insticatorBidAdapter_spec.js | 45 +++++++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/modules/insticatorBidAdapter.js b/modules/insticatorBidAdapter.js index 9bdb8a96ad1..be766e31e18 100644 --- a/modules/insticatorBidAdapter.js +++ b/modules/insticatorBidAdapter.js @@ -274,14 +274,32 @@ function buildUser(bid) { const userId = getUserId() || generateUUID(); const yob = deepAccess(bid, 'params.user.yob') const gender = deepAccess(bid, 'params.user.gender') + const keywords = deepAccess(bid, 'params.user.keywords') + const data = deepAccess(bid, 'params.user.data') setUserId(userId); - return { + const userData = { id: userId, - yob, - gender, - }; + } + + if (yob) { + userData.yob = yob; + } + + if (gender) { + userData.gender = gender; + } + + if (keywords) { + userData.keywords = keywords; + } + + if (data) { + userData.data = data; + } + + return userData } function extractSchain(bids, requestId) { @@ -568,6 +586,13 @@ export const spec = { let endpointUrl = config.getConfig('insticator.endpointUrl') || ENDPOINT; endpointUrl = endpointUrl.replace(/^http:/, 'https:'); + // Use the first bid request's bid_request_url if it exists ( for updating server url) + if (validBidRequests.length > 0) { + if (deepAccess(validBidRequests[0], 'params.bid_endpoint_request_url')) { + endpointUrl = deepAccess(validBidRequests[0], 'params.bid_endpoint_request_url').replace(/^http:/, 'https:'); + } + } + if (validBidRequests.length > 0) { requests.push({ method: 'POST', diff --git a/test/spec/modules/insticatorBidAdapter_spec.js b/test/spec/modules/insticatorBidAdapter_spec.js index c18e9d04105..78b8b13590f 100644 --- a/test/spec/modules/insticatorBidAdapter_spec.js +++ b/test/spec/modules/insticatorBidAdapter_spec.js @@ -621,6 +621,51 @@ describe('InsticatorBidAdapter', function () { expect(data.site).to.have.property('cat'); expect(data.site.cat).to.deep.equal(['IAB1', 'IAB2']); }); + + it('should have device.sua if present in bidderRequest ortb2', function () { + bidderRequest = { + ...bidderRequest, + ortb2: { + ...bidderRequest.ortb2, + device: { + ...bidderRequest.ortb2.device, + sua: {} + } + } + } + const requests = spec.buildRequests([bidRequest], bidderRequest); + const data = JSON.parse(requests[0].data); + expect(data).to.have.property('device'); + expect(data.device).to.have.property('sua'); + }) + + it('should use param bid_endpoint_request_url for request endpoint if present', function () { + const tempBiddRequest = { + ...bidRequest, + params: { + ...bidRequest.params, + bid_endpoint_request_url: 'https://example.com' + } + } + const requests = spec.buildRequests([tempBiddRequest], bidderRequest); + expect(requests[0].url).to.equal('https://example.com'); + }); + + it('should have user keywords if present in bidrequest', function () { + const tempBiddRequest = { + ...bidRequest, + params: { + ...bidRequest.params, + user: { + keywords: 'keyword1,keyword2' + } + } + } + const requests = spec.buildRequests([tempBiddRequest], bidderRequest); + const data = JSON.parse(requests[0].data); + expect(data.user).to.have.property('keywords'); + expect(data.user.keywords).to.equal('keyword1,keyword2'); + }); }); describe('interpretResponse', function () { From 7ad51e996dd7a1208412a879d0f843cdd4c8af99 Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Tue, 26 Mar 2024 01:46:55 +0530 Subject: [PATCH 5/8] - enhance user object with ext and consent - remove video param validation --- modules/insticatorBidAdapter.js | 47 +++++++--------- .../spec/modules/insticatorBidAdapter_spec.js | 55 ++++++++++++------- 2 files changed, 55 insertions(+), 47 deletions(-) diff --git a/modules/insticatorBidAdapter.js b/modules/insticatorBidAdapter.js index be766e31e18..18e7789a35b 100644 --- a/modules/insticatorBidAdapter.js +++ b/modules/insticatorBidAdapter.js @@ -12,22 +12,6 @@ const USER_ID_COOKIE_EXP = 2592000000; // 30 days const BID_TTL = 300; // 5 minutes const GVLID = 910; -const filterArray = (arr, target) => { - if (!isArrayOfNums(arr) || arr.length === 0) { - return []; - } - const targetSet = new Set(target); - return arr.filter(el => targetSet.has(el)); -}; - -const VIDEO_NUM_ARRAY_PARAMS = { - 'protocols': [2, 3, 5, 6, 7, 8], - 'api': [1, 2, 3, 4, 5, 6, 7], - 'playbackmethod': [1, 2, 3, 4, 5, 6, 7], - 'delivery': [1, 2, 3], - 'battr': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], -} - export const OPTIONAL_VIDEO_PARAMS = { 'minduration': (value) => isInteger(value), 'maxduration': (value) => isInteger(value), @@ -139,18 +123,15 @@ function buildVideo(bidRequest) { const bidRequestVideo = deepAccess(bidRequest, 'mediaTypes.video'); const videoBidderParams = deepAccess(bidRequest, 'params.video', {}); - const videoParams = { - ...bidRequestVideo, - ...videoBidderParams // bidder specific overrides for video - } + let optionalParams = {}; for (const param in OPTIONAL_VIDEO_PARAMS) { - if (videoParams[param]) { - if (param in VIDEO_NUM_ARRAY_PARAMS) { - optionalParams[param] = filterArray(videoParams[param], VIDEO_NUM_ARRAY_PARAMS[param]); - } else { - optionalParams[param] = videoParams[param]; - } + if (bidRequestVideo[param] && OPTIONAL_VIDEO_PARAMS[param](bidRequestVideo[param])) { + optionalParams[param] = bidRequestVideo[param]; + } + // remove invalid optional params from bidder specific overrides + if (videoBidderParams[param] && !OPTIONAL_VIDEO_PARAMS[param](videoBidderParams[param])) { + delete videoBidderParams[param]; } } @@ -163,7 +144,8 @@ function buildVideo(bidRequest) { mimes, w, h, - ...videoParams // bidder specific overrides for video + ...optionalParams, + ...videoBidderParams // bidder specific overrides for video } return videoObj @@ -276,6 +258,7 @@ function buildUser(bid) { const gender = deepAccess(bid, 'params.user.gender') const keywords = deepAccess(bid, 'params.user.keywords') const data = deepAccess(bid, 'params.user.data') + const ext = deepAccess(bid, 'params.user.ext') setUserId(userId); @@ -299,6 +282,10 @@ function buildUser(bid) { userData.data = data; } + if (ext) { + userData.ext = ext; + } + return userData } @@ -377,6 +364,11 @@ function buildRequest(validBidRequests, bidderRequest) { } } } + + if (req.regs.ext.gdpr === 1 && req.regs.ext.gdprConsentString) { + req.user.ext.consent = req.regs.ext.gdprConsentString || ''; + } + return req; } @@ -554,7 +546,6 @@ function validateVideo(bid) { if (video[param]) { if (!OPTIONAL_VIDEO_PARAMS[param](video[param])) { logError(`insticator: video ${param} is invalid or not supported by insticator`); - return false } } } diff --git a/test/spec/modules/insticatorBidAdapter_spec.js b/test/spec/modules/insticatorBidAdapter_spec.js index 78b8b13590f..e1698550266 100644 --- a/test/spec/modules/insticatorBidAdapter_spec.js +++ b/test/spec/modules/insticatorBidAdapter_spec.js @@ -78,6 +78,7 @@ describe('InsticatorBidAdapter', function () { }, }, timeout: 300, + gdprApplies: 1, gdprConsent: { consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', vendorData: {}, @@ -261,25 +262,6 @@ describe('InsticatorBidAdapter', function () { })).to.be.true; }); - it('should return false if optional video fields are not valid', () => { - expect(spec.isBidRequestValid({ - ...bidRequest, - ...{ - mediaTypes: { - video: { - mimes: [ - 'video/mp4', - 'video/mpeg', - ], - playerSize: [250, 300], - placement: 1, - startdelay: 'NaN', - }, - } - } - })).to.be.false; - }); - it('should return false if video min duration > max duration', () => { expect(spec.isBidRequestValid({ ...bidRequest, @@ -666,6 +648,41 @@ describe('InsticatorBidAdapter', function () { expect(data.user).to.have.property('keywords'); expect(data.user.keywords).to.equal('keyword1,keyword2'); }); + + it('should remove video params if they are invalid', function () { + const tempBiddRequest = { + ...bidRequest, + mediaTypes: { + ...bidRequest.mediaTypes, + video: { + mimes: [ + 'video/mp4', + 'video/mpeg', + 'video/x-flv', + 'video/webm', + 'video/ogg', + ], + protocols: 'NaN', + w: '300', + h: '250', + } + } + } + const requests = spec.buildRequests([tempBiddRequest], bidderRequest); + const data = JSON.parse(requests[0].data); + expect(data.imp[0].video).to.not.have.property('plcmt'); + }); + + it('should have user consent and gdpr string if gdprConsent is passed', function () { + const requests = spec.buildRequests([bidRequest], bidderRequest); + const data = JSON.parse(requests[0].data); + expect(data.regs).to.be.an('object'); + expect(data.regs.ext).to.be.an('object'); + expect(data.regs.ext.gdpr).to.equal(1); + expect(data.regs.ext.gdprConsentString).to.equal(bidderRequest.gdprConsent.consentString); + expect(data.user.ext).to.have.property('consent'); + expect(data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); + }); }); describe('interpretResponse', function () { From 06858eddead0e6c6a304ef22536b77832b942a1f Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Tue, 26 Mar 2024 01:51:38 +0530 Subject: [PATCH 6/8] add test case for more than one privacy platforms --- test/spec/modules/insticatorBidAdapter_spec.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/spec/modules/insticatorBidAdapter_spec.js b/test/spec/modules/insticatorBidAdapter_spec.js index e1698550266..5e41cd6d7aa 100644 --- a/test/spec/modules/insticatorBidAdapter_spec.js +++ b/test/spec/modules/insticatorBidAdapter_spec.js @@ -683,6 +683,14 @@ describe('InsticatorBidAdapter', function () { expect(data.user.ext).to.have.property('consent'); expect(data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); }); + + it('should have one or more privacy policies if present in bidrequest, like gpp, gdpr and us_privacy', function () { + const requests = spec.buildRequests([bidRequest], { ...bidderRequest, ...{ uspConsent: '1YNN' } }); + const data = JSON.parse(requests[0].data); + expect(data.regs.ext).to.have.property('gdpr'); + expect(data.regs.ext).to.have.property('us_privacy'); + expect(data.regs.ext).to.have.property('gppSid'); + }); }); describe('interpretResponse', function () { From df112dc1e28340b45788bb71c25e934dbd039332 Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Tue, 26 Mar 2024 11:25:49 +0530 Subject: [PATCH 7/8] update user.ext.consent --- modules/insticatorBidAdapter.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/insticatorBidAdapter.js b/modules/insticatorBidAdapter.js index 18e7789a35b..655481f26af 100644 --- a/modules/insticatorBidAdapter.js +++ b/modules/insticatorBidAdapter.js @@ -1,7 +1,7 @@ import {config} from '../src/config.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {deepAccess, generateUUID, logError, isArray, isInteger, isArrayOfNums} from '../src/utils.js'; +import {deepAccess, generateUUID, logError, isArray, isInteger, isArrayOfNums, deepSetValue} from '../src/utils.js'; import {getStorageManager} from '../src/storageManager.js'; import {find} from '../src/polyfill.js'; @@ -365,8 +365,8 @@ function buildRequest(validBidRequests, bidderRequest) { } } - if (req.regs.ext.gdpr === 1 && req.regs.ext.gdprConsentString) { - req.user.ext.consent = req.regs.ext.gdprConsentString || ''; + if (bidderRequest.gdprConsent) { + deepSetValue(req, 'user.ext.consent', bidderRequest.gdprConsent.consentString); } return req; From e38b2f694ee697b0ae78fe0c1ca5dc5980ae7857 Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Wed, 10 Apr 2024 15:39:05 +0530 Subject: [PATCH 8/8] update coppa and support video context --- modules/insticatorBidAdapter.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/modules/insticatorBidAdapter.js b/modules/insticatorBidAdapter.js index 655481f26af..617ce49f171 100644 --- a/modules/insticatorBidAdapter.js +++ b/modules/insticatorBidAdapter.js @@ -105,6 +105,7 @@ function buildVideo(bidRequest) { const placement = deepAccess(bidRequest, 'mediaTypes.video.placement') || 3; const plcmt = deepAccess(bidRequest, 'mediaTypes.video.plcmt') || undefined; const playerSize = deepAccess(bidRequest, 'mediaTypes.video.playerSize'); + const context = deepAccess(bidRequest, 'mediaTypes.video.context'); if (!w && playerSize) { if (Array.isArray(playerSize[0])) { @@ -139,6 +140,10 @@ function buildVideo(bidRequest) { optionalParams['plcmt'] = plcmt; } + if (context !== undefined) { + optionalParams['context'] = context; + } + let videoObj = { placement, mimes, @@ -197,7 +202,13 @@ function buildDevice(bidRequest) { return device; } -function _getCoppa() { +function _getCoppa(bidderRequest) { + const coppa = deepAccess(bidderRequest, 'ortb2.regs.coppa'); + + // If coppa is defined in the request, use it + if (coppa !== undefined) { + return coppa; + } return config.getConfig('coppa') === true ? 1 : 0; } @@ -225,7 +236,7 @@ function buildRegs(bidderRequest) { regs.ext.gdprConsentString = bidderRequest.gdprConsent.consentString; } - regs.coppa = _getCoppa(); + regs.coppa = _getCoppa(bidderRequest); const { gpp, gppSid } = _getGppConsent(bidderRequest);