diff --git a/modules/seedingAllianceBidAdapter.js b/modules/seedingAllianceBidAdapter.js
index 64b9cd5d4aa..29953da7ffa 100755
--- a/modules/seedingAllianceBidAdapter.js
+++ b/modules/seedingAllianceBidAdapter.js
@@ -2,120 +2,111 @@
'use strict';
import { registerBidder } from '../src/adapters/bidderFactory.js';
-import { NATIVE } from '../src/mediaTypes.js';
-import { _map, deepSetValue, isEmpty, deepAccess } from '../src/utils.js';
+import { NATIVE, BANNER } from '../src/mediaTypes.js';
+import { _map, isArray, isEmpty, deepSetValue, replaceAuctionPrice } from '../src/utils.js';
import { config } from '../src/config.js';
import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
-const BIDDER_CODE = 'seedingAlliance';
const GVL_ID = 371;
+const BIDDER_CODE = 'seedingAlliance';
const DEFAULT_CUR = 'EUR';
const ENDPOINT_URL = 'https://b.nativendo.de/cds/rtb/bid?format=openrtb2.5&ssp=pb';
-const NATIVE_ASSET_IDS = {0: 'title', 1: 'body', 2: 'sponsoredBy', 3: 'image', 4: 'cta', 5: 'icon'};
+const NATIVE_ASSET_IDS = { 0: 'title', 1: 'body', 2: 'sponsoredBy', 3: 'image', 4: 'cta', 5: 'icon' };
const NATIVE_PARAMS = {
- title: {
- id: 0,
- name: 'title'
- },
-
- body: {
- id: 1,
- name: 'data',
- type: 2
- },
-
- sponsoredBy: {
- id: 2,
- name: 'data',
- type: 1
- },
-
- image: {
- id: 3,
- type: 3,
- name: 'img'
- },
-
- cta: {
- id: 4,
- type: 12,
- name: 'data'
- },
-
- icon: {
- id: 5,
- type: 1,
- name: 'img'
- }
+ title: { id: 0, name: 'title' },
+ body: { id: 1, name: 'data', type: 2 },
+ sponsoredBy: { id: 2, name: 'data', type: 1 },
+ image: { id: 3, type: 3, name: 'img' },
+ cta: { id: 4, type: 12, name: 'data' },
+ icon: { id: 5, type: 1, name: 'img' }
};
export const spec = {
code: BIDDER_CODE,
-
gvlid: GVL_ID,
+ supportedMediaTypes: [NATIVE, BANNER],
- supportedMediaTypes: [NATIVE],
-
- isBidRequestValid: function(bid) {
+ isBidRequestValid: function (bid) {
return !!bid.params.adUnitId;
},
- buildRequests: (validBidRequests, bidderRequest) => {
+ buildRequests: (validBidRequests = [], bidderRequest) => {
// convert Native ORTB definition to old-style prebid native definition
validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests);
- const pt = setOnAny(validBidRequests, 'params.pt') || setOnAny(validBidRequests, 'params.priceType') || 'net';
- const tid = bidderRequest.auctionId;
- const cur = [config.getConfig('currency.adServerCurrency') || DEFAULT_CUR];
let url = bidderRequest.refererInfo.page;
- const imp = validBidRequests.map((bid, id) => {
- const assets = _map(bid.nativeParams, (bidParams, key) => {
- const props = NATIVE_PARAMS[key];
-
- const asset = {
- required: bidParams.required & 1
- };
+ const imps = validBidRequests.map((bidRequest, id) => {
+ const imp = {
+ id: String(id + 1),
+ tagid: bidRequest.params.adUnitId
+ };
- if (props) {
- asset.id = props.id;
+ /**
+ * Native Ad
+ */
+ if (bidRequest.nativeParams) {
+ const assets = _map(bidRequest.nativeParams, (nativeAsset, key) => {
+ const props = NATIVE_PARAMS[key];
+
+ if (props) {
+ let wmin, hmin, w, h;
+ let aRatios = nativeAsset.aspect_ratios;
+
+ if (aRatios && aRatios[0]) {
+ aRatios = aRatios[0];
+ wmin = aRatios.min_width || 0;
+ hmin = aRatios.ratio_height * wmin / aRatios.ratio_width | 0;
+ }
- let w, h;
+ if (nativeAsset.sizes) {
+ const sizes = flatten(nativeAsset.sizes);
+ w = parseInt(sizes[0], 10);
+ h = parseInt(sizes[1], 10);
+ }
- if (bidParams.sizes) {
- w = bidParams.sizes[0];
- h = bidParams.sizes[1];
+ const asset = {
+ id: props.id,
+ required: nativeAsset.required & 1
+ };
+
+ asset[props.name] = {
+ len: nativeAsset.len,
+ type: props.type,
+ wmin,
+ hmin,
+ w,
+ h
+ };
+
+ return asset;
+ } else {
+ // TODO Filter impressions with required assets we don't support
}
+ }).filter(Boolean);
- asset[props.name] = {
- len: bidParams.len,
- type: props.type,
- w,
- h
- };
+ imp.native = {
+ request: {
+ assets
+ }
+ };
+ } else {
+ let sizes = transformSizes(bidRequest.sizes);
- return asset;
+ imp.banner = {
+ format: sizes,
+ w: sizes[0] ? sizes[0].w : 0,
+ h: sizes[0] ? sizes[0].h : 0
}
- })
- .filter(Boolean);
+ }
- if (bid.params.url) {
- url = bid.params.url;
+ if (bidRequest.params.url) {
+ url = bidRequest.params.url;
}
- return {
- id: String(id + 1),
- tagid: bid.params.adUnitId,
- tid: tid,
- pt: pt,
- native: {
- request: {
- assets
- }
- }
- };
+ return imp;
});
const request = {
@@ -123,12 +114,9 @@ export const spec = {
site: {
page: url
},
- device: {
- ua: navigator.userAgent
- },
- cur,
- imp,
- user: {},
+ cur: [config.getConfig('currency.adServerCurrency') || DEFAULT_CUR],
+ imp: imps,
+ tmax: bidderRequest.timeout,
regs: {
ext: {
gdpr: 0,
@@ -137,23 +125,22 @@ export const spec = {
}
};
- if (bidderRequest && bidderRequest.gdprConsent) {
+ if (bidderRequest.gdprConsent) {
+ request.user = {};
+
deepSetValue(request, 'user.ext.consent', bidderRequest.gdprConsent.consentString);
deepSetValue(request, 'regs.ext.gdpr', (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean' && bidderRequest.gdprConsent.gdprApplies) ? 1 : 0);
}
return {
method: 'POST',
- url: ENDPOINT_URL,
+ url: config.getConfig('seedingAlliance.endpoint') || ENDPOINT_URL,
data: JSON.stringify(request),
- options: {
- contentType: 'application/json'
- },
- bids: validBidRequests
+ bidRequests: validBidRequests
};
},
- interpretResponse: function(serverResponse, { bids }) {
+ interpretResponse: function (serverResponse, { bidRequests }) {
if (isEmpty(serverResponse.body)) {
return [];
}
@@ -165,35 +152,72 @@ export const spec = {
return result;
}, []) : [];
- return bids
- .map((bid, id) => {
+ return bidRequests
+ .map((bidRequest, id) => {
const bidResponse = bidResponses[id];
+ const type = bidRequest.nativeParams ? NATIVE : BANNER;
+
if (bidResponse) {
- return {
- requestId: bid.bidId,
+ const bidObject = {
+ requestId: bidRequest.bidId, // TODO get this value from response?
cpm: bidResponse.price,
creativeId: bidResponse.crid,
- ttl: 1000,
- netRevenue: (!bid.netRevenue || bid.netRevenue === 'net'),
+ ttl: 600,
+ netRevenue: true,
currency: cur,
- mediaType: NATIVE,
+ mediaType: type,
bidderCode: BIDDER_CODE,
- native: parseNative(bidResponse),
meta: {
advertiserDomains: bidResponse.adomain && bidResponse.adomain.length > 0 ? bidResponse.adomain : []
}
};
+
+ if (type === NATIVE) {
+ bidObject.native = parseNative(bidResponse);
+ bidObject.mediaType = NATIVE;
+ }
+
+ if (type === BANNER) {
+ bidObject.ad = replaceAuctionPrice(bidResponse.adm, bidResponse.price);
+ bidObject.width = bidResponse.w;
+ bidObject.height = bidResponse.h;
+ bidObject.mediaType = BANNER;
+ }
+
+ return bidObject;
}
})
.filter(Boolean);
}
};
-registerBidder(spec);
+function transformSizes(requestSizes) {
+ if (!isArray(requestSizes)) {
+ return [];
+ }
+
+ if (requestSizes.length === 2 && !isArray(requestSizes[0])) {
+ return [{
+ w: parseInt(requestSizes[0], 10),
+ h: parseInt(requestSizes[1], 10)
+ }];
+ } else if (isArray(requestSizes[0])) {
+ return requestSizes.map(item => ({
+ w: parseInt(item[0], 10),
+ h: parseInt(item[1], 10)
+ }));
+ }
+
+ return [];
+}
+
+function flatten(arr) {
+ return [].concat(...arr);
+}
function parseNative(bid) {
- const {assets, link, imptrackers} = bid.adm.native;
+ const { assets, link, imptrackers } = bid.adm.native;
let clickUrl = link.url.replace(/\$\{AUCTION_PRICE\}/g, bid.price);
@@ -228,15 +252,4 @@ function parseNative(bid) {
return result;
}
-function setOnAny(collection, key) {
- for (let i = 0, result; i < collection.length; i++) {
- result = deepAccess(collection[i], key);
- if (result) {
- return result;
- }
- }
-}
-
-function flatten(arr) {
- return [].concat(...arr);
-}
+registerBidder(spec);
diff --git a/test/spec/modules/seedingAllianceAdapter_spec.js b/test/spec/modules/seedingAllianceAdapter_spec.js
index 81af9546ff0..6086db01de4 100755
--- a/test/spec/modules/seedingAllianceAdapter_spec.js
+++ b/test/spec/modules/seedingAllianceAdapter_spec.js
@@ -38,7 +38,7 @@ describe('SeedingAlliance adapter', function () {
});
it('should have default request structure', function () {
- let keys = 'site,device,cur,imp,user,regs'.split(',');
+ let keys = 'site,cur,imp,regs'.split(',');
let validBidRequests = [{
bidId: 'bidId',
params: {}
@@ -60,14 +60,17 @@ describe('SeedingAlliance adapter', function () {
assert.equal(request.id, validBidRequests[0].auctionId);
});
- it('Verify the device', function () {
+ it('Verify the site url', function () {
+ let siteUrl = 'https://www.yourdomain.tld/your-directory/';
let validBidRequests = [{
bidId: 'bidId',
- params: {}
+ params: {
+ url: siteUrl
+ }
}];
let request = JSON.parse(spec.buildRequests(validBidRequests, { refererInfo: { referer: 'page' } }).data);
- assert.equal(request.device.ua, navigator.userAgent);
+ assert.equal(request.site.page, siteUrl);
});
it('Verify native asset ids', function () {
@@ -109,7 +112,7 @@ describe('SeedingAlliance adapter', function () {
});
describe('interpretResponse', function () {
- const goodResponse = {
+ const goodNativeResponse = {
body: {
cur: 'EUR',
id: '4b516b80-886e-4ec0-82ae-9209e6d625fb',
@@ -136,51 +139,91 @@ describe('SeedingAlliance adapter', function () {
]
}
};
+
+ const goodBannerResponse = {
+ body: {
+ cur: 'EUR',
+ id: 'b4516b80-886e-4ec0-82ae-9209e6d625fb',
+ seatbid: [
+ {
+ seat: 'seedingAlliance',
+ bid: [{
+ adm: '',
+ impid: 1,
+ price: 0.90,
+ h: 250,
+ w: 300
+ }]
+ }
+ ]
+ }
+ };
+
const badResponse = { body: {
cur: 'EUR',
id: '4b516b80-886e-4ec0-82ae-9209e6d625fb',
seatbid: []
}};
- const bidRequest = {
+ const bidNativeRequest = {
data: {},
- bids: [{ bidId: 'bidId1' }]
+ bidRequests: [{bidId: 'bidId1', nativeParams: {title: {required: true, len: 800}}}]
+ };
+
+ const bidBannerRequest = {
+ data: {},
+ bidRequests: [{bidId: 'bidId1', sizes: [300, 250]}]
};
it('should return null if body is missing or empty', function () {
- const result = spec.interpretResponse(badResponse, bidRequest);
+ const result = spec.interpretResponse(badResponse, bidNativeRequest);
assert.equal(result.length, 0);
delete badResponse.body
- const result1 = spec.interpretResponse(badResponse, bidRequest);
+ const result1 = spec.interpretResponse(badResponse, bidNativeRequest);
assert.equal(result.length, 0);
});
it('should return the correct params', function () {
- const result = spec.interpretResponse(goodResponse, bidRequest);
- const bid = goodResponse.body.seatbid[0].bid[0];
-
- assert.deepEqual(result[0].currency, goodResponse.body.cur);
- assert.deepEqual(result[0].requestId, bidRequest.bids[0].bidId);
- assert.deepEqual(result[0].cpm, bid.price);
- assert.deepEqual(result[0].creativeId, bid.crid);
- assert.deepEqual(result[0].mediaType, 'native');
- assert.deepEqual(result[0].bidderCode, 'seedingAlliance');
+ const resultNative = spec.interpretResponse(goodNativeResponse, bidNativeRequest);
+ const bidNative = goodNativeResponse.body.seatbid[0].bid[0];
+
+ assert.deepEqual(resultNative[0].bidderCode, 'seedingAlliance');
+ assert.deepEqual(resultNative[0].currency, goodNativeResponse.body.cur);
+ assert.deepEqual(resultNative[0].requestId, bidNativeRequest.bidRequests[0].bidId);
+ assert.deepEqual(resultNative[0].cpm, bidNative.price);
+ assert.deepEqual(resultNative[0].creativeId, bidNative.crid);
+ assert.deepEqual(resultNative[0].mediaType, 'native');
+
+ const resultBanner = spec.interpretResponse(goodBannerResponse, bidBannerRequest);
+
+ assert.deepEqual(resultBanner[0].bidderCode, 'seedingAlliance');
+ assert.deepEqual(resultBanner[0].mediaType, 'banner');
+ assert.deepEqual(resultBanner[0].width, bidBannerRequest.bidRequests[0].sizes[0]);
+ assert.deepEqual(resultBanner[0].height, bidBannerRequest.bidRequests[0].sizes[1]);
});
- it('should return the correct tracking links', function () {
- const result = spec.interpretResponse(goodResponse, bidRequest);
- const bid = goodResponse.body.seatbid[0].bid[0];
+ it('should return the correct native tracking links', function () {
+ const result = spec.interpretResponse(goodNativeResponse, bidNativeRequest);
+ const bid = goodNativeResponse.body.seatbid[0].bid[0];
const regExpPrice = new RegExp('price=' + bid.price);
result[0].native.clickTrackers.forEach(function (clickTracker) {
- assert.ok(clickTracker.search(regExpPrice) > -1);
+ assert.ok(clickTracker.search(regExpPrice) > -1);
});
result[0].native.impressionTrackers.forEach(function (impTracker) {
- assert.ok(impTracker.search(regExpPrice) > -1);
+ assert.ok(impTracker.search(regExpPrice) > -1);
});
});
+
+ it('should return the correct banner content', function () {
+ const result = spec.interpretResponse(goodBannerResponse, bidBannerRequest);
+ const bid = goodBannerResponse.body.seatbid[0].bid[0];
+ const regExpContent = new RegExp('');
+
+ assert.ok(result[0].ad.search(regExpContent) > -1);
+ });
});
});