-
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
New Module: Bid response filter #12147
Changes from 2 commits
ce5bcdb
a89fcbd
ed8dda8
5697f4e
585bb46
66bc55a
8366048
f90c448
fb9458c
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 |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { config } from '../../src/config.js'; | ||
import { getHook } from '../../src/hook.js'; | ||
|
||
export const MODULE_NAME = 'bidResponseFilter'; | ||
export const PUBLISHER_FILTER_REJECTION_REASON = 'PUBLISHER_FILTER_REJECTION_REASON'; | ||
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. these should be human readable |
||
export const BID_CATEGORY_REJECTION_REASON = 'BID_CATEGORY_REJECTION_REASON'; | ||
export const BID_ADV_DOMAINS_REJECTION_REASON = 'BID_ADV_DOMAINS_REJECTION_REASON'; | ||
export const BID_ATTR_REJECTION_REASON = 'BID_ATTR_REJECTION_REASON'; | ||
|
||
function init() { | ||
getHook('addBidResponse').before(addBidResponseHook); | ||
}; | ||
|
||
export function addBidResponseHook(next, adUnitCode, bid, reject) { | ||
const { bcat = [], badv = [], battr = [] } = config.getAnyConfig('ortb2') || {}; | ||
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. ortb2 can be different for each bid response. You can get a specific response's with It may be worth to add a 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 just noticed that Assuming the first one should have priority, we could:
(pending confirmation on the relative priority of |
||
const moduleConfig = config.getConfig(MODULE_NAME); | ||
|
||
const catConfig = moduleConfig?.cat || { enforce: true, block_unknown_cat: true }; | ||
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. if I
my expectation would be that |
||
const advConfig = moduleConfig?.adv || { enforce: true, block_unknown_adomain: true }; | ||
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. It's probably out of scope, but I don't like these parameter names. If we weren't following PBS this would be something like 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. those are good reasons to abandon the hope of matching the syntax. oh well |
||
const attrConfig = moduleConfig?.attr || { enforce: true, block_unknown_attr: true }; | ||
|
||
const { primaryCatId, secondaryCatIds = [], advertiserDomains = [], attr: metaAttr } = bid.meta || {}; | ||
|
||
// checking if bid fulfills ortb2 fields rules | ||
if ((catConfig.enforce && bcat.some(category => [primaryCatId, ...secondaryCatIds].includes(category))) || | ||
(catConfig.block_unknown_cat && !primaryCatId)) { | ||
reject(BID_CATEGORY_REJECTION_REASON); | ||
} else if ((advConfig.enforce && badv.some(domain => advertiserDomains.includes(domain))) || | ||
(advConfig.block_unknown_adomain && !advertiserDomains.length)) { | ||
reject(BID_ADV_DOMAINS_REJECTION_REASON); | ||
} else if ((attrConfig.enforce && battr.includes(metaAttr)) || | ||
(attrConfig.block_unknown_attr && !metaAttr)) { | ||
reject(BID_ATTR_REJECTION_REASON); | ||
} else { | ||
return next(adUnitCode, bid, reject); | ||
} | ||
} | ||
|
||
init(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { BID_ADV_DOMAINS_REJECTION_REASON, BID_ATTR_REJECTION_REASON, BID_CATEGORY_REJECTION_REASON, MODULE_NAME, PUBLISHER_FILTER_REJECTION_REASON, addBidResponseHook } from '../../../modules/bidResponseFilter'; | ||
import { config } from '../../../src/config'; | ||
|
||
describe('bidResponseFilter', () => { | ||
afterEach(() => { | ||
config.resetConfig(); | ||
}); | ||
|
||
it('should pass the bid after successful ortb2 rules validation', () => { | ||
const call = sinon.stub(); | ||
const bid = { | ||
meta: { | ||
advertiserDomains: ['domain1.com', 'domain2.com'], | ||
primaryCatId: 'EXAMPLE-CAT-ID', | ||
attr: 'attr' | ||
} | ||
}; | ||
config.setConfig({ortb2: { | ||
badv: [], bcat: ['BANNED_CAT1', 'BANNED_CAT2'], battr: 'BANNED_ATTR' | ||
}}); | ||
|
||
addBidResponseHook(call, 'adcode', bid, () => {}); | ||
sinon.assert.calledOnce(call); | ||
}); | ||
|
||
it('should reject the bid after failed ortb2 cat rule validation', () => { | ||
const reject = sinon.stub(); | ||
const call = sinon.stub(); | ||
const bid = { | ||
meta: { | ||
advertiserDomains: ['domain1.com', 'domain2.com'], | ||
primaryCatId: 'BANNED_CAT1', | ||
attr: 'attr' | ||
} | ||
}; | ||
config.setConfig({ortb2: { | ||
badv: [], bcat: ['BANNED_CAT1', 'BANNED_CAT2'], battr: 'BANNED_ATTR' | ||
}}); | ||
|
||
addBidResponseHook(call, 'adcode', bid, reject); | ||
sinon.assert.calledWith(reject, BID_CATEGORY_REJECTION_REASON); | ||
}); | ||
|
||
it('should reject the bid after failed ortb2 adv domains rule validation', () => { | ||
const rejection = sinon.stub(); | ||
const call = sinon.stub(); | ||
const bid = { | ||
meta: { | ||
advertiserDomains: ['domain1.com', 'domain2.com'], | ||
primaryCatId: 'VALID_CAT', | ||
attr: 'attr' | ||
} | ||
}; | ||
config.setConfig({ortb2: { | ||
badv: ['domain2.com'], bcat: ['BANNED_CAT1', 'BANNED_CAT2'], battr: 'BANNED_ATTR' | ||
}}); | ||
|
||
addBidResponseHook(call, 'adcode', bid, rejection); | ||
sinon.assert.calledWith(rejection, BID_ADV_DOMAINS_REJECTION_REASON); | ||
}); | ||
|
||
it('should reject the bid after failed ortb2 attr rule validation', () => { | ||
const reject = sinon.stub(); | ||
const call = sinon.stub(); | ||
const bid = { | ||
meta: { | ||
advertiserDomains: ['validdomain1.com', 'validdomain2.com'], | ||
primaryCatId: 'VALID_CAT', | ||
attr: 'BANNED_ATTR' | ||
} | ||
}; | ||
config.setConfig({ortb2: { | ||
badv: ['domain2.com'], bcat: ['BANNED_CAT1', 'BANNED_CAT2'], battr: 'BANNED_ATTR' | ||
}}); | ||
|
||
addBidResponseHook(call, 'adcode', bid, reject); | ||
sinon.assert.calledWith(reject, BID_ATTR_REJECTION_REASON); | ||
}); | ||
|
||
it('should omit the validation if the flag is set to false', () => { | ||
const call = sinon.stub(); | ||
const bid = { | ||
meta: { | ||
advertiserDomains: ['validdomain1.com', 'validdomain2.com'], | ||
primaryCatId: 'BANNED_CAT1', | ||
attr: 'valid_attr' | ||
} | ||
}; | ||
config.setConfig({ortb2: { | ||
badv: ['domain2.com'], bcat: ['BANNED_CAT1', 'BANNED_CAT2'], battr: 'BANNED_ATTR' | ||
}}); | ||
|
||
config.setConfig({ [MODULE_NAME]: { cat: { enforce: false }} }); | ||
|
||
addBidResponseHook(call, 'adcode', bid, () => {}); | ||
sinon.assert.calledOnce(call); | ||
}); | ||
|
||
it('should allow bid for unknown flag set to false', () => { | ||
const call = sinon.stub(); | ||
const bid = { | ||
meta: { | ||
advertiserDomains: ['validdomain1.com', 'validdomain2.com'], | ||
primaryCatId: undefined, | ||
attr: 'valid_attr' | ||
} | ||
}; | ||
config.setConfig({ortb2: { | ||
badv: ['domain2.com'], bcat: ['BANNED_CAT1', 'BANNED_CAT2'], battr: 'BANNED_ATTR' | ||
}}); | ||
|
||
config.setConfig({ [MODULE_NAME]: { cat: { block_unknown_cat: false }} }); | ||
|
||
addBidResponseHook(call, 'adcode', bid, () => {}); | ||
sinon.assert.calledOnce(call); | ||
}); | ||
}) |
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.
is a primary category also a secondary category?