forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New Module: Bid response filter (prebid#12147)
* initial commit * update * review changes * + auction index * unit tests to ortb converter * review changes * battr setting * improvements * fix log message --------- Co-authored-by: Marcin Komorski <marcinkomorski@Marcins-MacBook-Pro.local> Co-authored-by: Marcin Komorski <marcinkomorski@marcins-mbp.home> Co-authored-by: Demetrio Girardi <dgirardi@prebid.org>
- Loading branch information
1 parent
df04741
commit 7ac768f
Showing
11 changed files
with
333 additions
and
3 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
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,40 @@ | ||
import { auctionManager } from '../../src/auctionManager.js'; | ||
import { config } from '../../src/config.js'; | ||
import { getHook } from '../../src/hook.js'; | ||
|
||
export const MODULE_NAME = 'bidResponseFilter'; | ||
export const BID_CATEGORY_REJECTION_REASON = 'Category is not allowed'; | ||
export const BID_ADV_DOMAINS_REJECTION_REASON = 'Adv domain is not allowed'; | ||
export const BID_ATTR_REJECTION_REASON = 'Attr is not allowed'; | ||
|
||
function init() { | ||
getHook('addBidResponse').before(addBidResponseHook); | ||
}; | ||
|
||
export function addBidResponseHook(next, adUnitCode, bid, reject, index = auctionManager.index) { | ||
const {bcat = [], badv = []} = index.getOrtb2(bid) || {}; | ||
const battr = index.getBidRequest(bid)?.ortb2Imp[bid.mediaType]?.battr || index.getAdUnit(bid)?.ortb2Imp[bid.mediaType]?.battr || []; | ||
const moduleConfig = config.getConfig(MODULE_NAME); | ||
|
||
const catConfig = {enforce: true, blockUnknown: true, ...(moduleConfig?.cat || {})}; | ||
const advConfig = {enforce: true, blockUnknown: true, ...(moduleConfig?.adv || {})}; | ||
const attrConfig = {enforce: true, blockUnknown: true, ...(moduleConfig?.attr || {})}; | ||
|
||
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.blockUnknown && !primaryCatId)) { | ||
reject(BID_CATEGORY_REJECTION_REASON); | ||
} else if ((advConfig.enforce && badv.some(domain => advertiserDomains.includes(domain))) || | ||
(advConfig.blockUnknown && !advertiserDomains.length)) { | ||
reject(BID_ADV_DOMAINS_REJECTION_REASON); | ||
} else if ((attrConfig.enforce && battr.includes(metaAttr)) || | ||
(attrConfig.blockUnknown && !metaAttr)) { | ||
reject(BID_ATTR_REJECTION_REASON); | ||
} else { | ||
return next(adUnitCode, bid, reject); | ||
} | ||
} | ||
|
||
init(); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
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', () => { | ||
let mockAuctionIndex | ||
beforeEach(() => { | ||
config.resetConfig(); | ||
mockAuctionIndex = { | ||
getBidRequest: () => {}, | ||
getAdUnit: () => {} | ||
}; | ||
}); | ||
|
||
it('should pass the bid after successful ortb2 rules validation', () => { | ||
const call = sinon.stub(); | ||
|
||
mockAuctionIndex.getOrtb2 = () => ({ | ||
badv: [], bcat: ['BANNED_CAT1', 'BANNED_CAT2'] | ||
}); | ||
|
||
const bid = { | ||
meta: { | ||
advertiserDomains: ['domain1.com', 'domain2.com'], | ||
primaryCatId: 'EXAMPLE-CAT-ID', | ||
attr: 'attr' | ||
} | ||
}; | ||
|
||
addBidResponseHook(call, 'adcode', bid, () => {}, mockAuctionIndex); | ||
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' | ||
} | ||
}; | ||
mockAuctionIndex.getOrtb2 = () => ({ | ||
badv: [], bcat: ['BANNED_CAT1', 'BANNED_CAT2'] | ||
}); | ||
|
||
addBidResponseHook(call, 'adcode', bid, reject, mockAuctionIndex); | ||
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' | ||
} | ||
}; | ||
mockAuctionIndex.getOrtb2 = () => ({ | ||
badv: ['domain2.com'], bcat: ['BANNED_CAT1', 'BANNED_CAT2'] | ||
}); | ||
|
||
addBidResponseHook(call, 'adcode', bid, rejection, mockAuctionIndex); | ||
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' | ||
}, | ||
mediaType: 'video' | ||
}; | ||
mockAuctionIndex.getOrtb2 = () => ({ | ||
badv: ['domain2.com'], bcat: ['BANNED_CAT1', 'BANNED_CAT2'] | ||
}); | ||
|
||
mockAuctionIndex.getBidRequest = () => ({ | ||
ortb2Imp: { | ||
video: { | ||
battr: 'BANNED_ATTR' | ||
} | ||
} | ||
}) | ||
|
||
addBidResponseHook(call, 'adcode', bid, reject, mockAuctionIndex); | ||
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' | ||
} | ||
}; | ||
|
||
mockAuctionIndex.getOrtb2 = () => ({ | ||
badv: ['domain2.com'], bcat: ['BANNED_CAT1', 'BANNED_CAT2'] | ||
}); | ||
|
||
config.setConfig({[MODULE_NAME]: {cat: {enforce: false}}}); | ||
|
||
addBidResponseHook(call, 'adcode', bid, () => {}, mockAuctionIndex); | ||
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' | ||
} | ||
}; | ||
|
||
mockAuctionIndex.getOrtb2 = () => ({ | ||
badv: ['domain2.com'], bcat: ['BANNED_CAT1', 'BANNED_CAT2'] | ||
}); | ||
|
||
config.setConfig({[MODULE_NAME]: {cat: {blockUnknown: false}}}); | ||
|
||
addBidResponseHook(call, 'adcode', bid, () => {}); | ||
sinon.assert.calledOnce(call); | ||
}); | ||
}) |
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
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.