Skip to content

Commit

Permalink
33Across: CCPA Compliance + Schain support (#5365)
Browse files Browse the repository at this point in the history
* check gdpr in buildRequest

* User sync based on whether gdpr applies or not

* check if consent data exists during user sync

* split user sync into further branches: 1) when gdpr does not apply 2) when consent data is unavailable

* contribute viewability to ttxRequest

* update tests

* remove window mock from tests

* use local variables

* introduce ServerRequestBuilder

* add withOptions() method to ServerRequestBuilder

* add semicolons

* sync up package-lock.json with upstream/master

* stub window.top in tests

* introduce getTopWindowSize() for test purpose

* reformat code

* add withSite() method to TtxRequestBuilder

add withSite() method to TtxRequestBuilder

* add isIframe() and _isViewabilityMeasurable()

* handle NON_MEASURABLE viewability in nested iframes

* consider page visibility, stub utils functions getWindowTop() and getWindowSelf()

* contribute viewability as 0 for inactive tab

* add prebidjs version to ttx request

* send caller as an array

* fix JSDoc in utils.js

* send viewability as non measurable when unable to locate target HTMLElement, add warning message

* introduce mapAdSlotPathToElementId()

* introduce getAdSlotHTMLElement(), add logging

* introduce mapAdSlotPathToElementId()

* update logging in ad unit path to element id mapping

* rephrase logging, fix tests

* update adapter documentation

* remove excessive logging

* improve logging

* revert change

* fix return of _mapAdUnitPathToElementId()

* improve logging of _mapAdUnitPathToElementId()

* do not use Array.find()

* return id once element is found

* return id once element is found

* let -> const

* Removing killswitch behavior for GDPR

* Updated comments to reflect current gdpr logic

* URI encode consent string

* Updated example site ID to help Prebid team e2e test our adapter

* send page url in ortb

* Removed redundant pageUrl default

* Restored package-log.json that mirrors prebid's repo

* Sending USP string during buildRequest

* Adding USP consent data to user sync

* add unit test for syncing without bidrequest

* Changed to uspConsent to make the connatation consistent

* Resetting adapter state in adapter after user sync rather than exposing it.

* removed console log

* Adding schain info

* remove setting empty format ext

* better tests invalid values

* removing validation of schain

* Fixed lint errors

Co-authored-by: Gleb Glushtsov <[email protected]>
Co-authored-by: Gleb Glushtsov <[email protected]>
Co-authored-by: Gleb Glushtsov <[email protected]>
Co-authored-by: Aparna Hegde <[email protected]>
Co-authored-by: Aparna Hegde <[email protected]>
Co-authored-by: Aparna Hegde <[email protected]>
Co-authored-by: Aparna Hegde <[email protected]>
Co-authored-by: Aparna Hegde <[email protected]>
Co-authored-by: Aparna Hegde <[email protected]>
  • Loading branch information
10 people authored Jun 22, 2020
1 parent 4e59331 commit 57f8beb
Show file tree
Hide file tree
Showing 2 changed files with 280 additions and 33 deletions.
52 changes: 38 additions & 14 deletions modules/33acrossBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ const BIDDER_CODE = '33across';
const END_POINT = 'https://ssc.33across.com/api/v1/hb';
const SYNC_ENDPOINT = 'https://ssc-cms.33across.com/ps/?m=xch&rt=html&ru=deb';

const adapterState = {};
const adapterState = {
uniqueSiteIds: []
};

const NON_MEASURABLE = 'nm';

Expand Down Expand Up @@ -65,7 +67,7 @@ function _getAdSlotHTMLElement(adUnitCode) {

// Infer the necessary data from valid bid for a minimal ttxRequest and create HTTP request
// NOTE: At this point, TTX only accepts request for a single impression
function _createServerRequest(bidRequest, gdprConsent = {}, pageUrl) {
function _createServerRequest(bidRequest, gdprConsent = {}, uspConsent, pageUrl) {
const ttxRequest = {};
const params = bidRequest.params;
const element = _getAdSlotHTMLElement(bidRequest.adUnitCode);
Expand All @@ -84,7 +86,7 @@ function _createServerRequest(bidRequest, gdprConsent = {}, pageUrl) {
ttxRequest.imp = [];
ttxRequest.imp[0] = {
banner: {
format: sizes.map(size => Object.assign(size, {ext: {}}))
format: sizes
},
ext: {
ttx: {
Expand All @@ -97,6 +99,7 @@ function _createServerRequest(bidRequest, gdprConsent = {}, pageUrl) {
if (pageUrl) {
ttxRequest.site.page = pageUrl;
}

// Go ahead send the bidId in request to 33exchange so it's kept track of in the bid response and
// therefore in ad targetting process
ttxRequest.id = bidRequest.bidId;
Expand All @@ -109,19 +112,28 @@ function _createServerRequest(bidRequest, gdprConsent = {}, pageUrl) {
};
ttxRequest.regs = {
ext: {
gdpr: (gdprConsent.gdprApplies === true) ? 1 : 0
gdpr: (gdprConsent.gdprApplies === true) ? 1 : 0,
us_privacy: uspConsent || null
}
};
ttxRequest.ext = {
ttx: {
prebidStartedAt: Date.now(),
caller: [{
caller: [ {
'name': 'prebidjs',
'version': '$prebid.version$'
}]
} ]
}
};

if (bidRequest.schain) {
ttxRequest.source = {
ext: {
schain: bidRequest.schain
}
}
}

// Finally, set the openRTB 'test' param if this is to be a test bid
if (params.test === 1) {
ttxRequest.test = 1;
Expand All @@ -134,6 +146,7 @@ function _createServerRequest(bidRequest, gdprConsent = {}, pageUrl) {
contentType: 'text/plain',
withCredentials: true
};

// Allow the ability to configure the HB endpoint for testing purposes.
const ttxSettings = config.getConfig('ttxSettings');
const url = (ttxSettings && ttxSettings.url) || END_POINT;
Expand All @@ -148,15 +161,15 @@ function _createServerRequest(bidRequest, gdprConsent = {}, pageUrl) {
}

// Sync object will always be of type iframe for TTX
function _createSync({siteId = 'zzz000000000003zzz', gdprConsent = {}}) {
function _createSync({ siteId = 'zzz000000000003zzz', gdprConsent = {}, uspConsent }) {
const ttxSettings = config.getConfig('ttxSettings');
const syncUrl = (ttxSettings && ttxSettings.syncUrl) || SYNC_ENDPOINT;

const {consentString, gdprApplies} = gdprConsent;
const { consentString, gdprApplies } = gdprConsent;

const sync = {
type: 'iframe',
url: `${syncUrl}&id=${siteId}&gdpr_consent=${encodeURIComponent(consentString)}`
url: `${syncUrl}&id=${siteId}&gdpr_consent=${encodeURIComponent(consentString)}&us_privacy=${encodeURIComponent(uspConsent)}`
};

if (typeof gdprApplies === 'boolean') {
Expand Down Expand Up @@ -192,7 +205,7 @@ function _getBoundingBox(element, { w, h } = {}) {

function _transformSizes(sizes) {
if (utils.isArray(sizes) && sizes.length === 2 && !utils.isArray(sizes[0])) {
return [_getSize(sizes)];
return [ _getSize(sizes) ];
}

return sizes.map(_getSize);
Expand Down Expand Up @@ -239,7 +252,8 @@ function _getPercentInView(element, topWin, { w, h } = {}) {
bottom: topWin.innerHeight
}, elementBoundingBox ]);

let elementInViewArea, elementTotalArea;
let elementInViewArea,
elementTotalArea;

if (elementInViewBoundingBox !== null) {
// Some or all of the element is in view
Expand Down Expand Up @@ -301,11 +315,12 @@ function buildRequests(bidRequests, bidderRequest) {
gdprApplies: false
}, bidderRequest && bidderRequest.gdprConsent);

const uspConsent = bidderRequest && bidderRequest.uspConsent;
const pageUrl = (bidderRequest && bidderRequest.refererInfo) ? (bidderRequest.refererInfo.referer) : (undefined);

adapterState.uniqueSiteIds = bidRequests.map(req => req.params.siteId).filter(utils.uniques);

return bidRequests.map(req => _createServerRequest(req, gdprConsent, pageUrl));
return bidRequests.map(req => _createServerRequest(req, gdprConsent, uspConsent, pageUrl));
}

// NOTE: At this point, the response from 33exchange will only ever contain one bid i.e. the highest bid
Expand All @@ -324,8 +339,17 @@ function interpretResponse(serverResponse, bidRequest) {
// Else no syncs
// For logic on how we handle gdpr data see _createSyncs and module's unit tests
// '33acrossBidAdapter#getUserSyncs'
function getUserSyncs(syncOptions, responses, gdprConsent) {
return (syncOptions.iframeEnabled) ? adapterState.uniqueSiteIds.map((siteId) => _createSync({gdprConsent, siteId})) : ([]);
function getUserSyncs(syncOptions, responses, gdprConsent, uspConsent) {
const syncUrls = (
(syncOptions.iframeEnabled)
? adapterState.uniqueSiteIds.map((siteId) => _createSync({ gdprConsent, uspConsent, siteId }))
: ([])
);

// Clear adapter state of siteID's since we don't need this info anymore.
adapterState.uniqueSiteIds = [];

return syncUrls;
}

export const spec = {
Expand Down
Loading

0 comments on commit 57f8beb

Please sign in to comment.