Source: components/account.js

/**
 *  @overview provides methods for accessing and updating accounts via CloudHealth's API
 *  @see {@link https://github.com/cloudhealth/cht_api_guide/blob/master/account_api.md|cht_api_guide}
 *  @author Ben Watson <ben.watson@coxautoinc.com>
 */

var https = require('https');
var async = require('async');
var utils = require('../utils/chapi');

/**
 *  @class Account
 *  @memberof module:cox-chapi
 *  @param {string} [api_key]
 */
var Account = function(api_key) {
  this.set_api_key(api_key);
}

/**
 *  creates and returns an options object that can be given to utils.send_request
 *  @private
 *  @param {string} method - the method to use (ie. GET, POST, etc.)
 *  @param {string} [path] - a string to append to the path field of options
 *  @param {string[]} [params] - an array of parameters to add to the url in the
 *    form "key=value"
 *  @return {object} an options object
 */
Account.prototype._options = function(method, path, params) {
  return utils._options('/v1/aws_accounts', method, path, params, this._api_key);
};

/**
 *  sets the api key to use when making calls to CloudHealth's API
 *  @function module:cox-chapi.Account#set_api_key
 *  @param {string} api_key
 */
Account.prototype.set_api_key = function(api_key) {
  this._api_key = api_key;
}

/**
 *  gets a JSON object containing all the accounts
 *  @function module:cox-chapi.Account#list
 *  @param {object} [flags] - an object specifying the following options
 *  @param {number} [flags.page] - the page number of the page to get
 *  @param {number} [flags.page_count] - the number of accounts to list per page
 *  @param {boolean} [flags.all] - if true, return complete list (all pages) but this may take longer
 *  @param {boolean} [flags.stats] - if true, the page count, number of entries per
 *                                   page, and number of pages will be given in an
 *                                   object rather than the array of accounts
 *  @param {arrayCallback} cb - called with an array of accounts
 */
Account.prototype.list = function(flags, cb) {
  if (typeof flags === 'function') {
    cb = flags;
    flags = {};
  }

  if (flags.all) {
    return this._list_all(cb);
  }
  else {
    return this._list(flags, cb);
  }
};

/**
 *  Helper for #list
 *  @private
 */
Account.prototype._list = function(flags, cb) {
  var send_request_flags = {};
  var params = [];
  if (flags.stats) {
    send_request_flags.headers = true;
  }
  else {
    if (flags.page) params.push('page=' + flags.page);
    if (flags.page_count) params.push('page_count=' + flags.page_count);
  }

  var options = this._options('GET', '', params);

  utils.send_request(send_request_flags, options, null, this._list_cb.bind(this, flags, cb));
};

/**
 *  Helper callback for #list
 *  @private
 */
Account.prototype._list_cb = function(flags, cb, err, result) {
  if (err) return cb(err, result);

  // handle call for only stats
  if (flags.stats) {
    var stats = {
      page_count: result.link && (result.link.match(/&page=([0-9]+)>;\s?rel="last"/))[1],
      per_page: result["x-per-page"],
      total: result["x-total"],
    };
    return cb(null, stats);
  }
  else {
    return cb(null, result.aws_accounts);
  }
};

/**
 *  gets a list of all accounts rather than paginating and returning a single page
 *  @private
 *  @function module:cox-chapi.Account#_list_all
 *  @param {arrayCallback} cb - called with an array of accounts
 */
Account.prototype._list_all = function(cb) {
  this.list({stats: true}, (err, stats) => {
    if (err) return cb(err);
    var calls = [];
    for (var i=0, len=stats.page_count; i<len; i++) {
      calls.push(this.list.bind(this, {page: i+1}));
    }
    async.parallel(calls, (err, results) => {
      if (err) return cb(err);
      var accounts = results.reduce((prev, curr) => prev.concat(curr), []);
      cb(null, accounts);
    });
  });
}

/**
 *  gets a JSON object containing data for a single account
 *  @function module:cox-chapi.Account#get
 *  @param {number} id - the id of the account
 *  @param {objectCallback} cb - called with the account
 */
Account.prototype.get = function(id, cb) {
  var options = this._options('GET', '/' + id);

  utils.send_request(options, null, cb);
};

/**
 *  gets accounts such that field matches the value
 *  @function module:cox-chapi.Account#find_by
 *  @param {string} field - the name of the field to search by
 *  @param {string} value - the value to match
 *  @param {Array} [list] - an optional array of accounts to search (if given,
 *                          the search will not make http requests, improving
 *                          speed)
 *  @param {arrayCallback} cb - called with an array containing the matching
 *                              accounts
 */
Account.prototype.find_by = function(field, value, list, cb) {
  if (typeof list === 'function') {
    cb = list;
    list = null;
  }

  return this._find_by(field, value, list, cb);
}

/**
 *  Helper for #find_by
 *  @private
 */
Account.prototype._find_by = function(field, value, list, cb) {
  if (list) {
    var matches = list.filter(
      (account) => account[field] && account[field].toString().match(new RegExp(value, 'i'))
    );
    cb(null, matches);
  }
  else {
    this.list({all: true}, (err, matches) => {
      if (err) return cb(err);
      this.find_by(field, value, matches, cb);
    });
  }
};

/**
 *  Creates an account from the json object
 *  @function module:cox-chapi.Account#create
 *  @param {object} account - an object specifying fields for the new account
 *  @param {objectCallback} cb - called with the new account
 */
Account.prototype.create = function(account, cb) {
  var options = this._options('POST');

  utils.send_request(options, JSON.stringify(account), cb);
};

/**
 *  Updates fields for the account with the specified id to match the given object
 *  @function module:cox-chapi.Account#update
 *  @param {object} account - an object specifying fields with updated values
 *  @param {number} account.id - the id of the account
 *  @param {objectCallback} cb - called with the updated account
 */
Account.prototype.update = function(account, cb) {
  var options = this._options('PUT', '/' + account.id);

  delete account.id;

  utils.send_request(options, JSON.stringify(account), cb);
};

/**
 *  Deletes the account with the specified id
 *  @function module:cox-chapi.Account#destroy
 *  @param {number} id - the id of the account
 *  @param {stringCallback} cb - called with a success message
 */
Account.prototype.destroy = function(id, cb) {
  var options = this._options('DELETE', '/' + id);

  utils.send_request(options, null, this._delete_cb.bind(this, id, cb));
};

/**
 *  Helper callback for #delete
 *  @private
 */
Account.prototype._delete_cb = function(id, cb, err, result) {
  if(err) {
    cb(err, result);
  }
  else {
    cb(null, 'account destroyed');
  }
};

module.exports = Account;