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

Michao Bid Adapter: Initial release #12507

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
240 changes: 240 additions & 0 deletions modules/michaoBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
import { ortbConverter } from '../libraries/ortbConverter/converter.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { config } from '../src/config.js';
import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
import { Renderer } from '../src/Renderer.js';
import {
deepSetValue,
isNumber,
isStr,
logError,
replaceAuctionPrice,
triggerPixel,
} from '../src/utils.js';

const ENV = {
BIDDER_CODE: 'michao',
SUPPORTED_MEDIA_TYPES: [BANNER, VIDEO, NATIVE],
ENDPOINT: 'https://rtb.michao-ssp.com/openrtb/prebid',
NET_REVENUE: true,
DEFAULT_CURRENCY: 'USD',
RENDERER_URL:
'https://cdn.jsdelivr.net/npm/in-renderer-js@latest/dist/in-video-renderer.umd.min.js',
};

export const spec = {
code: ENV.BIDDER_CODE,
supportedMediaTypes: ENV.SUPPORTED_MEDIA_TYPES,

isBidRequestValid: function (bid) {
if (!hasParamsObject(bid)) {
return false;
}

if (!validateMichaoParams(bid.params)) {
domainLogger.bidRequestValidationError();
return false;
}

return true;
},

buildRequests: function (validBidRequests, bidderRequest) {
const bidRequests = [];

validBidRequests.forEach((validBidRequest) => {
if (hasVideoMediaType(validBidRequest)) {
bidRequests.push(buildRequest(validBidRequest, bidderRequest, 'video'));
}

if (hasBannerMediaType(validBidRequest)) {
bidRequests.push(
buildRequest(validBidRequest, bidderRequest, 'banner')
);
}

if (hasNativeMediaType(validBidRequest)) {
bidRequests.push(
buildRequest(validBidRequest, bidderRequest, 'native')
);
}
});

return bidRequests;
},

interpretResponse: function (serverResponse, request) {
return interpretResponse(serverResponse, request);
},

getUserSyncs: function (
syncOptions,
serverResponses,
gdprConsent,
uspConsent
) {
if (syncOptions.iframeEnabled) {
return [syncUser(gdprConsent)];
}
},

onBidBillable: function (bid) {
if (bid.burl && isStr(bid.burl)) {
billBid(bid);
}
},
};

export const domainLogger = {
bidRequestValidationError() {
logError('Michao Bid Adapter: wrong format of site or placement.');
},
};

export function buildRequest(bidRequest, bidderRequest, mediaType) {
const openRTBBidRequest = converter.toORTB({
bidRequests: [bidRequest],
bidderRequest,
context: {
mediaType: mediaType,
},
});

return {
method: 'POST',
url: ENV.ENDPOINT,
data: openRTBBidRequest,
options: { contentType: 'application/json', withCredentials: true },
};
}

export function interpretResponse(response, request) {
const bids = converter.fromORTB({
response: response.body,
request: request.data,
}).bids;

return bids;
}

export function syncUser(gdprConsent) {
let gdprParams = '';

if (typeof gdprConsent === 'object') {
if (typeof gdprConsent.gdprApplies === 'boolean') {
gdprParams = `gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${
gdprConsent.consentString
}`;
} else {
gdprParams = `gdpr_consent=${gdprConsent.consentString}`;
}
}

return {
type: 'iframe',
url: 'https://sync.michao-ssp.com/cookie-syncs?' + gdprParams,
};
}

export function addRenderer(bid) {
bid.renderer.push(() => {
const inRenderer = new window.InVideoRenderer();
inRenderer.render(bid.adUnitCode, bid);
});
}

export function hasParamsObject(bid) {
return typeof bid.params === 'object';
}

export function validateMichaoParams(params) {
let valid = true;

if (!isNumber(params?.site)) {
valid = false;
}

if (!isStr(params?.placement)) {
valid = false;
}

return valid
}

export function billBid(bid) {
bid.burl = replaceAuctionPrice(bid.burl, bid.originalCpm || bid.cpm);
triggerPixel(bid.burl);
}

const converter = ortbConverter({
request(buildRequest, imps, bidderRequest, context) {
const bidRequest = context.bidRequests[0];
const openRTBBidRequest = buildRequest(imps, bidderRequest, context);
openRTBBidRequest.cur = [ENV.DEFAULT_CURRENCY];
openRTBBidRequest.test = config.getConfig('debug') ? 1 : 0;
openRTBBidRequest.bcat = bidRequest.params?.bcat || [];
openRTBBidRequest.badv = bidRequest.params?.badv || [];
deepSetValue(
openRTBBidRequest,
'site.id',
bidRequest.params.site.toString()
);
if (bidRequest?.schain) {
deepSetValue(openRTBBidRequest, 'source.schain', bidRequest.schain);
}

return openRTBBidRequest;
},

imp(buildImp, bidRequest, context) {
const imp = buildImp(bidRequest, context);
deepSetValue(imp, 'ext.placement', bidRequest.params.placement.toString());
deepSetValue(imp, 'rwdd', bidRequest.params?.reward ? 1 : 0);
deepSetValue(imp, 'bidfloor', isNumber(bidRequest.params?.bidFloor) ? bidRequest.params?.bidFloor : 0);

return imp;
},

bidResponse(buildBidResponse, bid, context) {
const { bidRequest } = context;
let bidResponse = buildBidResponse(bid, context);
if (hasVideoMediaType(bidRequest)) {
bidResponse.vastXml = bid.adm;
if (bidRequest.mediaTypes.video?.context === 'outstream') {
const renderer = Renderer.install({
id: bid.bidId,
url: ENV.RENDERER_URL,
adUnitCode: bid.adUnitCode,
});
renderer.setRender(addRenderer);
bidResponse.renderer = renderer;
}
}

return bidResponse;
},

context: {
netRevenue: ENV.NET_REVENUE,
currency: ENV.DEFAULT_CURRENCY,
ttl: 360,
},
});

function hasBannerMediaType(bid) {
return hasMediaType(bid, 'banner');
}

function hasVideoMediaType(bid) {
return hasMediaType(bid, 'video');
}

function hasNativeMediaType(bid) {
return hasMediaType(bid, 'native');
}

function hasMediaType(bid, mediaType) {
return bid.mediaTypes.hasOwnProperty(mediaType);
}

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

```markdown
Module Name: Michao Bidder Adapter
Module Type: Bidder Adapter
Maintainer: miyamoto.kai@lookverin.com
```

# Description

Module that connects to Michao’s demand sources

Supported Ad format:
* Banner
* Video (instream and outstream)
* Native

# Test Parameters
```
var adUnits = [
// Banner adUnit
{
code: 'banner-div',
mediaTypes: {
banner: {
sizes: [[300, 250]],
}
},
bids: [{
bidder: 'michao',
params: {
site: 1,
placement: '1',
}
}]
},
// Video adUnit
{
code: 'video-div',
mediaTypes: {
video: {
context: 'outstream',
playerSize: [640, 480],
minduration: 0,
maxduration: 120,
mimes: ['video/mp4'],
protocols: [7]
}
},
bids: [{
bidder: 'michao',
params: {
site: 1,
placement: '1',
}
}]
},
// Native AdUnit
{
code: 'native-div',
mediaTypes: {
native: {
ortb: {
assets: [
{
id: 1,
required: 1,
img: {
type: 3,
w: 989,
h: 742,
},
},
]
}
}
},
bids: [{
bidder: 'michao',
params: {
site: 1,
placement: '1',
}
}]
}
];
```
Loading
Loading