diff --git a/modules/eywamediaBidAdapter.js b/modules/eywamediaBidAdapter.js new file mode 100644 index 00000000000..543775dc3aa --- /dev/null +++ b/modules/eywamediaBidAdapter.js @@ -0,0 +1,181 @@ +import * as utils from '../src/utils'; +import { registerBidder } from '../src/adapters/bidderFactory'; + +const BIDDER_CODE = 'eywamedia'; +const CURRENCY = 'USD'; +const VERSION = '1.0.0'; +const TIME_TO_LIVE = 360; +const NET_REVENUE = true; +const COOKIE_NAME = 'emaduuid'; +const UUID_LEN = 36; +const SERVER_ENDPOINT = 'https://adtarbostg.eywamedia.com/auctions/prebidjs/3000'; +const localWindow = getTopWindow(); + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: ['banner'], + /** + * Determines whether or not the given bid request is valid. + * @param {object} bid, bid to validate + * @return boolean, true if valid, otherwise false + */ + isBidRequestValid: function(bid) { + return !!(bid.params.publisherId); + }, + /** + * 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 requestPayload Info describing the request to the server. + */ + buildRequests: function(bidRequests, bidRequest) { + const device = getDeviceInfo(); + const site = getSiteInfo(); + const user = getUserInfo(); + + let requestPayload = { + id: utils.generateUUID(), + publisherId: bidRequests[0].params.publisherId, + device: device, + site: site, + user: user, + bidPayload: bidRequests, + cacheBust: new Date().getTime().toString(), + adapterVersion: VERSION, + tmax: bidRequest.timeout + }; + + return { + method: 'POST', + url: SERVER_ENDPOINT, + options: { + contentType: 'application/json' + }, + data: requestPayload + } + }, + + /** + * Makes Eywamedia Ad Server response compatible to Prebid specs + * @param serverResponse successful response from Ad Server + * @param bidderRequest original bidRequest + * @return {Bid[]} an array of bids + */ + interpretResponse: function (serverResponse, bidRequest) { + var bidObject, response; + var bidRespones = []; + var responses = serverResponse.body; + for (var i = 0; i < responses.length; i++) { + response = responses[i]; + bidObject = { + requestId: response.bidId, + cpm: response.cpm, + width: parseInt(response.width), + height: parseInt(response.height), + creativeId: response.bidId, + currency: CURRENCY, + netRevenue: NET_REVENUE, + ttl: TIME_TO_LIVE, + ad: response.ad, + bidderCode: BIDDER_CODE, + transactionId: response.transactionId, + mediaType: response.respType, + }; + bidRespones.push(bidObject); + } + return bidRespones; + } +} +registerBidder(spec); + +/*************************************** + * Helper Functions + ***************************************/ + +/** + * get device type + */ +function getDeviceType() { + let ua = navigator.userAgent; + // Tablets must be checked before phones. + if ((/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i).test(ua)) { + return 5; // "Tablet" + } + if ((/Mobile|iP(hone|od|ad)|Android|BlackBerry|IEMobile|Kindle|NetFront|Silk-Accelerated|(hpw|web)OS|Fennec|Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune/).test(ua)) { + return 4; // "Phone" + } + return 2; // Personal Computers +}; + +/** + * get device info + */ +function getDeviceInfo() { + const language = navigator.language; + return { + ua: navigator.userAgent, + language: navigator[language], + devicetype: getDeviceType(), + dnt: utils.getDNT(), + geo: {}, + js: 1 + }; +}; + +/** + * get site info + */ +function getSiteInfo() { + const topLocation = utils.getTopWindowLocation(); + return { + domain: topLocation.hostname, + page: topLocation.href, + referrer: utils.getTopWindowReferrer(), + desc: getPageDescription(), + title: localWindow.document.title, + }; +}; + +/** + * get user info + */ +function getUserInfo() { + return { + id: getUserID(), + }; +}; + +/** + * get user Id + */ +const getUserID = () => { + const i = document.cookie.indexOf(COOKIE_NAME); + + if (i === -1) { + const uuid = utils.generateUUID(); + document.cookie = `${COOKIE_NAME}=${uuid}; path=/`; + return uuid; + } + + const j = i + COOKIE_NAME.length + 1; + return document.cookie.substring(j, j + UUID_LEN); +}; + +/** + * get page description + */ +function getPageDescription() { + if (document.querySelector('meta[name="description"]')) { + return document.querySelector('meta[name="description"]').getAttribute('content'); // Value of the description metadata from the publisher's page. + } else { + return ''; + } +}; + +function getTopWindow() { + try { + return window.top; + } catch (e) { + return window; + } +}; diff --git a/modules/eywamediaBidAdapter.md b/modules/eywamediaBidAdapter.md new file mode 100644 index 00000000000..76b9b032c1b --- /dev/null +++ b/modules/eywamediaBidAdapter.md @@ -0,0 +1,37 @@ +# Overview + +``` +Module Name: Eywamedia Bid Adapter +Module Type: Bidder Adapter +Maintainer: sharath@eywamedia.com +Note: Our ads will only render in mobile and desktop +``` + +# Description + +Connects to Eywamedia Ad Server for bids. + +Eywamedia bid adapter supports Banners. + +# Test Parameters +``` +var adUnits = [ + // Banner adUnit + { + code: 'div-gpt-ad-1460505748561-0', + sizes: [[300, 250], [300,600]], + bids: [{ + bidder: 'eywamedia', + params: { + publisherId: 'f63a2362-5aa4-4829-bbd2-2678ced8b63e', //Required - GUID (may include numbers and characters) + bidFloor: 0.50, // optional + cats: ["iab1-1","iab23-2"], // optional + keywords: ["sports", "cricket"], // optional + lat: 12.33333, // optional + lon: 77.32322, // optional + locn: "country$region$city$zip" // optional + } + }] + } +]; +``` diff --git a/test/spec/modules/eywamediaBidAdapter_spec.js b/test/spec/modules/eywamediaBidAdapter_spec.js new file mode 100644 index 00000000000..945c0dd0d01 --- /dev/null +++ b/test/spec/modules/eywamediaBidAdapter_spec.js @@ -0,0 +1,253 @@ +import { expect } from 'chai'; +import { spec } from 'modules/eywamediaBidAdapter'; + +describe('EywamediaAdapter', function () { + let serverResponse, bidRequests, bidRequest, bidResponses; + const ENDPOINT = 'https://adtarbostg.eywamedia.com/auctions/prebidjs/3000'; + + bidRequests = [ + { + 'auctionId': 'fc917230-a5e1-4a42-b7d9-8fb776124e43', + 'sizes': [[300, 250]], + 'bidRequestsCount': 1, + 'params': { + 'publisherId': '1234_abcd' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]] + } + }, + 'crumbs': { + 'pubcid': '8b640d4e-1f6d-4fd3-b63f-2570572d8100' + }, + 'bidId': '28b09d0543d671', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'd909c39c-ecc9-41a4-897c-2d2fdfdf41b1', + 'src': 'client', + 'bidder': 'eywamedia', + 'bidderRequestId': '14d8cbc769114b' + }, + { + 'auctionId': 'fc917230-a5e1-4a42-b7d9-8fb776124e43', + 'sizes': [[728, 90]], + 'bidRequestsCount': 1, + 'params': { + 'publisherId': '1234_abcd' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[728, 90]] + } + }, + 'crumbs': { + 'pubcid': '8b640d4e-1f6d-4fd3-b63f-2570572d8100' + }, + 'bidId': '28b09d0543d672', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'd909c39c-ecc9-41a4-897c-2d2fdfdf41b2', + 'src': 'client', + 'bidder': 'eywamedia', + 'bidderRequestId': '14d8cbc769114b' + } + ]; + + bidRequest = { + 'auctionId': 'c88115a4-7e71-43d0-9c96-a9b43ebd143d', + 'auctionStart': 1564725164517, + 'bidderCode': 'eywamedia', + 'bidderRequestId': '191afa18994fdd', + 'bids': [], + 'refererInfo': { + 'canonicalUrl': '', + 'numIframes': 0, + 'reachedTop': true, + 'referer': '' + }, + 'stack': [ + '' + ], + 'start': 1564725164520, + 'timeout': 3000 + }; + + let testBid = { + 'bidder': 'eywamedia', + 'params': { + 'publisherId': '1234_abcd' + } + }; + + describe('isBidRequestValid', function () { + it('should return true when required params found', function () { + assert(spec.isBidRequestValid(testBid)); + }); + + it('should return false when required params are missing', function () { + testBid.params = { + test: '231212312' + }; + assert.isFalse(spec.isBidRequestValid(testBid)); + }); + }); + + describe('buildRequests', function () { + it('should attempt to send bid requests to the endpoint via POST', function () { + const requests = spec.buildRequests(bidRequests, bidRequest); + expect(requests.method).to.equal('POST'); + expect(requests.url).to.be.equal(ENDPOINT); + }); + + it('should not blow up if crumbs is undefined', function () { + let bidArray = [ + { ...testBid, crumbs: undefined } + ] + expect(function () { spec.buildRequests(bidArray, bidRequest) }).not.to.throw() + }) + + it('should return true when required params found', function () { + testBid.params.publisherId = '1234_abcd'; + assert(spec.isBidRequestValid(testBid)); + }); + }); + + describe('interpretResponse', function () { + beforeEach(function () { + serverResponse = { + 'body': + [ + { + 'ad': '', + 'adSlot': '', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'adUrl': 'http://eywamedia.com', + 'bidId': '28b09d0543d671', + 'bidder': 'eywamedia', + 'bidderCode': 'eywamedia', + 'cpm': 1, + 'height': 250, + 'requestTimestamp': 1564725162, + 'respType': 'banner', + 'size': '300X250', + 'statusMessage': 'Bid available', + 'transactionId': 'd909c39c-ecc9-41a4-897c-2d2fdfdf41b1', + 'usesGenericKeys': true, + 'width': 300 + }, + { + 'ad': '', + 'adSlot': '', + 'adUnitCode': 'div-gpt-ad-1460505748561-1', + 'adUrl': 'http://eywamedia.com', + 'bidId': '28b09d0543d672', + 'bidder': 'eywamedia', + 'bidderCode': 'eywamedia', + 'cpm': 1, + 'height': 90, + 'requestTimestamp': 1564725164, + 'respType': 'banner', + 'size': '728X90', + 'statusMessage': 'Bid available', + 'transactionId': 'd909c39c-ecc9-41a4-897c-2d2fdfdf41b2', + 'usesGenericKeys': true, + 'width': 728 + } + ], + 'headers': 'header?' + }; + + bidRequest = { + 'data': + { + 'bidPayload': + [ + { + 'auctionId': 'fc917230-a5e1-4a42-b7d9-8fb776124e43', + 'sizes': [[300, 250]], + 'bidRequestsCount': 1, + 'params': { + 'publisherId': '1234_abcd' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]] + } + }, + 'crumbs': { + 'pubcid': '8b640d4e-1f6d-4fd3-b63f-2570572d8100' + }, + 'bidId': '28b09d0543d671', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'd909c39c-ecc9-41a4-897c-2d2fdfdf41b1', + 'src': 'client', + 'bidder': 'eywamedia', + 'bidderRequestId': '14d8cbc769114b' + }, + { + 'auctionId': 'fc917230-a5e1-4a42-b7d9-8fb776124e43', + 'sizes': [[728, 90]], + 'bidRequestsCount': 1, + 'params': { + 'publisherId': '1234_abcd' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[728, 90]] + } + }, + 'crumbs': { + 'pubcid': '8b640d4e-1f6d-4fd3-b63f-2570572d8100' + }, + 'bidId': '28b09d0543d672', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'd909c39c-ecc9-41a4-897c-2d2fdfdf41b2', + 'src': 'client', + 'bidder': 'eywamedia', + 'bidderRequestId': '14d8cbc769114b' + } + ] + } + }; + bidResponses = [ + { + 'ad': '', + 'bidderCode': 'eywamedia', + 'cpm': 1, + 'creativeId': '28b09d0543d671', + 'currency': 'USD', + 'height': 250, + 'mediaType': 'banner', + 'netRevenue': true, + 'requestId': '28b09d0543d671', + 'transactionId': 'd909c39c-ecc9-41a4-897c-2d2fdfdf41b1', + 'ttl': 360, + 'width': 300 + }, + { + 'ad': '', + 'bidderCode': 'eywamedia', + 'cpm': 1, + 'creativeId': '28b09d0543d672', + 'currency': 'USD', + 'height': 90, + 'mediaType': 'banner', + 'netRevenue': true, + 'requestId': '28b09d0543d672', + 'transactionId': 'd909c39c-ecc9-41a4-897c-2d2fdfdf41b2', + 'ttl': 360, + 'width': 728 + } + ] + }); + + it('should respond with empty response when there is empty serverResponse', function () { + let result = spec.interpretResponse({ body: {} }, bidRequest); + assert.deepEqual(result, []); + }); + + it('should respond with multile response when there is multiple serverResponse', function () { + let result = spec.interpretResponse(serverResponse, bidRequest); + assert.deepEqual(result, bidResponses); + }); + }); +});