Skip to content

Commit 736b20f

Browse files
committed
Merge branch 'prebid-8' into fix-appnexus-segments
2 parents 710afd1 + ded443f commit 736b20f

40 files changed

+1830
-760
lines changed

modules/.submodules.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
"verizonMediaIdSystem",
4646
"zeotapIdPlusIdSystem",
4747
"adqueryIdSystem",
48-
"gravitoIdSystem"
48+
"gravitoIdSystem",
49+
"freepassIdSystem"
4950
],
5051
"adpod": [
5152
"freeWheelAdserverVideo",

modules/1plusXRtdProvider.js

Lines changed: 26 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
import {submodule} from '../src/hook.js';
2-
import {config} from '../src/config.js';
3-
import {ajax} from '../src/ajax.js';
4-
import {deepAccess, deepSetValue, isArray, isNumber, logError, logMessage, mergeDeep} from '../src/utils.js';
1+
import { submodule } from '../src/hook.js';
2+
import { ajax } from '../src/ajax.js';
3+
import {
4+
logMessage, logError,
5+
deepAccess, deepSetValue, mergeDeep,
6+
isNumber, isArray,
7+
} from '../src/utils.js';
58

69
// Constants
710
const REAL_TIME_MODULE = 'realTimeData';
@@ -146,7 +149,7 @@ const getTargetingDataFromPapi = (papiUrl) => {
146149
* @param {string[]} topics Represents the topics of the page
147150
* @returns {Object} Object describing the updates to make on bidder configs
148151
*/
149-
export const buildOrtb2Updates = ({ segments = [], topics = [] }, bidder) => {
152+
export const buildOrtb2Updates = ({ segments = [], topics = [] }) => {
150153
const userData = {
151154
name: ORTB2_NAME,
152155
segment: segments.map((segmentId) => ({ id: segmentId }))
@@ -163,74 +166,46 @@ export const buildOrtb2Updates = ({ segments = [], topics = [] }, bidder) => {
163166
* Merges the targeting data with the existing config for bidder and updates
164167
* @param {string} bidder Bidder for which to set config
165168
* @param {Object} ortb2Updates Updates to be applied to bidder config
166-
* @param {Object} bidderConfigs All current bidder configs
167-
* @returns {Object} Updated bidder config
169+
* @param {Object} biddersOrtb2 All current bidder configs
168170
*/
169-
export const updateBidderConfig = (bidder, ortb2Updates, bidderConfigs) => {
170-
const { site, siteContentData, userData } = ortb2Updates;
171-
const bidderConfigCopy = mergeDeep({}, bidderConfigs[bidder]);
171+
export const updateBidderConfig = (bidder, ortb2Updates, biddersOrtb2) => {
172+
const { siteContentData, userData } = ortb2Updates;
173+
mergeDeep(biddersOrtb2, { [bidder]: {} });
174+
const bidderConfig = deepAccess(biddersOrtb2, bidder);
172175

173-
if (site) {
174-
// Legacy : cf. comment on buildOrtb2Updates first lines
175-
const currentSite = deepAccess(bidderConfigCopy, 'ortb2.site');
176-
const updatedSite = mergeDeep(currentSite, site);
177-
deepSetValue(bidderConfigCopy, 'ortb2.site', updatedSite);
178-
}
179-
180-
if (siteContentData) {
181-
const siteDataPath = 'ortb2.site.content.data';
182-
const currentSiteContentData = deepAccess(bidderConfigCopy, siteDataPath) || [];
176+
{
177+
const siteDataPath = 'site.content.data';
178+
const currentSiteContentData = deepAccess(bidderConfig, siteDataPath) || [];
183179
const updatedSiteContentData = [
184180
...currentSiteContentData.filter(({ name }) => name != siteContentData.name),
185181
siteContentData
186182
];
187-
deepSetValue(bidderConfigCopy, siteDataPath, updatedSiteContentData);
183+
deepSetValue(bidderConfig, siteDataPath, updatedSiteContentData);
188184
}
189185

190-
if (userData) {
191-
const userDataPath = 'ortb2.user.data';
192-
const currentUserData = deepAccess(bidderConfigCopy, userDataPath) || [];
186+
{
187+
const userDataPath = 'user.data';
188+
const currentUserData = deepAccess(bidderConfig, userDataPath) || [];
193189
const updatedUserData = [
194190
...currentUserData.filter(({ name }) => name != userData.name),
195191
userData
196192
];
197-
deepSetValue(bidderConfigCopy, userDataPath, updatedUserData);
193+
deepSetValue(bidderConfig, userDataPath, updatedUserData);
198194
}
199-
200-
return bidderConfigCopy;
201195
};
202196

203-
const setAppnexusAudiences = (audiences) => {
204-
config.setConfig({
205-
appnexusAuctionKeywords: {
206-
'1plusX': audiences,
207-
},
208-
});
209-
}
210-
211197
/**
212198
* Updates bidder configs with the targeting data retreived from Profile API
213199
* @param {Object} papiResponse Response from Profile API
214200
* @param {Object} config Module configuration
215201
* @param {string[]} config.bidders Bidders specified in module's configuration
216202
*/
217-
export const setTargetingDataToConfig = (papiResponse, { bidders }) => {
218-
const bidderConfigs = config.getBidderConfig();
203+
export const setTargetingDataToConfig = (papiResponse, { bidders, biddersOrtb2 }) => {
219204
const { s: segments, t: topics } = papiResponse;
220205

206+
const ortb2Updates = buildOrtb2Updates({ segments, topics });
221207
for (const bidder of bidders) {
222-
const ortb2Updates = buildOrtb2Updates({ segments, topics }, bidder);
223-
const updatedBidderConfig = updateBidderConfig(bidder, ortb2Updates, bidderConfigs);
224-
if (updatedBidderConfig) {
225-
config.setBidderConfig({
226-
bidders: [bidder],
227-
config: updatedBidderConfig
228-
});
229-
}
230-
if (bidder === 'appnexus') {
231-
// Do the legacy stuff for appnexus with segments
232-
setAppnexusAudiences(segments);
233-
}
208+
updateBidderConfig(bidder, ortb2Updates, biddersOrtb2);
234209
}
235210
}
236211

@@ -256,13 +231,14 @@ const getBidRequestData = (reqBidsConfigObj, callback, moduleConfig, userConsent
256231
try {
257232
// Get the required config
258233
const { customerId, bidders } = extractConfig(moduleConfig, reqBidsConfigObj);
234+
const { ortb2Fragments: { bidder: biddersOrtb2 } } = reqBidsConfigObj;
259235
// Get PAPI URL
260236
const papiUrl = getPapiUrl(customerId, extractConsent(userConsent) || {}, extractFpid())
261237
// Call PAPI
262238
getTargetingDataFromPapi(papiUrl)
263239
.then((papiResponse) => {
264240
logMessage(LOG_PREFIX, 'Get targeting data request successful');
265-
setTargetingDataToConfig(papiResponse, { bidders });
241+
setTargetingDataToConfig(papiResponse, { bidders, biddersOrtb2 });
266242
callback();
267243
})
268244
} catch (error) {

modules/adhashBidAdapter.js

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import {registerBidder} from '../src/adapters/bidderFactory.js';
1+
import { registerBidder } from '../src/adapters/bidderFactory.js';
22
import { getStorageManager } from '../src/storageManager.js';
33
import { includes } from '../src/polyfill.js';
44
import { BANNER, VIDEO } from '../src/mediaTypes.js';
55

6-
const VERSION = '3.2';
6+
const VERSION = '3.6';
77
const BAD_WORD_STEP = 0.1;
88
const BAD_WORD_MIN = 0.2;
99
const ADHASH_BIDDER_CODE = 'adhash';
@@ -19,6 +19,8 @@ const ADHASH_BIDDER_CODE = 'adhash';
1919
* @returns boolean flag is the page safe
2020
*/
2121
function brandSafety(badWords, maxScore) {
22+
const delimiter = '~';
23+
2224
/**
2325
* Performs the ROT13 encoding on the string argument and returns the resulting string.
2426
* The Adhash bidder uses ROT13 so that the response is not blocked by:
@@ -40,17 +42,17 @@ function brandSafety(badWords, maxScore) {
4042
/**
4143
* Calculates the scoring for each bad word with dimishing returns
4244
* @param {integer} points points that this word costs
43-
* @param {integer} occurances number of occurances
45+
* @param {integer} occurrences number of occurrences
4446
* @returns {float} final score
4547
*/
46-
const scoreCalculator = (points, occurances) => {
48+
const scoreCalculator = (points, occurrences) => {
4749
let positive = true;
4850
if (points < 0) {
4951
points *= -1;
5052
positive = false;
5153
}
5254
let result = 0;
53-
for (let i = 0; i < occurances; i++) {
55+
for (let i = 0; i < occurrences; i++) {
5456
result += Math.max(points - i * BAD_WORD_STEP, BAD_WORD_MIN);
5557
}
5658
return positive ? result : -result;
@@ -60,22 +62,50 @@ function brandSafety(badWords, maxScore) {
6062
* Checks what rule will match in the given array with words
6163
* @param {string} rule rule type (full, partial, starts, ends, regexp)
6264
* @param {string} decodedWord decoded word
63-
* @param {array} wordsToMatch array to find a match
65+
* @param {string} wordsToMatch list of all words on the page separated by delimiters
6466
* @returns {object|boolean} matched rule and occurances. If nothing is matched returns false
6567
*/
6668
const wordsMatchedWithRule = function (rule, decodedWord, wordsToMatch) {
67-
if (rule === 'full' && wordsToMatch && wordsToMatch.includes(decodedWord)) {
68-
return { rule, occurances: wordsToMatch.filter(element => element === decodedWord).length };
69-
} else if (rule === 'partial' && wordsToMatch && wordsToMatch.some(element => element.indexOf(decodedWord) > -1)) {
70-
return { rule, occurances: wordsToMatch.filter(element => element.indexOf(decodedWord) > -1).length };
71-
} else if (rule === 'starts' && wordsToMatch && wordsToMatch.some(word => word.startsWith(decodedWord))) {
72-
return { rule, occurances: wordsToMatch.filter(element => element.startsWith(decodedWord)).length };
73-
} else if (rule === 'ends' && wordsToMatch && wordsToMatch.some(word => word.endsWith(decodedWord))) {
74-
return { rule, occurances: wordsToMatch.filter(element => element.endsWith(decodedWord)).length };
75-
} else if (rule === 'regexp' && wordsToMatch && wordsToMatch.some(element => element.match(new RegExp(decodedWord, 'i')))) {
76-
return { rule, occurances: wordsToMatch.filter(element => element.match(new RegExp(decodedWord, 'i'))).length };
69+
if (!wordsToMatch) {
70+
return false;
71+
}
72+
73+
let occurrences;
74+
let adjustedWordToMatch;
75+
decodedWord = decodedWord.split(' ').join(`${delimiter}${delimiter}`);
76+
switch (rule) {
77+
case 'full':
78+
adjustedWordToMatch = `${delimiter}${decodedWord}${delimiter}`;
79+
break;
80+
case 'partial':
81+
adjustedWordToMatch = decodedWord;
82+
break;
83+
case 'starts':
84+
adjustedWordToMatch = `${delimiter}${decodedWord}`;
85+
break;
86+
case 'ends':
87+
adjustedWordToMatch = `${decodedWord}${delimiter}`;
88+
break;
89+
case 'combo':
90+
const allOccurrences = [];
91+
const paddedWordsToMatch = `${delimiter}${wordsToMatch}${delimiter}`;
92+
const decodedWordsSplit = decodedWord.split(`${delimiter}${delimiter}`);
93+
for (const decodedWordPart of decodedWordsSplit) {
94+
adjustedWordToMatch = `${delimiter}${decodedWordPart}${delimiter}`;
95+
allOccurrences.push(paddedWordsToMatch.split(adjustedWordToMatch).length - 1);
96+
}
97+
occurrences = Math.min(...allOccurrences);
98+
return occurrences > 0 ? { rule, occurrences } : false;
99+
case 'regexp':
100+
occurrences = [...wordsToMatch.matchAll(new RegExp(decodedWord, 'gi'))].length;
101+
return occurrences > 0 ? { rule, occurrences } : false;
102+
default:
103+
return false;
77104
}
78-
return false;
105+
106+
const paddedWordsToMatch = `${delimiter}${wordsToMatch}${delimiter}`;
107+
occurrences = paddedWordsToMatch.split(adjustedWordToMatch).length - 1;
108+
return occurrences > 0 ? { rule, occurrences } : false;
79109
};
80110

81111
// Default parameters if the bidder is unable to send some of them
@@ -91,11 +121,11 @@ function brandSafety(badWords, maxScore) {
91121
.toLowerCase()
92122
.trim();
93123
const content = window.top.document.body.innerText.toLowerCase();
94-
const contentWords = content.trim().split(/\s+/).length;
95124
// \p{L} matches a single unicode code point in the category 'letter'. Matches any kind of letter from any language.
96125
const regexp = new RegExp('[\\p{L}]+', 'gu');
97-
const words = content.match(regexp);
98-
const wordsInUrl = wordsAndNumbersInUrl.match(regexp);
126+
const wordsMatched = content.match(regexp);
127+
const words = wordsMatched.join(`${delimiter}${delimiter}`);
128+
const wordsInUrl = wordsAndNumbersInUrl.match(regexp).join(`${delimiter}${delimiter}`);
99129

100130
for (const [word, rule, points] of badWords) {
101131
const decodedWord = rot13(word.toLowerCase());
@@ -110,19 +140,11 @@ function brandSafety(badWords, maxScore) {
110140

111141
// Check if site content's words match any of our brand safety rules
112142
const matchedRule = wordsMatchedWithRule(rule, decodedWord, words);
113-
if (matchedRule.rule === 'full') {
114-
score += scoreCalculator(points, matchedRule.occurances);
115-
} else if (matchedRule.rule === 'partial') {
116-
score += scoreCalculator(points, matchedRule.occurances);
117-
} else if (matchedRule.rule === 'starts') {
118-
score += scoreCalculator(points, matchedRule.occurances);
119-
} else if (matchedRule.rule === 'ends') {
120-
score += scoreCalculator(points, matchedRule.occurances);
121-
} else if (matchedRule.rule === 'regexp') {
122-
score += scoreCalculator(points, matchedRule.occurances);
143+
if (matchedRule !== false) {
144+
score += scoreCalculator(points, matchedRule.occurrences);
123145
}
124146
}
125-
return score < (maxScore * contentWords) / 1000;
147+
return score < (maxScore * wordsMatched.length) / 1000;
126148
} catch (e) {
127149
return true;
128150
}
@@ -183,8 +205,8 @@ export const spec = {
183205
}
184206

185207
// Needed for the ad density calculation
186-
var adHeight = validBidRequests[i].sizes[index][1];
187-
var adWidth = validBidRequests[i].sizes[index][0];
208+
const adHeight = validBidRequests[i].sizes[index][1];
209+
const adWidth = validBidRequests[i].sizes[index][0];
188210
if (!window.adsCount) {
189211
window.adsCount = 0;
190212
}
@@ -247,7 +269,7 @@ export const spec = {
247269
const bidderResponse = JSON.stringify({ responseText: JSON.stringify(responseBody) });
248270
const requestData = JSON.stringify(request.data);
249271

250-
var response = {
272+
let response = {
251273
requestId: request.bidRequest.bidId,
252274
cpm: responseBody.creatives[0].costEUR,
253275
width: request.bidRequest.sizes[0][0],

modules/adkernelBidAdapter.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ export const spec = {
9090
{code: 'denakop'},
9191
{code: 'rtbanalytica'},
9292
{code: 'unibots'},
93-
{code: 'catapultx'},
9493
{code: 'ergadx'},
9594
{code: 'turktelekom'},
9695
{code: 'felixads'},
@@ -100,7 +99,8 @@ export const spec = {
10099
{code: 'rtbdemand_com'},
101100
{code: 'bidbuddy'},
102101
{code: 'adliveconnect'},
103-
{code: 'didnadisplay'}
102+
{code: 'didnadisplay'},
103+
{code: 'qortex'}
104104
],
105105
supportedMediaTypes: [BANNER, VIDEO, NATIVE],
106106

modules/asoBidAdapter.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ export const spec = {
2828
code: BIDDER_CODE,
2929
supportedMediaTypes: [BANNER, VIDEO],
3030
aliases: [
31-
{code: 'bcmint'}
31+
{code: 'bcmint'},
32+
{code: 'bidgency'}
3233
],
3334

3435
isBidRequestValid: bid => {

modules/beopBidAdapter.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ export const spec = {
4848
*/
4949
buildRequests: function(validBidRequests, bidderRequest) {
5050
const slots = validBidRequests.map(beOpRequestSlotsMaker);
51+
const firstPartyData = bidderRequest.ortb2;
52+
const psegs = (firstPartyData && firstPartyData.user && firstPartyData.user.ext && firstPartyData.user.ext.data) ? firstPartyData.user.ext.data.permutive : undefined;
5153
const pageUrl = getPageUrl(bidderRequest.refererInfo, window);
5254
const gdpr = bidderRequest.gdprConsent;
5355
const firstSlot = slots[0];
@@ -69,6 +71,10 @@ export const spec = {
6971
tc_string: (gdpr && gdpr.gdprApplies) ? gdpr.consentString : null,
7072
};
7173

74+
if (psegs) {
75+
Object.assign(payloadObject, {psegs: psegs});
76+
}
77+
7278
const payloadString = JSON.stringify(payloadObject);
7379
return {
7480
method: 'POST',

0 commit comments

Comments
 (0)