From e6568ba6491e41c3e3c57dd32ae730247214f18f Mon Sep 17 00:00:00 2001 From: Junichi Hoshina Date: Tue, 7 Dec 2021 17:39:59 +0900 Subject: [PATCH 1/5] Add new FreakOut bid adapter --- modules/freakoutBidAdapter.js | 178 +++++++++++++++++++ modules/freakoutBidAdapter.md | 38 ++++ test/spec/modules/freakoutBidAdapter_spec.js | 177 ++++++++++++++++++ 3 files changed, 393 insertions(+) create mode 100644 modules/freakoutBidAdapter.js create mode 100644 modules/freakoutBidAdapter.md create mode 100644 test/spec/modules/freakoutBidAdapter_spec.js diff --git a/modules/freakoutBidAdapter.js b/modules/freakoutBidAdapter.js new file mode 100644 index 00000000000..0344eb89adf --- /dev/null +++ b/modules/freakoutBidAdapter.js @@ -0,0 +1,178 @@ +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {tryAppendQueryString, isEmpty} from '../src/utils.js'; +import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; +import {config} from '../src/config.js'; + +const BIDDER_CODE = 'freakout'; +const ENDPOINT = 'https://ad.rfp.fout.jp/ad'; +const ADAPTER_VERSION = '1.0.0'; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + + /** + * Determines whether the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function (bid) { + return !!(bid.params.adspot_id); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} validBidRequests - an array of bids + * @param {*} bidderRequest + * @return {ServerRequest[]} Info describing the request to the server. + */ + buildRequests: function (validBidRequests, bidderRequest) { + const serverRequests = []; + + let endpointUrl = config.getConfig(`${BIDDER_CODE}.endpoint_url`); + + for (let i = 0; i < validBidRequests.length; i++) { + const req = validBidRequests[i]; + + let query = ''; + query = tryAppendQueryString(query, 'adspot_id', req.params.adspot_id); + query = tryAppendQueryString(query, 'ad_type', req.params.ad_type); + query = tryAppendQueryString(query, 'media_url', bidderRequest.refererInfo.referer); + query = tryAppendQueryString(query, 'hb', 'prebidjs'); + query = tryAppendQueryString(query, 'pb_ver', '$prebid.version$'); + query = tryAppendQueryString(query, 'pb_adapter_ver', ADAPTER_VERSION); + query = tryAppendQueryString(query, 'pb_tid', req.transactionId); + query = tryAppendQueryString(query, 'pb_bid', req.bidId); + query = tryAppendQueryString(query, 'cur', getCurrency()); + query = tryAppendQueryString(query, 'sizes', getSizes(req)); + + serverRequests.push({ + method: 'GET', + url: endpointUrl || ENDPOINT, + data: query, + adspotId: req.params.adspot_id + }); + } + + return serverRequests; + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @param {ServerRequest} serverRequest + * @return {Array} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse, serverRequest) { + const body = serverResponse.body; + if (isEmpty(body)) { + return []; + } + + const adspotId = serverRequest.adspotId; + + const ad = body.items[0]; + const creative = makeCreative(adspotId, body); + + const bid = { + requestId: ad.pb_bid, + cpm: Number(ad.cpm), + currency: ad.cur, + width: Number(ad.creative_width), + height: Number(ad.creative_height), + ad: creative, + ttl: Number(ad.ttl) || 300, + creativeId: ad.creative_id, + netRevenue: true, + }; + if (ad.vast_xml) { + bid.vastXml = ad.vast_xml; + } + + return [bid]; + }, + + /** + * Register the user sync pixels which should be dropped after the auction. + * + * @param {SyncOptions} syncOptions Which user syncs are allowed? + * @param {ServerResponse[]} serverResponses List of server's responses. + * @return {UserSync[]} The user syncs which should be dropped. + */ + getUserSyncs: function (syncOptions, serverResponses) { + const syncs = []; + + if (serverResponses.length === 0) { + return syncs; + } + + serverResponses.forEach(res => { + const body = res.body; + if (syncOptions.pixelEnabled && Array.isArray(body.sync_urls)) { + body.sync_urls.forEach(url => { + syncs.push({ + type: 'image', + url: url + }) + }); + } + if (syncOptions.iframeEnabled && Array.isArray(body.sync_iframe_urls)) { + body.sync_iframe_urls.forEach(url => { + syncs.push({ + type: 'iframe', + url: url + }) + }); + } + }); + + return syncs; + } +}; + +/** + * @param {BidRequest} req + * @return {string|null} + */ +function getSizes(req) { + /** @type {string[][]|undefined} */ + const sizes = req.sizes; + if (!sizes || sizes.length < 1) return null; + return sizes.filter(x => x.length === 2) + .map(x => `${x[0]}x${x[1]}`) + .join(','); +} + +/** + * @return {string} USD or JPY + */ +function getCurrency() { + if (config.getConfig('currency.adServerCurrency') && + config.getConfig('currency.adServerCurrency').toUpperCase() === 'USD') { + return 'USD'; + } + return 'JPY'; +} + +/** + * @param {string} adspotId + * @param {*} body + */ +function makeCreative(adspotId, body) { + return `
` + + `` + + `` + + ``; +} + +function safeJSONString(s) { + return s.replace(/&/g, '\\u0026') + .replace(/>/g, '\\u003e') + .replace(/', + creative_width: '300', + creative_height: '250', + ttl: 200, + cpm: 30, + cur: 'JPY', + pb_bid: '2b84475b5b636e', + }, + ], + }; + + const expectedResponse = { + // ad: '
', + cpm: 30, + creativeId: 'creative-1', + currency: 'JPY', + height: 250, + netRevenue: true, + requestId: '2b84475b5b636e', + ttl: 200, + width: 300, + }; + + const result = spec.interpretResponse({body: response}, bidderRequests); + expect(result).to.have.lengthOf(1); + expect(result[0]).to.include(expectedResponse); + expect(result[0].ad).to.be.a('string'); + }); + + it('handles no bid responses', function () { + const response = ''; + + const result = spec.interpretResponse({body: response}, bidderRequests); + expect(result).to.have.lengthOf(0); + }); + }); + + describe('getUserSyncs', function () { + const bidResponse = { + body: { + sync_urls: [ + 'https://sync1.example.com', + 'https://sync2.example.com', + ], + sync_iframe_urls: [ + 'https://sync3.example.com', + 'https://sync4.example.com', + ], + }, + }; + + it('should return pixel syncs', function () { + const syncs = spec.getUserSyncs({pixelEnabled: true, iframeEnabled: true}, [bidResponse]); + expect(syncs).to.deep.equal([ + { + type: 'image', + url: 'https://sync1.example.com', + }, + { + type: 'image', + url: 'https://sync2.example.com', + }, + { + type: 'iframe', + url: 'https://sync3.example.com', + }, + { + type: 'iframe', + url: 'https://sync4.example.com', + }, + ]); + }); + }) +}); From 492939481aac95c298c0f273be58b4e82b2e0f87 Mon Sep 17 00:00:00 2001 From: Junichi Hoshina Date: Wed, 2 Feb 2022 13:27:19 +0900 Subject: [PATCH 2/5] Add parameter ad_type --- modules/freakoutBidAdapter.md | 3 ++- test/spec/modules/freakoutBidAdapter_spec.js | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/freakoutBidAdapter.md b/modules/freakoutBidAdapter.md index 13dcc62ff9b..9f0c984d86a 100644 --- a/modules/freakoutBidAdapter.md +++ b/modules/freakoutBidAdapter.md @@ -30,7 +30,8 @@ var adUnits = [ bids: [{ bidder: 'freakout', params: { - adspot_id: 'NDgxOjUx' + adspot_id: 'NDgxOjUx', + ad_type: 14 } }] } diff --git a/test/spec/modules/freakoutBidAdapter_spec.js b/test/spec/modules/freakoutBidAdapter_spec.js index f94f41cdfa7..326ded41f82 100644 --- a/test/spec/modules/freakoutBidAdapter_spec.js +++ b/test/spec/modules/freakoutBidAdapter_spec.js @@ -18,7 +18,8 @@ describe('FreakOutAdapter', function () { let bid = { bidder: 'freakout', params: { - adspot_id: 'ABCD1234' + adspot_id: 'ABCD1234', + ad_type: 14 } }; @@ -39,7 +40,8 @@ describe('FreakOutAdapter', function () { { bidder: 'freakout', params: { - adspot_id: 'ABCD1234' + adspot_id: 'ABCD1234', + ad_type: 14 }, adUnitCode: 'adunit-code', sizes: [ @@ -64,7 +66,7 @@ describe('FreakOutAdapter', function () { const requests = spec.buildRequests(bidRequests, bidderRequest); expect(requests[0].url).to.equal(ENDPOINT); expect(requests[0].method).to.equal('GET'); - expect(requests[0].data).to.equal(`adspot_id=ABCD1234&media_url=https%3A%2F%2Fexample.com&hb=prebidjs&pb_ver=${prebid.version}&pb_adapter_ver=${ADAPTER_VERSION}&pb_tid=791e9d84-af92-4903-94da-24c7426d9d0c&pb_bid=2b84475b5b636e&cur=JPY&sizes=300x250%2C320x50%2C320x100&`); + expect(requests[0].data).to.equal(`adspot_id=ABCD1234&ad_type=14&media_url=https%3A%2F%2Fexample.com&hb=prebidjs&pb_ver=${prebid.version}&pb_adapter_ver=${ADAPTER_VERSION}&pb_tid=791e9d84-af92-4903-94da-24c7426d9d0c&pb_bid=2b84475b5b636e&cur=JPY&sizes=300x250%2C320x50%2C320x100&`); }); }); @@ -74,6 +76,7 @@ describe('FreakOutAdapter', function () { bidder: 'freakout', params: { adspot_id: 'ABCD1234', + ad_type: 14 }, adUnitCode: 'adunit-code', sizes: [ From aa3059ec02883f47b1d241ea631510de5b445b05 Mon Sep 17 00:00:00 2001 From: Junichi Hoshina Date: Thu, 18 Apr 2024 07:39:43 +0000 Subject: [PATCH 3/5] tryAppendQueryString fix import path --- modules/freakoutBidAdapter.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/freakoutBidAdapter.js b/modules/freakoutBidAdapter.js index 0344eb89adf..f71d0235773 100644 --- a/modules/freakoutBidAdapter.js +++ b/modules/freakoutBidAdapter.js @@ -1,7 +1,8 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {tryAppendQueryString, isEmpty} from '../src/utils.js'; +import {isEmpty} from '../src/utils.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; +import {tryAppendQueryString} from '../libraries/urlUtils/urlUtils.js'; const BIDDER_CODE = 'freakout'; const ENDPOINT = 'https://ad.rfp.fout.jp/ad'; From f376f061f9ee4c096e76c028252d92e5c8cbb626 Mon Sep 17 00:00:00 2001 From: Junichi Hoshina Date: Fri, 19 Apr 2024 06:18:05 +0000 Subject: [PATCH 4/5] Use ortb2Imp.ext.tid instead of transactionId --- modules/freakoutBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/freakoutBidAdapter.js b/modules/freakoutBidAdapter.js index f71d0235773..3dfe8947aa8 100644 --- a/modules/freakoutBidAdapter.js +++ b/modules/freakoutBidAdapter.js @@ -44,7 +44,7 @@ export const spec = { query = tryAppendQueryString(query, 'hb', 'prebidjs'); query = tryAppendQueryString(query, 'pb_ver', '$prebid.version$'); query = tryAppendQueryString(query, 'pb_adapter_ver', ADAPTER_VERSION); - query = tryAppendQueryString(query, 'pb_tid', req.transactionId); + query = tryAppendQueryString(query, 'pb_tid', req.ortb2Impl?.ext?.tid); query = tryAppendQueryString(query, 'pb_bid', req.bidId); query = tryAppendQueryString(query, 'cur', getCurrency()); query = tryAppendQueryString(query, 'sizes', getSizes(req)); From 408a63eb5781fdc44f7493362381b9ab82abe088 Mon Sep 17 00:00:00 2001 From: Junichi Hoshina Date: Thu, 25 Apr 2024 08:59:23 +0000 Subject: [PATCH 5/5] Fix test --- modules/freakoutBidAdapter.js | 2 +- test/spec/modules/freakoutBidAdapter_spec.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/freakoutBidAdapter.js b/modules/freakoutBidAdapter.js index 3dfe8947aa8..698bd7378fe 100644 --- a/modules/freakoutBidAdapter.js +++ b/modules/freakoutBidAdapter.js @@ -44,7 +44,7 @@ export const spec = { query = tryAppendQueryString(query, 'hb', 'prebidjs'); query = tryAppendQueryString(query, 'pb_ver', '$prebid.version$'); query = tryAppendQueryString(query, 'pb_adapter_ver', ADAPTER_VERSION); - query = tryAppendQueryString(query, 'pb_tid', req.ortb2Impl?.ext?.tid); + query = tryAppendQueryString(query, 'pb_tid', req.ortb2Imp?.ext?.tid); query = tryAppendQueryString(query, 'pb_bid', req.bidId); query = tryAppendQueryString(query, 'cur', getCurrency()); query = tryAppendQueryString(query, 'sizes', getSizes(req)); diff --git a/test/spec/modules/freakoutBidAdapter_spec.js b/test/spec/modules/freakoutBidAdapter_spec.js index 326ded41f82..a54706a8021 100644 --- a/test/spec/modules/freakoutBidAdapter_spec.js +++ b/test/spec/modules/freakoutBidAdapter_spec.js @@ -52,7 +52,11 @@ describe('FreakOutAdapter', function () { bidId: '2b84475b5b636e', bidderRequestId: '1f4001782ac16c', auctionId: 'aba03555-4802-4c45-9f15-05ffa8594cff', - transactionId: '791e9d84-af92-4903-94da-24c7426d9d0c' + ortb2Imp: { + ext: { + tid: '791e9d84-af92-4903-94da-24c7426d9d0c', + } + } }, ];