Skip to content

Commit

Permalink
VidoomyBidAdapter: refactor cookie sync (#7601)
Browse files Browse the repository at this point in the history
* fix: add delay between cookie sync calls

* fix(VidoomyBidAdapter): use default triggerPixel

* fix: use getUserSyncs hook to sync cookies

* fix: handle 204 no response without error log

* chore: refactor getUserSyncs

* test: update vidoomyBidAdapter tests

* fix: remove Macro

* fix: query params

* fix: gdpr consent

* fix: vidoomyBidAdapter tests

* fix: use USP_CONSENT in cookie sync urls
  • Loading branch information
sasanfarokh committed Nov 2, 2021
1 parent 4ae7e1b commit e14b009
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 113 deletions.
151 changes: 51 additions & 100 deletions modules/vidoomyBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,17 @@ const ENDPOINT = `https://d.vidoomy.com/api/rtbserver/prebid/`;
const BIDDER_CODE = 'vidoomy';
const GVLID = 380;

const COOKIE_SYNC_JSON = 'https://vpaid.vidoomy.com/sync/urls.json';
const COOKIE_SYNC_FALLBACK_URLS = [
'https://x.bidswitch.net/sync?ssp=vidoomy',
'https://ib.adnxs.com/getuid?https%3A%2F%2Fa-prebid.vidoomy.com%2Fsetuid%3Fbidder%3Dadnxs%26gdpr%3D{{GDPR}}%26gdpr_consent%3D{{GDPR_CONSENT}}%26uid%3D%24UID',
'https://pixel-sync.sitescout.com/dmp/pixelSync?nid=120&redir=https%3A%2F%2Fa.vidoomy.com%2Fapi%2Frtbserver%2Fcookie%3Fi%3DCEN%26uid%3D%7BuserId%7D',
'https://sync.1rx.io/usersync2/vidoomy?redir=https%3A%2F%2Fa.vidoomy.com%2Fapi%2Frtbserver%2Fcookie%3Fi%3DUN%26uid%3D%5BRX_UUID%5D',
'https://rtb.openx.net/sync/prebid?gdpr={{GDPR}}&gdpr_consent={{GDPR_CONSENT}}&r=https%3A%2F%2Fa-prebid.vidoomy.com%2Fsetuid%3Fbidder%3Dopenx%26uid%3D$%7BUID%7D',
'https://ads.pubmatic.com/AdServer/js/user_sync.html?gdpr={{GDPR}}&gdpr_consent={{GDPR_CONSENT}}&us_privacy=&predirect=https%3A%2F%2Fa-prebid.vidoomy.com%2Fsetuid%3Fbidder%3Dpubmatic%26gdpr%3D{{GDPR}}%26gdpr_consent%3D{{GDPR_CONSENT}}%26uid%3D',
'https://cm.adform.net/cookie?redirect_url=https%3A%2F%2Fa-prebid.vidoomy.com%2Fsetuid%3Fbidder%3Dadf%26gdpr%3D{{GDPR}}%26gdpr_consent%3D{{GDPR_CONSENT}}%26uid%3D%24UID',
'https://ups.analytics.yahoo.com/ups/58531/occ?gdpr={{GDPR}}&gdpr_consent={{GDPR_CONSENT}}',
'https://ap.lijit.com/pixel?redir=https%3A%2F%2Fa-prebid.vidoomy.com%2Fsetuid%3Fbidder%3Dsovrn%26gdpr%3D{{GDPR}}%26gdpr_consent%3D{{GDPR_CONSENT}}%26uid%3D%24UID'
];

const isBidRequestValid = bid => {
if (!bid.params) {
Expand All @@ -36,7 +46,7 @@ const isBidRequestValid = bid => {
};

const isBidResponseValid = bid => {
if (!bid.requestId || !bid.cpm || !bid.ttl || !bid.currency) {
if (!bid || !bid.requestId || !bid.cpm || !bid.ttl || !bid.currency) {
return false;
}
switch (bid.mediaType) {
Expand Down Expand Up @@ -67,35 +77,33 @@ const buildRequests = (validBidRequests, bidderRequest) => {

const videoContext = deepAccess(bid, 'mediaTypes.video.context');

const queryParams = [];
queryParams.push(['id', bid.params.id]);
queryParams.push(['adtype', adType]);
queryParams.push(['w', w]);
queryParams.push(['h', h]);
queryParams.push(['pos', parseInt(bid.params.position) || 1]);
queryParams.push(['ua', navigator.userAgent]);
queryParams.push(['l', navigator.language && navigator.language.indexOf('-') !== -1 ? navigator.language.split('-')[0] : '']);
queryParams.push(['dt', /Mobi/.test(navigator.userAgent) ? 2 : 1]);
queryParams.push(['pid', bid.params.pid]);
queryParams.push(['requestId', bid.bidId]);
queryParams.push(['d', getDomainWithoutSubdomain(hostname)]);
queryParams.push(['sp', encodeURIComponent(aElement.href)]);
const queryParams = {
id: bid.params.id,
adtype: adType,
w,
h,
pos: parseInt(bid.params.position) || 1,
ua: navigator.userAgent,
l: navigator.language && navigator.language.indexOf('-') !== -1 ? navigator.language.split('-')[0] : '',
dt: /Mobi/.test(navigator.userAgent) ? 2 : 1,
pid: bid.params.pid,
requestId: bid.bidId,
d: getDomainWithoutSubdomain(hostname),
sp: encodeURIComponent(aElement.href),
usp: bidderRequest.uspConsent || '',
coppa: !!config.getConfig('coppa'),
videoContext: videoContext || ''
};

if (bidderRequest.gdprConsent) {
queryParams.push(['gdpr', bidderRequest.gdprConsent.gdprApplies]);
queryParams.push(['gdprcs', bidderRequest.gdprConsent.consentString]);
queryParams.gdpr = bidderRequest.gdprConsent.gdprApplies;
queryParams.gdprcs = bidderRequest.gdprConsent.consentString;
}
queryParams.push(['usp', bidderRequest.uspConsent || '']);
queryParams.push(['coppa', !!config.getConfig('coppa')]);

const rawQueryParams = queryParams.map(qp => qp.join('=')).join('&');

cookieSync(bidderRequest)

const url = `${ENDPOINT}?${rawQueryParams}`;
return {
method: 'GET',
url: url,
data: {videoContext}
url: ENDPOINT,
data: queryParams
}
});
return serverRequests;
Expand All @@ -117,6 +125,7 @@ const render = (bid) => {
const interpretResponse = (serverResponse, bidRequest) => {
try {
let responseBody = serverResponse.body;
if (!responseBody) return;
if (responseBody.mediaType === 'video') {
responseBody.ad = responseBody.vastUrl;
const videoContext = bidRequest.data.videoContext;
Expand Down Expand Up @@ -185,91 +194,33 @@ const interpretResponse = (serverResponse, bidRequest) => {
}
};

function getUserSyncs (syncOptions, responses, gdprConsent, uspConsent) {
if (syncOptions.iframeEnabled || syncOptions.pixelEnabled) {
const pixelType = syncOptions.pixelEnabled ? 'image' : 'iframe';
const urls = deepAccess(responses, '0.body.pixels') || COOKIE_SYNC_FALLBACK_URLS;

return [].concat(urls).map(url => ({
type: pixelType,
url: url
.replace('{{GDPR}}', gdprConsent ? gdprConsent.gdprApplies : '0')
.replace('{{GDPR_CONSENT}}', gdprConsent ? encodeURIComponent(gdprConsent.consentString) : '')
.replace('{{USP_CONSENT}}', uspConsent ? encodeURIComponent(uspConsent) : '')
}));
}
};

export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER, VIDEO],
isBidRequestValid,
buildRequests,
interpretResponse,
gvlid: GVLID,
getUserSyncs,
};

registerBidder(spec);

let cookieSynced = false;
function cookieSync(bidderRequest) {
if (cookieSynced) return;
const xhr = new XMLHttpRequest();
xhr.open('GET', COOKIE_SYNC_JSON)
xhr.addEventListener('load', function () {
const macro = Macro({
gpdr: bidderRequest.gdprConsent ? bidderRequest.gdprConsent.gdprApplies : '0',
gpdr_consent: bidderRequest.gdprConsent ? bidderRequest.gdprConsent.consentString : '',
});
JSON.parse(this.responseText).filter(Boolean).forEach(url => {
firePixel(macro.replace(url))
})
})
xhr.send()
cookieSynced = true;
}

function firePixel(url) {
const img = document.createElement('img');
img.width = 1;
img.height = 1;
img.src = url;
document.body.appendChild(img);
setTimeout(() => {
img.remove();
}, 10000)
}

function normalizeKey (x) {
return x.replace(/_/g, '').toLowerCase();
}

function Macro (obj) {
const macros = {};
for (const key in obj) {
macros[normalizeKey(key)] = obj[key];
}

const set = (key, value) => {
macros[normalizeKey(key)] = typeof value === 'function' ? value : String(value);
};

return {
set,
setAll (obj) {
for (const key in obj) {
macros[normalizeKey(key)] = set(obj[key]);
}
},
replace (string, extraMacros = {}) {
const allMacros = {
...macros,
...extraMacros,
};
const regexes = [
/{{\s*([a-zA-Z0-9_]+)\s*}}/g,
/\$\$\s*([a-zA-Z0-9_]+)\s*\$\$/g,
/\[\s*([a-zA-Z0-9_]+)\s*\]/g,
/\{\s*([a-zA-Z0-9_]+)\s*\}/g,
];
regexes.forEach(regex => {
string = string.replace(regex, (str, x) => {
x = normalizeKey(x);
let value = allMacros[x];
value = typeof value === 'function' ? value(allMacros) : value;
return !value && value !== 0 ? '' : value;
});
});
return string;
},
};
}

function getDomainWithoutSubdomain (hostname) {
const parts = hostname.split('.');
const newParts = [];
Expand Down
45 changes: 32 additions & 13 deletions test/spec/modules/vidoomyBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { newBidder } from 'src/adapters/bidderFactory.js';
import { INSTREAM } from '../../../src/video';

const ENDPOINT = `https://d.vidoomy.com/api/rtbserver/prebid/`;
const PIXELS = ['/test.png', '/test2.png?gdpr={{GDPR}}&gdpr_consent={{GDPR_CONSENT}}']

describe('vidoomyBidAdapter', function() {
const adapter = newBidder(spec);
Expand Down Expand Up @@ -101,24 +102,24 @@ describe('vidoomyBidAdapter', function() {
});

it('attaches source and version to endpoint URL as query params', function () {
expect(request[0].url).to.include(ENDPOINT);
expect(request[1].url).to.include(ENDPOINT);
expect(request[0].url).to.equal(ENDPOINT);
expect(request[1].url).to.equal(ENDPOINT);
});

it('only accepts first width and height sizes', function () {
expect(request[0].url).to.include('w=300');
expect(request[0].url).to.include('h=250');
expect(request[0].url).to.not.include('w=200');
expect(request[0].url).to.not.include('h=100');
expect(request[1].url).to.include('w=400');
expect(request[1].url).to.include('h=225');
expect('' + request[0].data.w).to.equal('300');
expect('' + request[0].data.h).to.equal('250');
expect('' + request[0].data.w).to.not.equal('200');
expect('' + request[0].data.h).to.not.equal('100');
expect('' + request[1].data.w).to.equal('400');
expect('' + request[1].data.h).to.equal('225');
});

it('should send id and pid parameters', function () {
expect(request[0].url).to.include('id=123123');
expect(request[0].url).to.include('pid=123123');
expect(request[1].url).to.include('id=456456');
expect(request[1].url).to.include('pid=456456');
expect('' + request[0].data.id).to.equal('123123');
expect('' + request[0].data.pid).to.equal('123123');
expect('' + request[1].data.id).to.equal('456456');
expect('' + request[1].data.pid).to.equal('456456');
});
});

Expand Down Expand Up @@ -182,7 +183,8 @@ describe('vidoomyBidAdapter', function() {
'networkName': null,
'primaryCatId': 'IAB3-1',
'secondaryCatIds': null
}
},
'pixels': PIXELS
}
}

Expand All @@ -206,5 +208,22 @@ describe('vidoomyBidAdapter', function() {

expect(result[0].requestId).to.equal(serverResponseBanner.body.requestId);
});

it('should sync user cookies', function () {
const GDPR_CONSENT = 'GDPR_TEST'
const result = spec.getUserSyncs({
pixelEnabled: true
}, [serverResponseBanner], { consentString: GDPR_CONSENT, gdprApplies: 1 }, null)
expect(result).to.eql([
{
type: 'image',
url: PIXELS[0]
},
{
type: 'image',
url: `/test2.png?gdpr=1&gdpr_consent=${GDPR_CONSENT}`
}
])
});
});
});

0 comments on commit e14b009

Please sign in to comment.