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

Delta Projects bid adapter: add new bid adapter #7564

Merged
merged 3 commits into from
Oct 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
252 changes: 252 additions & 0 deletions modules/deltaprojectsBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER } from '../src/mediaTypes.js';
import {
_each, _map, isFn, isNumber, createTrackPixelHtml, deepAccess, parseUrl, logWarn, logError
} from '../src/utils.js';
import {config} from '../src/config.js';

export const BIDDER_CODE = 'deltaprojects';
export const BIDDER_ENDPOINT_URL = 'https://d5p.de17a.com/dogfight/prebid';
export const USERSYNC_URL = 'https://userservice.de17a.com/getuid/prebid';

/** -- isBidRequestValid --**/
function isBidRequestValid(bid) {
if (!bid) return false;

if (bid.bidder !== BIDDER_CODE) return false;

// publisher id is required
const publisherId = deepAccess(bid, 'params.publisherId')
if (!publisherId) {
logError('Invalid bid request, missing publisher id in params');
return false;
}

return true;
}

/** -- Build requests --**/
function buildRequests(validBidRequests, bidderRequest) {
/** == shared ==**/
// -- build id
const id = bidderRequest.auctionId;

// -- build site
const loc = parseUrl(bidderRequest.refererInfo.referer);
const publisherId = setOnAny(validBidRequests, 'params.publisherId');
const siteId = setOnAny(validBidRequests, 'params.siteId');
const site = {
id: siteId,
domain: loc.hostname,
page: loc.href,
ref: loc.href,
publisher: { id: publisherId },
};

// -- build device
const ua = navigator.userAgent;
const device = {
ua,
w: screen.width,
h: screen.height
}

// -- build user, reg
let user = { ext: {} };
const regs = { ext: {} };
const gdprConsent = bidderRequest && bidderRequest.gdprConsent;
if (gdprConsent) {
user.ext = { consent: gdprConsent.consentString };
if (typeof gdprConsent.gdprApplies == 'boolean') {
regs.ext.gdpr = gdprConsent.gdprApplies ? 1 : 0
}
}

// -- build tmax
let tmax = (bidderRequest && bidderRequest.timeout > 0) ? bidderRequest.timeout : undefined;

// build bid specific
return validBidRequests.map(validBidRequest => {
const openRTBRequest = buildOpenRTBRequest(validBidRequest, id, site, device, user, tmax, regs);
return {
method: 'POST',
url: BIDDER_ENDPOINT_URL,
data: openRTBRequest,
options: { contentType: 'application/json' },
bids: [validBidRequest],
};
});
}

function buildOpenRTBRequest(validBidRequest, id, site, device, user, tmax, regs) {
// build cur
const currency = config.getConfig('currency.adServerCurrency') || deepAccess(validBidRequest, 'params.currency');
const cur = currency && [currency];

// build impression
const impression = buildImpression(validBidRequest, currency);

// build test
const test = deepAccess(validBidRequest, 'params.test') ? 1 : 0

const at = 1

// build source
const source = {
tid: validBidRequest.transactionId,
fd: 1,
}

return {
id,
at,
imp: [impression],
site,
device,
user,
test,
tmax,
cur,
source,
regs,
ext: {},
};
}

function buildImpression(bid, currency) {
const impression = {
id: bid.bidId,
tagid: bid.params.tagId,
ext: {},
};

const bannerMediaType = deepAccess(bid, `mediaTypes.${BANNER}`);
impression.banner = buildImpressionBanner(bid, bannerMediaType);

// bid floor
const bidFloor = getBidFloor(bid, BANNER, '*', currency);
if (bidFloor) {
impression.bidfloor = bidFloor.floor;
impression.bidfloorcur = bidFloor.currency;
}

return impression;
}

function buildImpressionBanner(bid, bannerMediaType) {
const bannerSizes = (bannerMediaType && bannerMediaType.sizes) || bid.sizes;
return {
format: _map(bannerSizes, ([width, height]) => ({ w: width, h: height })),
};
}

/** -- Interpret response --**/
function interpretResponse(serverResponse) {
if (!serverResponse.body) {
logWarn('Response body is invalid, return !!');
return [];
}

const { body: { id, seatbid, cur } } = serverResponse;
if (!id || !seatbid) {
logWarn('Id / seatbid of response is invalid, return !!');
return [];
}

const bidResponses = [];

_each(seatbid, seatbid => {
_each(seatbid.bid, bid => {
const bidObj = {
requestId: bid.impid,
cpm: parseFloat(bid.price),
width: parseInt(bid.w),
height: parseInt(bid.h),
creativeId: bid.crid || bid.id,
dealId: bid.dealid || null,
currency: cur,
netRevenue: true,
ttl: 60,
};

bidObj.mediaType = BANNER;
bidObj.ad = bid.adm;
if (bid.nurl) {
bidObj.ad += createTrackPixelHtml(decodeURIComponent(bid.nurl));
}
if (bid.ext) {
bidObj[BIDDER_CODE] = bid.ext;
}
bidResponses.push(bidObj);
});
});
return bidResponses;
}

/** -- On Bid Won -- **/
function onBidWon(bid) {
let cpm = bid.cpm;
if (bid.currency && bid.currency !== bid.originalCurrency && typeof bid.getCpmInNewCurrency === 'function') {
cpm = bid.getCpmInNewCurrency(bid.originalCurrency);
}
const wonPrice = Math.round(cpm * 1000000);
const wonPriceMacroPatten = /\$\{AUCTION_PRICE:B64\}/g;
bid.ad = bid.ad.replace(wonPriceMacroPatten, wonPrice);
}

/** -- Get user syncs --**/
function getUserSyncs(syncOptions, serverResponses, gdprConsent) {
const syncs = []

if (syncOptions.pixelEnabled) {
let gdprParams;
if (gdprConsent) {
if (typeof gdprConsent.gdprApplies === 'boolean') {
gdprParams = `?gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`;
} else {
gdprParams = `?gdpr_consent=${gdprConsent.consentString}`;
}
} else {
gdprParams = '';
}
syncs.push({
type: 'image',
url: USERSYNC_URL + gdprParams
});
}
return syncs;
}

/** -- Get bid floor --**/
export function getBidFloor(bid, mediaType, size, currency) {
if (isFn(bid.getFloor)) {
const bidFloorCurrency = currency || 'USD';
const bidFloor = bid.getFloor({currency: bidFloorCurrency, mediaType: mediaType, size: size});
if (isNumber(bidFloor.floor)) {
return bidFloor;
}
}
}

/** -- Helper methods --**/
function setOnAny(collection, key) {
for (let i = 0, result; i < collection.length; i++) {
result = deepAccess(collection[i], key);
if (result) {
return result;
}
}
}

/** -- Register -- */
export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER],
isBidRequestValid,
buildRequests,
interpretResponse,
onBidWon,
getUserSyncs,
};

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

```
Module Name: Delta Projects Bid Adapter
Module Type: Bidder Adapter
Maintainer: dev@deltaprojects.com
```

# Description

Connects to Delta Projects DSP for bids.

# Test Parameters
```
// define banner unit
var bannerUnit = {
code: 'div-gpt-ad-1460505748561-0',
mediaTypes: {
banner: {
sizes: [[300, 250], [300,600]],
}
},
// Replace this object to test a new Adapter!
bids: [{
bidder: 'deltaprojects',
params: {
publisherId: '4' //required
}
}]
};
```

Loading