-
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.
SupplyChain object support in Prebid (#4084)
* moving dctr related code in a function * moving parsedRequest variable out of the loop and moving GDPR related block at bottom * added a todo comment * exporting hasOwn function * added functionality to pass schain object - adapter manager will validate schain object - if it is valid then only it can be passed on to all bidders - bidders do not need to validate again * changed logMessage to logError - also fixed isInteger check * Moved schain related code from adapaterManager.js to schain.js * indentation chnages * logical bug fix * added test cases for schain * PubMatic: pass schain object in request * indentation * unit test for PubMatic schain support * using isInteger from utils * moved schain as a module * indentation * removed commented code * added try-catch as the statement code was breaking CI for IE-11 * Revert "added try-catch as the statement code was breaking CI for IE-11" This reverts commit 88f495f. * added a try-catch for a staement as it was breaking CI sometimes * added schain.md for schain module * added a few links * fixed typos * simplified the approach in adpater code * trying to restart CI * Revert "trying to restart CI" This reverts commit 25f877c. * adding support in prebidServerBidAdpater as well * bug fix * minor changes - moved consts out of function - added a error log on finding an invalid schain object * modified a comment * added name to a test case * Revert "added a try-catch for a staement as it was breaking CI sometimes" This reverts commit e9606bf. * moving schain validation logic inside PM adapter * Revert "moving schain validation logic inside PM adapter" This reverts commit 31d00d5. * added validation mode: strict, relaxed, off * updated documentation * moved a comment * changed value in example
- Loading branch information
1 parent
87e84b8
commit a7ad5ef
Showing
8 changed files
with
575 additions
and
41 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
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,147 @@ | ||
import {config} from '../src/config'; | ||
import {getGlobal} from '../src/prebidGlobal'; | ||
import { isNumber, isStr, isArray, isPlainObject, hasOwn, logError, isInteger } from '../src/utils'; | ||
|
||
// https://github.com/InteractiveAdvertisingBureau/openrtb/blob/master/supplychainobject.md | ||
|
||
const schainErrorPrefix = 'Invalid schain object found: '; | ||
const shouldBeAString = ' should be a string'; | ||
const shouldBeAnInteger = ' should be an Integer'; | ||
const shouldBeAnObject = ' should be an object'; | ||
const shouldBeAnArray = ' should be an Array'; | ||
const MODE = { | ||
STRICT: 'strict', | ||
RELAXED: 'relaxed', | ||
OFF: 'off' | ||
}; | ||
|
||
// validate the supply chain object | ||
export function isSchainObjectValid(schainObject, returnOnError) { | ||
if (!isPlainObject(schainObject)) { | ||
logError(schainErrorPrefix + `schain` + shouldBeAnObject); | ||
if (returnOnError) return false; | ||
} | ||
|
||
// complete: Integer | ||
if (!isNumber(schainObject.complete) || !isInteger(schainObject.complete)) { | ||
logError(schainErrorPrefix + `schain.complete` + shouldBeAnInteger); | ||
if (returnOnError) return false; | ||
} | ||
|
||
// ver: String | ||
if (!isStr(schainObject.ver)) { | ||
logError(schainErrorPrefix + `schain.ver` + shouldBeAString); | ||
if (returnOnError) return false; | ||
} | ||
|
||
// ext: Object [optional] | ||
if (hasOwn(schainObject, 'ext')) { | ||
if (!isPlainObject(schainObject.ext)) { | ||
logError(schainErrorPrefix + `schain.ext` + shouldBeAnObject); | ||
if (returnOnError) return false; | ||
} | ||
} | ||
|
||
// nodes: Array of objects | ||
if (!isArray(schainObject.nodes)) { | ||
logError(schainErrorPrefix + `schain.nodes` + shouldBeAnArray); | ||
if (returnOnError) return false; | ||
} | ||
|
||
// now validate each node | ||
let isEachNodeIsValid = true; | ||
schainObject.nodes.forEach(node => { | ||
// asi: String | ||
if (!isStr(node.asi)) { | ||
isEachNodeIsValid = isEachNodeIsValid && false; | ||
logError(schainErrorPrefix + `schain.nodes[].asi` + shouldBeAString); | ||
} | ||
|
||
// sid: String | ||
if (!isStr(node.sid)) { | ||
isEachNodeIsValid = isEachNodeIsValid && false; | ||
logError(schainErrorPrefix + `schain.nodes[].sid` + shouldBeAString); | ||
} | ||
|
||
// hp: Integer | ||
if (!isNumber(node.hp) || !isInteger(node.hp)) { | ||
isEachNodeIsValid = isEachNodeIsValid && false; | ||
logError(schainErrorPrefix + `schain.nodes[].hp` + shouldBeAnInteger); | ||
} | ||
|
||
// rid: String [Optional] | ||
if (hasOwn(node, 'rid')) { | ||
if (!isStr(node.rid)) { | ||
isEachNodeIsValid = isEachNodeIsValid && false; | ||
logError(schainErrorPrefix + `schain.nodes[].rid` + shouldBeAString); | ||
} | ||
} | ||
|
||
// name: String [Optional] | ||
if (hasOwn(node, 'name')) { | ||
if (!isStr(node.name)) { | ||
isEachNodeIsValid = isEachNodeIsValid && false; | ||
logError(schainErrorPrefix + `schain.nodes[].name` + shouldBeAString); | ||
} | ||
} | ||
|
||
// domain: String [Optional] | ||
if (hasOwn(node, 'domain')) { | ||
if (!isStr(node.domain)) { | ||
isEachNodeIsValid = isEachNodeIsValid && false; | ||
logError(schainErrorPrefix + `schain.nodes[].domain` + shouldBeAString); | ||
} | ||
} | ||
|
||
// ext: Object [Optional] | ||
if (hasOwn(node, 'ext')) { | ||
if (!isPlainObject(node.ext)) { | ||
isEachNodeIsValid = isEachNodeIsValid && false; | ||
logError(schainErrorPrefix + `schain.nodes[].ext` + shouldBeAnObject); | ||
} | ||
} | ||
}); | ||
|
||
if (returnOnError && !isEachNodeIsValid) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
export function copySchainObjectInAdunits(adUnits, schainObject) { | ||
// copy schain object in all adUnits as adUnits[].bid.schain | ||
adUnits.forEach(adUnit => { | ||
adUnit.bids.forEach(bid => { | ||
bid.schain = schainObject; | ||
}); | ||
}); | ||
} | ||
|
||
export function init(config) { | ||
let mode = MODE.STRICT; | ||
getGlobal().requestBids.before(function(fn, reqBidsConfigObj) { | ||
let schainObject = config.getConfig('schain'); | ||
if (!isPlainObject(schainObject)) { | ||
logError(schainErrorPrefix + 'schain config will not be passed to bidders as schain is not an object.'); | ||
} else { | ||
if (isStr(schainObject.validation) && Object.values(MODE).indexOf(schainObject.validation) != -1) { | ||
mode = schainObject.validation; | ||
} | ||
if (mode === MODE.OFF) { | ||
// no need to validate | ||
copySchainObjectInAdunits(reqBidsConfigObj.adUnits || getGlobal().adUnits, schainObject.config); | ||
} else { | ||
if (isSchainObjectValid(schainObject.config, mode === MODE.STRICT)) { | ||
copySchainObjectInAdunits(reqBidsConfigObj.adUnits || getGlobal().adUnits, schainObject.config); | ||
} else { | ||
logError(schainErrorPrefix + 'schain config will not be passed to bidders as it is not valid.'); | ||
} | ||
} | ||
} | ||
// calling fn allows prebid to continue processing | ||
return fn.call(this, reqBidsConfigObj); | ||
}, 40); | ||
} | ||
|
||
init(config) |
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,50 @@ | ||
# schain module | ||
|
||
Aggregators who manage Prebid wrappers on behalf of multiple publishers need to declare their intermediary status in the Supply Chain Object. | ||
As the spec prohibits us from adding upstream intermediaries, Prebid requests in this case need to come with the schain information. | ||
In this use case, it's seems cumbersome to have every bidder in the wrapper separately configured the same schain information. | ||
|
||
Refer: | ||
- https://iabtechlab.com/sellers-json/ | ||
- https://github.com/InteractiveAdvertisingBureau/openrtb/blob/master/supplychainobject.md | ||
|
||
## Sample code for passing the schain object | ||
``` | ||
pbjs.setConfig( { | ||
"schain": | ||
"validation": "strict", | ||
"config": { | ||
"ver":"1.0", | ||
"complete": 1, | ||
"nodes": [ | ||
{ | ||
"asi":"indirectseller.com", | ||
"sid":"00001", | ||
"hp":1 | ||
}, | ||
{ | ||
"asi":"indirectseller-2.com", | ||
"sid":"00002", | ||
"hp":0 | ||
}, | ||
] | ||
} | ||
} | ||
}); | ||
``` | ||
|
||
## Workflow | ||
The schain module is not enabled by default as it may not be neccessary for all publishers. | ||
If required, schain module can be included as following | ||
``` | ||
$ gulp build --modules=schain,pubmaticBidAdapter,openxBidAdapter,rubiconBidAdapter,sovrnBidAdapter | ||
``` | ||
The schain module will validate the schain object passed using pbjs.setConfig API. | ||
If the schain object is valid then it will be passed on to bidders/adapters in ```validBidRequests[].schain``` | ||
You may refer pubmaticBidAdapter implementaion for the same. | ||
|
||
## Validation modes | ||
- ```strict```: It is the default validation mode. In this mode, schain object will not be passed to adapters if it is invalid. Errors are thrown for invalid schain object. | ||
- ```relaxed```: In this mode, errors are thrown for an invalid schain object but the invalid schain object is still passed to adapters. | ||
- ```off```: In this mode, no validations are performed and schain object is passed as is to adapters. |
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.