Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adnuntias Bid Adapter: Added GDPR support and segment passing #6796

Merged
merged 8 commits into from
Jun 3, 2021
32 changes: 28 additions & 4 deletions modules/adnuntiusBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,62 @@
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER } from '../src/mediaTypes.js';
import * as utils from '../src/utils.js';
import { config } from '../src/config.js';

const BIDDER_CODE = 'adnuntius';
const ENDPOINT_URL = 'https://delivery.adnuntius.com/i?tzo=';
const GVLID = 855;

const getSegmentsFromOrtb = function (ortb2) {
const userData = utils.deepAccess(ortb2, 'user.data');
let segments;
if (userData) {
userData.forEach(userdat => {
segments = (userdat.segment) ? userdat.segment.map(segment => segment.id) : undefined
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mikael-lundin thanks for updating. Do you only want to pass those segments defined with the name 'adnuntius'? Currently there is no filter setup for this here, meaning that if any segment data defined after this type will overwrite the data I believe you are intended to leverage. i.e. if the below is defined in the config, you will only receive the segment 3 and not 1 and 2.

ortb2: {
    user: {							
        data: [{								
            name: "adnuntius",								
            segment: [	{ id: "1" },	{ id: "2" }	]							
        },{								
            name: "other",								
            segment: [	{ id: "3" }]							
        }]						
    }					
}

I would suggest either setting a filter for the name so you only match on those segments like:

userData.filter(data => data.name === 'adnuntius').forEach(userdat => {...});

Or if you want to collect all segment data, I would suggest something along the lines of this seeing as you check for segment length and then you can also remove the first two parts of the condition since segments will always be an array:

let segments = [];
  if (userData) {
    userData.forEach(userdat => {
      if (userdat.segment) segments.push(...userdat.segment.map(segment => segment.id));
    });
  }

A bunch of ways you can do this, but I wanted to make sure that this is corrected so you receive the data you are expecting. Also, I may suggest adding a filter prior to the segment map function to ensure the index of the array contains a property called id - the reason being is that this data structure is fairly new and if a pub were to create it using an array like ['1234','5678'] instead of [{id: '1234'}, {id:'5678'}] you will receive empty comma separated values. Could be something as simple as the following I think would work:

userdat.segment.filter(seg => seg.id).map(...);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for that, you kind of saved my ass a bit! :D I've added some changes to it so that it works more as you say, and for now we will just pass all the segments that we see to the adserver.

});
}
return segments
}

export const spec = {
code: BIDDER_CODE,

gvlid: GVLID,
supportedMediaTypes: [BANNER],
isBidRequestValid: function (bid) {
return !!(bid.bidId || (bid.params.member && bid.params.invCode));
},

buildRequests: function (validBidRequests) {
buildRequests: function (validBidRequests, bidderRequest) {
const networks = {};
const bidRequests = {};
const requests = [];
const ortb2 = config.getConfig('ortb2');
const segments = getSegmentsFromOrtb(ortb2);
const tzo = new Date().getTimezoneOffset();
const gdprApplies = utils.deepAccess(bidderRequest, 'gdprConsent.gdprApplies');
const consentString = utils.deepAccess(bidderRequest, 'gdprConsent.consentString');
const reqConsent = (gdprApplies !== undefined) ? '&consentString=' + consentString : '';
const reqSegments = (segments !== undefined && utils.isArray(segments) && segments.length > 0) ? '&segments=' + segments.join(',') : '';

for (var i = 0; i < validBidRequests.length; i++) {
const bid = validBidRequests[i]
const network = bid.params.network || 'network';
const targeting = bid.params.targeting || {};

bidRequests[network] = bidRequests[network] || [];
bidRequests[network].push(bid);

networks[network] = networks[network] || {};
networks[network].adUnits = networks[network].adUnits || [];
networks[network].adUnits.push({ ...bid.params.targeting, auId: bid.params.auId, targetId: bid.bidId });
networks[network].adUnits.push({ ...targeting, auId: bid.params.auId, targetId: bid.bidId });
}

const networkKeys = Object.keys(networks)
for (var j = 0; j < networkKeys.length; j++) {
const network = networkKeys[j];
requests.push({
method: 'POST',
url: ENDPOINT_URL + tzo + '&format=json',
url: ENDPOINT_URL + tzo + '&format=json' + reqSegments + reqConsent,
data: JSON.stringify(networks[network]),
bid: bidRequests[network]
});
Expand Down
33 changes: 33 additions & 0 deletions test/spec/modules/adnuntiusBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@
import { expect } from 'chai'; // may prefer 'assert' in place of 'expect'
import { spec } from 'modules/adnuntiusBidAdapter.js';
import { newBidder } from 'src/adapters/bidderFactory.js';
import { config } from 'src/config.js';

describe('adnuntiusBidAdapter', function () {
beforeEach(function () {
config.setConfig({ segments: [] });
});
const tzo = new Date().getTimezoneOffset();
const ENDPOINT_URL = `https://delivery.adnuntius.com/i?tzo=${tzo}&format=json`;
// const ENDPOINT_URL_SEGMENTS = `https://delivery.adnuntius.com/i?tzo=${tzo}&format=json&segments=segment1,segment2`;
const ENDPOINT_URL_SEGMENTS = `https://delivery.adnuntius.com/i?tzo=${tzo}&format=json`;
const ENDPOINT_URL_CONSENT = `https://delivery.adnuntius.com/i?tzo=${tzo}&format=json&consentString=consentString`;
const adapter = newBidder(spec);

const bidRequests = [
Expand Down Expand Up @@ -116,6 +123,32 @@ describe('adnuntiusBidAdapter', function () {
expect(request[0]).to.have.property('data');
expect(request[0].data).to.equal('{\"adUnits\":[{\"auId\":\"8b6bc\",\"targetId\":\"123\"}]}');
});

it('should pass segments if available in config', function () {
config.setConfig({
segments: ['segment1', 'segment2']
});
const request = spec.buildRequests(bidRequests);
expect(request.length).to.equal(1);
expect(request[0]).to.have.property('url')
expect(request[0].url).to.equal(ENDPOINT_URL_SEGMENTS);
});
});

describe('user privacy', function () {
it('should send GDPR Consent data if gdprApplies', function () {
let request = spec.buildRequests(bidRequests, { gdprConsent: { gdprApplies: true, consentString: 'consentString' } });
expect(request.length).to.equal(1);
expect(request[0]).to.have.property('url')
expect(request[0].url).to.equal(ENDPOINT_URL_CONSENT);
});

it('should not send GDPR Consent data if gdprApplies equals undefined', function () {
let request = spec.buildRequests(bidRequests, { gdprConsent: { gdprApplies: undefined, consentString: 'consentString' } });
expect(request.length).to.equal(1);
expect(request[0]).to.have.property('url')
expect(request[0].url).to.equal(ENDPOINT_URL);
});
});

describe('interpretResponse', function () {
Expand Down