Skip to content

Commit

Permalink
Playground XYZ - new adapter (prebid#2606)
Browse files Browse the repository at this point in the history
* add playground adapters

* clean up

* update with upstream master

* add test file clean up adapter by removing native referecnes

* test file

* replace appnexus with playground reference in error logs

* remove commented code

* change key in response object from appnexus to playgroundxyz

* change tests so we test for ordering by cpm as well

* dont drop other bids, just set cpm to 0 and send it through

* clean up

* restore glulp file

* fix documentation

* remove cpm logic from adapter

* change application type to application\json for playground adapter

* update adaptor to use openRtb

* add device and site to bid

* add extra space on error msg

* remove package-lock

* update pg details

* Update playgroundxyzBidAdapter.md
  • Loading branch information
teranchristian authored and AlessandroDG committed Sep 13, 2018
1 parent e2154e3 commit df08a1b
Show file tree
Hide file tree
Showing 3 changed files with 368 additions and 0 deletions.
160 changes: 160 additions & 0 deletions modules/playgroundxyzBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import * as utils from 'src/utils';
import { registerBidder } from 'src/adapters/bidderFactory';
import { BANNER } from 'src/mediaTypes';

const BIDDER_CODE = 'playgroundxyz';
const URL = 'https://ads.playground.xyz/host-config/prebid';

export const spec = {
code: BIDDER_CODE,
aliases: ['playgroundxyz'],
supportedMediaTypes: [BANNER],

/**
* Determines whether or not the given bid request is valid.
*
* @param {object} bid The bid to validate.
* @return boolean True if this is a valid bid, and false otherwise.
*/
isBidRequestValid: function (bid) {
return !!(bid.params.placementId);
},

/**
* Make a server request from the list of BidRequests.
*
* @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be sent to the Server.
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function (bidRequests, bidderRequest) {
const topLocation = utils.getTopWindowLocation();
const payload = JSON.stringify({
id: bidRequests[0].auctionId,
site: {
domain: window.location.protocol + '//' + topLocation.hostname,
name: topLocation.hostname,
page: topLocation.href,
},
device: {
ua: navigator.userAgent,
language: navigator.language,
devicetype: isMobile() ? 1 : isConnectedTV() ? 3 : 2,
},
imp: bidRequests.map(mapImpression)
});

const options = {
contentType: 'application/json',
withCredentials: false
};

return {
method: 'POST',
url: URL,
data: payload,
options,
bidderRequest
};
},

/**
* Unpack the response from the server into a list of bids.
*
* @param {*} serverResponse A successful response from the server.
* @return {Bid[]} An array of bids which were nested inside the server.
*/
interpretResponse: function (serverResponse, { bidderRequest }) {
serverResponse = serverResponse.body;
const bids = [];

if (!serverResponse || serverResponse.error) {
let errorMessage = `in response for ${bidderRequest.bidderCode} adapter`;
if (serverResponse && serverResponse.error) { errorMessage += `: ${serverResponse.error}`; }
utils.logError(errorMessage);
return bids;
}

if (!utils.isArray(serverResponse.seatbid)) {
let errorMessage = `in response for ${bidderRequest.bidderCode} adapter `;
utils.logError(errorMessage += 'Malformed seatbid response');
return bids;
}

serverResponse.seatbid.forEach(sBid => {
if (sBid.hasOwnProperty('bid')) {
sBid.bid.forEach(iBid => {
if (iBid.price !== 0) {
const bid = newBid(iBid);
bids.push(bid);
}
});
}
});
return bids;
},

getUserSyncs: function (syncOptions) {
if (syncOptions.iframeEnabled) {
return [{
type: 'iframe',
url: '//acdn.adnxs.com/ib/static/usersync/v3/async_usersync.html'
}];
}
}
}

function newBid(bid) {
return {
requestId: bid.impid,
mediaType: BANNER,
cpm: bid.price,
creativeId: bid.adid,
ad: bid.adm,
width: bid.w,
height: bid.h,
ttl: 300,
netRevenue: true,
currency: 'USD',
};
}

function mapImpression(bid) {
return {
id: bid.bidId,
banner: mapBanner(bid),
ext: {
appnexus: {
placement_id: parseInt(bid.params.placementId, 10)
}
}
};
}

function mapBanner(bid) {
return {
w: parseInt(bid.sizes[0][0], 10),
h: parseInt(bid.sizes[0][1], 10),
format: mapSizes(bid.sizes)
};
}

function mapSizes(bidSizes) {
const format = [];
bidSizes.forEach(size => {
format.push({
w: parseInt(size[0], 10),
h: parseInt(size[1], 10)
});
});
return format;
}

function isMobile() {
return (/(ios|ipod|ipad|iphone|android)/i).test(navigator.userAgent);
}

function isConnectedTV() {
return (/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(global.navigator.userAgent);
}

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

```
Module Name: Playground XYZ Bid Adapter
Module Type: Bidder Adapter
Maintainer: tech+prebid@playgroundxyz.com
```

# Description

Connects to playgroundxyz ad server for bids.

Playground XYZ bid adapter supports Banner.

# Test Parameters
```
var adUnits = [
// Banner adUnit
{
code: 'banner-div',
sizes: [[300, 250], [300,600]],
bids: [{
bidder: 'playgroundxyz',
params: {
placementId: '10433394'
}
}]
},
// Video instream adUnit
{
code: 'video-instream',
sizes: [640, 480],
mediaTypes: {
video: {
context: 'instream'
},
},
bids: [{
bidder: 'playgroundxyz',
params: {
placementId: '9333431',
video: {
skippable: true,
playback_methods: ['auto_play_sound_off']
}
}
}]
},
// Video outstream adUnit
{
code: 'video-outstream',
sizes: [[640, 480]],
mediaTypes: {
video: {
context: 'outstream'
}
},
bids: [
{
bidder: 'playgroundxyz',
params: {
placementId: '5768085',
video: {
skippable: true,
playback_method: ['auto_play_sound_off']
}
}
}
]
}
];
```
136 changes: 136 additions & 0 deletions test/spec/modules/playgroundxyzBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { expect } from 'chai';
import { spec } from 'modules/playgroundxyzBidAdapter';
import { newBidder } from 'src/adapters/bidderFactory';
import { deepClone } from 'src/utils';

const URL = 'https://ads.playground.xyz/host-config/prebid';

describe('playgroundxyzBidAdapter', () => {
const adapter = newBidder(spec);

describe('inherited functions', () => {
it('exists and is a function', () => {
expect(adapter.callBids).to.exist.and.to.be.a('function');
});
});

describe('isBidRequestValid', () => {
let bid = {
'bidder': 'playgroundxyz',
'params': {
'placementId': '10433394'
},
'adUnitCode': 'adunit-code',
'sizes': [[300, 250], [320, 50]],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
'auctionId': '1d1a030790a475',
};

it('should return true when required params found', () => {
expect(spec.isBidRequestValid(bid)).to.equal(true);
});

it('should return false when required params are not passed', () => {
let bid = Object.assign({}, bid);
delete bid.params;
bid.params = {
'placementId': 0
};
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
});

describe('buildRequests', () => {
let bidRequests = [
{
'bidder': 'playgroundxyz',
'params': {
'placementId': '10433394'
},
'adUnitCode': 'adunit-code',
'sizes': [[300, 250], [300, 600]],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
'auctionId': '1d1a030790a475',
}
];

it('sends bid request to ENDPOINT via POST', () => {
let bidRequest = Object.assign([], bidRequests);

const request = spec.buildRequests(bidRequest);
const data = JSON.parse(request.data);
const banner = data.imp[0].banner;

expect(Object.keys(data.imp[0].ext)).to.have.members(['appnexus']);
expect([banner.w, banner.h]).to.deep.equal([300, 250]);
expect(banner.format).to.deep.equal([{w: 300, h: 250}, {w: 300, h: 600}]);
expect(request.url).to.equal(URL);
expect(request.method).to.equal('POST');
});
})

describe('interpretResponse', () => {
let response = {
'id': 'bidd_id',
'seatbid': [ {
'bid': [
{
'id': '4434762738980910431',
'impid': '221f2bdc1fbc31',
'price': 1,
'adid': '91673066',
'adm': '<script src=\'pgxyz\'></script>',
'adomain': [ 'pg.xyz' ],
'iurl': 'http://pgxyz.com/cr?id=91673066',
'cid': 'c_id',
'crid': 'c_rid',
'h': 50,
'w': 320,
'ext': {
'appnexus': {
'brand_id': 1,
'auction_id': 1087655594852566000,
'bidder_id': 2,
'bid_ad_type': 0
}
}
}
],
'seat': '4321'
}],
'bidid': '6894227111893743356',
'cur': 'USD'
};

let bidderRequest = {
'bidderCode': 'playgroundxyz'
};

it('should get correct bid response', () => {
let expectedResponse = [
{
'requestId': '221f2bdc1fbc31',
'cpm': 1,
'creativeId': 91673066,
'width': 300,
'height': 50,
'ad': '<script src=\'pgxyz\'></script>',
'mediaType': 'banner',
'currency': 'USD',
'ttl': 300,
'netRevenue': true
}
];
let result = spec.interpretResponse({ body: response }, {bidderRequest});
expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0]));
});

it('handles nobid responses', () => {
let response = '';
let result = spec.interpretResponse({ body: response }, {bidderRequest});
expect(result.length).to.equal(0);
});
});
});

0 comments on commit df08a1b

Please sign in to comment.