Source: classeur-api-client.js

'use strict';

const _ = require('lodash'),
    async = require('async'),
    RestClient = require('node-rest-client').Client,
    functionUtils = require('./function-utils');

function query(path, args, cb) {
    args.headers = {
        'x-agent-info': 'github.com/zbentley/classeur-api-client'
    };

    let req = this.RestClient.get(this.root + path, args, function(data, response) {
        if ( response.statusCode == 200 ) {
            cb(null, JSON.parse(data));
        } else {
            cb(`Got an error (${response.statusCode}): ${response.statusMessage}`, null);
        }
    });

    req.on('requestTimeout',function(req){
        req.abort();
        cb('request expired', null);
    });

    req.on('responseTimeout', _.partial(cb, 'request timed out', null));
    req.on('error',  _.partialRight(cb, null));
}

function multiQuery(type, wantArray, Array, cb) {
    const self = this;

    async.map(
        Array,
        function(item, cb) {
            _.bind(query, self, type + item, {}, cb)();
        },
        functionUtils.scrubArrayCallback(cb, wantArray)
    );
}

function metadataQuery(field, wantArray, ids, cb) {
    _.bind(query, this)(
        'metadata/' + field,
        {
            parameters: {
                id: ids.join(','),
            }
        },
        functionUtils.scrubArrayCallback(cb, wantArray)
    );
}

/**
 * Constructs a new API client.
 * @classdesc Object-oriented interface to the Classeur REST API.
 * @class ClasseurClient
 * @example
 * const ClasseurClient = require('classeur-api-client'),
 *      client = new ClasseurClient('my user id', 'my api key');
 * @param {string} userId - Classeur user ID string.
 * @param {string} apiKey - API Key string. Keep this secret.
 * @param {string} [host=app.classeur.io] - Fully qualified hostname to connect to. Can be prefixed with `http://` or `https://`.
 * @returns {Object} Returns a ClasseurClient instance.
 */
module.exports = class {
    constructor(userId, apiKey, host) {
        host = host || 'app.classeur.io';
        this.RestClient = new RestClient({
            user: userId,
            password: apiKey,
        });
        host.replace(/\Ahttps?:[/][/]/g, '');
        this.root = `https://${host}/api/v1/`;
    }
};

Object.assign(
    module.exports.prototype,
    // Has to lend the prototype, otherwise the methods show up as static.
    /** @lends ClasseurClient.prototype */
    {
        /**
         * Retrieve one or more files.
         * @method
         * @param {String[]} ids - Array of Classeur file IDs to retrieve.
         * @param {ClasseurClient~scrubbedCallback(?(Error))} callback - Called with `(error, result)`.
         * - `result` will be an Array of {@link ClasseurClient~File} objects, or `null` on error.
         *//**
         * Retrieve one or more files.
         * Like {@link ClasseurClient#getFiles}, but with spread: accepts a variable number of file IDs in the arguments, instead of an Array.
         * @method
         * @variation 2
         * @param {...String} ids - Classeur file IDs to retrieve.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be an Array of {@link ClasseurClient~File} objects, or `null` on error.
         */
        getFiles: _.partial(functionUtils.restOrArrayAndCallback(multiQuery), 'files/', true),
        /**
         * Retrieve a single file.
         * @method
         * @param {String} id - Classeur file ID to retrieve.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be a {@link ClasseurClient~File} object, or `null` on error.
         */
        getFile: _.partial(functionUtils.singleElementAndCallback(multiQuery), 'files/', false),
        /**
         * Retrieve one or more folders.
         * @method
         * @param {String[]} ids - Array of Classeur folder IDs to retrieve.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be an Array of {@link ClasseurClient~Folder} objects, or `null` on error.
         *//**
         * Like {@link ClasseurClient#getFolders}, but with spread: accepts a variable number of folder IDs in the arguments, instead of an Array.
         * @method
         * @variation 2
         * @param {...String} ids - Classeur folder IDs to retrieve.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be an Array of {@link ClasseurClient~Folder} objects, or `null` on error.
         */
        getFolders: _.partial(functionUtils.restOrArrayAndCallback(multiQuery), 'folders/', true),
        /**
         * Retrieve a single folder.
         * @method
         * @param {String} id - Classeur folder ID to retrieve.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be a {@link ClasseurClient~Folder} object, or `null` on error.
         */
        getFolder: _.partial(functionUtils.singleElementAndCallback(multiQuery), 'folders/', false),
        /**
         * Retrieve all users on the Classeur account to which the ClasseurClient is connected.
         * @method
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be an Array of {@link ClasseurClient~User} objects, or `null` on error.
         */
        getUsers: _.partial(functionUtils.singleElementAndCallback(multiQuery), 'users', true, ''),
        /**
         * Retrieve metadata for one or more users.
         * @method
         * @param {String[]} ids - Array of Classeur user IDs for which to retrieve metadata.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be an Array of {@link ClasseurClient~UserMetadata} objects, or `null` on error.
         *//**
         * Like {@link ClasseurClient#getUsersMetadata}, but with spread: accepts a variable number of folder IDs in the arguments, instead of an Array.
         * @method
         * @variation 2
         * @param {...String} ids - Classeur user IDs for which to retrieve metadata.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be an Array of {@link ClasseurClient~UserMetadata} objects, or `null` on error.
         */
        getUsersMetadata: _.partial(functionUtils.restOrArrayAndCallback(metadataQuery), 'users', true),
        /**
         * Retrieve metadata for one or more folders.
         * @method
         * @param {String[]} ids - Array of Classeur folder IDs for which to retrieve metadata.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be an Array of {@link ClasseurClient~FolderMetadata} objects, or `null` on error.
         *//**
         * Like {@link ClasseurClient#getUsersMetadata}, but with spread: accepts a variable number of folder IDs in the arguments, instead of an Array.
         * @method
         * @variation 2
         * @param {...String} ids - Classeur folder IDs for which to retrieve metadata.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be an Array of {@link ClasseurClient~FolderMetadata} objects, or `null` on error.
         */
        getFoldersMetadata: _.partial(functionUtils.restOrArrayAndCallback(metadataQuery), 'files', true),
        /**
         * Retrieve metadata for one or more files.
         * @method
         * @param {String[]} ids - Array of Classeur file IDs for which to retrieve metadata.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be an Array of {@link ClasseurClient~FileMetadata} objects, or `null` on error.
         *//**
         * Like {@link ClasseurClient#getUsersMetadata}, but with spread: accepts a variable number of folder IDs in the arguments, instead of an Array.
         * @method
         * @variation 2
         * @param {...String} ids - Classeur file IDs for which to retrieve metadata.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be an Array of {@link ClasseurClient~FileMetadata} objects, or `null` on error.
         */
        getFilesMetadata: _.partial(functionUtils.restOrArrayAndCallback(metadataQuery), 'folders', true),
        /**
         * Retrieve metadata for a user.
         * @method
         * @param {String} id - The Classeur user ID for which to retrieve metadata.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be a {@link ClasseurClient~UserMetadata} object, or `null` on error.
         */
        getUserMetadata: _.partial(functionUtils.singleElementAndCallback(metadataQuery), 'users', false),
        /**
         * Retrieve metadata for a file.
         * @method
         * @param {String} id - The Classeur file ID for which to retrieve metadata.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be a {@link ClasseurClient~FileMetadata} object, or `null` on error.
         */
        getFileMetadata: _.partial(functionUtils.singleElementAndCallback(metadataQuery), 'files', false),
        /**
         * Retrieve metadata for a folder.
         * @method
         * @param {String} id - The Classeur folder ID for which to retrieve metadata.
         * @param {ClasseurClient~scrubbedCallback} callback - Called with `(error, result)`.
         * - `result` will be a {@link ClasseurClient~FolderMetadata} object, or `null` on error.
         */
        getFolderMetadata: _.partial(functionUtils.singleElementAndCallback(metadataQuery), 'folders', false)
    }
);