-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AdHash bid adapter: update to support latest version #9286
Changes from 24 commits
e7d3b8a
814f3a8
d5e34de
4eb1553
bdc4fad
35f24dc
e681fbd
c837c36
a6c5faf
fc5809d
3fa0e52
66fddd1
0c7953c
66d14ba
1c2470a
6e4148b
ae443ae
441240d
a589f12
8dacbc9
9cd75bf
dbd9f3d
65a0d26
e27cbe4
d68efac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,12 @@ | ||
import {registerBidder} from '../src/adapters/bidderFactory.js'; | ||
import {includes} from '../src/polyfill.js'; | ||
import {BANNER} from '../src/mediaTypes.js'; | ||
import { getStorageManager } from '../src/storageManager.js'; | ||
import { includes } from '../src/polyfill.js'; | ||
import { BANNER } from '../src/mediaTypes.js'; | ||
|
||
const VERSION = '1.0'; | ||
const VERSION = '3.2'; | ||
const BAD_WORD_STEP = 0.1; | ||
const BAD_WORD_MIN = 0.2; | ||
const ADHASH_BIDDER_CODE = 'adhash'; | ||
|
||
/** | ||
* Function that checks the page where the ads are being served for brand safety. | ||
|
@@ -54,32 +56,80 @@ function brandSafety(badWords, maxScore) { | |
return positive ? result : -result; | ||
}; | ||
|
||
/** | ||
* Checks what rule will match in the given array with words | ||
* @param {string} rule rule type (full, partial, starts, ends, regexp) | ||
* @param {string} decodedWord decoded word | ||
* @param {array} wordsToMatch array to find a match | ||
* @returns {object|boolean} matched rule and occurances. If nothing is matched returns false | ||
*/ | ||
const wordsMatchedWithRule = function (rule, decodedWord, wordsToMatch) { | ||
if (rule === 'full' && wordsToMatch && wordsToMatch.includes(decodedWord)) { | ||
return { rule, occurances: wordsToMatch.filter(element => element === decodedWord).length }; | ||
} else if (rule === 'partial' && wordsToMatch && wordsToMatch.some(element => element.indexOf(decodedWord) > -1)) { | ||
return { rule, occurances: wordsToMatch.filter(element => element.indexOf(decodedWord) > -1).length }; | ||
} else if (rule === 'starts' && wordsToMatch && wordsToMatch.some(word => word.startsWith(decodedWord))) { | ||
return { rule, occurances: wordsToMatch.filter(element => element.startsWith(decodedWord)).length }; | ||
} else if (rule === 'ends' && wordsToMatch && wordsToMatch.some(word => word.endsWith(decodedWord))) { | ||
return { rule, occurances: wordsToMatch.filter(element => element.endsWith(decodedWord)).length }; | ||
} else if (rule === 'regexp' && wordsToMatch && wordsToMatch.some(element => element.match(new RegExp(decodedWord, 'i')))) { | ||
return { rule, occurances: wordsToMatch.filter(element => element.match(new RegExp(decodedWord, 'i'))).length }; | ||
} | ||
return false; | ||
}; | ||
|
||
// Default parameters if the bidder is unable to send some of them | ||
badWords = badWords || []; | ||
maxScore = parseInt(maxScore) || 10; | ||
|
||
try { | ||
let score = 0; | ||
const decodedUrl = decodeURI(window.top.location.href.substring(window.top.location.origin.length)); | ||
const wordsAndNumbersInUrl = decodedUrl | ||
.replaceAll(/[-,\._/\?=&#%]/g, ' ') | ||
.replaceAll(/\s\s+/g, ' ') | ||
.toLowerCase() | ||
.trim(); | ||
const content = window.top.document.body.innerText.toLowerCase(); | ||
const words = content.trim().split(/\s+/).length; | ||
const contentWords = content.trim().split(/\s+/).length; | ||
// \p{L} matches a single unicode code point in the category 'letter'. Matches any kind of letter from any language. | ||
const regexp = new RegExp('[\\p{L}]+', 'gu'); | ||
const words = content.match(regexp); | ||
const wordsInUrl = wordsAndNumbersInUrl.match(regexp); | ||
|
||
for (const [word, rule, points] of badWords) { | ||
if (rule === 'full' && new RegExp('\\b' + rot13(word) + '\\b', 'i').test(content)) { | ||
const occurances = content.match(new RegExp('\\b' + rot13(word) + '\\b', 'g')).length; | ||
score += scoreCalculator(points, occurances); | ||
} else if (rule === 'partial' && content.indexOf(rot13(word.toLowerCase())) > -1) { | ||
const occurances = content.match(new RegExp(rot13(word), 'g')).length; | ||
score += scoreCalculator(points, occurances); | ||
const decodedWord = rot13(word.toLowerCase()); | ||
|
||
// Checks the words in the url of the page only for negative words. Don't serve any ad when at least one match is found | ||
if (points > 0) { | ||
const matchedRuleInUrl = wordsMatchedWithRule(rule, decodedWord, wordsInUrl); | ||
if (matchedRuleInUrl.rule) { | ||
return false; | ||
} | ||
} | ||
|
||
// Check if site content's words match any of our brand safety rules | ||
const matchedRule = wordsMatchedWithRule(rule, decodedWord, words); | ||
if (matchedRule.rule === 'full') { | ||
score += scoreCalculator(points, matchedRule.occurances); | ||
} else if (matchedRule.rule === 'partial') { | ||
score += scoreCalculator(points, matchedRule.occurances); | ||
} else if (matchedRule.rule === 'starts') { | ||
score += scoreCalculator(points, matchedRule.occurances); | ||
} else if (matchedRule.rule === 'ends') { | ||
score += scoreCalculator(points, matchedRule.occurances); | ||
} else if (matchedRule.rule === 'regexp') { | ||
score += scoreCalculator(points, matchedRule.occurances); | ||
} | ||
} | ||
return score < maxScore * words / 500; | ||
return score < (maxScore * contentWords) / 1000; | ||
} catch (e) { | ||
return true; | ||
} | ||
} | ||
|
||
export const spec = { | ||
code: 'adhash', | ||
url: 'https://bidder.adhash.com/rtb?version=' + VERSION + '&prebid=true', | ||
code: ADHASH_BIDDER_CODE, | ||
supportedMediaTypes: [ BANNER ], | ||
|
||
isBidRequestValid: (bid) => { | ||
|
@@ -98,17 +148,50 @@ export const spec = { | |
}, | ||
|
||
buildRequests: (validBidRequests, bidderRequest) => { | ||
const storage = getStorageManager({ bidderCode: ADHASH_BIDDER_CODE }); | ||
const { gdprConsent } = bidderRequest; | ||
const { url } = spec; | ||
const bidRequests = []; | ||
let referrer = ''; | ||
if (bidderRequest && bidderRequest.refererInfo) { | ||
// TODO: is 'page' the right value here? | ||
referrer = bidderRequest.refererInfo.page; | ||
try { | ||
referrer = window.top.location.href; | ||
} catch (e) { | ||
referrer = window.location.href; | ||
} | ||
for (var i = 0; i < validBidRequests.length; i++) { | ||
var index = Math.floor(Math.random() * validBidRequests[i].sizes.length); | ||
var size = validBidRequests[i].sizes[index].join('x'); | ||
const body = document.body; | ||
const html = document.documentElement; | ||
const pageHeight = Math.max( | ||
body.scrollHeight, | ||
body.offsetHeight, | ||
html.clientHeight, | ||
html.scrollHeight, | ||
html.offsetHeight | ||
); | ||
const pageWidth = Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth); | ||
|
||
for (let i = 0; i < validBidRequests.length; i++) { | ||
const bidderURL = validBidRequests[i].params.bidderURL || 'https://bidder.adhash.com'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please ensure that the url passed through There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added a check in isBidRequestValid as well as unit test for that. |
||
const url = `${bidderURL}/rtb?version=${VERSION}&prebid=true`; | ||
const index = Math.floor(Math.random() * validBidRequests[i].sizes.length); | ||
const size = validBidRequests[i].sizes[index].join('x'); | ||
|
||
let recentAds = []; | ||
if (storage.localStorageIsEnabled()) { | ||
const prefix = validBidRequests[i].params.prefix || 'adHash'; | ||
recentAds = JSON.parse(storage.getDataFromLocalStorage(prefix + 'recentAds') || '[]'); | ||
} | ||
|
||
// Needed for the ad density calculation | ||
var adHeight = validBidRequests[i].sizes[index][1]; | ||
var adWidth = validBidRequests[i].sizes[index][0]; | ||
if (!window.adsCount) { | ||
window.adsCount = 0; | ||
} | ||
if (!window.adsTotalSurface) { | ||
window.adsTotalSurface = 0; | ||
} | ||
window.adsTotalSurface += adHeight * adWidth; | ||
window.adsCount++; | ||
|
||
bidRequests.push({ | ||
method: 'POST', | ||
url: url + '&publisher=' + validBidRequests[i].params.publisherId, | ||
|
@@ -131,10 +214,14 @@ export const spec = { | |
position: validBidRequests[i].adUnitCode | ||
}], | ||
blockedCreatives: [], | ||
currentTimestamp: new Date().getTime(), | ||
recentAds: [], | ||
currentTimestamp: (new Date().getTime() / 1000) | 0, | ||
recentAds: recentAds, | ||
GDPRApplies: gdprConsent ? gdprConsent.gdprApplies : null, | ||
GDPR: gdprConsent ? gdprConsent.consentString : null | ||
GDPR: gdprConsent ? gdprConsent.consentString : null, | ||
servedAdsCount: window.adsCount, | ||
adsTotalSurface: window.adsTotalSurface, | ||
pageHeight: pageHeight, | ||
pageWidth: pageWidth | ||
}, | ||
options: { | ||
withCredentials: false, | ||
|
@@ -157,16 +244,19 @@ export const spec = { | |
} | ||
|
||
const publisherURL = JSON.stringify(request.bidRequest.params.platformURL); | ||
const bidderURL = request.bidRequest.params.bidderURL || 'https://bidder.adhash.com'; | ||
const oneTimeId = request.bidRequest.adUnitCode + Math.random().toFixed(16).replace('0.', '.'); | ||
const globalScript = !request.bidRequest.params.globalScript | ||
? `<script src="${bidderURL}/static/scripts/creative.min.js"></script>` | ||
: ''; | ||
const bidderResponse = JSON.stringify({ responseText: JSON.stringify(responseBody) }); | ||
const requestData = JSON.stringify(request.data); | ||
|
||
return [{ | ||
requestId: request.bidRequest.bidId, | ||
cpm: responseBody.creatives[0].costEUR, | ||
ad: | ||
`<div id="${oneTimeId}"></div> | ||
<script src="https://bidder.adhash.com/static/scripts/creative.min.js"></script> | ||
`<div id="${oneTimeId}"></div>${globalScript} | ||
<script>callAdvertiser(${bidderResponse},['${oneTimeId}'],${requestData},${publisherURL})</script>`, | ||
width: request.bidRequest.sizes[0][0], | ||
height: request.bidRequest.sizes[0][1], | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can read the referer value from bidderRequest object,
bidderRequest.refererInfo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am now using bidderRequest.refererInfo.