From c771f39fc727be2f0f64345f13c4d53b632ebccd Mon Sep 17 00:00:00 2001 From: MIGOdanis Date: Thu, 12 Apr 2018 16:04:21 +0800 Subject: [PATCH 1/8] add getUserSyncs function --- modules/clickforceBidAdapter.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/clickforceBidAdapter.js b/modules/clickforceBidAdapter.js index 9267540cb61..71e16a08077 100644 --- a/modules/clickforceBidAdapter.js +++ b/modules/clickforceBidAdapter.js @@ -61,6 +61,19 @@ export const spec = { }); }); return cfResponses; + }, + getUserSyncs: function(syncOptions, serverResponses) { + if (syncOptions.iframeEnabled){ + return [{ + type: "iframe", + url: "https://cdn.doublemax.net/js/capmapping.htm" + }] + }else if(syncOptions.pixelEnabled){ + return [{ + type: "image", + url: "https://c.doublemax.net/cm" + }] + } } }; registerBidder(spec); From 125ccb060579dce7d6fa6b262ede34723dd930af Mon Sep 17 00:00:00 2001 From: MIGOdanis Date: Thu, 12 Apr 2018 16:24:56 +0800 Subject: [PATCH 2/8] bug fix --- modules/clickforceBidAdapter.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/clickforceBidAdapter.js b/modules/clickforceBidAdapter.js index 71e16a08077..fbcd5f2685c 100644 --- a/modules/clickforceBidAdapter.js +++ b/modules/clickforceBidAdapter.js @@ -63,15 +63,15 @@ export const spec = { return cfResponses; }, getUserSyncs: function(syncOptions, serverResponses) { - if (syncOptions.iframeEnabled){ + if (syncOptions.iframeEnabled) { return [{ - type: "iframe", - url: "https://cdn.doublemax.net/js/capmapping.htm" + type: 'iframe', + url: 'https://cdn.doublemax.net/js/capmapping.htm' }] - }else if(syncOptions.pixelEnabled){ + } else if (syncOptions.pixelEnabled) { return [{ - type: "image", - url: "https://c.doublemax.net/cm" + type: 'image', + url: 'https://c.doublemax.net/cm' }] } } From 2c248b3660cf7e43952bcfa2a40a13cf92bc1335 Mon Sep 17 00:00:00 2001 From: MIGOdanis Date: Wed, 18 Apr 2018 11:27:06 +0800 Subject: [PATCH 3/8] add test spec --- .../spec/modules/clickforceBidAdapter_spec.js | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 test/spec/modules/clickforceBidAdapter_spec.js diff --git a/test/spec/modules/clickforceBidAdapter_spec.js b/test/spec/modules/clickforceBidAdapter_spec.js new file mode 100644 index 00000000000..a993abdf1fa --- /dev/null +++ b/test/spec/modules/clickforceBidAdapter_spec.js @@ -0,0 +1,107 @@ +import { expect } from 'chai'; +import { spec } from 'modules/clickforceBidAdapter'; +import { newBidder } from 'src/adapters/bidderFactory'; + +describe('ClickforceAdapter', () => { + 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': 'clickforce', + 'params': { + 'zone': '6682' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250] + ], + '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 = { + 'someIncorrectParam': 0 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', () => { + let bidRequests = [{ + 'bidder': 'clickforce', + 'params': { + 'zone': '6682' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475' + }]; + + const request = spec.buildRequests(bidRequests); + + it('sends bid request to our endpoint via POST', () => { + expect(request.method).to.equal('POST'); + }); + }); + describe('interpretResponse', () => { + let response = [{ + 'cpm': 0.5, + 'width': '300', + 'height': '250', + 'callback_uid': '220ed41385952a', + 'type': 'Default Ad', + 'tag': '', + 'creativeId': '1f99ac5c3ef10a4097499a5686b30aff-6682', + 'requestId': '220ed41385952a', + 'currency': 'USD', + 'ttl': 60, + 'netRevenue': true, + 'zone': '6682' + }]; + + it('should get the correct bid response', () => { + let expectedResponse = [{ + 'requestId': '220ed41385952a', + 'cpm': 0.5, + 'width': '300', + 'height': '250', + 'creativeId': '1f99ac5c3ef10a4097499a5686b30aff-6682', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 60, + 'ad': '' + }]; + + let bidderRequest; + let result = spec.interpretResponse({ body: response }, {bidderRequest}); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + }); + + it('handles empty bid response', () => { + let response = { + body: {} + }; + let result = spec.interpretResponse(response); + expect(result.length).to.equal(0); + }); + }); +}); \ No newline at end of file From 8b6e4d0b993e64a3d4d2facb4ebc7ad443b0c756 Mon Sep 17 00:00:00 2001 From: MIGOdanis Date: Wed, 18 Apr 2018 12:05:20 +0800 Subject: [PATCH 4/8] fix of docment format --- .../spec/modules/clickforceBidAdapter_spec.js | 174 +++++++++--------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/test/spec/modules/clickforceBidAdapter_spec.js b/test/spec/modules/clickforceBidAdapter_spec.js index a993abdf1fa..12ac3121390 100644 --- a/test/spec/modules/clickforceBidAdapter_spec.js +++ b/test/spec/modules/clickforceBidAdapter_spec.js @@ -3,105 +3,105 @@ import { spec } from 'modules/clickforceBidAdapter'; import { newBidder } from 'src/adapters/bidderFactory'; describe('ClickforceAdapter', () => { - const adapter = newBidder(spec); + const adapter = newBidder(spec); - describe('inherited functions', () => { - it('exists and is a function', () => { - expect(adapter.callBids).to.exist.and.to.be.a('function'); - }); + describe('inherited functions', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); }); + }); - describe('isBidRequestValid', () => { - let bid = { - 'bidder': 'clickforce', - 'params': { - 'zone': '6682' - }, - 'adUnitCode': 'adunit-code', - 'sizes': [ - [300, 250] - ], - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475' - }; + describe('isBidRequestValid', () => { + let bid = { + 'bidder': 'clickforce', + 'params': { + 'zone': '6682' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250] + ], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475' + }; - it('should return true when required params found', () => { - expect(spec.isBidRequestValid(bid)).to.equal(true); - }); + 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 = { - 'someIncorrectParam': 0 - }; - expect(spec.isBidRequestValid(bid)).to.equal(false); - }); + it('should return false when required params are not passed', () => { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + 'someIncorrectParam': 0 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); }); + }); - describe('buildRequests', () => { - let bidRequests = [{ - 'bidder': 'clickforce', - 'params': { - 'zone': '6682' - }, - 'adUnitCode': 'adunit-code', - 'sizes': [ - [300, 250], - [300, 600] - ], - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475' - }]; + describe('buildRequests', () => { + let bidRequests = [{ + 'bidder': 'clickforce', + 'params': { + 'zone': '6682' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250] + ], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475' + }]; - const request = spec.buildRequests(bidRequests); + const request = spec.buildRequests(bidRequests); - it('sends bid request to our endpoint via POST', () => { - expect(request.method).to.equal('POST'); - }); + it('sends bid request to our endpoint via POST', () => { + expect(request.method).to.equal('POST'); }); - describe('interpretResponse', () => { - let response = [{ - 'cpm': 0.5, - 'width': '300', - 'height': '250', - 'callback_uid': '220ed41385952a', - 'type': 'Default Ad', - 'tag': '', - 'creativeId': '1f99ac5c3ef10a4097499a5686b30aff-6682', - 'requestId': '220ed41385952a', - 'currency': 'USD', - 'ttl': 60, - 'netRevenue': true, - 'zone': '6682' - }]; + }); + + describe('interpretResponse', () => { + let response = [{ + 'cpm': 0.5, + 'width': '300', + 'height': '250', + 'callback_uid': '220ed41385952a', + 'type': 'Default Ad', + 'tag': '', + 'creativeId': '1f99ac5c3ef10a4097499a5686b30aff-6682', + 'requestId': '220ed41385952a', + 'currency': 'USD', + 'ttl': 60, + 'netRevenue': true, + 'zone': '6682' + }]; - it('should get the correct bid response', () => { - let expectedResponse = [{ - 'requestId': '220ed41385952a', - 'cpm': 0.5, - 'width': '300', - 'height': '250', - 'creativeId': '1f99ac5c3ef10a4097499a5686b30aff-6682', - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 60, - 'ad': '' - }]; + it('should get the correct bid response', () => { + let expectedResponse = [{ + 'requestId': '220ed41385952a', + 'cpm': 0.5, + 'width': '300', + 'height': '250', + 'creativeId': '1f99ac5c3ef10a4097499a5686b30aff-6682', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 60, + 'ad': '' + }]; - let bidderRequest; - let result = spec.interpretResponse({ body: response }, {bidderRequest}); - expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); - }); + let bidderRequest; + let result = spec.interpretResponse({ body: response }, {bidderRequest}); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + }); - it('handles empty bid response', () => { - let response = { - body: {} - }; - let result = spec.interpretResponse(response); - expect(result.length).to.equal(0); - }); + it('handles empty bid response', () => { + let response = { + body: {} + }; + let result = spec.interpretResponse(response); + expect(result.length).to.equal(0); }); + }); }); \ No newline at end of file From 2c5f21b91ab636f68a4e9f220742639998b91b00 Mon Sep 17 00:00:00 2001 From: MIGOdanis Date: Wed, 18 Apr 2018 12:50:27 +0800 Subject: [PATCH 5/8] fix of end line --- test/spec/modules/clickforceBidAdapter_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spec/modules/clickforceBidAdapter_spec.js b/test/spec/modules/clickforceBidAdapter_spec.js index 12ac3121390..3154f7bb93a 100644 --- a/test/spec/modules/clickforceBidAdapter_spec.js +++ b/test/spec/modules/clickforceBidAdapter_spec.js @@ -104,4 +104,4 @@ describe('ClickforceAdapter', () => { expect(result.length).to.equal(0); }); }); -}); \ No newline at end of file +}); From 5de592dd9b7ae01131f5ff27999ea0d670e9bc96 Mon Sep 17 00:00:00 2001 From: MIGOdanis Date: Fri, 27 Apr 2018 11:02:58 +0800 Subject: [PATCH 6/8] add getUserSyncs function into test file and updated test parameters --- modules/clickforceBidAdapter.md | 10 ++++++++++ .../spec/modules/clickforceBidAdapter_spec.js | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/modules/clickforceBidAdapter.md b/modules/clickforceBidAdapter.md index 912f9132331..5d8a5ac8119 100644 --- a/modules/clickforceBidAdapter.md +++ b/modules/clickforceBidAdapter.md @@ -29,3 +29,13 @@ joey@clickforce.com.tw (MR. Joey) }] }]; ``` +### Configuration + +CLICKFORCE recommend the UserSync configuration below. It's can be optimize the CPM for the request. +```javascript +pbjs.setConfig({ + userSync: { + iframeEnabled: true, + syncDelay: 1000 +}}); +``` \ No newline at end of file diff --git a/test/spec/modules/clickforceBidAdapter_spec.js b/test/spec/modules/clickforceBidAdapter_spec.js index 3154f7bb93a..8b0955590a0 100644 --- a/test/spec/modules/clickforceBidAdapter_spec.js +++ b/test/spec/modules/clickforceBidAdapter_spec.js @@ -104,4 +104,24 @@ describe('ClickforceAdapter', () => { expect(result.length).to.equal(0); }); }); + + describe('getUserSyncs function', () => { + it('should register type is iframe', () => { + const syncOptions = { + 'iframeEnabled': 'true' + } + let userSync = spec.getUserSyncs(syncOptions); + expect(userSync[0].type).to.equal('iframe'); + expect(userSync[0].url).to.equal('https://cdn.doublemax.net/js/capmapping.htm'); + }); + + it('should register type is image', () => { + const syncOptions = { + 'pixelEnabled': 'true' + } + let userSync = spec.getUserSyncs(syncOptions); + expect(userSync[0].type).to.equal('image'); + expect(userSync[0].url).to.equal('https://c.doublemax.net/cm'); + }); + }); }); From 4c88a09cb2cff25e08be6e5d09dfeb57bbdd57d0 Mon Sep 17 00:00:00 2001 From: MIGOdanis Date: Wed, 27 Jun 2018 15:51:27 +0800 Subject: [PATCH 7/8] add native ad --- modules/clickforceBidAdapter.js | 75 +++++++++++++--- .../spec/modules/clickforceBidAdapter_spec.js | 87 ++++++++++++++++--- 2 files changed, 136 insertions(+), 26 deletions(-) diff --git a/modules/clickforceBidAdapter.js b/modules/clickforceBidAdapter.js index fbcd5f2685c..c9e54f9efac 100644 --- a/modules/clickforceBidAdapter.js +++ b/modules/clickforceBidAdapter.js @@ -1,12 +1,12 @@ import * as utils from 'src/utils'; import {registerBidder} from 'src/adapters/bidderFactory'; - +import {BANNER, NATIVE} from 'src/mediaTypes'; const BIDDER_CODE = 'clickforce'; const ENDPOINT_URL = '//ad.doublemax.net/adserver/prebid.json?cb=' + new Date().getTime() + '&hb=1&ver=1.21'; export const spec = { code: BIDDER_CODE, - + supportedMediaTypes: [BANNER, NATIVE], /** * Determines whether or not the given bid request is valid. * @@ -34,7 +34,8 @@ export const spec = { return { method: 'POST', url: ENDPOINT_URL, - data: bidParams + data: bidParams, + validBidRequests: validBidRequests }; }, @@ -47,18 +48,63 @@ export const spec = { */ interpretResponse: function(serverResponse, bidRequest) { const cfResponses = []; - utils._each(serverResponse.body, function(response) { - cfResponses.push({ - requestId: response.requestId, - cpm: response.cpm, - width: response.width, - height: response.height, - creativeId: response.creativeId, - currency: response.currency, - netRevenue: response.netRevenue, - ttl: response.ttl, - ad: response.tag + const bidRequestList = []; + + if (typeof bidRequest != 'undefined') { + utils._each(bidRequest.validBidRequests, function(req) { + bidRequestList[req.bidId] = req; }); + } + + utils._each(serverResponse.body, function(response) { + if (response.requestId != null) { + // native ad size + if (response.width == 3) { + cfResponses.push({ + requestId: response.requestId, + cpm: response.cpm, + width: response.width, + height: response.height, + creativeId: response.creativeId, + currency: response.currency, + netRevenue: response.netRevenue, + ttl: response.ttl, + native: { + title: response.tag.content.title, + body: response.tag.content.content, + image: { + url: response.tag.content.image, + height: 900, + width: 1600 + }, + icon: { + url: response.tag.content.icon, + height: 900, + width: 900 + }, + clickUrl: response.tag.cu, + cta: response.tag.content.button_text, + sponsoredBy: response.tag.content.advertiser, + impressionTrackers: response.tag.iu, + }, + mediaType: 'native', + }); + } else { + // display ad + cfResponses.push({ + requestId: response.requestId, + cpm: response.cpm, + width: response.width, + height: response.height, + creativeId: response.creativeId, + currency: response.currency, + netRevenue: response.netRevenue, + ttl: response.ttl, + ad: response.tag, + mediaType: 'banner', + }); + } + } }); return cfResponses; }, @@ -76,4 +122,5 @@ export const spec = { } } }; + registerBidder(spec); diff --git a/test/spec/modules/clickforceBidAdapter_spec.js b/test/spec/modules/clickforceBidAdapter_spec.js index 8b0955590a0..c09b69a6320 100644 --- a/test/spec/modules/clickforceBidAdapter_spec.js +++ b/test/spec/modules/clickforceBidAdapter_spec.js @@ -78,24 +78,87 @@ describe('ClickforceAdapter', () => { 'zone': '6682' }]; - it('should get the correct bid response', () => { - let expectedResponse = [{ - 'requestId': '220ed41385952a', - 'cpm': 0.5, - 'width': '300', - 'height': '250', - 'creativeId': '1f99ac5c3ef10a4097499a5686b30aff-6682', - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 60, - 'ad': '' - }]; + let response1 = [{ + 'cpm': 0.0625, + 'width': '3', + 'height': '3', + 'callback_uid': '2e27ec595bf1a', + 'type': 'public Bid', + 'tag': { + 'content': { + 'title': 'title', + 'content': 'content', + 'advertiser': 'advertiser', + 'button_text': 'button_text', + 'image': 'image', + 'icon': 'icon' + }, + 'cu': ['cu'], + 'iu': ['iu'], + 'p': '6878:11062:32586:8380573788dad9b9fc17edde444c4dcf:2795' + }, + 'creativeId': '8380573788dad9b9fc17edde444c4dcf-6878', + 'requestId': '2e27ec595bf1a', + 'currency': 'USD', + 'ttl': 60, + 'netRevenue': true, + 'zone': '6878' + }]; + + let expectedResponse = [{ + 'requestId': '220ed41385952a', + 'cpm': 0.5, + 'width': '300', + 'height': '250', + 'creativeId': '1f99ac5c3ef10a4097499a5686b30aff-6682', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 60, + 'ad': '', + 'mediaType': 'banner', + }]; + + let expectedResponse1 = [{ + 'requestId': '2e27ec595bf1a', + 'cpm': 0.0625, + 'width': '3', + 'height': '3', + 'creativeId': '8380573788dad9b9fc17edde444c4dcf-6878', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 60, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'image', + 'width': 1600, + 'height': 900 + }, + 'title': 'title', + 'sponsoredBy': 'advertiser', + 'body': 'content', + 'icon': { + 'url': 'icon', + 'width': 900, + 'height': 900 + }, + 'clickUrl': 'cu', + 'impressionTrackers': ['iu'] + } + }]; + it('should get the correct bid response by display ad', () => { let bidderRequest; let result = spec.interpretResponse({ body: response }, {bidderRequest}); expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); }); + it('should get the correct bid response by native ad', () => { + let bidderRequest; + let result = spec.interpretResponse({ body: response1 }, {bidderRequest}); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse1[0])); + }); + it('handles empty bid response', () => { let response = { body: {} From 4945a13401726697c9ccd61250ccf3c2fe6305fb Mon Sep 17 00:00:00 2001 From: MIGOdanis Date: Wed, 27 Jun 2018 16:17:06 +0800 Subject: [PATCH 8/8] update md doc --- modules/clickforceBidAdapter.md | 41 ++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/modules/clickforceBidAdapter.md b/modules/clickforceBidAdapter.md index 5d8a5ac8119..07fe9475881 100644 --- a/modules/clickforceBidAdapter.md +++ b/modules/clickforceBidAdapter.md @@ -16,7 +16,7 @@ It requires adapters to start bidding and no extra setting is needed. If you'd l joey@clickforce.com.tw (MR. Joey) -# Test Parameters +# Test Parameters (Display ad) ``` var adUnits = [{ code: 'banner-ad-div', @@ -29,6 +29,45 @@ joey@clickforce.com.tw (MR. Joey) }] }]; ``` +# Test Parameters (Native ad) +``` + var adUnits = [{ + code: 'banner-ad-div', + sizes: [[300, 250]], + mediaTypes: { + native: { + title: { + required: true, + }, + body: { + required: true + }, + image: { + required: true, + }, + icon: { + required: false, + }, + clickUrl: { + required: true + }, + cta: { + required: true + }, + sponsoredBy: { + required: true + } + } + }, + bids: [{ + bidder: "clickforce", + params: { + zone: "6878", + } + }] + }]; +``` + ### Configuration CLICKFORCE recommend the UserSync configuration below. It's can be optimize the CPM for the request.