diff --git a/modules/fluctBidAdapter.js b/modules/fluctBidAdapter.js index 3ba1356acd..0281e47c95 100644 --- a/modules/fluctBidAdapter.js +++ b/modules/fluctBidAdapter.js @@ -10,7 +10,7 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'fluct'; const END_POINT = 'https://hb.adingo.jp/prebid/'; -const VERSION = '1.3'; +const VERSION = '1.5'; const NET_REVENUE = true; const TTL = 300; const DEFAULT_CURRENCY = 'JPY'; @@ -118,6 +118,20 @@ export const spec = { const data = {}; data.page = page; + + const ortb2Site = bidderRequest.ortb2?.site; + if (ortb2Site) { + data.site = {}; + if (ortb2Site.cat) data.site.cat = ortb2Site.cat; + if (ortb2Site.sectioncat) data.site.sectioncat = ortb2Site.sectioncat; + if (ortb2Site.pagecat) data.site.pagecat = ortb2Site.pagecat; + if (ortb2Site.keywords) data.site.keywords = ortb2Site.keywords; + if (ortb2Site.content) data.site.content = ortb2Site.content; + if (ortb2Site.domain) data.site.domain = ortb2Site.domain; + if (ortb2Site.ref) data.site.ref = ortb2Site.ref; + if (ortb2Site.ext?.data) data.site.ext = { data: ortb2Site.ext.data }; + } + data.adUnitCode = request.adUnitCode; data.bidId = request.bidId; data.user = { @@ -131,6 +145,9 @@ export const spec = { if (impExt) { data.transactionId = impExt.tid; data.gpid = impExt.gpid ?? impExt.data?.adserver?.adslot; + if (impExt.data) { + deepSetValue(data, 'imp.ext.data', impExt.data); + } } if (bidderRequest.gdprConsent) { deepSetValue(data, 'regs.gdpr', { @@ -187,6 +204,22 @@ export const spec = { data.instl = deepAccess(request, 'ortb2Imp.instl') === 1 || request.params.instl === 1 ? 1 : 0; + if (deepAccess(request, 'ortb2Imp.rwdd') === 1) data.rwdd = 1; + + const pos = deepAccess(request, 'mediaTypes.banner.pos') ?? deepAccess(request, 'ortb2Imp.ext.data.pos'); + if (pos != null) data.pos = pos; + + const ortb2Device = bidderRequest.ortb2?.device; + if (ortb2Device) { + data.device = {}; + if (ortb2Device.sua) data.device.sua = ortb2Device.sua; + if (ortb2Device.ua) data.device.ua = ortb2Device.ua; + if (ortb2Device.w) data.device.w = ortb2Device.w; + if (ortb2Device.h) data.device.h = ortb2Device.h; + if (ortb2Device.language) data.device.language = ortb2Device.language; + if (ortb2Device.devicetype) data.device.devicetype = ortb2Device.devicetype; + } + // Set top-level bidfloor to the highest floor across all sizes const highestFloorData = getHighestBidFloor(request); if (highestFloorData) { diff --git a/test/spec/modules/fluctBidAdapter_spec.js b/test/spec/modules/fluctBidAdapter_spec.js index eeb1e3535e..99d7d1c78a 100644 --- a/test/spec/modules/fluctBidAdapter_spec.js +++ b/test/spec/modules/fluctBidAdapter_spec.js @@ -439,6 +439,166 @@ describe('fluctAdapter', function () { expect(request.data.regs.gpp.sid).to.eql([1, 2, 3]); }); + it('includes no data.site by default', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.site).to.eql(undefined); + }); + + it('includes data.site if ortb2.site exists', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { + site: { + cat: ['IAB1', 'IAB2'], + sectioncat: ['IAB1-1'], + pagecat: ['IAB1-2'], + keywords: 'sports,news', + content: { language: 'ja' }, + domain: 'example.com', + ref: 'https://referrer.example.com', + ext: { data: { customKey: 'customValue' } }, + }, + }, + }))[0]; + expect(request.data.site).to.eql({ + cat: ['IAB1', 'IAB2'], + sectioncat: ['IAB1-1'], + pagecat: ['IAB1-2'], + keywords: 'sports,news', + content: { language: 'ja' }, + domain: 'example.com', + ref: 'https://referrer.example.com', + ext: { data: { customKey: 'customValue' } }, + }); + }); + + it('includes only specified fields in data.site', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { + site: { + cat: ['IAB1'], + domain: 'example.com', + }, + }, + }))[0]; + expect(request.data.site).to.eql({ + cat: ['IAB1'], + domain: 'example.com', + }); + }); + + it('includes no data.pos by default', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.pos).to.eql(undefined); + }); + + it('includes data.pos from mediaTypes.banner.pos', function () { + const request = spec.buildRequests(bidRequests.map((req) => ({ + ...req, + mediaTypes: { banner: { sizes: [[300, 250]], pos: 1 } }, + })), bidderRequest)[0]; + expect(request.data.pos).to.eql(1); + }); + + it('includes data.pos from ortb2Imp.ext.data.pos as fallback', function () { + const request = spec.buildRequests(bidRequests.map((req) => ({ + ...req, + ortb2Imp: { ext: { data: { pos: 3 } } }, + })), bidderRequest)[0]; + expect(request.data.pos).to.eql(3); + }); + + it('prefers mediaTypes.banner.pos over ortb2Imp.ext.data.pos', function () { + const request = spec.buildRequests(bidRequests.map((req) => ({ + ...req, + mediaTypes: { banner: { sizes: [[300, 250]], pos: 1 } }, + ortb2Imp: { ext: { data: { pos: 3 } } }, + })), bidderRequest)[0]; + expect(request.data.pos).to.eql(1); + }); + + it('includes no data.device by default', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.device).to.eql(undefined); + }); + + it('includes data.device if ortb2.device exists', function () { + const sua = { browsers: [{ brand: 'Chrome', version: ['120'] }] }; + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { + device: { + sua, + ua: 'Mozilla/5.0', + w: 1920, + h: 1080, + language: 'ja', + devicetype: 2, + }, + }, + }))[0]; + expect(request.data.device).to.eql({ + sua, + ua: 'Mozilla/5.0', + w: 1920, + h: 1080, + language: 'ja', + devicetype: 2, + }); + }); + + it('includes only specified fields in data.device', function () { + const sua = { browsers: [{ brand: 'Chrome', version: ['120'] }] }; + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { + device: { sua }, + }, + }))[0]; + expect(request.data.device).to.eql({ sua }); + }); + + it('includes no data.imp by default', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.imp).to.eql(undefined); + }); + + it('includes data.imp.ext.data from ortb2Imp.ext.data', function () { + const request = spec.buildRequests(bidRequests.map((req) => ({ + ...req, + ortb2Imp: { + ext: { + data: { + section: 'sports', + contentType: 'article', + }, + }, + }, + })), bidderRequest)[0]; + expect(request.data.imp.ext.data).to.eql({ + section: 'sports', + contentType: 'article', + }); + }); + + it('sends no rwdd by default', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.rwdd).to.eql(undefined); + }); + + it('sends ortb2Imp.rwdd as rwdd', function () { + const request = spec.buildRequests(bidRequests.map((req) => ({ + ...req, + ortb2Imp: { rwdd: 1 }, + })), bidderRequest)[0]; + expect(request.data.rwdd).to.eql(1); + }); + + it('sends no rwdd when ortb2Imp.rwdd is 0', function () { + const request = spec.buildRequests(bidRequests.map((req) => ({ + ...req, + ortb2Imp: { rwdd: 0 }, + })), bidderRequest)[0]; + expect(request.data.rwdd).to.eql(undefined); + }); + it('sends no instl as instl = 0', function () { const request = spec.buildRequests(bidRequests, bidderRequest)[0]; expect(request.data.instl).to.eql(0);