forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Dianomi Bid adapter: add new bid adapter (prebid#8519)
* start of dianomi adapter * improving adapter * Rename and add the missing "i" * our bidder supports native (or it will) * Updated dianomiAdapter * dianomi adapter update endpoint and smartadId paramter * removed nested request in buildRequests/native object to align better with ortb native 1.2 * dianomi adapter upddate, remove native {request} nesting * update md, tried to make it similar to adform's * updated urls to live endpoints * a couple little tweaks to md * added userSync and allow changing of endpoint * updated Maintainer email * added tests, need to look at coppa tests still as not sure if we should be testing that * couple of test changes * small change to tests * switched to v7 Co-authored-by: Michael Stevens <[email protected]> Co-authored-by: Chris Almeida-Symons <[email protected]> Co-authored-by: Martin Hill <[email protected]>
- Loading branch information
1 parent
485c500
commit e58de0f
Showing
3 changed files
with
1,665 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,369 @@ | ||
// jshint esversion: 6, es3: false, node: true | ||
'use strict'; | ||
|
||
import { registerBidder } from '../src/adapters/bidderFactory.js'; | ||
import { NATIVE, BANNER, VIDEO } from '../src/mediaTypes.js'; | ||
import { | ||
mergeDeep, | ||
_map, | ||
deepAccess, | ||
parseSizesInput, | ||
deepSetValue, | ||
formatQS, | ||
} from '../src/utils.js'; | ||
import { config } from '../src/config.js'; | ||
import { Renderer } from '../src/Renderer.js'; | ||
|
||
const { getConfig } = config; | ||
|
||
const BIDDER_CODE = 'dianomi'; | ||
const GVLID = 885; | ||
const BIDDER_ALIAS = [{ code: 'dia', gvlid: GVLID }]; | ||
const NATIVE_ASSET_IDS = { | ||
0: 'title', | ||
2: 'icon', | ||
3: 'image', | ||
5: 'sponsoredBy', | ||
4: 'body', | ||
1: 'cta', | ||
}; | ||
const NATIVE_PARAMS = { | ||
title: { | ||
id: 0, | ||
name: 'title', | ||
}, | ||
icon: { | ||
id: 2, | ||
type: 1, | ||
name: 'img', | ||
}, | ||
image: { | ||
id: 3, | ||
type: 3, | ||
name: 'img', | ||
}, | ||
sponsoredBy: { | ||
id: 5, | ||
name: 'data', | ||
type: 1, | ||
}, | ||
body: { | ||
id: 4, | ||
name: 'data', | ||
type: 2, | ||
}, | ||
cta: { | ||
id: 1, | ||
type: 12, | ||
name: 'data', | ||
}, | ||
}; | ||
let endpoint = 'www-prebid.dianomi.com'; | ||
|
||
const OUTSTREAM_RENDERER_URL = (hostname) => `https://${hostname}/prebid/outstream/renderer.js`; | ||
|
||
export const spec = { | ||
code: BIDDER_CODE, | ||
aliases: BIDDER_ALIAS, | ||
gvlid: GVLID, | ||
supportedMediaTypes: [NATIVE, BANNER, VIDEO], | ||
isBidRequestValid: (bid) => { | ||
const params = bid.params || {}; | ||
const { smartadId } = params; | ||
return !!smartadId; | ||
}, | ||
buildRequests: (validBidRequests, bidderRequest) => { | ||
let app, site; | ||
|
||
const commonFpd = bidderRequest.ortb2 || {}; | ||
let { user } = commonFpd; | ||
|
||
if (typeof getConfig('app') === 'object') { | ||
app = getConfig('app') || {}; | ||
if (commonFpd.app) { | ||
mergeDeep(app, commonFpd.app); | ||
} | ||
} else { | ||
site = getConfig('site') || {}; | ||
if (commonFpd.site) { | ||
mergeDeep(site, commonFpd.site); | ||
} | ||
|
||
if (!site.page) { | ||
site.page = bidderRequest.refererInfo.page; | ||
} | ||
} | ||
|
||
const device = getConfig('device') || {}; | ||
device.w = device.w || window.innerWidth; | ||
device.h = device.h || window.innerHeight; | ||
device.ua = device.ua || navigator.userAgent; | ||
|
||
const paramsEndpoint = setOnAny(validBidRequests, 'params.endpoint'); | ||
|
||
if (paramsEndpoint) { | ||
endpoint = paramsEndpoint; | ||
} | ||
|
||
const pt = | ||
setOnAny(validBidRequests, 'params.pt') || | ||
setOnAny(validBidRequests, 'params.priceType') || | ||
'net'; | ||
const tid = validBidRequests[0].transactionId; | ||
const currency = getConfig('currency.adServerCurrency'); | ||
const cur = currency && [currency]; | ||
const eids = setOnAny(validBidRequests, 'userIdAsEids'); | ||
const schain = setOnAny(validBidRequests, 'schain'); | ||
|
||
const imp = validBidRequests.map((bid, id) => { | ||
bid.netRevenue = pt; | ||
|
||
const floorInfo = bid.getFloor | ||
? bid.getFloor({ | ||
currency: currency || 'USD', | ||
}) | ||
: {}; | ||
const bidfloor = floorInfo.floor; | ||
const bidfloorcur = floorInfo.currency; | ||
const { smartadId } = bid.params; | ||
|
||
const imp = { | ||
id: id + 1, | ||
tagid: smartadId, | ||
bidfloor, | ||
bidfloorcur, | ||
ext: { | ||
bidder: { | ||
smartadId: smartadId, | ||
}, | ||
}, | ||
}; | ||
|
||
const assets = _map(bid.nativeParams, (bidParams, key) => { | ||
const props = NATIVE_PARAMS[key]; | ||
const asset = { | ||
required: bidParams.required & 1, | ||
}; | ||
if (props) { | ||
asset.id = props.id; | ||
let wmin, hmin, w, h; | ||
let aRatios = bidParams.aspect_ratios; | ||
|
||
if (aRatios && aRatios[0]) { | ||
aRatios = aRatios[0]; | ||
wmin = aRatios.min_width || 0; | ||
hmin = ((aRatios.ratio_height * wmin) / aRatios.ratio_width) | 0; | ||
} | ||
|
||
if (bidParams.sizes) { | ||
const sizes = flatten(bidParams.sizes); | ||
w = sizes[0]; | ||
h = sizes[1]; | ||
} | ||
|
||
asset[props.name] = { | ||
len: bidParams.len, | ||
type: props.type, | ||
wmin, | ||
hmin, | ||
w, | ||
h, | ||
}; | ||
|
||
return asset; | ||
} | ||
}).filter(Boolean); | ||
|
||
if (assets.length) { | ||
imp.native = { | ||
assets, | ||
}; | ||
} | ||
|
||
const bannerParams = deepAccess(bid, 'mediaTypes.banner'); | ||
|
||
if (bannerParams && bannerParams.sizes) { | ||
const sizes = parseSizesInput(bannerParams.sizes); | ||
const format = sizes.map((size) => { | ||
const [width, height] = size.split('x'); | ||
const w = parseInt(width, 10); | ||
const h = parseInt(height, 10); | ||
return { w, h }; | ||
}); | ||
|
||
imp.banner = { | ||
format, | ||
}; | ||
} | ||
|
||
const videoParams = deepAccess(bid, 'mediaTypes.video'); | ||
if (videoParams) { | ||
imp.video = videoParams; | ||
} | ||
|
||
return imp; | ||
}); | ||
|
||
const request = { | ||
id: bidderRequest.auctionId, | ||
site, | ||
app, | ||
user, | ||
device, | ||
source: { tid, fd: 1 }, | ||
ext: { pt }, | ||
cur, | ||
imp, | ||
}; | ||
|
||
if (deepAccess(bidderRequest, 'gdprConsent.gdprApplies') !== undefined) { | ||
deepSetValue(request, 'user.ext.consent', bidderRequest.gdprConsent.consentString); | ||
deepSetValue(request, 'regs.ext.gdpr', bidderRequest.gdprConsent.gdprApplies & 1); | ||
} | ||
|
||
if (bidderRequest.uspConsent) { | ||
deepSetValue(request, 'regs.ext.us_privacy', bidderRequest.uspConsent); | ||
} | ||
|
||
if (eids) { | ||
deepSetValue(request, 'user.ext.eids', eids); | ||
} | ||
|
||
if (schain) { | ||
deepSetValue(request, 'source.ext.schain', schain); | ||
} | ||
|
||
return { | ||
method: 'POST', | ||
url: 'https://' + endpoint + '/cgi-bin/smartads_prebid.pl', | ||
data: JSON.stringify(request), | ||
bids: validBidRequests, | ||
}; | ||
}, | ||
interpretResponse: function (serverResponse, { bids }) { | ||
if (!serverResponse.body || serverResponse?.body?.nbr) { | ||
return; | ||
} | ||
const { seatbid, cur } = serverResponse.body; | ||
|
||
const bidResponses = flatten(seatbid.map((seat) => seat.bid)).reduce((result, bid) => { | ||
result[bid.impid - 1] = bid; | ||
return result; | ||
}, []); | ||
|
||
return bids | ||
.map((bid, id) => { | ||
const bidResponse = bidResponses[id]; | ||
if (bidResponse) { | ||
const mediaType = deepAccess(bidResponse, 'ext.prebid.type'); | ||
const result = { | ||
requestId: bid.bidId, | ||
cpm: bidResponse.price, | ||
creativeId: bidResponse.crid, | ||
ttl: 360, | ||
netRevenue: bid.netRevenue === 'net', | ||
currency: cur, | ||
mediaType, | ||
width: bidResponse.w, | ||
height: bidResponse.h, | ||
dealId: bidResponse.dealid, | ||
meta: { | ||
mediaType, | ||
advertiserDomains: bidResponse.adomain, | ||
}, | ||
}; | ||
|
||
if (bidResponse.native) { | ||
result.native = parseNative(bidResponse); | ||
} else { | ||
result[mediaType === VIDEO ? 'vastXml' : 'ad'] = bidResponse.adm; | ||
} | ||
|
||
if ( | ||
!bid.renderer && | ||
mediaType === VIDEO && | ||
deepAccess(bid, 'mediaTypes.video.context') === 'outstream' | ||
) { | ||
result.renderer = Renderer.install({ | ||
id: bid.bidId, | ||
url: OUTSTREAM_RENDERER_URL(endpoint), | ||
adUnitCode: bid.adUnitCode, | ||
}); | ||
result.renderer.setRender(renderer); | ||
} | ||
|
||
return result; | ||
} | ||
}) | ||
.filter(Boolean); | ||
}, | ||
getUserSyncs: (syncOptions, responses, gdprConsent, uspConsent) => { | ||
if (syncOptions.iframeEnabled) { | ||
// data is only assigned if params are available to pass to syncEndpoint | ||
const params = {}; | ||
|
||
if (gdprConsent) { | ||
if (typeof gdprConsent.gdprApplies === 'boolean') { | ||
params['gdpr'] = Number(gdprConsent.gdprApplies); | ||
} | ||
if (typeof gdprConsent.consentString === 'string') { | ||
params['gdpr_consent'] = gdprConsent.consentString; | ||
} | ||
} | ||
|
||
if (uspConsent) { | ||
params['us_privacy'] = encodeURIComponent(uspConsent); | ||
} | ||
|
||
return { | ||
type: 'iframe', | ||
url: `https://${endpoint}/prebid/usersync/index.html?${formatQS(params)}`, | ||
}; | ||
} | ||
}, | ||
}; | ||
|
||
registerBidder(spec); | ||
|
||
function parseNative(bid) { | ||
const { assets, link, imptrackers, jstracker } = bid.native; | ||
const result = { | ||
clickUrl: link.url, | ||
clickTrackers: link.clicktrackers || undefined, | ||
impressionTrackers: imptrackers || undefined, | ||
javascriptTrackers: jstracker ? [jstracker] : undefined, | ||
}; | ||
assets.forEach((asset) => { | ||
const kind = NATIVE_ASSET_IDS[asset.id]; | ||
const content = kind && asset[NATIVE_PARAMS[kind].name]; | ||
if (content) { | ||
result[kind] = content.text || | ||
content.value || { | ||
url: content.url, | ||
width: content.w, | ||
height: content.h, | ||
}; | ||
} | ||
}); | ||
|
||
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); | ||
} | ||
|
||
function renderer(bid) { | ||
bid.renderer.push(() => { | ||
window.Dianomi.renderOutstream(bid); | ||
}); | ||
} |
Oops, something went wrong.