diff --git a/modules/otmBidAdapter.js b/modules/otmBidAdapter.js new file mode 100644 index 00000000000..a0e91a480a2 --- /dev/null +++ b/modules/otmBidAdapter.js @@ -0,0 +1,146 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import {logInfo, logError, getBidIdParameter, _each, getValue, isFn, isPlainObject} from '../src/utils.js'; +import { BANNER } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'otm'; +const OTM_BID_URL = 'https://ssp.otm-r.com/adjson'; +const DEF_CUR = 'RUB' + +export const spec = { + + code: BIDDER_CODE, + url: OTM_BID_URL, + 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.tid; + }, + + /** + * Build bidder requests. + * + * @param validBidRequests + * @param bidderRequest + * @returns {[]} + */ + buildRequests: function (validBidRequests, bidderRequest) { + logInfo('validBidRequests', validBidRequests); + + const bidRequests = []; + let tz = new Date().getTimezoneOffset() + let referrer = ''; + if (bidderRequest && bidderRequest.refererInfo) { + referrer = bidderRequest.refererInfo.referer; + } + + _each(validBidRequests, (bid) => { + let domain = getValue(bid.params, 'domain') || '' + let tid = getValue(bid.params, 'tid') + let cur = getValue(bid.params, 'currency') || DEF_CUR + let bidid = getBidIdParameter('bidId', bid) + let transactionid = getBidIdParameter('transactionId', bid) + let auctionid = getBidIdParameter('auctionId', bid) + let bidfloor = _getBidFloor(bid) + + _each(bid.sizes, size => { + let width = 0; + let height = 0; + if (size.length && typeof size[0] === 'number' && typeof size[1] === 'number') { + width = size[0]; + height = size[1]; + } + bidRequests.push({ + method: 'GET', + url: OTM_BID_URL, + data: { + tz: tz, + w: width, + h: height, + domain: domain, + l: referrer, + s: tid, + cur: cur, + bidid: bidid, + transactionid: transactionid, + auctionid: auctionid, + bidfloor: bidfloor, + }, + }) + }) + }) + return bidRequests; + }, + + /** + * Generate response. + * + * @param serverResponse + * @param request + * @returns {[]|*[]} + */ + interpretResponse: function (serverResponse, request) { + logInfo('serverResponse', serverResponse.body); + + const responsesBody = serverResponse ? serverResponse.body : {}; + const bidResponses = []; + try { + if (responsesBody.length === 0) { + return []; + } + + _each(responsesBody, (bid) => { + if (bid.ad) { + bidResponses.push({ + requestId: bid.bidid, + cpm: bid.cpm, + width: bid.w, + height: bid.h, + creativeId: bid.creativeid, + currency: bid.currency || 'RUB', + netRevenue: true, + ad: bid.ad, + ttl: bid.ttl, + transactionId: bid.transactionid, + meta: { + advertiserDomains: bid.adDomain ? [bid.adDomain] : [] + } + }); + } + }); + } catch (error) { + logError(error); + } + + return bidResponses; + } +}; + +/** + * Get floor value + * @param bid + * @returns {null|*} + * @private + */ +function _getBidFloor(bid) { + if (!isFn(bid.getFloor)) { + return bid.params.bidfloor ? bid.params.bidfloor : 0; + } + + let floor = bid.getFloor({ + currency: DEF_CUR, + mediaType: '*', + size: '*' + }); + if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === DEF_CUR) { + return floor.floor; + } + return 0; +} + +registerBidder(spec); diff --git a/modules/otmBidAdapter.md b/modules/otmBidAdapter.md index 4962d3a8052..e5834da5729 100644 --- a/modules/otmBidAdapter.md +++ b/modules/otmBidAdapter.md @@ -1,36 +1,37 @@ # Overview -Module Name: OTM Bidder Adapter -Module Type: Bidder Adapter -Maintainer: ? +**Module Name**: OTM Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: e.kretsu@otm-r.com # Description -You can use this adapter to get a bid from otm-r.com. +OTM Bidder Adapter for Prebid.js. About: https://otm-r.com -About us : http://otm-r.com +Use `otm` as bidder: +# Params +- `tid` required, specific id AdUnit slot. +- `domain` optional, specific custom domain. +- `bidfloor` optional. -# Test Parameters -```javascript - var adUnits = [ - { - code: 'div-otm-example', - sizes: [[320, 480]], - bids: [ - { - bidder: "otm", - params: { - tid: "99", - bidfloor: 20 - } - } - ] - } - ]; +## AdUnits configuration example ``` + var adUnits = [{ + code: 'your-slot', //use exactly the same code as your slot div id. + mediaTypes: { + banner: { + sizes: [[320, 480]] + } + }, + bids: [{ + bidder: 'otm', + params: { + tid: 'XXXXX', + domain: 'specific custom domain, if needed', + bidfloor: 20 + } + }] + }]; -Where: - -* tid - A tag id (should have low cardinality) -* bidfloor - Floor price +``` diff --git a/test/spec/modules/otmBidAdapter_spec.js b/test/spec/modules/otmBidAdapter_spec.js new file mode 100644 index 00000000000..6eb5768c3af --- /dev/null +++ b/test/spec/modules/otmBidAdapter_spec.js @@ -0,0 +1,67 @@ +import {expect} from 'chai'; +import {spec} from 'modules/otmBidAdapter'; + +describe('otmBidAdapter', function () { + it('validate_pub_params', function () { + expect(spec.isBidRequestValid({ + bidder: 'otm', + params: { + tid: '123', + bidfloor: 20 + } + })).to.equal(true); + }); + + it('validate_generated_params', function () { + let bidRequestData = [{ + bidId: 'bid1234', + bidder: 'otm', + params: { + tid: '123', + bidfloor: 20 + }, + sizes: [[240, 400]] + }]; + + let request = spec.buildRequests(bidRequestData); + let req_data = request[0].data; + + expect(req_data.bidid).to.equal('bid1234'); + }); + + it('validate_response_params', function () { + let bidRequestData = { + data: { + bidId: 'bid1234' + } + }; + + let serverResponse = { + body: [ + { + 'auctionid': '3c6f8e22-541b-485c-9214-e974d9fb1b6f', + 'cpm': 847.097, + 'ad': 'test html', + 'w': 240, + 'h': 400, + 'currency': 'RUB', + 'ttl': 300, + 'creativeid': '1_7869053', + 'bidid': '101f211def7c99', + 'transactionid': 'transaction_id_1' + } + ] + }; + + let bids = spec.interpretResponse(serverResponse, bidRequestData); + expect(bids).to.have.lengthOf(1); + let bid = bids[0]; + expect(bid.cpm).to.equal(847.097); + expect(bid.currency).to.equal('RUB'); + expect(bid.width).to.equal(240); + expect(bid.height).to.equal(400); + expect(bid.netRevenue).to.equal(true); + expect(bid.requestId).to.equal('101f211def7c99'); + expect(bid.ad).to.equal('test html'); + }); +});