Source: managers/collaborations.ts

/**
 * @fileoverview Manager for the Box Collaboration Resource
 */

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

import BoxClient from "../box-client";
import urlPath from "../util/url-path";
import {
	Collaboration,
	CollaborationAccesibleBy,
	CollaborationRole,
	CollaborationStatus,
	CollaborationUpdate
} from "../schemas";

// -----------------------------------------------------------------------------
// Typedefs
// -----------------------------------------------------------------------------

type ItemType = "file" | "folder";

// ------------------------------------------------------------------------------
// Private
// ------------------------------------------------------------------------------
const BASE_PATH = "/collaborations";

// ------------------------------------------------------------------------------
// Public
// ------------------------------------------------------------------------------

/**
 * Simple manager for interacting with all 'Collaboration' endpoints and actions.
 *
 * @constructor
 * @param {BoxClient} client - The Box API Client that is responsible for making calls to the API
 * @returns {void}
 */
class Collaborations {
	client: BoxClient;

	constructor(client: BoxClient) {
		this.client = client;
	}

	/**
	 * Requests a collaboration object with a given ID.
	 *
	 * API Endpoint: '/collaborations/:collaborationID'
	 * Method: GET
	 *
	 * @param {string} collaborationID - Box ID of the collaboration being requested
	 * @param {Object} [options] - Additional options for the request. Can be left null in most cases.
	 * @param {Function} [callback] - Passed the collaboration information if it was acquired successfully
	 * @returns {Promise<Collaboration>} A promise resolving to the collaboration object
	 */
	get(
		collaborationID: string,
		options?: Record<string, any>,
		callback?: Function
	): Promise<Collaboration> {
		const params = {
			qs: options
		};
		const apiPath = urlPath(BASE_PATH, collaborationID);
		return this.client.wrapWithDefaultHandler(this.client.get)(
			apiPath,
			params,
			callback
		);
	}

	/**
	 * Gets a user's pending collaborations
	 *
	 * API Endpoint: '/collaborations'
	 * Method: GET
	 *
	 * @param {Function} [callback] - Called with a collection of pending collaborations if successful
	 * @returns {Promise<Collaborations>} A promise resolving to the collection of pending collaborations
	 */
	getPending(callback?: Function): Promise<Collaborations> {
		const params = {
			qs: {
				status: "pending"
			}
		};
		return this.client.wrapWithDefaultHandler(this.client.get)(
			BASE_PATH,
			params,
			callback
		);
	}

	private updateInternal(
		collaborationID: string,
		updates: CollaborationUpdate | { status: CollaborationStatus },
		callback?: Function
	): Promise<Collaboration> {
		const params = {
			body: updates
		};

		const apiPath = urlPath(BASE_PATH, collaborationID);
		return this.client.wrapWithDefaultHandler(this.client.put)(
			apiPath,
			params,
			callback
		);
	}

	/**
	 * Update some information about a given collaboration.
	 *
	 * API Endpoint: '/collaborations/:collaborationID'
	 * Method: PUT
	 *
	 * @param {string} collaborationID - Box ID of the collaboration being requested
	 * @param {CollaborationUpdate} updates - Fields of the collaboration to be updated
	 * @param {Function} [callback] - Passed the updated collaboration information if it was acquired successfully
	 * @returns {Promise<Collaboration>} A promise resolving to the updated collaboration object
	 */
	update(
		collaborationID: string,
		updates: CollaborationUpdate,
		callback?: Function
	): Promise<Collaboration> {
		return this.updateInternal(collaborationID, updates, callback);
	}

	/**
	 * Update the status of a pending collaboration.
	 *
	 * API Endpoint: '/collaborations/:collaborationID'
	 * Method: PUT
	 *
	 * @param {string} collaborationID - Box ID of the collaboration being requested
	 * @param {CollaborationStatus} newStatus - The new collaboration status ('accepted'/'rejected')
	 * @param {Function} [callback] - Passed the updated collaboration information if it was acquired successfully
	 * @returns {Promise<Collaboration>} A promise resolving to the accepted collaboration object
	 */
	respondToPending(
		collaborationID: string,
		newStatus: CollaborationStatus,
		callback?: Function
	): Promise<Collaboration> {
		return this.updateInternal(
			collaborationID,
			{
				status: newStatus
			},
			callback);
	}

	/**
	 * Invite a collaborator to a folder. You'll have to create the 'accessible_by' input object
	 * yourself, but the method allows for multiple types of collaborator invites. See
	 * {@link http://developers.box.com/docs/#collaborations-add-a-collaboration} for formatting
	 * help.
	 *
	 * API Endpoint: '/collaborations
	 * Method: POST
	 *
	 * @param {CollaborationAccesibleBy} accessibleBy - The accessible_by object expected by the API
	 * @param {string} itemID - Box ID of the item to which the user should be invited
	 * @param {CollaborationRole} role - The role which the invited collaborator should have
	 * @param {Object} [options] - Optional parameters for the collaboration
	 * @param {ItemType} [options.type=folder] - Type of object to be collaborated
	 * @param {boolean} [options.notify] - Determines if the user or group will receive email notifications
	 * @param {boolean} [options.can_view_path] - Whether view path collaboration feature is enabled or not
	 * @param {boolean} [options.is_access_only] - WARN: Feature not yet available.
	 *   Do not display collaborated items on collaborator's All Files Pages
	 *   and suppress notifications sent to collaborators regarding access-only content.
	 *   This feature is going to be released in Q4. Watch our
	 * 	 [announcements](https://developer.box.com/changelog/) to learn about its availability.
	 * @param {Function} [callback] - Called with the new collaboration if successful
	 * @returns {Promise<Collaboration>} A promise resolving to the created collaboration object
	 */
	create(
		accessibleBy: CollaborationAccesibleBy,
		itemID: string,
		role: CollaborationRole,
		options?:
			| {
			type?: ItemType;
			notify?: boolean;
			can_view_path?: boolean;
			is_access_only?: boolean;
		}
			| Function,
		callback?: Function
	): Promise<Collaboration> {
		const defaultOptions = {
			type: "folder"
		};

		if (typeof options === "function") {
			callback = options;
			options = {};
		}

		options = Object.assign({}, defaultOptions, options);

		const params: {
			body: Record<string, any>;
			qs?: Record<string, any>;
		} = {
			body: {
				item: {
					type: options.type,
					id: itemID
				},
				accessible_by: accessibleBy,
				role
			}
		};

		if (typeof options.can_view_path === "boolean") {
			params.body.can_view_path = options.can_view_path;
		}

		if (typeof options.notify === "boolean") {
			params.qs = {
				notify: options.notify
			};
		}

		if(typeof options.is_access_only === 'boolean') {
			params.body.is_access_only = options.is_access_only;
		}

		return this.client.wrapWithDefaultHandler(this.client.post)(
			BASE_PATH,
			params,
			callback
		);
	}

	/**
	 * Invite a user to collaborate on an item via their user ID.
	 *
	 * API Endpoint: '/collaborations
	 * Method: POST
	 *
	 * @param {int | string} userID - The ID of the user you'll invite as a collaborator
	 * @param {string} itemID - Box ID of the item to which the user should be invited
	 * @param {CollaborationRole} role - The role which the invited collaborator should have
	 * @param {Object} [options] - Optional parameters for the collaboration
	 * @param {ItemType} [options.type=folder] - Type of object to be collaborated
	 * @param {boolean} [options.notify] - Determines if the user will receive email notifications
	 * @param {boolean} [options.can_view_path] - Whether view path collaboration feature is enabled or not
	 * @param {Function} [callback] - Called with the new collaboration if successful
	 * @returns {Promise<Collaboration>} A promise resolving to the created collaboration object
	 */
	createWithUserID(
		userID: number | string,
		itemID: string,
		role: CollaborationRole,
		options?:
			| {
			type?: ItemType;
			notify?: boolean;
			can_view_path?: boolean;
		}
			| Function,
		callback?: Function
	): Promise<Collaboration> {
		if (typeof options === "function") {
			callback = options;
			options = {};
		}

		const accessibleBy: CollaborationAccesibleBy = {
			type: "user",
			id: `${userID}`
		};
		return this.create(accessibleBy, itemID, role, options, callback);
	}

	/**
	 * Invite a user to collaborate on an item via their user login email address.
	 *
	 * API Endpoint: '/collaborations
	 * Method: POST
	 *
	 * @param {string} email - The collaborator's email address
	 * @param {string} itemID - Box ID of the item to which the user should be invited
	 * @param {CollaborationRole} role - The role which the invited collaborator should have
	 * @param {Object} [options] - Optional parameters for the collaboration
	 * @param {ItemType} [options.type=folder] - Type of object to be collaborated
	 * @param {boolean} [options.notify] - Determines if the user will receive email notifications
	 * @param {boolean} [options.can_view_path] - Whether view path collaboration feature is enabled or not
	 * @param {Function} [callback] - Called with the new collaboration if successful
	 * @returns {Promise<Collaboration>} A promise resolving to the created collaboration object
	 */
	createWithUserEmail(
		email: string,
		itemID: string,
		role: CollaborationRole,
		options?:
			| {
			type?: ItemType;
			notify?: boolean;
			can_view_path?: boolean;
		}
			| Function,
		callback?: Function
	): Promise<Collaboration> {
		if (typeof options === "function") {
			callback = options;
			options = {};
		}

		const accessibleBy: CollaborationAccesibleBy = {
			type: "user",
			login: email
		};
		return this.create(accessibleBy, itemID, role, options, callback);
	}

	/**
	 * Invite a group to collaborate on an item via their group ID.
	 *
	 * API Endpoint: '/collaborations
	 * Method: POST
	 *
	 * @param {int | string} groupID - The ID of the group you'll invite as a collaborator
	 * @param {string} itemID - Box ID of the item to which the group should be invited
	 * @param {CollaborationRole} role - The role which the invited collaborator should have
	 * @param {Object} [options] - Optional parameters for the collaboration
	 * @param {ItemType} [options.type=folder] - Type of object to be collaborated
	 * @param {boolean} [options.notify] - Determines if the group will receive email notifications
	 * @param {boolean} [options.can_view_path] - Whether view path collaboration feature is enabled or not
	 * @param {Function} [callback] - Called with the new collaboration if successful
	 * @returns {Promise<Collaboration>} A promise resolving to the created collaboration object
	 */
	createWithGroupID(
		groupID: number | string,
		itemID: string,
		role: CollaborationRole,
		options?:
			| {
			type?: ItemType;
			notify?: boolean;
			can_view_path?: boolean;
		}
			| Function,
		callback?: Function
	): Promise<Collaboration> {
		if (typeof options === "function") {
			callback = options;
			options = {};
		}

		const accessibleBy: CollaborationAccesibleBy = {
			type: "group",
			id: `${groupID}`
		};
		return this.create(accessibleBy, itemID, role, options, callback);
	}

	/**
	 * Delete a given collaboration.
	 *
	 * API Endpoint: '/collaborations/:collaborationID'
	 * Method: DELETE
	 *
	 * @param {string} collaborationID - Box ID of the collaboration being requested
	 * @param {Function} [callback] - Empty response body passed if successful.
	 * @returns {Promise<void>} A promise resolving to nothing
	 */
	delete(collaborationID: string, callback?: Function): Promise<void> {
		const apiPath = urlPath(BASE_PATH, collaborationID);
		return this.client.wrapWithDefaultHandler(this.client.del)(
			apiPath,
			null,
			callback
		);
	}
}

/**
 * @module box-node-sdk/lib/managers/collaborations
 * @see {@Link Collaborations}
 */
export = Collaborations;