prebid/Prebid.js

View on GitHub
modules/adplusBidAdapter.js

Summary

Maintainability
B
6 hrs
Test Coverage
import { registerBidder } from '../src/adapters/bidderFactory.js';
import * as utils from '../src/utils.js';
import { BANNER } from '../src/mediaTypes.js';
import { getStorageManager } from '../src/storageManager.js';

// #region Constants
export const BIDDER_CODE = 'adplus';
export const ADPLUS_ENDPOINT = 'https://ssp.ad-plus.com.tr/server/headerBidding';
export const DGID_CODE = 'adplus_dg_id';
export const SESSION_CODE = 'adplus_s_id';
export const storage = getStorageManager({bidderCode: BIDDER_CODE});
const COOKIE_EXP = 1000 * 60 * 60 * 24; // 1 day
// #endregion

// #region Helpers
export function isValidUuid (uuid) {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
    uuid
  );
}

function getSessionId() {
  let sid = storage.cookiesAreEnabled() && storage.getCookie(SESSION_CODE);

  if (
    !sid || !isValidUuid(sid)
  ) {
    sid = utils.generateUUID();
    setSessionId(sid);
  }

  return sid;
}

function setSessionId(sid) {
  if (storage.cookiesAreEnabled()) {
    const expires = new Date(Date.now() + COOKIE_EXP).toISOString();

    storage.setCookie(SESSION_CODE, sid, expires);
  }
}
// #endregion

// #region Bid request validation
function isBidRequestValid(bid) {
  if (!bid) {
    utils.logError(BIDDER_CODE, 'bid, can not be empty', bid);
    return false;
  }

  if (!bid.params) {
    utils.logError(BIDDER_CODE, 'bid.params is required.');
    return false;
  }

  if (!bid.params.adUnitId || typeof bid.params.adUnitId !== 'string') {
    utils.logError(
      BIDDER_CODE,
      'bid.params.adUnitId is missing or has wrong type.'
    );
    return false;
  }

  if (!bid.params.inventoryId || typeof bid.params.inventoryId !== 'string') {
    utils.logError(
      BIDDER_CODE,
      'bid.params.inventoryId is missing or has wrong type.'
    );
    return false;
  }

  if (
    !bid.mediaTypes ||
    !bid.mediaTypes[BANNER] ||
    !utils.isArray(bid.mediaTypes[BANNER].sizes) ||
    bid.mediaTypes[BANNER].sizes.length <= 0 ||
    !utils.isArrayOfNums(bid.mediaTypes[BANNER].sizes[0])
  ) {
    utils.logError(BIDDER_CODE, 'Wrong or missing size parameters.');
    return false;
  }

  return true;
}
// #endregion

// #region Building the bid requests
/**
 *
 * @param {object} bid
 * @returns
 */
function createBidRequest(bid) {
  // Developer Params
  const {
    inventoryId,
    adUnitId,
    extraData,
    yearOfBirth,
    gender,
    categories,
    latitude,
    longitude,
    sdkVersion,
  } = bid.params;

  return {
    method: 'GET',
    url: ADPLUS_ENDPOINT,
    data: utils.cleanObj({
      bidId: bid.bidId,
      inventoryId,
      adUnitId,
      adUnitWidth: bid.mediaTypes[BANNER].sizes[0][0],
      adUnitHeight: bid.mediaTypes[BANNER].sizes[0][1],
      extraData,
      yearOfBirth,
      gender,
      categories,
      latitude,
      longitude,
      sdkVersion: sdkVersion || '1',
      session: getSessionId(),
      interstitial: 0,
      token: typeof window.top === 'object' && window.top[DGID_CODE] ? window.top[DGID_CODE] : undefined,
      secure: window.location.protocol === 'https:' ? 1 : 0,
      screenWidth: screen.width,
      screenHeight: screen.height,
      language: window.navigator.language || 'en-US',
      // TODO: these should probably look at refererInfo
      pageUrl: window.location.href,
      domain: window.location.hostname,
      referrer: window.location.referrer,
    }),
  };
}

function buildRequests(validBidRequests, bidderRequest) {
  return validBidRequests.map((req) => createBidRequest(req));
}
// #endregion

// #region Interpreting Responses
/**
 *
 * @param {HeaderBiddingResponse} responseData
 * @param { object } bidParams
 * @returns
 */
function createAdResponse(responseData, bidParams) {
  return {
    requestId: responseData.requestID,
    cpm: responseData.cpm,
    currency: responseData.currency,
    width: responseData.width,
    height: responseData.height,
    creativeId: responseData.creativeID,
    dealId: responseData.dealID,
    netRevenue: responseData.netRevenue,
    ttl: responseData.ttl,
    ad: responseData.ad,
    mediaType: responseData.mediaType,
    meta: {
      advertiserDomains: responseData.advertiserDomains,
      primaryCatId: utils.isArray(responseData.categoryIDs) && responseData.categoryIDs.length > 0
        ? responseData.categoryIDs[0] : undefined,
      secondaryCatIds: responseData.categoryIDs,
    },
  };
}

function interpretResponse(response, request) {
  // In case of empty response
  if (
    response.body == null ||
    !utils.isArray(response.body) ||
    response.body.length === 0
  ) {
    return [];
  }
  const bids = response.body.map((bid) => createAdResponse(bid));
  return bids;
}
// #endregion

// #region Bidder
export const spec = {
  code: BIDDER_CODE,
  supportedMediaTypes: [BANNER],
  isBidRequestValid,
  buildRequests,
  interpretResponse,
  onTimeout(timeoutData) {
    utils.logError('Adplus adapter timed out for the auction.', timeoutData);
  },
  onBidWon(bid) {
    utils.logInfo(
      `Adplus adapter won the auction. Bid id: ${bid.bidId}, Ad Unit Id: ${bid.adUnitId}, Inventory Id: ${bid.inventoryId}`
    );
  },
};

registerBidder(spec);
// #endregion