diff --git a/libraries/targetVideoUtils/bidderUtils.js b/libraries/targetVideoUtils/bidderUtils.js index f18540818cb..cf106566944 100644 --- a/libraries/targetVideoUtils/bidderUtils.js +++ b/libraries/targetVideoUtils/bidderUtils.js @@ -1,6 +1,7 @@ +import {SYNC_URL} from './constants.js'; import {VIDEO} from '../../src/mediaTypes.js'; import {getRefererInfo} from '../../src/refererDetection.js'; -import {createTrackPixelHtml, deepAccess, getBidRequest} from '../../src/utils.js'; +import {createTrackPixelHtml, deepAccess, getBidRequest, formatQS} from '../../src/utils.js'; export function getSizes(request) { let sizes = request.sizes; @@ -167,6 +168,40 @@ export function getAd(bid) { return {ad, adUrl, vastXml, vastUrl}; } +export function getSyncResponse(syncOptions, gdprConsent, uspConsent, gppConsent, endpoint) { + const params = { + endpoint + }; + + // 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; +} + export function getSiteObj() { const refInfo = (getRefererInfo && getRefererInfo()) || {}; diff --git a/libraries/targetVideoUtils/constants.js b/libraries/targetVideoUtils/constants.js index 1f47846eba4..33076b71e7d 100644 --- a/libraries/targetVideoUtils/constants.js +++ b/libraries/targetVideoUtils/constants.js @@ -9,7 +9,7 @@ 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' + 'plcmt', 'playbackmethod', 'protocols', 'startdelay', 'placement' ]; export { diff --git a/modules/bridBidAdapter.js b/modules/bridBidAdapter.js index 74f5e66b90b..c822f4d5c80 100644 --- a/modules/bridBidAdapter.js +++ b/modules/bridBidAdapter.js @@ -1,8 +1,8 @@ -import {_each, deepAccess, formatQS, getDefinedParams, parseGPTSingleSizeArrayToRtbSize} from '../src/utils.js'; +import {_each, deepAccess, 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'; +import {getAd, getSiteObj, getSyncResponse} from '../libraries/targetVideoUtils/bidderUtils.js' +import {GVLID, SOURCE, TIME_TO_LIVE, VIDEO_ENDPOINT_URL, VIDEO_PARAMS} from '../libraries/targetVideoUtils/constants.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -178,37 +178,7 @@ export const spec = { * 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; + return getSyncResponse(syncOptions, gdprConsent, uspConsent, gppConsent, 'brid'); } } diff --git a/modules/targetVideoBidAdapter.js b/modules/targetVideoBidAdapter.js index fd5d79d08b7..b01e3dddab3 100644 --- a/modules/targetVideoBidAdapter.js +++ b/modules/targetVideoBidAdapter.js @@ -1,7 +1,7 @@ import {_each, getDefinedParams, parseGPTSingleSizeArrayToRtbSize} from '../src/utils.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {formatRequest, getRtbBid, getSiteObj, videoBid, bannerBid, createVideoTag} from '../libraries/targetVideoUtils/bidderUtils.js'; +import {formatRequest, getRtbBid, getSiteObj, getSyncResponse, videoBid, bannerBid, createVideoTag} from '../libraries/targetVideoUtils/bidderUtils.js'; import {SOURCE, GVLID, BIDDER_CODE, VIDEO_PARAMS, BANNER_ENDPOINT_URL, VIDEO_ENDPOINT_URL, MARGIN, TIME_TO_LIVE} from '../libraries/targetVideoUtils/constants.js'; /** @@ -167,14 +167,26 @@ export const spec = { _each(resp.bid, (bid) => { const requestId = bidRequest.bidId; const params = bidRequest.params; - - bids.push(videoBid(bid, requestId, currency, params, TIME_TO_LIVE)); + const vBid = videoBid(bid, requestId, currency, params, TIME_TO_LIVE); + if (bids.length == 0 || bids[0].cpm < vBid.cpm) { + bids[0] = vBid; + } }); }); } return bids; + }, + + /** + * 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) => { + return getSyncResponse(syncOptions, gdprConsent, uspConsent, gppConsent, 'targetvideo'); } + } registerBidder(spec); diff --git a/test/spec/modules/targetVideoBidAdapter_spec.js b/test/spec/modules/targetVideoBidAdapter_spec.js index 442d7e7ef0b..61df5413862 100644 --- a/test/spec/modules/targetVideoBidAdapter_spec.js +++ b/test/spec/modules/targetVideoBidAdapter_spec.js @@ -1,4 +1,5 @@ import { spec } from '../../../modules/targetVideoBidAdapter.js' +import { SYNC_URL } from '../../../libraries/targetVideoUtils/constants.js'; describe('TargetVideo Bid Adapter', function() { const bidder = 'targetVideo'; @@ -237,4 +238,23 @@ describe('TargetVideo Bid Adapter', function() { expect(payload.regs.ext.us_privacy).to.equal(uspConsentString); expect(payload.regs.ext.gdpr).to.equal(1); }); + + 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=targetvideo&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); + }); });