Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ventes Bid Adapter: fix web placement support #7715

Merged
merged 12 commits into from
Nov 17, 2021
71 changes: 71 additions & 0 deletions modules/ventes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
layout: bidder
title: ventes
description: Prebid ventes Bidder Adapter
pbjs: false
biddercode: ventes
gdpr_supported: false
usp_supported: false
media_types: banner
coppa_supported: false
schain_supported: false
dchain_supported: false
prebid_member: false
---

### BidParams
{: .table .table-bordered .table-striped }
| Name | Scope | Description | Example | Type |
|-----------------|----------|-----------------------------------------------------------|----------------------------------------------|---------------|
| `placementId` | required | Placement ID from Ventes Avenues | `'VA-062-0013-0183'` | `string` |
| `publisherId` | required | Publisher ID from Ventes Avenues | `'VA-062'` | `string` |
| `user` | optional | Object that specifies information about an external user. | `user: { age: 25, gender: 0, dnt: true}` | `object` |
| `app` | optional | Object containing mobile app parameters. | `app : { id: 'app-id'}` | `object` |

#### User Object

{: .table .table-bordered .table-striped }
| Name | Description | Example | Type |
|-------------------|-------------------------------------------------------------------------------------------|-----------------------|-----------------------|
| `age` | The age of the user. | `35` | `integer` |
| `externalUid` | Specifies a string that corresponds to an external user ID for this user. | `'1234567890abcdefg'` | `string` |
| `segments` | Specifies the segments to which the user belongs. | `[1, 2]` | `Array<integer>` |
| `gender` | Specifies the gender of the user. Allowed values: Unknown: `0`; Male: `1`; Female: `2` | `1` | `integer` |
| `dnt` | Do not track flag. Indicates if tracking cookies should be disabled for this auction | `true` | `boolean` |
| `language` | Two-letter ANSI code for this user's language. | `EN` | `string` |


### Ad Unit Setup for Banner
```javascript
var adUnits = [
{
code: 'test-hb-ad-11111-1',
mediaTypes: {
banner: {
sizes: [
[300, 250]
]
}
},
bids: [{
bidder: 'ventes',
params: {
placementId: 'VA-062-0013-0183',
publisherId: '5cebea3c9eea646c7b623d5e',
IABCategories: "['IAB1', 'IAB5']",
device:{
ip: '123.145.167.189',
ifa:"AEBE52E7-03EE-455A-B3C4-E57283966239",
},
app: {
id: "agltb3B1Yi1pbmNyDAsSA0FwcBiJkfIUDA",
name: "Yahoo Weather",
bundle: 'com.kiloo.subwaysurf',
storeurl: 'https://play.google.com/store/apps/details?id=com.kiloo.subwaysurf&hl=en',
domain: 'somoaudience.com',
}
}
}]
}
]
```
168 changes: 104 additions & 64 deletions modules/ventesBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js';
import {convertCamelToUnderscore, isStr, isArray, isNumber, isPlainObject, replaceAuctionPrice} from '../src/utils.js';
import {
BANNER,
NATIVE,
VIDEO
} from '../src/mediaTypes.js';
import {
convertCamelToUnderscore,
isStr,
isArray,
isNumber,
isPlainObject,
replaceAuctionPrice
} from '../src/utils.js';
import find from 'core-js-pure/features/array/find.js';
import includes from 'core-js-pure/features/array/includes.js';
import {
registerBidder
} from '../src/adapters/bidderFactory.js';

const BID_METHOD = 'POST';
const BIDDER_URL = 'http://13.234.201.146:8088/va/ad';
const FIRST_PRICE = 1;
const NET_REVENUE = true;
const TTL = 10;
const USER_PARAMS = ['age', 'externalUid', 'segments', 'gender', 'dnt', 'language'];
const DEVICE_PARAMS = ['ua', 'geo', 'dnt', 'lmt', 'ip', 'ipv6', 'devicetype'];
const APP_DEVICE_PARAMS = ['geo', 'device_id']; // appid is collected separately

const DOMAIN_REGEX = new RegExp('//([^/]*)');

function groupBy(values, key) {
Expand All @@ -26,7 +33,11 @@ function groupBy(values, key) {

return Object
.keys(groups)
.map(id => ({id, key, values: groups[id]}));
.map(id => ({
id,
key,
values: groups[id]
}));
}

function validateMediaTypes(mediaTypes, allowedMediaTypes) {
Expand All @@ -45,22 +56,22 @@ function isBanner(mediaTypes) {

function validateBanner(banner) {
return isPlainObject(banner) &&
isArray(banner.sizes) &&
(banner.sizes.length > 0) &&
banner.sizes.every(validateMediaSizes);
isArray(banner.sizes) &&
(banner.sizes.length > 0) &&
banner.sizes.every(validateMediaSizes);
}

function validateMediaSizes(mediaSize) {
return isArray(mediaSize) &&
(mediaSize.length === 2) &&
mediaSize.every(size => (isNumber(size) && size >= 0));
(mediaSize.length === 2) &&
mediaSize.every(size => (isNumber(size) && size >= 0));
}

function hasUserInfo(bid) {
return !!bid.params.user;
}

function validateParameters(parameters, adUnit) {
function validateParameters(parameters) {
if (!(parameters.placementId)) {
return false;
}
Expand Down Expand Up @@ -101,8 +112,8 @@ function generateSiteFromAdUnitContext(bidRequests, adUnitContext) {

function validateServerRequest(serverRequest) {
return isPlainObject(serverRequest) &&
isPlainObject(serverRequest.data) &&
isArray(serverRequest.data.imp)
isPlainObject(serverRequest.data) &&
isArray(serverRequest.data.imp)
}

function createServerRequestFromAdUnits(adUnits, bidRequestId, adUnitContext) {
Expand All @@ -122,14 +133,15 @@ function generateBidRequestsFromAdUnits(bidRequests, bidRequestId, adUnitContext
let userObj = {};
if (userObjBid) {
Object.keys(userObjBid.params.user)
.filter(param => includes(USER_PARAMS, param))
.forEach((param) => {
let uparam = convertCamelToUnderscore(param);
if (param === 'segments' && isArray(userObjBid.params.user[param])) {
let segs = [];
userObjBid.params.user[param].forEach(val => {
if (isNumber(val)) {
segs.push({'id': val});
segs.push({
'id': val
});
} else if (isPlainObject(val)) {
segs.push(val);
}
Expand All @@ -146,7 +158,6 @@ function generateBidRequestsFromAdUnits(bidRequests, bidRequestId, adUnitContext
if (deviceObjBid && deviceObjBid.params && deviceObjBid.params.device) {
deviceObj = {};
Object.keys(deviceObjBid.params.device)
.filter(param => includes(DEVICE_PARAMS, param))
.forEach(param => deviceObj[param] = deviceObjBid.params.device[param]);
if (!deviceObjBid.hasOwnProperty('ua')) {
deviceObj.ua = navigator.userAgent;
Expand All @@ -159,37 +170,41 @@ function generateBidRequestsFromAdUnits(bidRequests, bidRequestId, adUnitContext
deviceObj.ua = navigator.userAgent;
deviceObj.language = navigator.language;
}
const appDeviceObjBid = find(bidRequests, hasAppInfo);
let appIdObj;
if (appDeviceObjBid && appDeviceObjBid.params && appDeviceObjBid.params.app && appDeviceObjBid.params.app.id) {
Object.keys(appDeviceObjBid.params.app)
.filter(param => includes(APP_DEVICE_PARAMS, param))
.forEach(param => appDeviceObjBid[param] = appDeviceObjBid.params.app[param]);
}

const payload = {}
payload.id = bidRequestId
payload.at = FIRST_PRICE
payload.at = 1
payload.cur = ['USD']
payload.imp = bidRequests.reduce(generateImpressionsFromAdUnit, [])
payload.site = generateSiteFromAdUnitContext(bidRequests, adUnitContext)
payload.device = deviceObj
if (appDeviceObjBid && payload.site != null) {
const appDeviceObjBid = find(bidRequests, hasAppInfo);
if (!appDeviceObjBid) {
payload.site = generateSiteFromAdUnitContext(bidRequests, adUnitContext)
} else {
let appIdObj;
if (appDeviceObjBid && appDeviceObjBid.params && appDeviceObjBid.params.app && appDeviceObjBid.params.app.id) {
appIdObj = {};
Object.keys(appDeviceObjBid.params.app)
.forEach(param => appIdObj[param] = appDeviceObjBid.params.app[param]);
}
payload.app = appIdObj;
}
payload.device = deviceObj;
payload.user = userObj
// payload.regs = getRegulationFromAdUnitContext(adUnitContext)
// payload.ext = generateBidRequestExtension()

return payload
}

function generateImpressionsFromAdUnit(acc, adUnit) {
const {bidId, mediaTypes, params} = adUnit;
const {placementId} = params;
const {
bidId,
mediaTypes,
params
} = adUnit;
const {
placementId
} = params;
const pmp = {};

if (placementId) pmp.deals = [{id: placementId}]
if (placementId) pmp.deals = [{ id: placementId }]

const imps = Object
.keys(mediaTypes)
Expand All @@ -204,21 +219,40 @@ function generateImpressionsFromAdUnit(acc, adUnit) {
}

function generateBannerFromAdUnit(impId, data, params) {
const {position, placementId} = params;
const {
position,
placementId
} = params;
const pos = position || 0;
const pmp = {};
const ext = {placementId};

if (placementId) pmp.deals = [{id: placementId}]
const ext = {
placementId
};

return data.sizes.map(([w, h]) => ({id: `${impId}`, banner: {format: [{w, h}], w, h, pos}, pmp, ext, tagid: placementId}));
if (placementId) pmp.deals = [{ id: placementId }]

return data.sizes.map(([w, h]) => ({
id: `${impId}`,
banner: {
format: [{
w,
h
}],
w,
h,
pos
},
pmp,
ext,
tagid: placementId
}));
}

function validateServerResponse(serverResponse) {
return isPlainObject(serverResponse) &&
isPlainObject(serverResponse.body) &&
isStr(serverResponse.body.cur) &&
isArray(serverResponse.body.seatbid);
isPlainObject(serverResponse.body) &&
isStr(serverResponse.body.cur) &&
isArray(serverResponse.body.seatbid);
}

function seatBidsToAds(seatBid, bidResponse, serverRequest) {
Expand All @@ -241,10 +275,8 @@ function validateBids(bid) {
return true;
}

const VAST_REGEXP = /VAST\s+version/;

function getMediaType(adm) {
const videoRegex = new RegExp(VAST_REGEXP);
const videoRegex = new RegExp(/VAST\s+version/);

if (videoRegex.test(adm)) {
return VIDEO;
Expand Down Expand Up @@ -273,14 +305,16 @@ function generateAdFromBid(bid, bidResponse) {
requestId: bid.impid,
cpm: bid.price,
currency: bidResponse.cur,
ttl: TTL,
ttl: 10,
creativeId: bid.crid,
mediaType: mediaType,
netRevenue: NET_REVENUE
netRevenue: true
};

if (bid.adomain) {
base.meta = { advertiserDomains: bid.adomain };
base.meta = {
advertiserDomains: bid.adomain
};
}

const size = getSizeFromBid(bid);
Expand All @@ -292,17 +326,21 @@ function generateAdFromBid(bid, bidResponse) {
width: size.width,
ad: creative.markup,
adUrl: creative.markupUrl,
// vastXml: isVideo && !isStr(creative.markupUrl) ? creative.markup : null,
// vastUrl: isVideo && isStr(creative.markupUrl) ? creative.markupUrl : null,
renderer: creative.renderer
};
}

function getSizeFromBid(bid) {
if (isNumber(bid.w) && isNumber(bid.h)) {
return { width: bid.w, height: bid.h };
return {
width: bid.w,
height: bid.h
};
}
return { width: null, height: null };
return {
width: null,
height: null
};
}

function getCreativeFromBid(bid) {
Expand Down Expand Up @@ -333,12 +371,12 @@ const venavenBidderSpec = {
const allowedBidderCodes = [this.code];

return isPlainObject(adUnit) &&
allowedBidderCodes.indexOf(adUnit.bidder) !== -1 &&
isStr(adUnit.adUnitCode) &&
isStr(adUnit.bidderRequestId) &&
isStr(adUnit.bidId) &&
validateMediaTypes(adUnit.mediaTypes, this.supportedMediaTypes) &&
validateParameters(adUnit.params, adUnit);
allowedBidderCodes.indexOf(adUnit.bidder) !== -1 &&
isStr(adUnit.adUnitCode) &&
isStr(adUnit.bidderRequestId) &&
isStr(adUnit.bidId) &&
validateMediaTypes(adUnit.mediaTypes, this.supportedMediaTypes) &&
validateParameters(adUnit.params);
},
buildRequests(bidRequests, bidderRequest) {
if (!bidRequests) return null;
Expand Down Expand Up @@ -367,4 +405,6 @@ const venavenBidderSpec = {

registerBidder(venavenBidderSpec);

export {venavenBidderSpec as spec};
export {
venavenBidderSpec as spec
};
1 change: 0 additions & 1 deletion modules/ventesBidAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ var adUnits = [
publisherId: '5cebea3c9eea646c7b623d5e',
IABCategories: "['IAB1', 'IAB5']",
device:{
ip: '123.145.167.189',
ifa:"AEBE52E7-03EE-455A-B3C4-E57283966239",
},
app: {
Expand Down