Skip to content

Commit

Permalink
My6sense new adapter (#2748)
Browse files Browse the repository at this point in the history
* My6sense new adapter

* endpoint fix

* Code fix

* Added changes in adapter md file

* Changed the end point

* supportedMediaTypes values added

* md file was updated with a valid widget key
  • Loading branch information
my6sense authored and mike-chowla committed Jul 10, 2018
1 parent df3e346 commit 8010d07
Show file tree
Hide file tree
Showing 3 changed files with 384 additions and 0 deletions.
197 changes: 197 additions & 0 deletions modules/my6senseBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import { BANNER, NATIVE } from 'src/mediaTypes';

const {registerBidder} = require('../src/adapters/bidderFactory');
const BIDDER_CODE = 'my6sense';
const END_POINT = '//papi.mynativeplatform.com/pub2/web/v1.15.0/hbwidget.json';
const END_POINT_METHOD = 'POST';

// called first
function isBidRequestValid(bid) {
return !(bid.bidder !== BIDDER_CODE || !bid.params || !bid.params.key);
}

function getUrl(url) {
if (!url) {
url = window.location.href;// "clean" url of current web page
}
var canonicalLink = null;
// first look for meta data with property "og:url"
var metaElements = document.getElementsByTagName('meta');
for (var i = 0; i < metaElements.length && !canonicalLink; i++) {
if (metaElements[i].getAttribute('property') == 'og:url') {
canonicalLink = metaElements[i].content;
}
}
if (!canonicalLink) {
var canonicalLinkContainer = document.querySelector("link[rel='canonical']");// html element containing the canonical link
if (canonicalLinkContainer) {
// get clean url from href of <link rel='canocial' .../>
canonicalLink = canonicalLinkContainer.href;
}
}
url = canonicalLink || url;
return encodeURIComponent(url).toString();
}

/**
* this function is used to fix param value before sending them to server, if user did not set it,
* default value for parameter will be returned
* example1: paidClicks: '[PAID_TRACKING_PIXEL]', will return {value: '', fromUser: false}
* example2: pageURL: 'www.my6sense.com', will return {value: 'www.my6sense.com', fromUser: true}
* @param key
* @param value
* @returns {{value: *, fromUser: boolean}}
*/
function fixRequestParamForServer(key, value) {
function isEmptyValue(key, value) {
return value === parametersMap[key].emptyValue;
}

const parametersMap = {
'pageUrl': {
emptyValue: '[PAGE_URL]',
defaultValue: getUrl()
},
'displayWithinIframe': {
emptyValue: '',
defaultValue: ''
},
'dataParams': {
emptyValue: '[KEY_VALUES]',
defaultValue: ''
},
'paidClicks': {
emptyValue: '[PAID_TRACKING_PIXEL]',
defaultValue: ''
},
'organicClicks': {
emptyValue: '[ORGANIC_TRACKING_PIXEL]',
defaultValue: ''
},
'dataView': {
emptyValue: '[VIEW_TRACKING_PIXEL]',
defaultValue: ''
},
// ZONE is not part of this object, handled on server side
};

// if param is not in list we do not change it (return it as is)
if (!parametersMap.hasOwnProperty(key)) {
return {
value: value,
fromUser: true
};
}

// if no value given by user set it to default
if (!value || isEmptyValue(key, value)) {
return {
value: parametersMap[key].defaultValue,
fromUser: false
};
}

return {
value: value,
fromUser: true
};
}

// called second

function buildGdprServerProperty(bidderRequest) {
var gdprObj = {
gdpr_consent: null,
gdpr: null
};

if (bidderRequest && 'gdprConsent' in bidderRequest) {
gdprObj.gdpr_consent = bidderRequest.gdprConsent.consentString || null;

gdprObj.gdpr = gdprObj.gdpr === null && bidderRequest.gdprConsent.gdprApplies == true ? true : gdprObj.gdpr;
gdprObj.gdpr = gdprObj.gdpr === null && bidderRequest.gdprConsent.gdprApplies == false ? false : gdprObj.gdpr;
gdprObj.gdpr = gdprObj.gdpr === null && bidderRequest.gdprConsent.gdprApplies == 1 ? true : gdprObj.gdpr;
gdprObj.gdpr = gdprObj.gdpr === null && bidderRequest.gdprConsent.gdprApplies == 0 ? false : gdprObj.gdpr;
}

return gdprObj;
}

function buildRequests(validBidRequests, bidderRequest) {
let requests = [];

if (validBidRequests && validBidRequests.length) {
validBidRequests.forEach(bidRequest => {
bidRequest.widget_num = 1; // mandatory property for server side
let isDataUrlSetByUser = false;
let debug = false;

if (bidRequest.params) {
for (let key in bidRequest.params) {
// loop over params and remove empty/untouched values
if (bidRequest.params.hasOwnProperty(key)) {
// if debug we update url string to get core debug version
if (key === 'debug' && bidRequest.params[key] === true) {
debug = true;
delete bidRequest.params[key];
continue;
}

let fixedObj = fixRequestParamForServer(key, bidRequest.params[key]);
bidRequest.params[key] = fixedObj.value;

// if pageUrl is set by user we should update variable for query string param
if (key === 'pageUrl' && fixedObj.fromUser === true) {
isDataUrlSetByUser = true;
}

// remove empty params from request
if (!bidRequest.params[key]) {
delete bidRequest.params[key];
}
}
}
}

let url = `${END_POINT}?widget_key=${bidRequest.params.key}&is_data_url_set=${isDataUrlSetByUser}`; // mandatory query string for server side
if (debug) {
url = `${END_POINT}?env=debug&widget_key=${bidRequest.params.key}&is_data_url_set=${isDataUrlSetByUser}`; // this url is for debugging
}

bidRequest.gdpr = buildGdprServerProperty(bidderRequest);

requests.push({
url: url,
method: END_POINT_METHOD,
data: JSON.stringify(bidRequest)
});
});
}

return requests;
}

// called third

function interpretResponse(serverResponse) {
const bidResponses = [];
// currently server returns a single response which is the body property
if (serverResponse.body) {
serverResponse.body.bidderCode = BIDDER_CODE;
bidResponses.push(serverResponse.body);
}

return bidResponses;
}

const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER, NATIVE],
isBidRequestValid,
buildRequests,
interpretResponse
};

registerBidder(spec);

module.exports = spec;
36 changes: 36 additions & 0 deletions modules/my6senseBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# HeaderBiddingAdapter

# Overview

```
Module Name: my6sense Bidder Adapter
Module Type: Bidder Adapter
```

# Description

Module that connects to my6sense demand sources.
Banner formats are supported.

# Test Parameters
```
var adUnits = [
// {
//
// sizes: [[1000, 600]],
// bids: [{
// bidder: 'my6sense',
// params: {
// key: 'OAJJBW2LRYi2CxfhzqogkA',
// pageUrl: '[PAGE_URL]',
// zone: '[ZONE]',
// dataView: ''
// organicClicks:'',
// paidClicks:'',
// }
// }]
// }
];
```
151 changes: 151 additions & 0 deletions test/spec/modules/my6senseBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { expect } from 'chai';
import spec from 'modules/my6senseBidAdapter';

describe('My6sense Bid adapter test', () => {
let bidRequests, serverResponses;
beforeEach(() => {
bidRequests = [
{
// valid 1
bidder: 'my6sense',
params: {
key: 'DTAeOJN67pCjY36dbhrM3G',
dataVersion: 3,
pageUrl: 'liran.com',
zone: '[ZONE]',
dataParams: '',
dataView: '',
organicClicks: '',
paidClicks: ''
}
},
{
// invalid 2- no params
bidder: 'my6sense'
},
{
// invalid 3 - no key in params
bidder: 'my6sense',
params: {
dataVersion: 3,
pageUrl: 'liran.com',
zone: '[ZONE]',
dataParams: '',
dataView: '',
organicClicks: '',
paidClicks: ''
}
},
{
// invalid 3 - wrong bidder name
bidder: 'test',
params: {
key: 'ZxA0bNhlO9tf5EZ1Q9ZYdS',
dataVersion: 3,
pageUrl: 'liran.com',
zone: '[ZONE]',
dataParams: '',
dataView: '',
organicClicks: '',
paidClicks: ''
}
}
];
serverResponses = [
{
headers: {},
body: {
cpm: 1.5,
width: 300,
height: 250,
placement_id: 1,
adm: '<script type="text/javascript" language="JavaScript">\r\n<!--\r\n\r\n//-->\r\n</script>'
}
},
{
headers: {},
body: {
cpm: 0,
width: 0,
height: 0,
placement_id: 1,
adm: '<script type="text/javascript" language="JavaScript">\r\n<!--\r\n\r\n//-->\r\n</script>'
}
},
{
headers: {},
body: {
cpm: 0,
width: 0,
height: 0,
placement_id: 0,
adm: ''
}
},
{
headers: {},
body: {
cpm: 5,
creativeId: '5b29f5d1e4b086e3ee8de36b',
currency: 'USD',
height: 250,
netRevenue: false,
requestId: '2954a0957643bb',
ttl: 360,
width: 300,
adm: '<script type="text/javascript" language="JavaScript">\r\n<!--\r\n\r\n//-->\r\n</script>'
}
}
]
});

describe('test if requestIsValid function', () => {
it('with valid data 1', () => {
expect(spec.isBidRequestValid(bidRequests[0])).to.equal(true);
});
it('with invalid data 2', () => {
expect(spec.isBidRequestValid(bidRequests[1])).to.equal(false);
});
it('with invalid data 3', () => {
expect(spec.isBidRequestValid(bidRequests[2])).to.equal(false);
});
it('with invalid data 3', () => {
expect(spec.isBidRequestValid(bidRequests[3])).to.equal(false);
});
});

describe('test if buildRequests function', () => {
it('normal', () => {
var requests = spec.buildRequests([bidRequests[0]]);
expect(requests).to.be.lengthOf(1);
});
});
describe('test bid responses', () => {
it('success 1', () => {
var bids = spec.interpretResponse(serverResponses[0], {'bidRequest': bidRequests[0]});
expect(bids).to.be.lengthOf(1);
expect(bids[0].cpm).to.equal(1.5);
expect(bids[0].width).to.equal(300);
expect(bids[0].height).to.equal(250);
expect(bids[0].adm).to.have.length.above(1);
});
it('success 2', () => {
var bids = spec.interpretResponse(serverResponses[3]);
expect(bids).to.be.lengthOf(1);
expect(bids[0].cpm).to.equal(5);
expect(bids[0].width).to.equal(300);
expect(bids[0].height).to.equal(250);
expect(bids[0].netRevenue).to.equal(false);
expect(bids[0].ttl).to.equal(360);
expect(bids[0].currency).to.equal('USD');
});
it('fail 1 (cpm=0)', () => {
var bids = spec.interpretResponse(serverResponses[1]);
expect(bids).to.be.lengthOf(1);
});
it('fail 2 (no response)', () => {
var bids = spec.interpretResponse([]);
expect(bids).to.be.lengthOf(0);
});
});
});

0 comments on commit 8010d07

Please sign in to comment.