Skip to content

Commit

Permalink
Nexx360 Bid Adapter: add new bid adapter (#8026)
Browse files Browse the repository at this point in the history
* nexx360 added

* Update nexx360BidAdapter.js

UserEids integrated

* Update nexx360BidAdapter.js

Indent fix
  • Loading branch information
gchicoye authored Feb 11, 2022
1 parent 76b9ea4 commit 57d4b88
Show file tree
Hide file tree
Showing 3 changed files with 324 additions and 0 deletions.
149 changes: 149 additions & 0 deletions modules/nexx360BidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import {ajax} from '../src/ajax.js';
import {config} from '../src/config.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {BANNER} from '../src/mediaTypes.js';

const BIDDER_CODE = 'nexx360';
const BIDDER_URL = 'https://fast.nexx360.io/prebid'
const CACHE_URL = 'https://fast.nexx360.io/cache'
const METRICS_TRACKER_URL = 'https://fast.nexx360.io/track-imp'

export const spec = {
code: BIDDER_CODE,
aliases: ['revenuemaker'], // short code
supportedMediaTypes: [BANNER],
/**
* Determines whether or not the given bid request is valid.
*
* @param {BidRequest} bid The bid params to validate.
* @return boolean True if this is a valid bid, and false otherwise.
*/
isBidRequestValid: function(bid) {
return !!(bid.params.account && bid.params.tagId);
},
/**
* Make a server request from the list of BidRequests.
*
* @param {validBidRequests[]} - an array of bids
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function(validBidRequests, bidderRequest) {
const adUnits = [];
const test = config.getConfig('debug') ? 1 : 0;
let adunitValue = null;
let userEids = null;
Object.keys(validBidRequests).forEach(key => {
adunitValue = validBidRequests[key];
adUnits.push({
account: adunitValue.params.account,
tagId: adunitValue.params.tagId,
label: adunitValue.adUnitCode,
bidId: adunitValue.bidId,
auctionId: adunitValue.auctionId,
transactionId: adunitValue.transactionId,
mediatypes: adunitValue.mediaTypes
});
if (adunitValue.userIdAsEids) userEids = adunitValue.userIdAsEids;
});
const payload = {
adUnits,
href: encodeURIComponent(bidderRequest.refererInfo.referer)
};
if (bidderRequest) { // modules informations (gdpr, ccpa, schain, userId)
if (bidderRequest.gdprConsent) {
payload.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0;
payload.gdprConsent = bidderRequest.gdprConsent.consentString;
} else {
payload.gdpr = 0;
payload.gdprConsent = '';
}
if (bidderRequest.uspConsent) { payload.uspConsent = bidderRequest.uspConsent; }
if (bidderRequest.schain) { payload.schain = bidderRequest.schain; }
if (userEids !== null) payload.userEids = userEids;
};
if (test) payload.test = 1;
const payloadString = JSON.stringify(payload);
return {
method: 'POST',
url: BIDDER_URL,
data: payloadString,
};
},
/**
* Unpack the response from the server into a list of bids.
*
* @param {ServerResponse} serverResponse A successful response from the server.
* @return {Bid[]} An array of bids which were nested inside the server.
*/
interpretResponse: function(serverResponse, bidRequest) {
const serverBody = serverResponse.body;
// const headerValue = serverResponse.headers.get('some-response-header');
const bidResponses = [];
let bidResponse = null;
let value = null;
if (serverBody.hasOwnProperty('responses')) {
Object.keys(serverBody['responses']).forEach(key => {
value = serverBody['responses'][key];
bidResponse = {
requestId: value['bidId'],
cpm: value['cpm'],
currency: value['currency'],
width: value['width'],
height: value['height'],
adUrl: `${CACHE_URL}?uuid=${value['uuid']}`,
ttl: value['ttl'],
creativeId: value['creativeId'],
netRevenue: true,
nexx360: {
'ssp': value['bidder'],
'consent': value['consent'],
'tagId': value['tagId']
},
/*
meta: {
'advertiserDomains': value['adomain']
}
*/
};
bidResponses.push(bidResponse);
});
}
return bidResponses;
},

/**
* Register the user sync pixels which should be dropped after the auction.
*
* @param {SyncOptions} syncOptions Which user syncs are allowed?
* @param {ServerResponse[]} serverResponses List of server's responses.
* @return {UserSync[]} The user syncs which should be dropped.
*/
getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {
if (typeof serverResponses === 'object' && serverResponses != null && serverResponses.length > 0 && serverResponses[0].hasOwnProperty('body') &&
serverResponses[0].body.hasOwnProperty('cookies') && typeof serverResponses[0].body.cookies === 'object') {
return serverResponses[0].body.cookies.slice(0, 5);
} else {
return [];
}
},

/**
* Register bidder specific code, which will execute if a bid from this bidder won the auction
* @param {Bid} The bid that won the auction
*/
onBidWon: function(bid) {
// fires a pixel to confirm a winning bid
const params = { type: 'prebid' };
if (bid.hasOwnProperty('nexx360')) {
if (bid.nexx360.hasOwnProperty('ssp')) params.ssp = bid.nexx360.ssp;
if (bid.nexx360.hasOwnProperty('tagId')) params.tag_id = bid.nexx360.tagId;
if (bid.nexx360.hasOwnProperty('consent')) params.consent = bid.nexx360.consent;
};
params.price = bid.cpm;
const url = `${METRICS_TRACKER_URL}?${new URLSearchParams(params).toString()}`;
ajax(url, null, undefined, {method: 'GET', withCredentials: true});
return true;
}

}
registerBidder(spec);
35 changes: 35 additions & 0 deletions modules/nexx360BidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Overview

```
Module Name: Nexx360 Bid Adapter
Module Type: Bidder Adapter
Maintainer: gabriel@nexx360.io
```

# Description

Connects to Nexx360 network for bids.

Nexx360 bid adapter supports Banner only for the time being.

# Test Parameters
```
var adUnits = [
// Banner adUnit
{
code: 'banner-div',
mediaTypes: {
banner: {
sizes: [[300, 250], [300,600]]
}
},
bids: [{
bidder: 'nexx360',
params: {
account: '1067',
tagId: 'luvxjvgn'
}
}]
},
];
```
140 changes: 140 additions & 0 deletions test/spec/modules/nexx360BidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import {expect} from 'chai';
import {spec} from 'modules/nexx360BidAdapter.js';
import {newBidder} from 'src/adapters/bidderFactory.js';
import {config} from 'src/config.js';
import * as utils from 'src/utils.js';
import { requestBidsHook } from 'modules/consentManagement.js';

describe('Nexx360 bid adapter tests', function () {
var DEFAULT_PARAMS = [{
adUnitCode: 'banner-div',
bidId: 'aaaa1234',
auctionId: 'bbbb1234',
transactionId: 'cccc1234',
mediaTypes: {
banner: {
sizes: [
[300, 250]
]
}
},
bidder: 'nexx360',
params: {
account: '1067',
tagId: 'luvxjvgn'
},
}];

var BID_RESPONSE = {'body': {
'responses': [
{
'bidId': '49a705a42610a',
'cpm': 0.437245,
'width': 300,
'height': 250,
'creativeId': '98493581',
'currency': 'EUR',
'netRevenue': true,
'ttl': 360,
'uuid': 'ce6d1ee3-2a05-4d7c-b97a-9e62097798ec',
'bidder': 'appnexus',
'consent': 1,
'tagId': 'luvxjvgn'
}
],
}};

const DEFAULT_OPTIONS = {
gdprConsent: {
gdprApplies: true,
consentString: 'BOzZdA0OzZdA0AGABBENDJ-AAAAvh7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__79__3z3_9pxP78k89r7337Mw_v-_v-b7JCPN_Y3v-8Kg',
vendorData: {}
},
refererInfo: {
referer: 'https://www.prebid.org',
canonicalUrl: 'https://www.prebid.org/the/link/to/the/page'
},
uspConsent: '111222333',
userId: { 'id5id': { uid: '1111' } },
schain: {
'ver': '1.0',
'complete': 1,
'nodes': [{
'asi': 'exchange1.com',
'sid': '1234',
'hp': 1,
'rid': 'bid-request-1',
'name': 'publisher',
'domain': 'publisher.com'
}]
},
};
it('Verify build request', function () {
const request = spec.buildRequests(DEFAULT_PARAMS, DEFAULT_OPTIONS);
expect(request).to.have.property('url').and.to.equal('https://fast.nexx360.io/prebid');
expect(request).to.have.property('method').and.to.equal('POST');
const requestContent = JSON.parse(request.data);
expect(requestContent.adUnits[0]).to.have.property('account').and.to.equal('1067');
expect(requestContent.adUnits[0]).to.have.property('tagId').and.to.equal('luvxjvgn');
expect(requestContent.adUnits[0]).to.have.property('label').and.to.equal('banner-div');
expect(requestContent.adUnits[0]).to.have.property('bidId').and.to.equal('aaaa1234');
expect(requestContent.adUnits[0]).to.have.property('auctionId').and.to.equal('bbbb1234');
expect(requestContent.adUnits[0]).to.have.property('mediatypes').exist;
});

it('Verify parse response', function () {
const request = spec.buildRequests(DEFAULT_PARAMS, DEFAULT_OPTIONS);
const response = spec.interpretResponse(BID_RESPONSE, request);
expect(response).to.have.lengthOf(1);
const bid = response[0];
expect(bid.cpm).to.equal(0.437245);
expect(bid.adUrl).to.equal('https://fast.nexx360.io/cache?uuid=ce6d1ee3-2a05-4d7c-b97a-9e62097798ec');
expect(bid.width).to.equal(300);
expect(bid.height).to.equal(250);
expect(bid.creativeId).to.equal('98493581');
expect(bid.currency).to.equal('EUR');
expect(bid.netRevenue).to.equal(true);
expect(bid.ttl).to.equal(360);
expect(bid.requestId).to.equal('49a705a42610a');
expect(bid.nexx360).to.exist;
expect(bid.nexx360.ssp).to.equal('appnexus');
});
it('Verifies bidder code', function () {
expect(spec.code).to.equal('nexx360');
});

it('Verifies bidder aliases', function () {
expect(spec.aliases).to.have.lengthOf(1);
expect(spec.aliases[0]).to.equal('revenuemaker');
});
it('Verifies if bid request valid', function () {
expect(spec.isBidRequestValid(DEFAULT_PARAMS[0])).to.equal(true);
});
it('Verifies bid won', function () {
const request = spec.buildRequests(DEFAULT_PARAMS, DEFAULT_OPTIONS);
const response = spec.interpretResponse(BID_RESPONSE, request);
const won = spec.onBidWon(response[0]);
expect(won).to.equal(true);
});
it('Verifies user sync without cookie in bid response', function () {
var syncs = spec.getUserSyncs({}, [BID_RESPONSE], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent);
expect(syncs).to.have.lengthOf(0);
});
it('Verifies user sync with cookies in bid response', function () {
BID_RESPONSE.body.cookies = [{'type': 'image', 'url': 'http://www.cookie.sync.org/'}];
var syncs = spec.getUserSyncs({}, [BID_RESPONSE], DEFAULT_OPTIONS.gdprConsent);
expect(syncs).to.have.lengthOf(1);
expect(syncs[0]).to.have.property('type').and.to.equal('image');
expect(syncs[0]).to.have.property('url').and.to.equal('http://www.cookie.sync.org/');
});
it('Verifies user sync with no bid response', function() {
var syncs = spec.getUserSyncs({}, null, DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent);
expect(syncs).to.have.lengthOf(0);
});
it('Verifies user sync with no bid body response', function() {
var syncs = spec.getUserSyncs({}, [], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent);
expect(syncs).to.have.lengthOf(0);
var syncs = spec.getUserSyncs({}, [{}], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent);
expect(syncs).to.have.lengthOf(0);
});
});

0 comments on commit 57d4b88

Please sign in to comment.