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

Equativ Bid Adapter: initial release, Smartadserver Bid Adapter: take lowest floor to send to endpoint #12326

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2f8a35c
add support of dsa
eszponder Aug 19, 2024
3120efd
Merge pull request #27 from smartadserver/dsa-2
eszponder Aug 19, 2024
9483a81
restore topics
eszponder Aug 19, 2024
5e04eae
Merge pull request #28 from smartadserver/dsa-2
eszponder Aug 19, 2024
6acff45
DSA fix for UT
eszponder Aug 20, 2024
55bbc9d
Merge pull request #29 from smartadserver/dsa-2
eszponder Aug 20, 2024
a0e1efe
Merge branch 'prebid:master' into master
krzysztofequativ Sep 2, 2024
b03579d
Merge branch 'prebid:master' into master
krzysztofequativ Sep 11, 2024
f618679
Merge branch 'prebid:master' into master
krzysztofequativ Oct 14, 2024
d5a3178
drafy of adapter
krzysztofequativ Sep 11, 2024
92091d4
fixes after dev test
krzysztofequativ Sep 12, 2024
23eac33
make world simpler
krzysztofequativ Sep 12, 2024
3a5eda0
fix prev commit
krzysztofequativ Sep 12, 2024
86a7845
return empty userSyncs array by default
krzysztofequativ Sep 12, 2024
52752e7
adjustments
janzych-smart Sep 16, 2024
b75a5c2
apply prettier
janzych-smart Sep 16, 2024
9ec6fe4
unit tests for Equativ adapter
janzych-smart Sep 17, 2024
259cba2
add dsp user sync
krzysztofequativ Sep 20, 2024
9a92f9d
add readme
krzysztofequativ Sep 20, 2024
811932c
body can be undef
krzysztofequativ Sep 20, 2024
ae67b8a
support additional br params
krzysztofequativ Sep 25, 2024
bc4e78a
remove user sync
krzysztofequativ Sep 27, 2024
3148ed8
do not send dt param
krzysztofequativ Oct 8, 2024
f08f05d
handle floors and network id
krzysztofequativ Oct 9, 2024
3fac9a9
handle empty media types
krzysztofequativ Oct 10, 2024
e65525d
get min floor
krzysztofequativ Oct 15, 2024
9ce2bc2
fix desc for u.t.
krzysztofequativ Oct 16, 2024
fb9b893
better name for u.t.
krzysztofequativ Oct 16, 2024
9f9c133
add u.t. for not supported media type
krzysztofequativ Oct 16, 2024
08e3c52
improve currency u.t.
krzysztofequativ Oct 16, 2024
0bc782c
updates after pr review
krzysztofequativ Oct 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions libraries/equativUtils/equativUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { VIDEO } from '../../src/mediaTypes.js';
import { deepAccess, isFn } from '../../src/utils.js';

const DEFAULT_FLOOR = 0.0;

/**
* Get floors from Prebid Price Floors module
*
* @param {object} bid Bid request object
* @param {string} currency Ad server currency
* @param {string} mediaType Bid media type
* @return {number} Floor price
*/
export function getBidFloor (bid, currency, mediaType) {
const floors = [];

if (isFn(bid.getFloor)) {
(deepAccess(bid, `mediaTypes.${mediaType}.${mediaType === VIDEO ? 'playerSize' : 'sizes'}`) || []).forEach(size => {
const floor = bid.getFloor({
currency: currency || 'USD',
mediaType,
size
}).floor;

floors.push(!isNaN(floor) ? floor : DEFAULT_FLOOR);
});
}

return floors.length ? Math.min(...floors) : DEFAULT_FLOOR;
}
133 changes: 133 additions & 0 deletions modules/equativBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { BANNER } from '../src/mediaTypes.js';
import { getBidFloor } from '../libraries/equativUtils/equativUtils.js'
import { ortbConverter } from '../libraries/ortbConverter/converter.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { deepAccess, deepSetValue, mergeDeep } from '../src/utils.js';

/**
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
* @typedef {import('../src/adapters/bidderFactory.js').ServerRequest} ServerRequest
*/

export const spec = {
code: 'equativ',
gvlid: 45,
supportedMediaTypes: [BANNER],

/**
* @param bidRequests
* @param bidderRequest
* @returns {ServerRequest[]}
*/
buildRequests: (bidRequests, bidderRequest) => {
return {
data: converter.toORTB({ bidderRequest, bidRequests }),
method: 'POST',
url: 'https://ssb-global.smartadserver.com/api/bid?callerId=169'
};
},

/**
* @param serverResponse
* @param bidRequest
* @returns {Bid[]}
*/
interpretResponse: (serverResponse, bidRequest) =>
converter.fromORTB({
request: bidRequest.data,
response: serverResponse.body,
}),

/**
* @param bidRequest
* @returns {boolean}
*/
isBidRequestValid: (bidRequest) => {
return !!(
deepAccess(bidRequest, 'params.networkId') ||
deepAccess(bidRequest, 'ortb2.site.publisher.id') ||
deepAccess(bidRequest, 'ortb2.app.publisher.id') ||
deepAccess(bidRequest, 'ortb2.dooh.publisher.id')
);
},

/**
* @param syncOptions
* @param serverResponse
* @returns {{type: string, url: string}[]}
*/
// getUserSyncs: (syncOptions, serverResponse) => {
// if (syncOptions.iframeEnabled && serverResponses[0]?.body.cSyncUrl) {
// return [
// {
// type: 'iframe',
// url: serverResponses[0].body.cSyncUrl,
// },
// ];
// }
// return (syncOptions.pixelEnabled && serverResponse.body?.dspPixels)
// ? serverResponse.body.dspPixels.map((pixel) => ({
// type: 'image',
// url: pixel,
// })) : [];
// },
};

export const converter = ortbConverter({
context: {
netRevenue: true,
ttl: 300,
},

imp(buildImp, bidRequest, context) {
const imp = buildImp(bidRequest, context);
const { siteId, pageId, formatId } = bidRequest.params;

delete imp.dt;

imp.bidfloor = imp.bidfloor || getBidFloor(bidRequest);
imp.secure = 1;
imp.tagid = bidRequest.adUnitCode;

if (siteId || pageId || formatId) {
const bidder = {};

if (siteId) {
bidder.siteId = siteId;
}

if (pageId) {
bidder.pageId = pageId;
}

if (formatId) {
bidder.formatId = formatId;
}

mergeDeep(imp, {
ext: { bidder },
});
}

return imp;
},

request(buildRequest, imps, bidderRequest, context) {
const bid = context.bidRequests[0];
const req = buildRequest(imps, bidderRequest, context);

if (deepAccess(bid, 'ortb2.site.publisher')) {
deepSetValue(req, 'site.publisher.id', bid.ortb2.site.publisher.id || bid.params.networkId);
} else if (deepAccess(bid, 'ortb2.app.publisher')) {
deepSetValue(req, 'app.publisher.id', bid.ortb2.app.publisher.id || bid.params.networkId);
} else if (deepAccess(bid, 'ortb2.dooh.publisher')) {
deepSetValue(req, 'dooh.publisher.id', bid.ortb2.dooh.publisher.id || bid.params.networkId);
} else {
deepSetValue(req, 'site.publisher.id', bid.params.networkId);
}

return req;
},
});

registerBidder(spec);
40 changes: 40 additions & 0 deletions modules/equativBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Overview

```
Module Name: Equativ Bidder Adapter (beta)
Module Type: Bidder Adapter
Maintainer: [email protected]
```

# Description

Connect to Equativ for bids.

The Equativ adapter requires setup and approval from the Equativ team. Please reach out to your technical account manager for more information.

# Test Parameters

## Web or In-app
```javascript
var adUnits = [
{
code: '/589236/banner_1',
mediaTypes: {
banner: {
sizes: [[300, 250]]
}
},
bids: [
{
bidder: 'equativ',
params: {
networkId: 13, // mandatory if no ortb2.(site or app).publisher.id set
siteId: 20743, // optional
pageId: 89653, // optional
formatId: 291, // optional
}
}
]
}
];
```
35 changes: 6 additions & 29 deletions modules/smartadserverBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,23 @@ import {
isArray,
isArrayOfNums,
isEmpty,
isFn,
isInteger,
isPlainObject,
logError
} from '../src/utils.js';
import { BANNER, VIDEO } from '../src/mediaTypes.js';
import { config } from '../src/config.js';
import { getBidFloor } from '../libraries/equativUtils/equativUtils.js'
import { registerBidder } from '../src/adapters/bidderFactory.js';

/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
* @typedef {import('../src/adapters/bidderFactory.js').ServerRequest} ServerRequest
* @typedef {import('../src/adapters/bidderFactory.js').UserSync} UserSync
*/

const BIDDER_CODE = 'smartadserver';
const GVL_ID = 45;
const DEFAULT_FLOOR = 0.0;

export const spec = {
code: BIDDER_CODE,
Expand Down Expand Up @@ -176,7 +175,7 @@ export const spec = {
* Makes server requests from the list of BidRequests.
*
* @param {BidRequest[]} validBidRequests an array of bids
* @param {BidderRequest} bidderRequest bidder request object
* @param {BidRequest} bidderRequest bidder request object
* @return {ServerRequest[]} Info describing the request to the server.
*/
buildRequests: function (validBidRequests, bidderRequest) {
Expand Down Expand Up @@ -257,15 +256,15 @@ export const spec = {
if (isSupportedVideoContext) {
let videoPayload = deepClone(payload);
spec.fillPayloadForVideoBidRequest(videoPayload, videoMediaType, bid.params.video);
videoPayload.bidfloor = bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency, VIDEO);
videoPayload.bidfloor = bid.params.bidfloor || getBidFloor(bid, adServerCurrency, VIDEO);
bidRequests.push(spec.createServerRequest(videoPayload, bid.params.domain));
}
} else {
type = VIDEO;
spec.fillPayloadForVideoBidRequest(payload, videoMediaType, bid.params.video);
}

payload.bidfloor = bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency, type);
payload.bidfloor = bid.params.bidfloor || getBidFloor(bid, adServerCurrency, type);
bidRequests.push(spec.createServerRequest(payload, bid.params.domain));
} else {
bidRequests.push({});
Expand Down Expand Up @@ -324,34 +323,12 @@ export const spec = {
return bidResponses;
},

/**
* Get floors from Prebid Price Floors module
*
* @param {object} bid Bid request object
* @param {string} currency Ad server currency
* @param {string} mediaType Bid media type
* @return {number} Floor price
*/
getBidFloor: function (bid, currency, mediaType) {
if (!isFn(bid.getFloor)) {
return DEFAULT_FLOOR;
}

const floor = bid.getFloor({
currency: currency || 'USD',
mediaType,
size: '*'
});

return isPlainObject(floor) && !isNaN(floor.floor) ? floor.floor : DEFAULT_FLOOR;
},

/**
* User syncs.
*
* @param {*} syncOptions Publisher prebid configuration.
* @param {*} serverResponses A successful response from the server.
* @return {syncs[]} An array of syncs that should be executed.
* @return {UserSync[]} An array of syncs that should be executed.
*/
getUserSyncs: function (syncOptions, serverResponses) {
const syncs = [];
Expand Down
Loading