Skip to content

Commit 5df0005

Browse files
authored
Ozone Bid Adapter: support oRTB Ext object (#13951)
* Update ozoneBidAdapter.js - added support for ortb.ext params - update on ozlabels custom KVP - slight tweak to fix submitted to handle empty eid response. * Update ozoneBidAdapter_spec.js updated spec file for 4.0.2 * Update ozoneBidAdapter.js * Update ozoneBidAdapter.js
1 parent 4e5b9f6 commit 5df0005

File tree

2 files changed

+419
-41
lines changed

2 files changed

+419
-41
lines changed

modules/ozoneBidAdapter.js

Lines changed: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const AUCTIONURI = '/openrtb2/auction';
2222
const OZONECOOKIESYNC = '/static/load-cookie.html';
2323
const OZONE_RENDERER_URL = 'https://prebid.the-ozone-project.com/ozone-renderer.js';
2424
const KEY_PREFIX = 'oz';
25-
const OZONEVERSION = '4.0.1';
25+
const OZONEVERSION = '4.0.2';
2626
export const spec = {
2727
gvlid: 524,
2828
version: OZONEVERSION,
@@ -129,6 +129,7 @@ export const spec = {
129129
return placementId.toString().match(/^[0-9]{10}$/);
130130
},
131131
buildRequests(validBidRequests, bidderRequest) {
132+
logInfo('**TESTING CONFIG', config.getConfig());
132133
this.propertyBag.buildRequestsStart = new Date().getTime();
133134
const bidderKey = BIDDER_CODE;
134135
const prefix = KEY_PREFIX;
@@ -147,17 +148,18 @@ export const spec = {
147148
logInfo('cookie sync bag', this.cookieSyncBag);
148149
let singleRequest = config.getConfig('ozone.singleRequest');
149150
singleRequest = singleRequest !== false;
150-
const ozoneRequest = {};
151-
const fpd = deepAccess(bidderRequest, 'ortb2', null);
151+
const ozoneRequest = {site: {}, regs: {}, user: {}};
152+
const fpd = deepAccess(bidderRequest, 'ortb2', {});
153+
const fpdPruned = this.pruneToExtPaths(fpd, {maxTestDepth: 2});
152154
logInfo('got ortb2 fpd: ', fpd);
153-
if (fpd && deepAccess(fpd, 'user')) {
154-
logInfo('added FPD user object');
155-
ozoneRequest.user = fpd.user;
156-
}
155+
logInfo('got ortb2 fpdPruned: ', fpdPruned);
156+
logInfo('going to assign the pruned (ext only) FPD ortb2 object to ozoneRequest, wholesale');
157+
mergeDeep(ozoneRequest, fpdPruned);
158+
toOrtb25(ozoneRequest);
157159
const getParams = this.getGetParametersAsObject();
158160
const wlOztestmodeKey = 'oztestmode';
159161
const isTestMode = getParams[wlOztestmodeKey] || null;
160-
ozoneRequest.device = bidderRequest?.ortb2?.device || {};
162+
mergeDeep(ozoneRequest, {device: bidderRequest?.ortb2?.device || {}});
161163
const placementIdOverrideFromGetParam = this.getPlacementIdOverrideFromGetParam();
162164
let schain = null;
163165
var auctionId = deepAccess(validBidRequests, '0.ortb2.source.tid');
@@ -166,6 +168,9 @@ export const spec = {
166168
}
167169
const tosendtags = validBidRequests.map(ozoneBidRequest => {
168170
var obj = {};
171+
let prunedImp = this.pruneToExtPaths(ozoneBidRequest.ortb2Imp, {maxTestDepth: 2});
172+
logInfo('merging into bid[] from pruned ozoneBidRequest.ortb2Imp (this includes adunits ortb2imp and gpid & tid from gptPreAuction if included', prunedImp);
173+
mergeDeep(obj, prunedImp);
169174
const placementId = placementIdOverrideFromGetParam || this.getPlacementId(ozoneBidRequest);
170175
obj.id = ozoneBidRequest.bidId;
171176
obj.tagid = placementId;
@@ -229,8 +234,8 @@ export const spec = {
229234
};
230235
}
231236
obj.placementId = placementId;
232-
deepSetValue(obj, 'ext.prebid', {'storedrequest': {'id': placementId}});
233-
obj.ext[bidderKey] = {};
237+
mergeDeep(obj, {ext: {prebid: {'storedrequest': {'id': placementId}}}});
238+
obj.ext[bidderKey] = obj.ext[bidderKey] || {};
234239
obj.ext[bidderKey].adUnitCode = ozoneBidRequest.adUnitCode;
235240
if (ozoneBidRequest.params.hasOwnProperty('customData')) {
236241
obj.ext[bidderKey].customData = ozoneBidRequest.params.customData;
@@ -266,14 +271,6 @@ export const spec = {
266271
if (!schain && deepAccess(ozoneBidRequest, 'ortb2.source.ext.schain')) {
267272
schain = ozoneBidRequest.ortb2.source.ext.schain;
268273
}
269-
const gpid = deepAccess(ozoneBidRequest, 'ortb2Imp.ext.gpid');
270-
if (gpid) {
271-
deepSetValue(obj, 'ext.gpid', gpid);
272-
}
273-
const transactionId = deepAccess(ozoneBidRequest, 'ortb2Imp.ext.tid');
274-
if (transactionId) {
275-
obj.ext.tid = transactionId;
276-
}
277274
if (auctionId) {
278275
obj.ext.auctionId = auctionId;
279276
}
@@ -313,17 +310,17 @@ export const spec = {
313310
extObj[bidderKey].origin = endpointOverride.auctionUrl || endpointOverride.origin;
314311
}
315312
const userExtEids = deepAccess(validBidRequests, '0.userIdAsEids', []);
316-
ozoneRequest.site = {
313+
mergeDeep(ozoneRequest.site, {
317314
'publisher': {'id': htmlParams.publisherId},
318315
'page': getRefererInfo().page,
319316
'id': htmlParams.siteId
320-
};
317+
});
321318
ozoneRequest.test = config.getConfig('debug') ? 1 : 0;
322319
if (bidderRequest && bidderRequest.gdprConsent) {
323320
logInfo('ADDING GDPR');
324321
const apiVersion = deepAccess(bidderRequest, 'gdprConsent.apiVersion', 1);
325-
ozoneRequest.regs = {ext: {gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0, apiVersion: apiVersion}};
326-
if (deepAccess(ozoneRequest, 'regs.ext.gdpr')) {
322+
mergeDeep(ozoneRequest.regs, {ext: {gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0, apiVersion: apiVersion}});
323+
if (bidderRequest.gdprConsent.gdprApplies) {
327324
deepSetValue(ozoneRequest, 'user.ext.consent', bidderRequest.gdprConsent.consentString);
328325
} else {
329326
logWarn('**** Strange CMP info: bidderRequest.gdprConsent exists BUT bidderRequest.gdprConsent.gdprApplies is false. See bidderRequest logged above. ****');
@@ -356,12 +353,12 @@ export const spec = {
356353
const arrRet = [];
357354
for (let i = 0; i < tosendtags.length; i += batchRequestsVal) {
358355
ozoneRequest.id = generateUUID();
359-
deepSetValue(ozoneRequest, 'user.ext.eids', userExtEids);
356+
mergeDeep(ozoneRequest, {user: {ext: {eids: userExtEids}}});
360357
if (auctionId) {
361358
deepSetValue(ozoneRequest, 'source.tid', auctionId);
362359
}
363360
ozoneRequest.imp = tosendtags.slice(i, i + batchRequestsVal);
364-
ozoneRequest.ext = extObj;
361+
mergeDeep(ozoneRequest, {ext: extObj});
365362
toOrtb25(ozoneRequest);
366363
if (ozoneRequest.imp.length > 0) {
367364
arrRet.push({
@@ -372,16 +369,17 @@ export const spec = {
372369
});
373370
}
374371
}
375-
logInfo('batch request going to return : ', arrRet);
372+
this.propertyBag.buildRequestsEnd = new Date().getTime();
373+
logInfo(`buildRequests batch request going to return at time ${this.propertyBag.buildRequestsEnd} (took ${this.propertyBag.buildRequestsEnd - this.propertyBag.buildRequestsStart}ms):`, arrRet);
376374
return arrRet;
377375
}
378376
if (singleRequest) {
379377
logInfo('single request starting');
380378
ozoneRequest.id = generateUUID();
381379
ozoneRequest.imp = tosendtags;
382-
ozoneRequest.ext = extObj;
380+
mergeDeep(ozoneRequest, {ext: extObj});
383381
toOrtb25(ozoneRequest);
384-
deepSetValue(ozoneRequest, 'user.ext.eids', userExtEids);
382+
mergeDeep(ozoneRequest, {user: {ext: {eids: userExtEids}}});
385383
if (auctionId) {
386384
deepSetValue(ozoneRequest, 'source.tid', auctionId);
387385
}
@@ -400,8 +398,8 @@ export const spec = {
400398
const ozoneRequestSingle = Object.assign({}, ozoneRequest);
401399
ozoneRequestSingle.id = generateUUID();
402400
ozoneRequestSingle.imp = [imp];
403-
ozoneRequestSingle.ext = extObj;
404-
deepSetValue(ozoneRequestSingle, 'user.ext.eids', userExtEids);
401+
mergeDeep(ozoneRequestSingle, {ext: extObj});
402+
mergeDeep(ozoneRequestSingle, {user: {ext: {eids: userExtEids}}});
405403
if (auctionId) {
406404
deepSetValue(ozoneRequestSingle, 'source.tid', auctionId);
407405
}
@@ -533,7 +531,7 @@ export const spec = {
533531
if (seat.match(/^ozappnexus/)) {
534532
adserverTargeting[prefix + '_' + seat + '_sid'] = String(allBidsForThisBidid[seat].cid);
535533
}
536-
labels = deepAccess(allBidsForThisBidid[seat], 'ext.prebid.labels', null);
534+
labels = deepAccess(allBidsForThisBidid[seat], 'ext.prebid.labels', null) || deepAccess(allBidsForThisBidid[seat], 'ext.bidder.prebid.label', null);
537535
if (labels) {
538536
adserverTargeting[prefix + '_' + seat + '_labels'] = labels.join(',');
539537
}
@@ -554,7 +552,7 @@ export const spec = {
554552
adserverTargeting[prefix + '_cache_id'] = deepAccess(thisBid, 'ext.prebid.targeting.hb_cache_id', 'no-id');
555553
adserverTargeting[prefix + '_uuid'] = deepAccess(thisBid, 'ext.prebid.targeting.hb_uuid', 'no-id');
556554
if (enhancedAdserverTargeting) {
557-
labels = deepAccess(winningBid, 'ext.prebid.labels', null);
555+
labels = deepAccess(winningBid, 'ext.prebid.labels', null) || deepAccess(winningBid, 'ext.bidder.prebid.label', null);
558556
if (labels) {
559557
adserverTargeting[prefix + '_labels'] = labels.join(',');
560558
}
@@ -674,10 +672,8 @@ export const spec = {
674672
},
675673
findAllUserIdsFromEids(bidRequest) {
676674
const ret = {};
677-
if (!Array.isArray(bidRequest.userIdAsEids)) {
678-
bidRequest.userIdAsEids = [];
679-
}
680-
for (const obj of bidRequest.userIdAsEids) {
675+
let userIdAsEids = bidRequest.userIdAsEids || [];
676+
for (const obj of userIdAsEids) {
681677
ret[obj.source] = deepAccess(obj, 'uids.0.id');
682678
}
683679
this.tryGetPubCidFromOldLocation(ret, bidRequest);
@@ -810,6 +806,43 @@ export const spec = {
810806
logObj.floorData = bid.floorData;
811807
}
812808
return logObj;
809+
},
810+
pruneToExtPaths: function (input, { testKey = 'ext', maxTestDepth = Infinity } = {}) {
811+
const isPlainObj = v => v && typeof v === 'object' && !Array.isArray(v);
812+
const deepClone = node => {
813+
if (Array.isArray(node)) return node.map(deepClone);
814+
if (isPlainObj(node)) {
815+
const out = {};
816+
for (const [k, v] of Object.entries(node)) out[k] = deepClone(v);
817+
return out;
818+
}
819+
return node;
820+
};
821+
const isEmpty = v =>
822+
v == null ||
823+
(Array.isArray(v) ? v.length === 0
824+
: isPlainObj(v) ? Object.keys(v).length === 0 : false);
825+
function prune(node, inExt, depth) {
826+
if (node == null) return undefined;
827+
if (typeof node !== 'object') return inExt ? node : undefined;
828+
if (inExt) return deepClone(node);
829+
if (Array.isArray(node)) {
830+
const kept = node
831+
.map(el => prune(el, false, depth))
832+
.filter(el => el !== undefined && !isEmpty(el));
833+
return kept.length ? kept : undefined;
834+
}
835+
const out = {};
836+
for (const [k, v] of Object.entries(node)) {
837+
const kDepth = depth + 1;
838+
const enterExt = (k === testKey) && (kDepth <= maxTestDepth);
839+
const child = prune(v, enterExt, kDepth);
840+
if (child !== undefined && !isEmpty(child)) out[k] = child;
841+
}
842+
return Object.keys(out).length ? out : undefined;
843+
}
844+
const result = prune(input, false, 0);
845+
return result ?? (Array.isArray(input) ? [] : {});
813846
}
814847
};
815848
export function injectAdIdsIntoAllBidResponses(seatbid) {

0 commit comments

Comments
 (0)