Skip to content

Commit

Permalink
NextMillennium Bid Adapter: support for GPP consent string, `site.pag…
Browse files Browse the repository at this point in the history
…ecat`, `site.content.cat` and `site.content.language` (#10761)

* added support for gpp consent string

* changed test for nextMillenniumBidAdapter

* added some tests

* added site.pagecat, site.content.cat and site.content.language to request

* lint fix

* formated code

* formated code

* formated code

* pachage-lock with prebid

* pachage-lock with prebid

* formatted code
  • Loading branch information
mhlm authored Dec 4, 2023
1 parent cbf1e15 commit 7be0a10
Show file tree
Hide file tree
Showing 2 changed files with 564 additions and 191 deletions.
245 changes: 134 additions & 111 deletions modules/nextMillenniumBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {
_each,
createTrackPixelHtml,
deepAccess, getBidIdParameter,
deepAccess,
deepSetValue,
getBidIdParameter,
getDefinedParams,
getWindowTop,
isArray,
Expand All @@ -20,17 +22,32 @@ import * as events from '../src/events.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {getRefererInfo} from '../src/refererDetection.js';

const NM_VERSION = '3.0.0';
const GVLID = 1060;
const BIDDER_CODE = 'nextMillennium';
const ENDPOINT = 'https://pbs.nextmillmedia.com/openrtb2/auction';
const TEST_ENDPOINT = 'https://test.pbs.nextmillmedia.com/openrtb2/auction';
const SYNC_ENDPOINT = 'https://cookies.nextmillmedia.com/sync?';
const SYNC_ENDPOINT = 'https://cookies.nextmillmedia.com/sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&type={{.TYPE_PIXEL}}';
const REPORT_ENDPOINT = 'https://report2.hb.brainlyads.com/statistics/metric';
const TIME_TO_LIVE = 360;

const VIDEO_PARAMS = [
'api', 'linearity', 'maxduration', 'mimes', 'minduration', 'placement',
'playbackmethod', 'protocols', 'startdelay'
'api',
'linearity',
'maxduration',
'mimes',
'minduration',
'placement',
'playbackmethod',
'protocols',
'startdelay',
];

const ALLOWED_ORTB2_PARAMETERS = [
'site.pagecat',
'site.content.cat',
'site.content.language',
];
const GVLID = 1060;

const sendingDataStatistic = initSendingDataStatistic();
events.on(CONSTANTS.EVENTS.AUCTION_INIT, auctionInitHandler);
Expand Down Expand Up @@ -61,85 +78,35 @@ export const spec = {
const id = getPlacementId(bid);
const auctionId = bid.auctionId;
const bidId = bid.bidId;
let sizes = bid.sizes;
if (sizes && !Array.isArray(sizes[0])) sizes = [sizes];

const site = getSiteObj();
const device = getDeviceObj();

const postBody = {
'id': bidderRequest?.bidderRequestId,
'ext': {
'prebid': {
'storedrequest': {
'id': id
}
id: bidderRequest?.bidderRequestId,
ext: {
prebid: {
storedrequest: {
id,
},
},

'nextMillennium': {
'refresh_count': window.nmmRefreshCounts[bid.adUnitCode]++,
'elOffsets': getBoundingClient(bid),
'scrollTop': window.pageYOffset || document.documentElement.scrollTop
}
nextMillennium: {
nm_version: NM_VERSION,
refresh_count: window.nmmRefreshCounts[bid.adUnitCode]++,
elOffsets: getBoundingClient(bid),
scrollTop: window.pageYOffset || document.documentElement.scrollTop,
},
},

device,
site,
imp: []
};

const imp = {
id: bid.adUnitCode,
ext: {
prebid: {
storedrequest: {id}
}
}
};

if (deepAccess(bid, 'mediaTypes.banner')) {
imp.banner = {
format: (sizes || []).map(s => { return {w: s[0], h: s[1]} })
};
imp: [],
};

const video = deepAccess(bid, 'mediaTypes.video');
if (video) {
imp.video = getDefinedParams(video, VIDEO_PARAMS);
if (video.playerSize) {
imp.video = Object.assign(
imp.video, parseGPTSingleSizeArrayToRtbSize(video.playerSize[0]) || {}
);
} else if (video.w && video.h) {
imp.video.w = video.w;
imp.video.h = video.h;
};
};

postBody.imp.push(imp);

const gdprConsent = bidderRequest && bidderRequest.gdprConsent;
const uspConsent = bidderRequest && bidderRequest.uspConsent;

if (gdprConsent || uspConsent) {
postBody.regs = { ext: {} };

if (uspConsent) {
postBody.regs.ext.us_privacy = uspConsent;
};

if (gdprConsent) {
if (typeof gdprConsent.gdprApplies !== 'undefined') {
postBody.regs.ext.gdpr = gdprConsent.gdprApplies ? 1 : 0;
};

if (typeof gdprConsent.consentString !== 'undefined') {
postBody.user = {
ext: { consent: gdprConsent.consentString }
};
};
};
};
postBody.imp.push(getImp(bid, id));
setConsentStrings(postBody, bidderRequest);
setOrtb2Parameters(postBody, bidderRequest?.ortb2);

const urlParameters = parseUrl(getWindowTop().location.href).search;
const isTest = urlParameters['pbs'] && urlParameters['pbs'] === 'test';
Expand All @@ -151,7 +118,7 @@ export const spec = {
data: JSON.stringify(postBody),
options: {
contentType: 'text/plain',
withCredentials: true
withCredentials: true,
},

bidId,
Expand All @@ -173,6 +140,7 @@ export const spec = {
const params = bidRequest.params;
const auctionId = bidRequest.auctionId;
const wurl = deepAccess(bid, 'ext.prebid.events.win');

// TODO: fix auctionId leak: https://github.com/prebid/Prebid.js/issues/9781
addWurl({auctionId, requestId, wurl});

Expand All @@ -189,8 +157,8 @@ export const spec = {
netRevenue: true,
ttl: TIME_TO_LIVE,
meta: {
advertiserDomains: bid.adomain || []
}
advertiserDomains: bid.adomain || [],
},
};

if (vastUrl || vastXml) {
Expand All @@ -210,38 +178,29 @@ export const spec = {
return bidResponses;
},

getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) {
getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent, gppConsent) {
if (!syncOptions.iframeEnabled && !syncOptions.pixelEnabled) return [];

const pixels = [];
const getSetPixelFunc = type => url => { pixels.push({type, url: replaceUsersyncMacros(url, gdprConsent, uspConsent, gppConsent, type)}) };
const getSetPixelsFunc = type => response => { deepAccess(response, `body.ext.sync.${type}`, []).forEach(getSetPixelFunc(type)) };

const setPixel = (type, url) => { (getSetPixelFunc(type))(url) };
const setPixelImages = getSetPixelsFunc('image');
const setPixelIframes = getSetPixelsFunc('iframe');

if (isArray(responses)) {
responses.forEach(response => {
if (syncOptions.pixelEnabled) {
deepAccess(response, 'body.ext.sync.image', []).forEach(imgUrl => {
pixels.push({
type: 'image',
url: replaceUsersyncMacros(imgUrl, gdprConsent, uspConsent)
});
})
}

if (syncOptions.iframeEnabled) {
deepAccess(response, 'body.ext.sync.iframe', []).forEach(iframeUrl => {
pixels.push({
type: 'iframe',
url: replaceUsersyncMacros(iframeUrl, gdprConsent, uspConsent)
});
})
}
if (syncOptions.pixelEnabled) setPixelImages(response);
if (syncOptions.iframeEnabled) setPixelIframes(response);
})
}

if (!pixels.length) {
let syncUrl = SYNC_ENDPOINT;
if (gdprConsent && gdprConsent.gdprApplies) syncUrl += 'gdpr=1&gdpr_consent=' + gdprConsent.consentString + '&';
if (uspConsent) syncUrl += 'us_privacy=' + uspConsent + '&';
if (syncOptions.iframeEnabled) pixels.push({type: 'iframe', url: syncUrl + 'type=iframe'});
if (syncOptions.pixelEnabled) pixels.push({type: 'image', url: syncUrl + 'type=image'});
if (syncOptions.pixelEnabled) setPixel('image', SYNC_ENDPOINT);
if (syncOptions.iframeEnabled) setPixel('iframe', SYNC_ENDPOINT);
}

return pixels;
},

Expand Down Expand Up @@ -281,24 +240,88 @@ export const spec = {
},
};

function replaceUsersyncMacros(url, gdprConsent, uspConsent) {
const { consentString, gdprApplies } = gdprConsent || {};
export function getImp(bid, id) {
const imp = {
id: bid.adUnitCode,
ext: {
prebid: {
storedrequest: {
id,
},
},
},
};

const banner = deepAccess(bid, 'mediaTypes.banner');
if (banner) {
imp.banner = {
format: (banner?.sizes || []).map(s => { return {w: s[0], h: s[1]} }),
};
};

const video = deepAccess(bid, 'mediaTypes.video');
if (video) {
imp.video = getDefinedParams(video, VIDEO_PARAMS);
if (video.playerSize) {
imp.video = Object.assign(imp.video, parseGPTSingleSizeArrayToRtbSize(video.playerSize) || {});
} else if (video.w && video.h) {
imp.video.w = video.w;
imp.video.h = video.h;
};
};

if (gdprApplies) {
const gdpr = Number(gdprApplies);
url = url.replace('{{.GDPR}}', gdpr);
return imp;
};

if (gdpr == 1 && consentString && consentString.length > 0) {
url = url.replace('{{.GDPRConsent}}', consentString);
}
} else {
url = url.replace('{{.GDPR}}', 0);
url = url.replace('{{.GDPRConsent}}', '');
}
export function setConsentStrings(postBody = {}, bidderRequest) {
const gdprConsent = bidderRequest?.gdprConsent;
const uspConsent = bidderRequest?.uspConsent;
let gppConsent = bidderRequest?.gppConsent?.gppString && bidderRequest?.gppConsent;
if (!gppConsent && bidderRequest?.ortb2?.regs?.gpp) gppConsent = bidderRequest?.ortb2?.regs;

if (uspConsent) {
url = url.replace('{{.USPrivacy}}', uspConsent);
if (gdprConsent || uspConsent || gppConsent) {
postBody.regs = { ext: {} };

if (uspConsent) {
postBody.regs.ext.us_privacy = uspConsent;
};

if (gppConsent) {
postBody.regs.gpp = gppConsent?.gppString || gppConsent?.gpp;
postBody.regs.gpp_sid = bidderRequest.gppConsent?.applicableSections || gppConsent?.gpp_sid;
};

if (gdprConsent) {
if (typeof gdprConsent.gdprApplies !== 'undefined') {
postBody.regs.ext.gdpr = gdprConsent.gdprApplies ? 1 : 0;
};

if (typeof gdprConsent.consentString !== 'undefined') {
postBody.user = {
ext: { consent: gdprConsent.consentString },
};
};
};
};
};

export function setOrtb2Parameters(postBody, ortb2 = {}) {
for (let parameter of ALLOWED_ORTB2_PARAMETERS) {
const value = deepAccess(ortb2, parameter);
if (value) deepSetValue(postBody, parameter, value);
}
}

export function replaceUsersyncMacros(url, gdprConsent = {}, uspConsent = '', gppConsent = {}, type = '') {
const { consentString = '', gdprApplies = false } = gdprConsent;
const gdpr = Number(gdprApplies);
url = url
.replace('{{.GDPR}}', gdpr)
.replace('{{.GDPRConsent}}', consentString)
.replace('{{.USPrivacy}}', uspConsent)
.replace('{{.GPP}}', gppConsent.gppString || '')
.replace('{{.GPPSID}}', (gppConsent.applicableSections || []).join(','))
.replace('{{.TYPE_PIXEL}}', type);

return url;
};
Expand Down
Loading

0 comments on commit 7be0a10

Please sign in to comment.