Source: base.js

'use strict'

const isFunction = require('101/is-function')
const keypather = require('keypather')()
const Promise = require('bluebird')

const Util = require('./util')

/**
 * Base class to wrap intercom client.
 * @class
 */
class Base {
  /**
   * Constructor for Base
   * @param {Object} client Intercom client.
   */
  constructor (client, name) {
    this.baseClient = client
    this.client = keypather.get(client, name)
    this.name = name
  }

  /**
   * Helper method to wrap all client methods.
   * @param {String} method Name of the method to wrap.
   * @returns {Promise} Returns success if intercom is disabled, otherwise
   *   returns results of call to intercom client.
   * @private
   */
  _wrap (method) {
    return Promise.resolve()
      .then(() => {
        if (!Util.canUseIntercom()) { return }

        if (!this.client) {
          throw new Error(`Base._wrap: invalid ${this.name} client`)
        }

        const clientMethod = this.client[method]
        if (!isFunction(clientMethod)) {
          throw new Error(
            `Base._wrap: ${this.name} client has no method '${method}'`
          )
        }

        return clientMethod.apply(
          this.client,
          // NOTE: The first argument is the method name, so we skip it here
          Array.prototype.slice.call(arguments, 1)
        )
      })
  }

  /**
   * Helper method to get all objects from all pages
   * @param {Object} body Response body from Intercom
   * @param {Promise<Array>} objects Concatenated list of all objects
   */
  _getAllObjects (body, objects) {
    return Promise.try(() => {
      if (!body) {
        throw new Error(`Failed to find ${this.name} on Intercom.`)
      }
      if (!body[this.name.toLowerCase()]) {
        return
      }
      objects = objects.concat(body[this.name])
      if (body.pages.page < body.pages.total_pages) {
        return this.baseClient.nextPage(body.pages)
          .get('body')
          .then(body => this._getAllObjects(body, objects))
      }
      return objects
    })
  }

  /**
   * List objects by specific parameters
   * @param {Object} query
   * @returns {Promise<Array>} - Returns success if intercom is disabled,
   *   otherwise returns list of companies
   * @see https://developers.intercom.io/reference#list-by-tag-or-segment
   */
  listBy (query) {
    return this._wrap('listBy', query)
      .get('body')
  }

  /**
   * List Objects.
   * @return {Promise} Resolves with the body of the list call for the type.
   */
  list () {
    return this._wrap('list')
      .bind(this)
      .get('body')
  }

}

module.exports = Base