diff --git a/modules/discoveryBidAdapter.js b/modules/discoveryBidAdapter.js index 816ec3cbe1f..315df48fa5d 100644 --- a/modules/discoveryBidAdapter.js +++ b/modules/discoveryBidAdapter.js @@ -6,7 +6,7 @@ import { BANNER, NATIVE } from '../src/mediaTypes.js'; const BIDDER_CODE = 'discovery'; const ENDPOINT_URL = 'https://rtb-jp.mediago.io/api/bid?tn='; const TIME_TO_LIVE = 500; -const storage = getStorageManager({bidderCode: BIDDER_CODE}); +export const storage = getStorageManager({bidderCode: BIDDER_CODE}); let globals = {}; let itemMaps = {}; const MEDIATYPE = [BANNER, NATIVE]; @@ -14,6 +14,9 @@ const MEDIATYPE = [BANNER, NATIVE]; /* ----- _ss_pp_id:start ------ */ const COOKIE_KEY_SSPPID = '_ss_pp_id'; const COOKIE_KEY_MGUID = '__mguid_'; +const COOKIE_KEY_PMGUID = '__pmguid_'; +const COOKIE_RETENTION_TIME = 365 * 24 * 60 * 60 * 1000; // 1 year +const COOKY_SYNC_IFRAME_URL = 'https://asset.popin.cc/js/cookieSync.html'; const NATIVERET = { id: 'id', @@ -55,24 +58,22 @@ const NATIVERET = { }; /** - * 获取用户id + * 获取并生成用户的id * @return {string} */ -const getUserID = () => { - let idd = storage.getCookie(COOKIE_KEY_SSPPID); - let idm = storage.getCookie(COOKIE_KEY_MGUID); - - if (idd && !idm) { - idm = idd; - } else if (idm && !idd) { - idd = idm; - } else if (!idd && !idm) { - const uuid = utils.generateUUID(); - storage.setCookie(COOKIE_KEY_MGUID, uuid); - storage.setCookie(COOKIE_KEY_SSPPID, uuid); - return uuid; +export const getPmgUID = () => { + if (!storage.cookiesAreEnabled()) return; + + let pmgUid = storage.getCookie(COOKIE_KEY_PMGUID); + if (!pmgUid) { + pmgUid = utils.generateUUID(); + const date = new Date(); + date.setTime(date.getTime() + COOKIE_RETENTION_TIME); + try { + storage.setCookie(COOKIE_KEY_PMGUID, pmgUid, date.toUTCString()); + } catch (e) {} } - return idd; + return pmgUid; }; /* ----- _ss_pp_id:end ------ */ @@ -381,9 +382,11 @@ function getParam(validBidRequests, bidderRequest) { ext: { eids, firstPartyData, + ssppid: storage.getCookie(COOKIE_KEY_SSPPID) || undefined, + pmguid: getPmgUID(), }, user: { - buyeruid: getUserID(), + buyeruid: storage.getCookie(COOKIE_KEY_MGUID) || undefined, id: sharedid || pubcid, }, tmax: timeout, @@ -547,6 +550,31 @@ export const spec = { return bidResponses; }, + getUserSyncs: function (syncOptions, serverResponse, gdprConsent, uspConsent, gppConsent) { + const origin = encodeURIComponent(location.origin || `https://${location.host}`); + let syncParamUrl = `dm=${origin}`; + + if (gdprConsent && gdprConsent.consentString) { + if (typeof gdprConsent.gdprApplies === 'boolean') { + syncParamUrl += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + syncParamUrl += `&gdpr=0&gdpr_consent=${gdprConsent.consentString}`; + } + } + if (uspConsent && uspConsent.consentString) { + syncParamUrl += `&ccpa_consent=${uspConsent.consentString}`; + } + + if (syncOptions.iframeEnabled) { + return [ + { + type: 'iframe', + url: `${COOKY_SYNC_IFRAME_URL}?${syncParamUrl}` + } + ]; + } + }, + /** * Register bidder specific code, which will execute if bidder timed out after an auction * @param {data} Containing timeout specific data diff --git a/test/spec/modules/discoveryBidAdapter_spec.js b/test/spec/modules/discoveryBidAdapter_spec.js index 8957f8bbd40..acfc519bef9 100644 --- a/test/spec/modules/discoveryBidAdapter_spec.js +++ b/test/spec/modules/discoveryBidAdapter_spec.js @@ -1,5 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/discoveryBidAdapter.js'; +import { spec, getPmgUID, storage } from 'modules/discoveryBidAdapter.js'; +import * as utils from 'src/utils.js'; describe('discovery:BidAdapterTests', function () { let bidRequestData = { @@ -98,6 +99,47 @@ describe('discovery:BidAdapterTests', function () { expect(req_data.imp).to.have.lengthOf(1); }); + describe('discovery: buildRequests', function() { + describe('getPmgUID function', function() { + let sandbox; + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + sandbox.stub(storage, 'getCookie'); + sandbox.stub(storage, 'setCookie'); + sandbox.stub(utils, 'generateUUID').returns('new-uuid'); + sandbox.stub(storage, 'cookiesAreEnabled'); + }) + + afterEach(() => { + sandbox.restore(); + }); + + it('should generate new UUID and set cookie if not exists', () => { + storage.cookiesAreEnabled.callsFake(() => true); + storage.getCookie.callsFake(() => null); + const uid = getPmgUID(); + expect(uid).to.equal('new-uuid'); + expect(storage.setCookie.calledOnce).to.be.true; + }); + + it('should return existing UUID from cookie', () => { + storage.cookiesAreEnabled.callsFake(() => true); + storage.getCookie.callsFake(() => 'existing-uuid'); + const uid = getPmgUID(); + expect(uid).to.equal('existing-uuid'); + expect(storage.setCookie.called).to.be.false; + }); + + it('should not set new UUID when cookies are not enabled', () => { + storage.cookiesAreEnabled.callsFake(() => false); + storage.getCookie.callsFake(() => null); + getPmgUID(); + expect(storage.setCookie.calledOnce).to.be.false; + }); + }) + }); + it('discovery:validate_response_params', function () { let tempAdm = '
' tempAdm += '%3Cscr'; @@ -137,4 +179,42 @@ describe('discovery:BidAdapterTests', function () { expect(bid.height).to.equal(250); expect(bid.currency).to.equal('USD'); }); + + describe('discovery: getUserSyncs', function() { + const COOKY_SYNC_IFRAME_URL = 'https://asset.popin.cc/js/cookieSync.html'; + const IFRAME_ENABLED = { + iframeEnabled: true, + pixelEnabled: false, + }; + const IFRAME_DISABLED = { + iframeEnabled: false, + pixelEnabled: false, + }; + const GDPR_CONSENT = { + consentString: 'gdprConsentString', + gdprApplies: true + }; + const USP_CONSENT = { + consentString: 'uspConsentString' + } + + let syncParamUrl = `dm=${encodeURIComponent(location.origin || `https://${location.host}`)}`; + syncParamUrl += '&gdpr=1&gdpr_consent=gdprConsentString&ccpa_consent=uspConsentString'; + const expectedIframeSyncs = [ + { + type: 'iframe', + url: `${COOKY_SYNC_IFRAME_URL}?${syncParamUrl}` + } + ]; + + it('should return nothing if iframe is disabled', () => { + const userSyncs = spec.getUserSyncs(IFRAME_DISABLED, undefined, GDPR_CONSENT, USP_CONSENT, undefined); + expect(userSyncs).to.be.undefined; + }); + + it('should do userSyncs if iframe is enabled', () => { + const userSyncs = spec.getUserSyncs(IFRAME_ENABLED, undefined, GDPR_CONSENT, USP_CONSENT, undefined); + expect(userSyncs).to.deep.equal(expectedIframeSyncs); + }); + }); });