Skip to content

Commit

Permalink
Inskin Bid adapter small changes (#5373)
Browse files Browse the repository at this point in the history
* Add plr_AdSlot parameter needed by Inskin Pagescroll ad format

* Send additional TCF related information to Inskin's ad server

* Fixed linting issues.

* Added unit tests
  • Loading branch information
cciocov authored Jul 5, 2020
1 parent 1c8a275 commit 76e680e
Show file tree
Hide file tree
Showing 2 changed files with 214 additions and 0 deletions.
129 changes: 129 additions & 0 deletions modules/inskinBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,43 @@ export const spec = {
parallel: true
}, validBidRequests[0].params);

data.keywords = data.keywords || [];
const restrictions = [];

if (bidderRequest && bidderRequest.gdprConsent) {
data.consent = {
gdprVendorId: 150,
gdprConsentString: bidderRequest.gdprConsent.consentString,
// will check if the gdprApplies field was populated with a boolean value (ie from page config). If it's undefined, then default to true
gdprConsentRequired: (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true
};

if (bidderRequest.gdprConsent.apiVersion === 2) {
const purposes = [
{id: 1, kw: 'nocookies'},
{id: 2, kw: 'nocontext'},
{id: 3, kw: 'nodmp'},
{id: 4, kw: 'nodata'},
{id: 7, kw: 'noclicks'},
{id: 9, kw: 'noresearch'}
];

const d = bidderRequest.gdprConsent.vendorData;

if (d) {
if (d.purposeOneTreatment) {
data.keywords.push('cst-nodisclosure');
restrictions.push('nodisclosure');
}

purposes.map(p => {
if (!checkConsent(p.id, d)) {
data.keywords.push('cst-' + p.kw);
restrictions.push(p.kw);
}
});
}
}
}

validBidRequests.map(bid => {
Expand All @@ -78,6 +108,11 @@ export const spec = {

placement.adTypes.push(5, 9, 163, 2163, 3006);

if (restrictions.length) {
placement.properties = placement.properties || {};
placement.properties.restrictions = restrictions;
}

if (placement.networkId && placement.siteId) {
data.placements.push(placement);
}
Expand Down Expand Up @@ -153,6 +188,7 @@ export const spec = {

const id = 'ism_tag_' + Math.floor((Math.random() * 10e16));
window[id] = {
plr_AdSlot: e.source.frameElement,
bidId: e.data.bidId,
bidPrice: bidsMap[e.data.bidId].price,
serverResponse
Expand Down Expand Up @@ -242,4 +278,97 @@ function retrieveAd(bidId, decision) {
return "<script>window.top.postMessage({from: 'ism-bid', bidId: '" + bidId + "'}, '*');\x3c/script>" + utils.createTrackPixelHtml(decision.impressionUrl);
}

function checkConsent(P, d) {
const GVL = {'150': {'id': 150, 'name': 'Inskin Media LTD', 'purposes': {'1': 1, '3': 3, '4': 4, '9': 9, '10': 10}, 'legIntPurposes': {'2': 2, '7': 7}, 'flexiblePurposes': {'2': 2, '7': 7}, 'specialPurposes': {'1': 1, '2': 2}, 'features': {'3': 3}, 'specialFeatures': {}, 'policyUrl': 'http://www.inskinmedia.com/privacy-policy.html'}};
const V = 150;

// vendor claims (inflexible) consent as their basis, publisher doesn't
// restrict the purpose, user consents to the purpose and user consents
// to the vendor
try {
if (
GVL[V].purposes[P] && !GVL[V].flexiblePurposes[P] &&
d.purpose.consents[P] &&
d.vendor.consents[V]
) {
return true;
}
} catch (e) {}

// vendor claims (inflexible) legitimate interest as their basis,
// publisher doesn't restrict the purpose, user was provided notice of the
// legitimate interest basis for this purpose and user was provided notice
// for the LI basis for this vendor
try {
if (
GVL[V].legIntPurposes[P] && !GVL[V].flexiblePurposes[P] &&
d.purpose.legitimateInterests[P] &&
d.vendor.legitimateInterests[V]
) {
return true;
}
} catch (e) {}

// vendor claims flexible legal basis with legitimate interest as the
// default, publisher restriction doesn't require consent, and ((user was
// provided notice of the legitimate interest basis for this
// purpose + vendor) OR (user consents to purpose + vendor))
try {
if (
GVL[V].legIntPurposes[P] && GVL[V].flexiblePurposes[P] &&
(
(d.purpose.legitimateInterests[P] && d.vendor.legitimateInterests[V]) ||
(d.purpose.consents[P] && d.vendor.consents[V])
)
) {
return true;
}
} catch (e) {}

// vendor claims flexible legal basis with legitimate interest as the
// default, publisher restriction does require consent, and user consents
// to purpose + vendor
try {
if (
GVL[V].legIntPurposes[P] && GVL[V].flexiblePurposes[P] &&
d.purpose.consents[P] &&
d.vendor.consents[V]
) {
return true;
}
} catch (e) {}

// vendor claims flexible legal basis with consent as the default,
// publisher restriction doesn't require legitimate interest, and ((user
// was provided notice of the legitimate interest basis for this purpose +
// vendor) OR (user consents to purpose + vendor))
try {
if (
GVL[V].purposes[P] && GVL[V].flexiblePurposes[P] &&
(
(d.purpose.legitimateInterests[P] && d.vendor.legitimateInterests[V]) ||
(d.purpose.consents[P] && d.vendor.consents[V])
)
) {
return true;
}
} catch (e) {}

// vendor claims flexible legal basis with consent as the default,
// publisher restriction does require legitimate interest, and user was
// provided notice for the legitimate interest basis for this purpose +
// vendor
try {
if (
GVL[V].purposes[P] && GVL[V].flexiblePurposes[P] &&
d.purpose.legitimateInterests[P] &&
d.vendor.legitimateInterests[V]
) {
return true;
}
} catch (e) {}

return false;
}

registerBidder(spec);
85 changes: 85 additions & 0 deletions test/spec/modules/inskinBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,91 @@ describe('InSkin BidAdapter', function () {
expect(payload.consent.gdprConsentString).to.exist.and.to.equal(consentString);
expect(payload.consent.gdprConsentRequired).to.exist.and.to.be.true;
});

it('should not add keywords if TCF v2 purposes are granted', function () {
const bidderRequest2 = Object.assign({}, bidderRequest, {
gdprConsent: {
gdprApplies: true,
consentString: 'consentString',
vendorData: {
vendor: {
consents: {
150: true
}
},
purpose: {
consents: {
1: true,
2: true,
3: true,
4: true,
5: true,
6: true,
7: true,
8: true,
9: true,
10: true
}
}
},
apiVersion: 2
}
});

const request = spec.buildRequests(bidRequests, bidderRequest2);
const payload = JSON.parse(request.data);

expect(payload.keywords).to.be.an('array').that.is.empty;
expect(payload.placements[0].properties).to.be.undefined;
});

it('should add keywords if TCF v2 purposes are not granted', function () {
const bidderRequest2 = Object.assign({}, bidderRequest, {
gdprConsent: {
gdprApplies: true,
consentString: 'consentString',
vendorData: {
vendor: {
consents: {
150: false
}
},
purpose: {
consents: {
1: true,
2: true,
3: true,
4: true,
5: true,
6: true,
7: true,
8: true,
9: true,
10: true
}
}
},
apiVersion: 2
}
});

const request = spec.buildRequests(bidRequests, bidderRequest2);
const payload = JSON.parse(request.data);

expect(payload.keywords).to.be.an('array').that.includes('cst-nocookies');
expect(payload.keywords).to.be.an('array').that.includes('cst-nocontext');
expect(payload.keywords).to.be.an('array').that.includes('cst-nodmp');
expect(payload.keywords).to.be.an('array').that.includes('cst-nodata');
expect(payload.keywords).to.be.an('array').that.includes('cst-noclicks');
expect(payload.keywords).to.be.an('array').that.includes('cst-noresearch');

expect(payload.placements[0].properties.restrictions).to.be.an('array').that.includes('nocookies');
expect(payload.placements[0].properties.restrictions).to.be.an('array').that.includes('nocontext');
expect(payload.placements[0].properties.restrictions).to.be.an('array').that.includes('nodmp');
expect(payload.placements[0].properties.restrictions).to.be.an('array').that.includes('nodata');
expect(payload.placements[0].properties.restrictions).to.be.an('array').that.includes('noclicks');
expect(payload.placements[0].properties.restrictions).to.be.an('array').that.includes('noresearch');
});
});
describe('interpretResponse validation', function () {
it('response should have valid bidderCode', function () {
Expand Down

0 comments on commit 76e680e

Please sign in to comment.