Skip to content

Commit

Permalink
new bidder adapter: mediasquareBidAdapter (#5317)
Browse files Browse the repository at this point in the history
* add adapter mediasquare

* Update mediasquareBidAdapter.md

* Update mediasquareBidAdapter.js

* test-coverage

* Update mediasquareBidAdapter.js

* Update mediasquareBidAdapter_spec.js

* Update mediasquareBidAdapter_spec.js

* Update mediasquareBidAdapter_spec.js

* Object.values unsupported by IE11
  • Loading branch information
matthieularere-msq authored Jun 8, 2020
1 parent bdaa411 commit 461fea9
Show file tree
Hide file tree
Showing 3 changed files with 313 additions and 0 deletions.
155 changes: 155 additions & 0 deletions modules/mediasquareBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
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 = 'mediasquare';
const BIDDER_URL_PROD = 'https://pbs-front.mediasquare.fr/'
const BIDDER_URL_TEST = 'https://bidder-test.mediasquare.fr/'
const BIDDER_ENDPOINT_AUCTION = 'msq_prebid';
const BIDDER_ENDPOINT_SYNC = 'cookie_sync';
const BIDDER_ENDPOINT_WINNING = 'winning';

export const spec = {
code: BIDDER_CODE,
aliases: ['msq'], // 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.owner || bid.params.code);
},
/**
* 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) {
let codes = [];
let endpoint = document.location.search.match(/msq_test=true/) ? BIDDER_URL_TEST : BIDDER_URL_PROD;
const test = config.getConfig('debug') ? 1 : 0;
let adunitValue = null;
Object.keys(validBidRequests).forEach(key => {
adunitValue = validBidRequests[key];
codes.push({
owner: adunitValue.params.owner,
code: adunitValue.params.code,
adunit: adunitValue.adUnitCode,
bidId: adunitValue.bidId,
auctionId: adunitValue.auctionId,
transactionId: adunitValue.transactionId,
mediatypes: adunitValue.mediaTypes
});
});
const payload = {
codes: codes,
referer: encodeURIComponent(bidderRequest.refererInfo.referer)
// schain: validBidRequests.schain,
};
if (bidderRequest && bidderRequest.gdprConsent) {
payload.gdpr = {
consent_string: bidderRequest.gdprConsent.consentString,
consent_required: bidderRequest.gdprConsent.gdprApplies
};
};
if (test) { payload.debug = true; }
const payloadString = JSON.stringify(payload);
return {
method: 'POST',
url: endpoint + BIDDER_ENDPOINT_AUCTION,
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['bid_id'],
cpm: value['cpm'],
width: value['width'],
height: value['height'],
creativeId: value['creative_id'],
currency: value['currency'],
netRevenue: value['net_revenue'],
ttl: value['ttl'],
ad: value['ad'],
mediasquare: {
'bidder': value['bidder'],
'code': value['code']
}
};
if (value.hasOwnProperty('deal_id')) { bidResponse['dealId'] = value['deal_id']; }
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) {
let params = '';
let endpoint = document.location.search.match(/msq_test=true/) ? BIDDER_URL_TEST : BIDDER_URL_PROD;
if (gdprConsent && typeof gdprConsent.consentString === 'string') {
if (typeof gdprConsent.gdprApplies === 'boolean') { params += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; } else { params += `&gdpr_consent=${gdprConsent.consentString}`; }
}
if (syncOptions.iframeEnabled) {
return {
type: 'iframe',
url: endpoint + BIDDER_ENDPOINT_SYNC + '?type=iframe' + params
};
}
if (syncOptions.pixelEnabled) {
return {
type: 'image',
url: endpoint + BIDDER_ENDPOINT_SYNC + '?type=pixel' + params
};
}
return false;
},

/**
* 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
let params = [];
let endpoint = document.location.search.match(/msq_test=true/) ? BIDDER_URL_TEST : BIDDER_URL_PROD;
let paramsToSearchFor = ['cpm', 'size', 'mediaType', 'currency', 'creativeId', 'adUnitCode', 'timeToRespond']
if (bid.hasOwnProperty('mediasquare')) {
if (bid['mediasquare'].hasOwnProperty('bidder')) { params.push('bidder=' + bid['mediasquare']['bidder']); }
if (bid['mediasquare'].hasOwnProperty('code')) { params.push('code=' + bid['mediasquare']['code']); }
};
for (let i = 0; i < paramsToSearchFor.length; i++) {
if (bid.hasOwnProperty(paramsToSearchFor[i])) { params.push(paramsToSearchFor[i] + '=' + bid[paramsToSearchFor[i]]); }
}
if (params.length > 0) { params = '?' + params.join('&'); }
ajax(endpoint + BIDDER_ENDPOINT_WINNING + params, null);
return true;
}

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

```
Module Name: MediaSquare Bid Adapter
Module Type: Bidder Adapter
Maintainer: [email protected]
```

# Description

Connects to Mediasquare network for bids.

Mediasquare 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: 'mediasquare',
params: {
owner: "test",
code: "publishername_atf_desktop_rg_pave"
}
}]
},
];
```
123 changes: 123 additions & 0 deletions test/spec/modules/mediasquareBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import {expect} from 'chai';
import {spec} from 'modules/mediasquareBidAdapter.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('MediaSquare bid adapter tests', function () {
var DEFAULT_PARAMS = [{
adUnitCode: 'banner-div',
bidId: 'aaaa1234',
auctionId: 'bbbb1234',
transactionId: 'cccc1234',
mediaTypes: {
banner: {
sizes: [
[300, 250]
]
}
},
bidder: 'mediasquare',
params: {
owner: 'test',
code: 'publishername_atf_desktop_rg_pave'
},
}];

var BID_RESPONSE = {'body': {
'responses': [{
'transaction_id': 'cccc1234',
'cpm': 22.256608,
'width': 300,
'height': 250,
'creative_id': '158534630',
'currency': 'USD',
'net_revenue': true,
'ttl': 300,
'ad': '< --- creative code --- >',
'bidder': 'msqClassic',
'code': 'test/publishername_atf_desktop_rg_pave',
'bid_id': 'aaaa1234',
}]
}};

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'
}
};
it('Verify build request', function () {
const request = spec.buildRequests(DEFAULT_PARAMS, DEFAULT_OPTIONS);
expect(request).to.have.property('url').and.to.equal('https://pbs-front.mediasquare.fr/msq_prebid');
expect(request).to.have.property('method').and.to.equal('POST');
const requestContent = JSON.parse(request.data);
expect(requestContent.codes[0]).to.have.property('owner').and.to.equal('test');
expect(requestContent.codes[0]).to.have.property('code').and.to.equal('publishername_atf_desktop_rg_pave');
expect(requestContent.codes[0]).to.have.property('adunit').and.to.equal('banner-div');
expect(requestContent.codes[0]).to.have.property('bidId').and.to.equal('aaaa1234');
expect(requestContent.codes[0]).to.have.property('auctionId').and.to.equal('bbbb1234');
expect(requestContent.codes[0]).to.have.property('transactionId').and.to.equal('cccc1234');
expect(requestContent.codes[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(22.256608);
expect(bid.ad).to.equal('< --- creative code --- >');
expect(bid.width).to.equal(300);
expect(bid.height).to.equal(250);
expect(bid.creativeId).to.equal('158534630');
expect(bid.currency).to.equal('USD');
expect(bid.netRevenue).to.equal(true);
expect(bid.ttl).to.equal(300);
expect(bid.requestId).to.equal('aaaa1234');
expect(bid.mediasquare).to.exist;
expect(bid.mediasquare.bidder).to.equal('msqClassic');
expect(bid.mediasquare.code).to.equal([DEFAULT_PARAMS[0].params.owner, DEFAULT_PARAMS[0].params.code].join('/'));
});

it('Verifies bidder code', function () {
expect(spec.code).to.equal('mediasquare');
});

it('Verifies bidder aliases', function () {
expect(spec.aliases).to.have.lengthOf(1);
expect(spec.aliases[0]).to.equal('msq');
});
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', function () {
var syncs = spec.getUserSyncs({
iframeEnabled: true,
pixelEnabled: false,
}, [BID_RESPONSE], DEFAULT_OPTIONS.gdprConsent);
expect(syncs).to.have.property('type').and.to.equal('iframe');
syncs = spec.getUserSyncs({
iframeEnabled: false,
pixelEnabled: true,
}, [BID_RESPONSE], DEFAULT_OPTIONS.gdprConsent);
expect(syncs).to.have.property('type').and.to.equal('image');
syncs = spec.getUserSyncs({
iframeEnabled: false,
pixelEnabled: false,
}, [BID_RESPONSE], DEFAULT_OPTIONS.gdprConsent);
expect(syncs).to.equal(false);
});
});

0 comments on commit 461fea9

Please sign in to comment.