mk9-prebid
Version:
Header Bidding Management Library
213 lines (181 loc) • 6.38 kB
JavaScript
import * as utils from '../src/utils.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { getStorageManager } from '../src/storageManager.js'
const BIDDER_CODE = 'concert';
const CONCERT_ENDPOINT = 'https://bids.concert.io';
const USER_SYNC_URL = 'https://cdn.concert.io/lib/bids/sync.html';
export const spec = {
code: BIDDER_CODE,
/**
* Determines whether or not the given bid request is valid.
*
* @param {BidRequest} bid The bid params to validate.
* @return boolean True if this is a valid bid, and false otherwise.
*/
isBidRequestValid: function(bid) {
if (!bid.params.partnerId) {
utils.logWarn('Missing partnerId bid parameter');
return false;
}
return true;
},
/**
* Make a server request from the list of BidRequests.
*
* @param {validBidRequests[]} - an array of bids
* @param {bidderRequest} -
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function(validBidRequests, bidderRequest) {
utils.logMessage(validBidRequests);
utils.logMessage(bidderRequest);
let payload = {
meta: {
prebidVersion: '$prebid.version$',
pageUrl: bidderRequest.refererInfo.referer,
screen: [window.screen.width, window.screen.height].join('x'),
debug: utils.debugTurnedOn(),
uid: getUid(bidderRequest),
optedOut: hasOptedOutOfPersonalization(),
adapterVersion: '1.1.1',
uspConsent: bidderRequest.uspConsent,
gdprConsent: bidderRequest.gdprConsent
}
}
payload.slots = validBidRequests.map(bidRequest => {
let slot = {
name: bidRequest.adUnitCode,
bidId: bidRequest.bidId,
transactionId: bidRequest.transactionId,
sizes: bidRequest.params.sizes || bidRequest.sizes,
partnerId: bidRequest.params.partnerId,
slotType: bidRequest.params.slotType,
adSlot: bidRequest.params.slot || bidRequest.adUnitCode,
placementId: bidRequest.params.placementId || '',
site: bidRequest.params.site || bidderRequest.refererInfo.referer
}
return slot;
});
utils.logMessage(payload);
return {
method: 'POST',
url: `${CONCERT_ENDPOINT}/bids/prebid`,
data: JSON.stringify(payload)
}
},
/**
* Unpack the response from the server into a list of bids.
*
* @param {ServerResponse} serverResponse A successful response from the server.
* @return {Bid[]} An array of bids which were nested inside the server.
*/
interpretResponse: function(serverResponse, bidRequest) {
utils.logMessage(serverResponse);
utils.logMessage(bidRequest);
const serverBody = serverResponse.body;
if (!serverBody || typeof serverBody !== 'object') {
return [];
}
let bidResponses = [];
bidResponses = serverBody.bids.map(bid => {
return {
requestId: bid.bidId,
cpm: bid.cpm,
width: bid.width,
height: bid.height,
ad: bid.ad,
ttl: bid.ttl,
meta: { advertiserDomains: bid && bid.adomain ? bid.adomain : [] },
creativeId: bid.creativeId,
netRevenue: bid.netRevenue,
currency: bid.currency
}
});
if (utils.debugTurnedOn() && serverBody.debug) {
utils.logMessage(`CONCERT`, serverBody.debug);
}
utils.logMessage(bidResponses);
return bidResponses;
},
/**
* Register the user sync pixels which should be dropped after the auction.
*
* @param {SyncOptions} syncOptions Which user syncs are allowed?
* @param {ServerResponse[]} serverResponses List of server's responses.
* @param {gdprConsent} object GDPR consent object.
* @param {uspConsent} string US Privacy String.
* @return {UserSync[]} The user syncs which should be dropped.
*/
getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {
const syncs = []
if (syncOptions.iframeEnabled && !hasOptedOutOfPersonalization()) {
let params = [];
if (gdprConsent && (typeof gdprConsent.gdprApplies === 'boolean')) {
params.push(`gdpr_applies=${gdprConsent.gdprApplies ? '1' : '0'}`);
}
if (gdprConsent && (typeof gdprConsent.consentString === 'string')) {
params.push(`gdpr_consent=${gdprConsent.consentString}`);
}
if (uspConsent && (typeof uspConsent === 'string')) {
params.push(`usp_consent=${uspConsent}`);
}
syncs.push({
type: 'iframe',
url: USER_SYNC_URL + (params.length > 0 ? `?${params.join('&')}` : '')
});
}
return syncs;
},
/**
* Register bidder specific code, which will execute if bidder timed out after an auction
* @param {data} Containing timeout specific data
*/
onTimeout: function(data) {
utils.logMessage('concert bidder timed out');
utils.logMessage(data);
},
/**
* Register bidder specific code, which will execute if a bid from this bidder won the auction
* @param {Bid} The bid that won the auction
*/
onBidWon: function(bid) {
utils.logMessage('concert bidder won bid');
utils.logMessage(bid);
}
}
registerBidder(spec);
const storage = getStorageManager();
/**
* Check or generate a UID for the current user.
*/
function getUid(bidderRequest) {
if (hasOptedOutOfPersonalization() || !consentAllowsPpid(bidderRequest)) {
return false;
}
const CONCERT_UID_KEY = 'c_uid';
let uid = storage.getDataFromLocalStorage(CONCERT_UID_KEY);
if (!uid) {
uid = utils.generateUUID();
storage.setDataInLocalStorage(CONCERT_UID_KEY, uid);
}
return uid;
}
/**
* Whether the user has opted out of personalization.
*/
function hasOptedOutOfPersonalization() {
const CONCERT_NO_PERSONALIZATION_KEY = 'c_nap';
return storage.getDataFromLocalStorage(CONCERT_NO_PERSONALIZATION_KEY) === 'true';
}
/**
* Whether the privacy consent strings allow personalization.
*
* @param {BidderRequest} bidderRequest Object which contains any data consent signals
*/
function consentAllowsPpid(bidderRequest) {
/* NOTE: We cannot easily test GDPR consent, without the
* `consent-string` npm module; so will have to rely on that
* happening on the bid-server. */
return !(bidderRequest.uspConsent === 'string' &&
bidderRequest.uspConsent.toUpperCase().substring(0, 2) === '1YY')
}