prebid/Prebid.js

View on GitHub
modules/imuIdSystem.js

Summary

Maintainability
A
3 hrs
Test Coverage
/**
 * The {@link module:modules/userId} module is required
 * @module modules/imuIdSystem
 *
 * @requires module:modules/userId
 */

import { timestamp, logError } from '../src/utils.js';
import { ajax } from '../src/ajax.js'
import { submodule } from '../src/hook.js';
import {getStorageManager} from '../src/storageManager.js';
import {MODULE_TYPE_UID} from '../src/activities/modules.js';

/**
 * @typedef {import('../modules/userId/index.js').Submodule} Submodule
 * @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig
 */

const MODULE_NAME = 'imuid';

export const storage = getStorageManager({moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME});

export const storageKey = '__im_uid';
export const storagePpKey = '__im_ppid';
export const cookieKey = '_im_vid';
export const apiDomain = 'sync6.im-apps.net';
const storageMaxAge = 1800000; // 30 minites (30 * 60 * 1000)
const cookiesMaxAge = 97200000000; // 37 months ((365 * 3 + 30) * 24 * 60 * 60 * 1000)

function setImDataInCookie(value) {
  storage.setCookie(
    cookieKey,
    value,
    new Date(timestamp() + cookiesMaxAge).toUTCString(),
    'none'
  );
}

export function removeImDataFromLocalStorage() {
  storage.removeDataFromLocalStorage(storageKey);
  storage.removeDataFromLocalStorage(`${storageKey}_mt`);
  storage.removeDataFromLocalStorage(storagePpKey);
}

export function getLocalData() {
  const mt = storage.getDataFromLocalStorage(`${storageKey}_mt`);
  let expired = true;
  if (Date.parse(mt) && Date.now() - (new Date(mt)).getTime() < storageMaxAge) {
    expired = false;
  }
  return {
    id: storage.getDataFromLocalStorage(storageKey),
    ppid: storage.getDataFromLocalStorage(storagePpKey),
    vid: storage.getCookie(cookieKey),
    expired: expired
  };
}

export function getApiUrl(cid, url) {
  if (url) {
    return `${url}?cid=${cid}`;
  }
  return `https://${apiDomain}/${cid}/pid`;
}

export function apiSuccessProcess(jsonResponse) {
  if (!jsonResponse) {
    return;
  }
  if (jsonResponse.uid && jsonResponse.ppid) {
    storage.setDataInLocalStorage(storageKey, jsonResponse.uid);
    storage.setDataInLocalStorage(`${storageKey}_mt`, new Date(timestamp()).toUTCString());
    storage.setDataInLocalStorage(storagePpKey, jsonResponse.ppid);
    if (jsonResponse.vid) {
      setImDataInCookie(jsonResponse.vid);
    }
  } else {
    removeImDataFromLocalStorage();
  }
}

export function getApiCallback(callback) {
  return {
    success: response => {
      let responseObj = {};
      if (response) {
        try {
          responseObj = JSON.parse(response);
          apiSuccessProcess(responseObj);
        } catch (error) {
          logError('User ID - imuid submodule: ' + error);
        }
      }
      if (callback && responseObj.uid) {
        const callbackObj = {
          imuid: responseObj.uid,
          imppid: responseObj.ppid
        };
        callback(callbackObj);
      }
    },
    error: error => {
      logError('User ID - imuid submodule was unable to get data from api: ' + error);
      if (callback) {
        callback();
      }
    }
  };
}

export function callImuidApi(apiUrl) {
  return function (callback) {
    ajax(apiUrl, getApiCallback(callback), undefined, {method: 'GET', withCredentials: true});
  };
}

/** @type {Submodule} */
export const imuIdSubmodule = {
  /**
   * used to link submodule with config
   * @type {string}
   */
  name: MODULE_NAME,
  /**
   * decode the stored id value for passing to bid requests
   * @function
   * @returns {{imuid: string, imppid: string} | undefined}
   */
  decode(ids) {
    if (ids && typeof ids === 'object') {
      return {
        imuid: ids.imuid,
        imppid: ids.imppid
      };
    }
    return undefined;
  },
  /**
   * @function
   * @param {SubmoduleConfig} [config]
   * @returns {{id:{imuid: string, imppid: string}} | undefined | {callback:function}}}
   */
  getId(config) {
    const configParams = (config && config.params) || {};
    if (!configParams || typeof configParams.cid !== 'number') {
      logError('User ID - imuid submodule requires a valid cid to be defined');
      return undefined;
    }
    let apiUrl = getApiUrl(configParams.cid, configParams.url);
    const localData = getLocalData();
    if (localData.vid) {
      apiUrl += `&vid=${localData.vid}`;
      setImDataInCookie(localData.vid);
    }

    if (!localData.id) {
      return {callback: callImuidApi(apiUrl)};
    }
    if (localData.expired) {
      callImuidApi(apiUrl)();
    }
    return {
      id: {
        imuid: localData.id,
        imppid: localData.ppid
      }
    };
  },
  primaryIds: ['imppid', 'imuid'],
  eids: {
    'imppid': {
      source: 'ppid.intimatemerger.com',
      atype: 1
    },
    'imuid': {
      source: 'intimatemerger.com',
      atype: 1
    },
  }
};

submodule('userId', imuIdSubmodule);