prebid/Prebid.js

View on GitHub
modules/viouslyBidAdapter.js

Summary

Maintainability
D
1 day
Test Coverage
import { deepAccess, logError, parseUrl, parseSizesInput, triggerPixel } from '../src/utils.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { config } from '../src/config.js';
import { BANNER, VIDEO } from '../src/mediaTypes.js';
import {find} from '../src/polyfill.js';

const BIDDER_CODE = 'viously';
const GVLID = 1028;
const CURRENCY = 'EUR';
const TTL = 60;
const HTTP_METHOD = 'POST';
const REQUEST_URL = 'https://bidder.viously.com/bid';
const REQUIRED_VIDEO_PARAMS = ['context', 'playbackmethod', 'playerSize'];
const REQUIRED_VIOUSLY_PARAMS = ['pid'];

export const spec = {
  code: BIDDER_CODE,
  gvlid: GVLID,
  supportedMediaTypes: [BANNER, VIDEO],

  /**
   * 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) {
    let videoParams = deepAccess(bid, 'mediaTypes.video');
    let bannerParams = deepAccess(bid, 'mediaTypes.banner');

    if (!bid.params) {
      logError('The bid params are missing');
      return false;
    }

    if (!bannerParams && !videoParams) {
      logError('The placement must be of banner or video type');
      return false;
    }

    /**
     * BANNER checks
     */

    if (bannerParams) {
      let sizes = bannerParams.sizes;

      if (!sizes || parseSizesInput(sizes).length == 0) {
        logError('mediaTypes.banner.sizes must be set for banner placement at the right format.');
        return false;
      }
    }

    /**
     * VIDEO checks
     */
    let areParamsValid = true;

    if (videoParams) {
      REQUIRED_VIDEO_PARAMS.forEach(function(videoParam) {
        if (typeof videoParams[videoParam] === 'undefined') {
          logError('mediaTypes.video.' + videoParam + ' must be set for video placement.');
          areParamsValid = false;
        }
      });

      if (parseSizesInput(videoParams.playerSize).length === 0) {
        logError('mediaTypes.video.playerSize must be set for video placement at the right format.');
        areParamsValid = false;
      }
    }

    /**
     * Viously checks
     */

    REQUIRED_VIOUSLY_PARAMS.forEach(function(viouslyParam) {
      if (typeof bid.params[viouslyParam] === 'undefined') {
        logError('The ' + viouslyParam + ' is missing.');
        areParamsValid = false;
      }
    });

    if (!areParamsValid) {
      return false;
    }

    return true;
  },

  buildRequests: function(validBidRequests, bidderRequest) {
    let payload = {};

    /** Viously Publisher ID */
    if (validBidRequests[0].params.pid) {
      payload.pid = validBidRequests[0].params.pid;
    }

    // Referer Info
    if (config.getConfig('pageUrl')) {
      let parsedUrl = parseUrl(config.getConfig('pageUrl'));

      payload.domain = parsedUrl.hostname;
      payload.page_domain = config.getConfig('pageUrl');
    } else if (bidderRequest && bidderRequest.refererInfo) {
      let parsedUrl = parseUrl(bidderRequest.refererInfo.page);

      payload.domain = parsedUrl.hostname;
      payload.page_domain = bidderRequest.refererInfo.page;
    }
    if (payload.domain) {
      /** Make sur that the scheme is not part of the domain */
      payload.domain = payload.domain.replace(/(^\w+:|^)\/\//, '');
      payload.domain = payload.domain.replace(/\/$/, '');
    }

    // Handle GDPR
    if (bidderRequest && bidderRequest.gdprConsent) {
      payload.gdpr = bidderRequest.gdprConsent.gdprApplies;
      payload.gdpr_consent = bidderRequest.gdprConsent.consentString;
      if (bidderRequest.gdprConsent.addtlConsent && bidderRequest.gdprConsent.addtlConsent.indexOf('~') !== -1) {
        payload.addtl_consent = bidderRequest.gdprConsent.addtlConsent;
      }
    }

    // US Privacy
    if (bidderRequest && bidderRequest.uspConsent) {
      payload.us_privacy = bidderRequest.uspConsent;
    }

    // Schain
    if (validBidRequests[0].schain) {
      payload.schain = validBidRequests[0].schain;
    }
    // Currency
    payload.currency_code = CURRENCY;

    // User IDs
    if (validBidRequests[0].userIdAsEids) {
      payload.users_uid = validBidRequests[0].userIdAsEids;
    }

    // Placements
    payload.placements = validBidRequests.map(bidRequest => {
      let request = {
        id: bidRequest.adUnitCode,
        bid_id: bidRequest.bidId
      };

      if (deepAccess(bidRequest, 'mediaTypes.banner')) {
        let position = deepAccess(bidRequest, 'mediaTypes.banner.pos');

        request.type = BANNER;

        request.sizes = parseSizesInput(deepAccess(bidRequest, 'mediaTypes.banner.sizes'));

        request.position = position || 0;
      } else {
        request.type = VIDEO;

        request.video_params = {
          context: deepAccess(bidRequest, 'mediaTypes.video.context'),
          playbackmethod: deepAccess(bidRequest, 'mediaTypes.video.playbackmethod'),
          size: parseSizesInput(deepAccess(bidRequest, 'mediaTypes.video.playerSize'))
        };
      }

      return request;
    });

    return {
      method: HTTP_METHOD,
      url: validBidRequests[0].params.endpoint ? validBidRequests[0].params.endpoint : REQUEST_URL,
      data: payload
    };
  },

  interpretResponse: function(serverResponse, requests) {
    const bidResponses = [];
    const responseBody = serverResponse.body;

    if (responseBody.ads && responseBody.ads.length > 0) {
      responseBody.ads.forEach(function(bidResponse) {
        if (bidResponse.bid) {
          let bidRequest = find(requests.data.placements, bid => bid.bid_id === bidResponse.bid_id);

          if (bidRequest) {
            let sizes = bidResponse.size.split('x');

            const bid = {
              requestId: bidRequest.bid_id,
              id: bidResponse.id,
              cpm: bidResponse.cpm,
              width: sizes[0],
              height: sizes[1],
              creativeId: bidResponse.creative_id || '',
              currency: CURRENCY,
              netRevenue: true,
              ttl: TTL,
              mediaType: bidResponse.type,
              meta: {},
              // Tracking data
              nurl: bidResponse.nurl ? bidResponse.nurl : []
            };

            if (bidResponse.type == VIDEO) {
              if (bidResponse.ad_url) {
                bid.vastUrl = bidResponse.ad_url;
              } else {
                bid.vastXml = bidResponse.ad;
              }
            } else {
              bid.ad = bidResponse.ad;
            }

            bidResponses.push(bid);
          }
        }
      });
    }

    return bidResponses;
  },

  getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {},

  onTimeout: function(timeoutData) {},

  onBidWon: function(bid) {
    if (bid && bid.nurl && bid.nurl.length > 0) {
      bid.nurl.forEach(function(winUrl) {
        triggerPixel(winUrl, null);
      });
    }
  },

  onSetTargeting: function(bid) {}
};

registerBidder(spec);