-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Prebid 8: pick keywords from FPD in addition to bid params (#9917)
* extract appnexus-style keyword logic into its own library * refactor appnexus clones to share keyword logic * pick keywords from ortb2 in addition to bid params
- Loading branch information
Showing
22 changed files
with
486 additions
and
449 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import {_each, getValueString, isArray, isStr, mergeDeep, isNumber} from '../../src/utils.js'; | ||
import {getAllOrtbKeywords} from '../keywords/keywords.js'; | ||
|
||
/** | ||
* Converts an object of arrays (either strings or numbers) into an array of objects containing key and value properties | ||
* normally read from bidder params | ||
* eg { foo: ['bar', 'baz'], fizz: ['buzz'] } | ||
* becomes [{ key: 'foo', value: ['bar', 'baz']}, {key: 'fizz', value: ['buzz']}] | ||
* @param {Object} keywords object of arrays representing keyvalue pairs | ||
* @param {string} paramName name of parent object (eg 'keywords') containing keyword data, used in error handling | ||
* @returns {Array<{key, value}>} | ||
*/ | ||
export function transformBidderParamKeywords(keywords, paramName = 'keywords') { | ||
const arrs = []; | ||
|
||
_each(keywords, (v, k) => { | ||
if (isArray(v)) { | ||
let values = []; | ||
_each(v, (val) => { | ||
val = getValueString(paramName + '.' + k, val); | ||
if (val || val === '') { | ||
values.push(val); | ||
} | ||
}); | ||
v = values; | ||
} else { | ||
v = getValueString(paramName + '.' + k, v); | ||
if (isStr(v)) { | ||
v = [v]; | ||
} else { | ||
return; | ||
} // unsuported types - don't send a key | ||
} | ||
v = v.filter(kw => kw !== '') | ||
const entry = {key: k} | ||
if (v.length > 0) { | ||
entry.value = v; | ||
} | ||
arrs.push(entry); | ||
}); | ||
|
||
return arrs; | ||
} | ||
|
||
// converts a comma separated list of keywords into the standard keyword object format used in appnexus bid params | ||
// 'genre=rock,genre=pop,pets=dog,music' goes to { 'genre': ['rock', 'pop'], 'pets': ['dog'], 'music': [''] } | ||
export function convertKeywordStringToANMap(keyStr) { | ||
if (isStr(keyStr) && keyStr !== '') { | ||
// will split based on commas and will eat white space before/after the comma | ||
return convertKeywordsToANMap(keyStr.split(/\s*(?:,)\s*/)); | ||
} else { | ||
return {} | ||
} | ||
} | ||
|
||
/** | ||
* @param {Array<String>} kwarray: keywords as an array of strings | ||
* @return {{}} appnexus-style keyword map | ||
*/ | ||
function convertKeywordsToANMap(kwarray) { | ||
const result = {}; | ||
kwarray.forEach(kw => { | ||
// if = exists, then split | ||
if (kw.indexOf('=') !== -1) { | ||
let kwPair = kw.split('='); | ||
let key = kwPair[0]; | ||
let val = kwPair[1]; | ||
|
||
// then check for existing key in result > if so add value to the array > if not, add new key and create value array | ||
if (result.hasOwnProperty(key)) { | ||
result[key].push(val); | ||
} else { | ||
result[key] = [val]; | ||
} | ||
} else { | ||
if (!result.hasOwnProperty(kw)) { | ||
result[kw] = []; | ||
} | ||
} | ||
}) | ||
return result; | ||
} | ||
|
||
/** | ||
* @param ortb2 | ||
* @return {{}} appnexus-style keyword map using all keywords contained in ortb2 | ||
*/ | ||
export function getANMapFromOrtb(ortb2) { | ||
return convertKeywordsToANMap(getAllOrtbKeywords(ortb2)); | ||
} | ||
|
||
export function getANKewyordParamFromMaps(...anKeywordMaps) { | ||
return transformBidderParamKeywords( | ||
mergeDeep(...anKeywordMaps.map(kwMap => Object.fromEntries( | ||
Object.entries(kwMap || {}) | ||
.map(([k, v]) => [k, (isNumber(v) || isStr(v)) ? [v] : v]) | ||
))) | ||
) | ||
} | ||
|
||
export function getANKeywordParam(ortb2, ...anKeywordsMaps) { | ||
return getANKewyordParamFromMaps( | ||
getANMapFromOrtb(ortb2), | ||
...anKeywordsMaps | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import {CLIENT_SECTIONS} from '../../src/fpd/oneClient.js'; | ||
import {deepAccess} from '../../src/utils.js'; | ||
|
||
const ORTB_KEYWORDS_PATHS = ['user.keywords'].concat( | ||
CLIENT_SECTIONS.flatMap((prefix) => ['keywords', 'content.keywords'].map(suffix => `${prefix}.${suffix}`)) | ||
); | ||
|
||
/** | ||
* @param commaSeparatedKeywords: any number of either keyword arrays, or comma-separated keyword strings | ||
* @returns an array with all unique keywords contained across all inputs | ||
*/ | ||
export function mergeKeywords(...commaSeparatedKeywords) { | ||
const keywords = new Set(); | ||
commaSeparatedKeywords | ||
.filter(kwds => kwds) | ||
.flatMap(kwds => Array.isArray(kwds) ? kwds : kwds.split(',')) | ||
.map(kw => kw.replace(/^\s*/, '').replace(/\s*$/, '')) | ||
.filter(kw => kw) | ||
.forEach(kw => keywords.add(kw)); | ||
return Array.from(keywords.keys()); | ||
} | ||
|
||
/** | ||
* Get an array with all keywords contained in an ortb2 object. | ||
*/ | ||
export function getAllOrtbKeywords(ortb2, ...extraCommaSeparatedKeywords) { | ||
return mergeKeywords( | ||
...ORTB_KEYWORDS_PATHS.map(path => deepAccess(ortb2, path)), | ||
...extraCommaSeparatedKeywords | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.