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

initial version of ozone adapter for review #3307

Merged
merged 5 commits into from
Dec 4, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 230 additions & 0 deletions modules/ozoneBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import * as utils from 'src/utils';
import { registerBidder } from 'src/adapters/bidderFactory';

const BIDDER_CODE = 'ozone';

var OZONEURI = 'https://elb.the-ozone-project.com/openrtb2/auction';
Copy link
Collaborator

Choose a reason for hiding this comment

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

Here const can be used. Also use let/const wherever applicable

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

var OZONECOOKIESYNC = 'https://elb.the-ozone-project.com/static/load-cookie.html';

export const spec = {
code: BIDDER_CODE,
supportedFormat: ['banner'],
Copy link
Collaborator

Choose a reason for hiding this comment

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

banner is default. No need to add supportedFormat if you only support banner

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

/**
* Basic check to see whether required parameters are in the request.
* @param bid
* @returns {boolean}
*/
isBidRequestValid(bid) {
if (!(bid.params.hasOwnProperty('placementId'))) {
console.log('OZONE BID ADAPTER VALIDATION FAILED : missing placementId : siteId, placementId and publisherId are REQUIRED');
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use utils.logInfo here and all other places where console.log is used

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

return false;
}
if (!(bid.params.placementId).toString().match(/^[0-9]{10}$/)) {
console.log('OZONE BID ADAPTER VALIDATION FAILED : placementId must be exactly 10 numeric characters');
return false;
}
if (!(bid.params.hasOwnProperty('publisherId'))) {
console.log('OZONE BID ADAPTER VALIDATION FAILED : missing publisherId : siteId, placementId and publisherId are REQUIRED');
return false;
}
if (!(bid.params.publisherId).toString().match(/^[a-zA-Z0-9\-]{12}$/)) {
console.log('OZONE BID ADAPTER VALIDATION FAILED : publisherId must be exactly 12 alphanumieric characters including hyphens');
return false;
}
if (!(bid.params.hasOwnProperty('siteId'))) {
console.log('OZONE BID ADAPTER VALIDATION FAILED : missing siteId : siteId, placementId and publisherId are REQUIRED');
return false;
}
if (!(bid.params.siteId).toString().match(/^[0-9]{10}$/)) {
console.log('OZONE BID ADAPTER VALIDATION FAILED : siteId must be exactly 10 numeric characters');
return false;
}
if (bid.params.hasOwnProperty('customData')) {
if (typeof bid.params.customData !== 'object') {
console.log('OZONE BID ADAPTER VALIDATION FAILED : customData is not an object');
return false;
}
}
if (bid.params.hasOwnProperty('customParams')) {
console.log('OZONE BID ADAPTER VALIDATION FAILED : customParams should be renamed to customData');
return false;
}
if (bid.params.hasOwnProperty('ozoneData')) {
if (typeof bid.params.ozoneData !== 'object') {
console.log('OZONE BID ADAPTER VALIDATION FAILED : ozoneData is not an object');
return false;
}
}
if (bid.params.hasOwnProperty('lotameData')) {
if (typeof bid.params.lotameData !== 'object') {
console.log('OZONE BID ADAPTER VALIDATION FAILED : lotameData is not an object');
return false;
}
}
return true;
},
/**
* @param serverResponse
* @param request
* @returns {*}
*/
interpretResponse(serverResponse, request) {
serverResponse = serverResponse.body || {};
if (serverResponse.seatbid) {
if (utils.isArray(serverResponse.seatbid)) {
const {seatbid: arrSeatbid} = serverResponse;
let winnerAds = arrSeatbid.reduce((bid, ads) => {
var _seat = ads.seat;
let ad = ads.bid.reduce(function(currentWinningBid, considerBid) {
if (currentWinningBid.price < considerBid.price) {
const bid = matchRequest(considerBid.impid, request);
const {width, height} = defaultSize(bid);
considerBid.cpm = considerBid.price;
considerBid.bidId = considerBid.impid;
considerBid.requestId = considerBid.impid;
considerBid.width = considerBid.w || width;
considerBid.height = considerBid.h || height;
considerBid.ad = considerBid.adm;
considerBid.netRevenue = true;
considerBid.creativeId = considerBid.crid;
considerBid.currency = 'USD';
considerBid.ttl = 60;
considerBid.seat = _seat;

return considerBid;
} else {
currentWinningBid.cpm = currentWinningBid.price;
return currentWinningBid;
}
}, {price: 0});
if (ad.adm) {
bid.push(ad)
}
return bid;
}, [])
let winnersClean = winnerAds.filter(w => {
if (w.bidId) {
return true;
}
return false;
});
console.log(['going to return winnersClean:', winnersClean]);
return winnersClean;
} else {
return [];
}
} else {
return [];
}
},
buildRequests(validBidRequests, bidderRequest) {
let ozoneRequest = validBidRequests[0].params;
ozoneRequest['id'] = utils.generateUUID();
ozoneRequest['auctionId'] = bidderRequest['auctionId'];

if (bidderRequest.hasOwnProperty('placementId')) {
bidderRequest.placementId = (bidderRequest.placementId).toString();
}
if (bidderRequest.hasOwnProperty('siteId')) {
bidderRequest.siteId = (bidderRequest.siteId).toString();
}
if (bidderRequest.hasOwnProperty('publisherId')) {
bidderRequest.publisherId = (bidderRequest.publisherId).toString();
}

if (!ozoneRequest.test) {
delete ozoneRequest.test;
}
if (bidderRequest.gdprConsent) {
ozoneRequest.regs = {};
ozoneRequest.regs.ext = {};
ozoneRequest.regs.ext.gdpr = bidderRequest.gdprConsent.gdprApplies === true ? 1 : 0;
if (ozoneRequest.regs.ext.gdpr) {
ozoneRequest.regs.ext.consent = bidderRequest.gdprConsent.consentString;
}
}
let tosendtags = validBidRequests.map(ozone => {
var obj = {};
obj.id = ozone.bidId;
obj.tagid = String(ozone.params.ozoneid);
obj.secure = window.location.protocol === 'https:' ? 1 : 0;
obj.banner = {
topframe: 1,
w: ozone.sizes[0][0] || 0,
h: ozone.sizes[0][1] || 0,
format: ozone.sizes.map(s => {
return {w: s[0], h: s[1]};
})
};
if (ozone.params.hasOwnProperty('customData')) {
obj.customData = ozone.params.customData;
}
if (ozone.params.hasOwnProperty('ozoneData')) {
obj.ozoneData = ozone.params.ozoneData;
}
if (ozone.params.hasOwnProperty('lotameData')) {
obj.lotameData = ozone.params.lotameData;
}
if (ozone.params.hasOwnProperty('publisherId')) {
obj.publisherId = (ozone.params.publisherId).toString();
}
if (ozone.params.hasOwnProperty('siteId')) {
obj.siteId = (ozone.params.siteId).toString();
}
obj.ext = {'prebid': {'storedrequest': {'id': (ozone.params.placementId).toString()}}};
return obj;
});
ozoneRequest.imp = tosendtags;
var ret = {
method: 'POST',
url: OZONEURI,
data: JSON.stringify(ozoneRequest),
bidderRequest: bidderRequest
};
console.log(['buildRequests going to return', ret]);
return ret;
},
getUserSyncs(optionsType) {
if (optionsType.iframeEnabled) {
return [{
type: 'iframe',
url: OZONECOOKIESYNC
}];
}
}
}

/**
* Function matchRequest(id: string, BidRequest: object)
* @param id
* @type string
* @param bidRequest
* @type Object
* @returns Object
*
*/
export function matchRequest(id, bidRequest) {
const {bids} = bidRequest.bidderRequest;
const [returnValue] = bids.filter(bid => bid.bidId === id);
return returnValue;
}

export function checkDeepArray(Arr) {
if (Array.isArray(Arr)) {
if (Array.isArray(Arr[0])) {
return Arr[0];
} else {
return Arr;
}
} else {
return Arr;
}
}
export function defaultSize(thebidObj) {
const {sizes} = thebidObj;
const returnObject = {};
returnObject.width = checkDeepArray(sizes)[0];
returnObject.height = checkDeepArray(sizes)[1];
return returnObject;
}
registerBidder(spec);
45 changes: 45 additions & 0 deletions modules/ozoneBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

# Overview

```
Module Name: Ozone Project Bidder Adapter
Module Type: Bidder Adapter
Maintainer: engineering@ozoneproject.com
```

# Description

Module that connects to the Ozone Project's demand source(s).

The Ozone Project bid adapter supports Banner mediaTypes ONLY.

# Test Parameters


A test ad unit that will consistently return test creatives:

```
//Banner adUnit
adUnits = [{
code: 'id-of-your-banner-div',
mediaTypes: {
banner: {
sizes: [[300, 250], [300,600]]
}
},
bids: [{
bidder: 'ozone',
params: {
publisherId: 'OZONENUK0001', /* an ID to identify the publisher account - required */
siteId: '4204204201', /* An ID used to identify a site within a publisher account - required */
placementId: '0420420421', /* an ID used to identify the piece of inventory - required - for appnexus test use 13144370. */
customData: {"key1": "value1", "key2": "value2}, /* optional JSON placeholder for passing publisher key-values for targeting. */
ozoneData: {"key1": "value1", "key2": "value2"}, /* optional JSON placeholder for for passing ozone project key-values for targeting. */
lotameData: {"key1": "value1", "key2": "value2} /* optional JSON placeholder for passing Lotame DMP data */
}
}]
}];
```