Skip to content

Commit

Permalink
Core: improve FPD enrichment (prebid#9659)
Browse files Browse the repository at this point in the history
* Move sua logic to core

* Improve FPD enrichment: merge in `setConfig({app, device, site})`; leave only one of `dooh`, `app`, `site`; enrich the one left with `domain` / `publisher`
  • Loading branch information
dgirardi authored and jorgeluisrocha committed May 18, 2023
1 parent 2d685eb commit 9107b2b
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 101 deletions.
38 changes: 4 additions & 34 deletions libraries/ortbConverter/processors/default.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {deepSetValue, logWarn, mergeDeep} from '../../../src/utils.js';
import {deepSetValue, mergeDeep} from '../../../src/utils.js';
import {bannerResponseProcessor, fillBannerImp} from './banner.js';
import {fillVideoImp, fillVideoResponse} from './video.js';
import {setResponseMediaType} from './mediaType.js';
import {fillNativeImp, fillNativeResponse} from './native.js';
import {BID_RESPONSE, IMP, REQUEST} from '../../../src/pbjsORTB.js';
import {config} from '../../../src/config.js';
import {clientSectionChecker} from '../../../src/fpd/oneClient.js';

export const DEFAULT_PROCESSORS = {
[REQUEST]: {
Expand All @@ -15,14 +15,10 @@ export const DEFAULT_PROCESSORS = {
mergeDeep(ortbRequest, bidderRequest.ortb2)
}
},
// override FPD app, site, and device with getConfig('app'), etc if defined
// TODO: these should be deprecated for v8
appFpd: fpdFromTopLevelConfig('app'),
siteFpd: fpdFromTopLevelConfig('site'),
deviceFpd: fpdFromTopLevelConfig('device'),
onlyOneClient: {
// make sure only one of 'dooh', 'app', 'site' is set in request
priority: -99,
fn: onlyOneClientSection
fn: clientSectionChecker('ORTB request')
},
props: {
// sets request properties id, tmax, test, source.tid
Expand Down Expand Up @@ -125,29 +121,3 @@ if (FEATURES.NATIVE) {
fn: fillNativeResponse
}
}

function fpdFromTopLevelConfig(prop) {
return {
priority: 90, // after FPD from 'ortb2', before the rest
fn(ortbRequest) {
const data = config.getConfig(prop);
if (typeof data === 'object') {
ortbRequest[prop] = mergeDeep({}, ortbRequest[prop], data);
}
}
}
}

export function onlyOneClientSection(ortbRequest) {
['dooh', 'app', 'site'].reduce((found, section) => {
if (ortbRequest[section] != null && Object.keys(ortbRequest[section]).length > 0) {
if (found != null) {
logWarn(`ORTB request specifies both '${found}' and '${section}'; dropping the latter.`)
delete ortbRequest[section];
} else {
found = section;
}
}
return found;
}, null);
}
63 changes: 50 additions & 13 deletions src/fpd/enrichment.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import {getRefererInfo, parseDomain} from '../refererDetection.js';
import {findRootDomain} from './rootDomain.js';
import {deepSetValue, getDefinedParams, getDNT, getWindowSelf, getWindowTop, mergeDeep} from '../utils.js';
import {config} from '../config.js';
import {getHighEntropySUA, getLowEntropySUA} from '../../libraries/fpd/sua.js';
import {getHighEntropySUA, getLowEntropySUA} from './sua.js';
import {GreedyPromise} from '../utils/promise.js';
import {CLIENT_SECTIONS, clientSectionChecker, hasSection} from './oneClient.js';

export const dep = {
getRefererInfo,
Expand All @@ -15,6 +16,8 @@ export const dep = {
getLowEntropySUA,
};

const oneClient = clientSectionChecker('FPD')

/**
* Enrich an ortb2 object with first party data.
* @param {Promise[{}]} fpd: a promise to an ortb2 object.
Expand All @@ -23,19 +26,39 @@ export const dep = {
export const enrichFPD = hook('sync', (fpd) => {
return GreedyPromise.all([fpd, getSUA().catch(() => null)])
.then(([ortb2, sua]) => {
const ri = dep.getRefererInfo();
mergeLegacySetConfigs(ortb2);
Object.entries(ENRICHMENTS).forEach(([section, getEnrichments]) => {
const data = getEnrichments();
const data = getEnrichments(ortb2, ri);
if (data && Object.keys(data).length > 0) {
ortb2[section] = mergeDeep({}, data, ortb2[section]);
}
});
if (sua) {
deepSetValue(ortb2, 'device.sua', Object.assign({}, sua, ortb2.device.sua));
}
ortb2 = oneClient(ortb2);
for (let section of CLIENT_SECTIONS) {
if (hasSection(ortb2, section)) {
ortb2[section] = mergeDeep({}, clientEnrichment(ortb2, ri), ortb2[section]);
break;
}
}
return ortb2;
});
});

function mergeLegacySetConfigs(ortb2) {
// merge in values from "legacy" setConfig({app, site, device})
// TODO: deprecate these eventually
['app', 'site', 'device'].forEach(prop => {
const cfg = config.getConfig(prop);
if (cfg != null) {
ortb2[prop] = mergeDeep({}, cfg, ortb2[prop]);
}
})
}

function winFallback(fn) {
try {
return fn(dep.getWindowTop());
Expand All @@ -51,20 +74,19 @@ function getSUA() {
: dep.getHighEntropySUA(hints);
}

function removeUndef(obj) {
return getDefinedParams(obj, Object.keys(obj))
}

const ENRICHMENTS = {
site() {
const ri = dep.getRefererInfo();
const domain = parseDomain(ri.page, {noLeadingWww: true});
const keywords = winFallback((win) => win.document.querySelector('meta[name=\'keywords\']'))
?.content?.replace?.(/\s/g, '');
return (site => getDefinedParams(site, Object.keys(site)))({
site(ortb2, ri) {
if (CLIENT_SECTIONS.filter(p => p !== 'site').some(hasSection.bind(null, ortb2))) {
// do not enrich site if dooh or app are set
return;
}
return removeUndef({
page: ri.page,
ref: ri.ref,
domain,
keywords,
publisher: {
domain: dep.findRootDomain(domain)
}
});
},
device() {
Expand Down Expand Up @@ -92,3 +114,18 @@ const ENRICHMENTS = {
return regs;
}
};

// Enrichment of properties common across dooh, app and site - will be dropped into whatever
// section is appropriate
function clientEnrichment(ortb2, ri) {
const domain = parseDomain(ri.page, {noLeadingWww: true});
const keywords = winFallback((win) => win.document.querySelector('meta[name=\'keywords\']'))
?.content?.replace?.(/\s/g, '');
return removeUndef({
domain,
keywords,
publisher: removeUndef({
domain: dep.findRootDomain(domain)
})
})
}
26 changes: 26 additions & 0 deletions src/fpd/oneClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {logWarn} from '../utils.js';

// mutually exclusive ORTB sections in order of priority - 'dooh' beats 'app' & 'site' and 'app' beats 'site';
// if one is set, the others will be removed
export const CLIENT_SECTIONS = ['dooh', 'app', 'site']

export function clientSectionChecker(logPrefix) {
return function onlyOneClientSection(ortb2) {
CLIENT_SECTIONS.reduce((found, section) => {
if (hasSection(ortb2, section)) {
if (found != null) {
logWarn(`${logPrefix} specifies both '${found}' and '${section}'; dropping the latter.`)
delete ortb2[section];
} else {
found = section;
}
}
return found;
}, null);
return ortb2;
}
}

export function hasSection(ortb2, section) {
return ortb2[section] != null && Object.keys(ortb2[section]).length > 0
}
4 changes: 2 additions & 2 deletions libraries/fpd/sua.js → src/fpd/sua.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {isEmptyStr, isStr, isEmpty} from '../../src/utils.js';
import {GreedyPromise} from '../../src/utils/promise.js';
import {isEmptyStr, isStr, isEmpty} from '../utils.js';
import {GreedyPromise} from '../utils/promise.js';

export const SUA_SOURCE_UNKNOWN = 0;
export const SUA_SOURCE_LOW_ENTROPY = 1;
Expand Down
Loading

0 comments on commit 9107b2b

Please sign in to comment.