diff --git a/integrationExamples/gpt/pbjs_ucfunnel_gpt.html b/integrationExamples/gpt/pbjs_ucfunnel_gpt.html
deleted file mode 100644
index cb33a887c23..00000000000
--- a/integrationExamples/gpt/pbjs_ucfunnel_gpt.html
+++ /dev/null
@@ -1,97 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Prebid.js Test
-Div-1
-
-
-
-
-
-
-
-
diff --git a/modules/ucfunnelBidAdapter.js b/modules/ucfunnelBidAdapter.js
index c9548a280a0..d0ed7044242 100644
--- a/modules/ucfunnelBidAdapter.js
+++ b/modules/ucfunnelBidAdapter.js
@@ -1,21 +1,38 @@
import * as utils from 'src/utils';
import {registerBidder} from 'src/adapters/bidderFactory';
-import { BANNER } from 'src/mediaTypes';
+import {BANNER, VIDEO, NATIVE} from 'src/mediaTypes';
const VER = 'ADGENT_PREBID-2018011501';
-const BID_REQUEST_BASE_URL = '//hb.aralego.com/header';
-const UCFUNNEL_BIDDER_CODE = 'ucfunnel';
+const BIDDER_CODE = 'ucfunnel';
+
+const VIDEO_CONTEXT = {
+ INSTREAM: 0,
+ OUSTREAM: 2
+}
export const spec = {
- code: UCFUNNEL_BIDDER_CODE,
- supportedMediaTypes: [BANNER],
+ code: BIDDER_CODE,
+ ENDPOINT: '//hb.aralego.com/header',
+ supportedMediaTypes: [BANNER, VIDEO, NATIVE],
/**
* Check if the bid is a valid zone ID in either number or string form
* @param {object} bid the ucfunnel bid to validate
* @return boolean for whether or not a bid is valid
*/
isBidRequestValid: function(bid) {
- return !!(bid && bid.params && bid.params.adid && typeof bid.params.adid === 'string');
+ const isVideoMediaType = utils.deepAccess(bid, 'mediaTypes.video');
+ const videoContext = utils.deepAccess(bid, 'mediaTypes.video.context');
+
+ if (typeof bid.params !== 'object' || typeof bid.params.adid != 'string') {
+ return false;
+ }
+
+ if (isVideoMediaType && videoContext === 'outstream') {
+ utils.logWarn('Warning: outstream video is not supported yet');
+ return false;
+ }
+
+ return true;
},
/**
@@ -23,21 +40,15 @@ export const spec = {
* @param {*} bidderRequest
* @return {ServerRequest}
*/
- buildRequests: function(validBidRequests, bidderRequest) {
- var bidRequests = [];
- for (var i = 0; i < validBidRequests.length; i++) {
- var bid = validBidRequests[i];
-
- var ucfunnelUrlParams = buildUrlParams(bid, bidderRequest);
-
- bidRequests.push({
+ buildRequests: function(bids, bidderRequest) {
+ return bids.map(bid => {
+ return {
method: 'GET',
- url: BID_REQUEST_BASE_URL,
- bidRequest: bid,
- data: ucfunnelUrlParams
- });
- }
- return bidRequests;
+ url: location.protocol + spec.ENDPOINT,
+ data: getRequestData(bid, bidderRequest),
+ bidRequest: bid
+ }
+ });
},
/**
@@ -46,55 +57,151 @@ export const spec = {
* @return {Bid[]} An array of formatted bids.
*/
interpretResponse: function (ucfunnelResponseObj, request) {
- var bidResponses = [];
- var bidRequest = request.bidRequest;
- var responseBody = ucfunnelResponseObj ? ucfunnelResponseObj.body : {};
+ const bidRequest = request.bidRequest;
+ const ad = ucfunnelResponseObj ? ucfunnelResponseObj.body : {};
+ const videoPlayerSize = parseSizes(bidRequest);
- bidResponses.push({
+ let bid = {
requestId: bidRequest.bidId,
- cpm: responseBody.cpm || 0,
- width: responseBody.width,
- height: responseBody.height,
- creativeId: responseBody.ad_id,
- dealId: responseBody.deal || null,
+ cpm: ad.cpm || 0,
+ creativeId: ad.ad_id,
+ dealId: ad.deal || null,
currency: 'USD',
netRevenue: true,
- ttl: 1000,
- mediaType: BANNER,
- ad: responseBody.adm
- });
+ ttl: 1000
+ };
+
+ if (ad.creative_type) {
+ bid.mediaType = ad.creative_type;
+ }
+
+ switch (ad.creative_type) {
+ case NATIVE:
+ let nativeAd = ad.native;
+ Object.assign(bid, {
+ width: 1,
+ height: 1,
+ native: {
+ title: nativeAd.title,
+ body: nativeAd.desc,
+ cta: nativeAd.ctatext,
+ sponsoredBy: nativeAd.sponsored,
+ image: nativeAd.image || nativeAd.image.url,
+ icon: nativeAd.icon || nativeAd.icon.url,
+ clickUrl: nativeAd.clickUrl,
+ impressionTrackers: nativeAd.impressionTrackers,
+ }
+ });
+ break;
+ case VIDEO:
+ Object.assign(bid, {
+ vastUrl: ad.vastUrl,
+ vastXml: ad.vastXml
+ });
+
+ if (videoPlayerSize && videoPlayerSize.length === 2) {
+ Object.assign(bid, {
+ width: videoPlayerSize[0],
+ height: videoPlayerSize[1]
+ });
+ }
+ break;
+ case BANNER:
+ default:
+ Object.assign(bid, {
+ width: ad.width,
+ height: ad.height,
+ ad: ad.adm
+ });
+ }
+
+ return [bid];
+ },
- return bidResponses;
+ getUserSyncs: function(syncOptions) {
+ if (syncOptions.iframeEnabled) {
+ return [{
+ type: 'iframe',
+ url: '//cdn.aralego.com/ucfad/cookie/sync.html'
+ }];
+ } else if (syncOptions.pixelEnabled) {
+ return [{
+ type: 'image',
+ url: '//sync.aralego.com/idSync'
+ }];
+ }
}
};
registerBidder(spec);
-function buildUrlParams(bid, bidderRequest) {
- const host = utils.getTopWindowLocation().host;
- const page = utils.getTopWindowLocation().pathname;
- const refer = document.referrer;
+function transformSizes(requestSizes) {
+ if (utils.isArray(requestSizes) && requestSizes.length === 2 && !utils.isArray(requestSizes[0])) {
+ return [parseInt(requestSizes[0], 10), parseInt(requestSizes[1], 10)];
+ } else if (typeof requestSizes === 'object' && requestSizes.length) {
+ return requestSizes[0];
+ }
+}
+
+function parseSizes(bid) {
+ let params = bid.params;
+ if (bid.mediaType === VIDEO) {
+ let size = [];
+ if (params.video && params.video.playerWidth && params.video.playerHeight) {
+ size = [
+ params.video.playerWidth,
+ params.video.playerHeight
+ ];
+ return size;
+ }
+ }
+
+ return transformSizes(bid.sizes);
+}
+
+function getRequestData(bid, bidderRequest) {
+ const size = parseSizes(bid);
+ const loc = utils.getTopWindowLocation();
+ const host = loc.host;
+ const page = loc.href;
+ const ref = utils.getTopWindowReferrer();
const language = navigator.language;
const dnt = (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0;
+ const videoContext = utils.deepAccess(bid, 'mediaTypes.video.context');
+ const videoMediaType = utils.deepAccess(bid, 'mediaTypes.video');
- let queryString = [
- 'ifr', '0',
- 'bl', language,
- 'je', '1',
- 'dnt', dnt,
- 'host', host,
- 'u', page,
- 'ru', refer,
- 'adid', utils.getBidIdParameter('adid', bid.params),
- 'ver', VER
- ];
+ // general bid data
+ let bidData = {
+ ver: VER,
+ ifr: 0,
+ bl: language,
+ je: 1,
+ dnt: dnt,
+ host: host,
+ u: page,
+ ru: ref,
+ adid: utils.getBidIdParameter('adid', bid.params),
+ w: size[0],
+ h: size[1]
+ };
+
+ if (bid.mediaType === 'video' || videoMediaType) {
+ switch (videoContext) {
+ case 'outstream':
+ bidData.atype = VIDEO_CONTEXT.OUSTREAM;
+ break;
+ case 'instream':
+ default:
+ bidData.atype = VIDEO_CONTEXT.INSTREAM;
+ break;
+ }
+ }
if (bidderRequest && bidderRequest.gdprConsent) {
- queryString.push('gdpr', bidderRequest.gdprConsent.gdprApplies ? 1 : 0);
- queryString.push('euconsent', bidderRequest.gdprConsent.consentString);
+ Object.assign(bidData, {
+ gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0,
+ euconsent: bidderRequest.gdprConsent.consentString
+ });
}
- return queryString.reduce(
- (memo, curr, index) =>
- index % 2 === 0 && queryString[index + 1] !== undefined ? memo + curr + '=' + encodeURIComponent(queryString[index + 1]) + '&' : memo, ''
- ).slice(0, -1);
+ return bidData;
}
diff --git a/test/spec/modules/ucfunnelBidAdapter_spec.js b/test/spec/modules/ucfunnelBidAdapter_spec.js
index 152c7c39b1e..e8a4624bf16 100644
--- a/test/spec/modules/ucfunnelBidAdapter_spec.js
+++ b/test/spec/modules/ucfunnelBidAdapter_spec.js
@@ -1,19 +1,20 @@
import { expect } from 'chai';
import { spec } from 'modules/ucfunnelBidAdapter';
+import {BANNER, VIDEO, NATIVE} from 'src/mediaTypes';
const URL = '//hb.aralego.com/header';
const BIDDER_CODE = 'ucfunnel';
-const validBidReq = {
+const validBannerBidReq = {
bidder: BIDDER_CODE,
params: {
- adid: 'test-ad-83444226E44368D1E32E49EEBE6D29'
+ adid: 'ad-34BBD2AA24B678BBFD4E7B9EE3B872D'
},
sizes: [[300, 250]],
bidId: '263be71e91dd9d',
auctionId: '9ad1fa8d-2297-4660-a018-b39945054746',
};
-const invalidBidReq = {
+const invalidBannerBidReq = {
bidder: BIDDER_CODE,
params: {
adid: 123456789
@@ -23,86 +24,166 @@ const invalidBidReq = {
auctionId: '9ad1fa8d-2297-4660-a018-b39945054746'
};
-const bidReq = [{
+const validBannerBidRes = {
+ creative_type: BANNER,
+ ad_id: 'ad-34BBD2AA24B678BBFD4E7B9EE3B872D',
+ adm: '',
+ cpm: 0.01,
+ height: 250,
+ width: 300
+};
+
+const validVideoBidReq = {
bidder: BIDDER_CODE,
params: {
- adid: 'test-ad-83444226E44368D1E32E49EEBE6D29'
+ adid: 'ad-9A22D466494297EAC443D967B2622DA9'
},
- sizes: [[300, 250]],
- bidId: '263be71e91dd9d',
- auctionId: '9ad1fa8d-2297-4660-a018-b39945054746'
-}];
+ sizes: [[640, 360]],
+ bidId: '263be71e91dd9f',
+ auctionId: '9ad1fa8d-2297-4660-a018-b39945054746',
+};
-const validBidRes = {
- ad_id: 'ad-83444226E44368D1E32E49EEBE6D29',
- adm: '',
+const validVideoBidRes = {
+ creative_type: VIDEO,
+ ad_id: 'ad-9A22D466494297EAC443D967B2622DA9',
+ vastUrl: 'https://ads.aralego.com/ads/58f9749f-0553-4993-8d9a-013a38b29e55',
+ vastXml: 'ucX I-Primo 00:00:30',
cpm: 0.01,
- height: 250,
- width: 300
+ width: 640,
+ height: 360
};
-const bidResponse = validBidRes;
-
-const bidResArray = [
- validBidRes,
- {
- ad: '',
- bidRequestId: '263be71e91dd9d',
- cpm: 100,
- adId: '123abc',
- currency: 'USD',
- netRevenue: true,
- width: 300,
- height: 250,
- ttl: 360
+const validNativeBidReq = {
+ bidder: BIDDER_CODE,
+ params: {
+ adid: 'ad-627736446B2BD3A60E8AEABDB7BD833E'
},
- {
- ad: 'Hello
',
- bidRequestId: '',
- cpm: 0,
- adId: '123abc',
- currency: 'USD',
- netRevenue: true,
- width: 300,
- height: 250,
- ttl: 360
- }
-];
+ sizes: [[1, 1]],
+ bidId: '263be71e91dda0',
+ auctionId: '9ad1fa8d-2297-4660-a018-b39945054746',
+};
+
+const validNativeBidRes = {
+ creative_type: NATIVE,
+ ad_id: 'ad-9A22D466494297EAC443D967B2622DA9',
+ native: {
+ title: 'ucfunnel adExchange',
+ body: 'We monetize your traffic via historic data driven protocol',
+ cta: 'Learn more',
+ sponsoredBy: 'ucfunnel Co., Ltd.',
+ image: {
+ url: 'https://cdn.aralego.net/img/main/AdGent-1200x627.jpg',
+ width: 1200,
+ height: 627
+ },
+ icon: {
+ url: 'https://cdn.aralego.net/img/logo/logo-84x84.jpg',
+ widt: 84,
+ heigh: 84
+ },
+ clickUrl: 'https://www.ucfunnel.com',
+ impressionTrackers: ['https://www.aralego.net/imp?mf=native&adid=ad-9A22D466494297EAC443D967B2622DA9&auc=9ad1fa8d-2297-4660-a018-b39945054746'],
+ },
+ cpm: 0.01,
+ height: 1,
+ width: 1
+};
describe('ucfunnel Adapter', () => {
describe('request', () => {
it('should validate bid request', () => {
- expect(spec.isBidRequestValid(validBidReq)).to.equal(true);
+ expect(spec.isBidRequestValid(validBannerBidReq)).to.equal(true);
});
it('should not validate incorrect bid request', () => {
- expect(spec.isBidRequestValid(invalidBidReq)).to.equal(false);
+ expect(spec.isBidRequestValid(invalidBannerBidReq)).to.equal(false);
});
});
describe('build request', () => {
- it('Verify bid request', () => {
- const request = spec.buildRequests(bidReq);
+ const request = spec.buildRequests([validBannerBidReq]);
+ it('should create a POST request for every bid', () => {
expect(request[0].method).to.equal('GET');
- expect(request[0].url).to.equal(URL);
- expect(request[0].data).to.match(new RegExp(`${bidReq[0].params.adid}`));
+ expect(request[0].url).to.equal(location.protocol + spec.ENDPOINT);
+ });
+
+ it('should attach the bid request object', () => {
+ expect(request[0].bidRequest).to.equal(validBannerBidReq);
+ });
+
+ it('should attach request data', () => {
+ const data = request[0].data;
+ const [ width, height ] = validBannerBidReq.sizes[0];
+ expect(data.w).to.equal(width);
+ expect(data.h).to.equal(height);
+ });
+
+ it('must parse bid size from a nested array', () => {
+ const width = 640;
+ const height = 480;
+ validBannerBidReq.sizes = [[ width, height ]];
+ const requests = spec.buildRequests([ validBannerBidReq ]);
+ const data = requests[0].data;
+ expect(data.w).to.equal(width);
+ expect(data.h).to.equal(height);
});
});
describe('interpretResponse', () => {
- it('should build bid array', () => {
- const request = spec.buildRequests(bidReq);
- const result = spec.interpretResponse({body: bidResponse}, request[0]);
- expect(result.length).to.equal(1);
+ describe('should support banner', () => {
+ const request = spec.buildRequests([ validBannerBidReq ]);
+ const result = spec.interpretResponse({body: validBannerBidRes}, request[0]);
+ it('should build bid array for banner', () => {
+ expect(result.length).to.equal(1);
+ });
+
+ it('should have all relevant fields', () => {
+ const bid = result[0];
+
+ expect(bid.mediaType).to.equal(BANNER);
+ expect(bid.ad).to.exist;
+ expect(bid.requestId).to.equal('263be71e91dd9d');
+ expect(bid.cpm).to.equal(0.01);
+ expect(bid.width).to.equal(300);
+ expect(bid.height).to.equal(250);
+ });
+ });
+
+ describe('should support video', () => {
+ const request = spec.buildRequests([ validVideoBidReq ]);
+ const result = spec.interpretResponse({body: validVideoBidRes}, request[0]);
+ it('should build bid array', () => {
+ expect(result.length).to.equal(1);
+ });
+
+ it('should have all relevant fields', () => {
+ const bid = result[0];
+
+ expect(bid.mediaType).to.equal(VIDEO);
+ expect(bid.vastUrl).to.exist;
+ expect(bid.vastXml).to.exist;
+ expect(bid.requestId).to.equal('263be71e91dd9f');
+ expect(bid.cpm).to.equal(0.01);
+ expect(bid.width).to.equal(640);
+ expect(bid.height).to.equal(360);
+ });
});
- it('should have all relevant fields', () => {
- const request = spec.buildRequests(bidReq);
- const result = spec.interpretResponse({body: bidResponse}, request[0]);
- const bid = result[0];
+ describe('should support native', () => {
+ const request = spec.buildRequests([ validNativeBidReq ]);
+ const result = spec.interpretResponse({body: validNativeBidRes}, request[0]);
+ it('should build bid array', () => {
+ expect(result.length).to.equal(1);
+ });
+
+ it('should have all relevant fields', () => {
+ const bid = result[0];
- expect(bid.requestId).to.equal('263be71e91dd9d');
- expect(bid.cpm).to.equal(0.01);
- expect(bid.width).to.equal(300);
- expect(bid.height).to.equal(250);
+ expect(bid.mediaType).to.equal(NATIVE);
+ expect(bid.native).to.exist;
+ expect(bid.requestId).to.equal('263be71e91dda0');
+ expect(bid.cpm).to.equal(0.01);
+ expect(bid.width).to.equal(1);
+ expect(bid.height).to.equal(1);
+ });
});
});
});