Source: managers/groups.ts

/**
 * @fileoverview Manager for the Groups resource
 * @author mwiller
 */

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

import BoxClient from '../box-client';
import urlPath from '../util/url-path';

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

/**
 * Enum of valid access levels for groups, which are used to specify who can
 * perform certain actions on the group.
 * @enum {GroupAccessLevel}
 */
enum GroupAccessLevel {
	ADMINS = 'admins_only',
	MEMBERS = 'admins_and_members',
	ALL_USERS = 'all_managed_users',
}

/**
 * Enum of valid user roles within a group
 * @enum {GroupUserRole}
 */
enum GroupUserRole {
	MEMBER = 'member',
	ADMIN = 'admin',
}

// -----------------------------------------------------------------------------
// Private
// -----------------------------------------------------------------------------

const BASE_PATH = '/groups',
	MEMBERSHIPS_PATH = '/group_memberships',
	MEMBERSHIPS_SUBRESOURCE = 'memberships',
	COLLABORATIONS_SUBRESOURCE = 'collaborations';

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

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

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

	/**
	 * Used to create a new group
	 *
	 * API Endpoint: '/groups'
	 * Method: POST
	 *
	 * @param {string} name - The name for the new group
	 * @param {Object} [options] - Additional parameters
	 * @param {string} [options.provenance] - Used to track the external source where the group is coming from
	 * @param {string} [options.external_sync_identifier] - Used as a group identifier for groups coming from an external source
	 * @param {string} [options.description] - Description of the group
	 * @param {GroupAccessLevel} [options.invitability_level] - Specifies who can invite this group to collaborate on folders
	 * @param {GroupAccessLevel} [options.member_viewability_level] - Specifies who can view the members of this group
	 * @param {Function} [callback] - Passed the new group object if it was created successfully, error otherwise
	 * @returns {Promise<Object>} A promise resolving to the new group object
	 */
	create(
		name: string,
		options?: {
			provenance?: string;
			external_sync_identifier?: string;
			description?: string;
			invitability_level?: GroupAccessLevel;
			member_viewability_level?: GroupAccessLevel;
		},
		callback?: Function
	) {
		var apiPath = urlPath(BASE_PATH),
			params: Record<string, any> = {
				body: options || {},
			};

		params.body.name = name;

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

	/**
	 * Used to fetch information about a group
	 *
	 * API Endpoint: '/groups/:groupID'
	 * Method: GET
	 *
	 * @param {string} groupID - The ID of the group to retrieve
	 * @param {Object} [options] - Additional options for the request. Can be left null in most cases.
	 * @param {Function} [callback] - Passed the group object if successful, error otherwise
	 * @returns {Promise<Object>} A promise resolving to the group object
	 */
	get(groupID: string, options?: Record<string, any>, callback?: Function) {
		var apiPath = urlPath(BASE_PATH, groupID),
			params = {
				qs: options,
			};

		return this.client.wrapWithDefaultHandler(this.client.get)(
			apiPath,
			params,
			callback
		);
	}

	/**
	 * Used to update or modify a group object
	 *
	 * API Endpoint: '/groups/:groupID'
	 * Method: PUT
	 *
	 * @param {string} groupID - The ID of the group to update
	 * @param {Object} updates - Group fields to update
	 * @param {Function} [callback] - Passed the updated group object if successful, error otherwise
	 * @returns {Promise<Object>} A promise resolving to the updated group object
	 */
	update(groupID: string, updates?: Record<string, any>, callback?: Function) {
		var apiPath = urlPath(BASE_PATH, groupID),
			params = {
				body: updates,
			};

		return this.client.wrapWithDefaultHandler(this.client.put)(
			apiPath,
			params,
			callback
		);
	}

	/**
	 * Delete a group
	 *
	 * API Endpoint: '/groups/:groupID'
	 * Method: DELETE
	 *
	 * @param {string} groupID - The ID of the group to delete
	 * @param {Function} [callback] - Passed nothing if successful, error otherwise
	 * @returns {Promise<void>} A promise resolving to nothing
	 */
	delete(groupID: string, callback?: Function) {
		var apiPath = urlPath(BASE_PATH, groupID);

		return this.client.wrapWithDefaultHandler(this.client.del)(
			apiPath,
			null,
			callback
		);
	}

	/**
	 * Add a user to a group, which creates a membership record for the user
	 *
	 * API Endpoint: '/group_memberships'
	 * Method: POST
	 *
	 * @param {string} groupID - The ID of the group to add the user to
	 * @param {string} userID - The ID of the user to add the the group
	 * @param {Object} [options] - Optional parameters for adding the user, can be left null in most cases
	 * @param {GroupUserRole} [options.role] - The role of the user in the group
	 * @param {Function} [callback] - Passed the membership record if successful, error otherwise
	 * @returns {Promise<Object>} A promise resolving to the new membership object
	 */
	addUser(
		groupID: string,
		userID: string,
		options?: {
			role?: GroupUserRole;
		},
		callback?: Function
	) {
		var apiPath = urlPath(MEMBERSHIPS_PATH),
			params = {
				body: {
					user: {
						id: userID,
					},
					group: {
						id: groupID,
					},
				},
			};

		Object.assign(params.body, options);

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

	/**
	 * Fetch a specific membership record, which shows that a given user is a member
	 * of some group.
	 *
	 * API Endpoint: '/group_memberships/:membershipID'
	 * Method: GET
	 *
	 * @param {string} membershipID - The ID of the membership to fetch
	 * @param {Object} [options] - Additional options for the request. Can be left null in most cases.
	 * @param {Function} [callback] - Passed the membership record if successful, error otherwise
	 * @returns {Promise<Object>} A promise resolving to the membership object
	 */
	getMembership(
		membershipID: string,
		options?: Record<string, any>,
		callback?: Function
	) {
		var apiPath = urlPath(MEMBERSHIPS_PATH, membershipID),
			params = {
				qs: options,
			};

		return this.client.wrapWithDefaultHandler(this.client.get)(
			apiPath,
			params,
			callback
		);
	}

	/**
	 * Used to update or modify a group object
	 *
	 * API Endpoint: '/group_memberships/:membershipID'
	 * Method: PUT
	 *
	 * @param {string} membershipID - The ID of the membership to update
	 * @param {Object} options - Membership record fields to update
	 * @param {Function} [callback] - Passed the updated membership object if successful, error otherwise
	 * @returns {Promise<Object>} A promise resolving to the updated membership object
	 */
	updateMembership(
		membershipID: string,
		options: Record<string, any>,
		callback?: Function
	) {
		var apiPath = urlPath(MEMBERSHIPS_PATH, membershipID),
			params = {
				body: options,
			};

		return this.client.wrapWithDefaultHandler(this.client.put)(
			apiPath,
			params,
			callback
		);
	}

	/**
	 * Used to remove a group membership
	 *
	 * API Endpoint: '/group_memberships/:membershipID'
	 * Method: DELETE
	 *
	 * @param {string} membershipID - The ID of the membership to be removed
	 * @param {Function} [callback] - Passed nothing if successful, error otherwise
	 * @returns {Promise<void>} A promise resolving to nothing
	 */
	removeMembership(membershipID: string, callback?: Function) {
		var apiPath = urlPath(MEMBERSHIPS_PATH, membershipID);

		return this.client.wrapWithDefaultHandler(this.client.del)(
			apiPath,
			null,
			callback
		);
	}

	/**
	 * Retreieve a list of memberships for the group, which show which users
	 * belong to the group
	 *
	 * API Endpoint: '/groups/:groupID/memberships'
	 * Method: GET
	 *
	 * @param {string} groupID - The ID of the group to get memberships for
	 * @param {Object} [options] - Optional parameters, can be left null in most cases
	 * @param {int} [options.limit] - The number of memberships to retrieve
	 * @param {int} [options.offset] - Paging marker, retrieve records starting at this position in the list
	 * @param {Function} [callback] - Passed a list of memberships if successful, error otherwise
	 * @returns {Promise<Object>} A promise resolving to the collection of memberships
	 */
	getMemberships(
		groupID: string,
		options?: {
			limit?: number;
			offset?: number;
		},
		callback?: Function
	) {
		var apiPath = urlPath(BASE_PATH, groupID, MEMBERSHIPS_SUBRESOURCE),
			params = {
				qs: options,
			};

		return this.client.wrapWithDefaultHandler(this.client.get)(
			apiPath,
			params,
			callback
		);
	}

	/**
	 * Retreieve a list of groups in the caller's enterprise.  This ability is
	 * restricted to certain users with permission to view groups.
	 *
	 * API Endpoint: '/groups'
	 * Method: GET
	 *
	 * @param {Object} [options] - Optional parameters, can be left null in most cases
	 * @param {string} [options.filter_term] - Limits the results to only groups whose name starts with the search term
	 * @param {int} [options.limit] - The number of memberships to retrieve
	 * @param {int} [options.offset] - Paging marker, retrieve records starting at this position in the list
	 * @param {Function} [callback] - Passed a list of groups if successful, error otherwise
	 * @returns {Promise<Object>} A promise resolving to the collection of groups
	 */
	getAll(
		options?: {
			filter_term?: string;
			limit?: number;
			offset?: number;
		},
		callback?: Function
	) {
		var apiPath = urlPath(BASE_PATH),
			params = {
				qs: options,
			};

		return this.client.wrapWithDefaultHandler(this.client.get)(
			apiPath,
			params,
			callback
		);
	}

	/**
	 * Retreieve a list of collaborations for the group, which show which items the
	 * group has access to.
	 *
	 * API Endpoint: '/groups/:groupID/collaborations'
	 * Method: GET
	 *
	 * @param {string} groupID - The ID of the group to get collaborations for
	 * @param {Object} [options] - Optional parameters, can be left null in most cases
	 * @param {int} [options.limit] - The number of memberships to retrieve
	 * @param {int} [options.offset] - Paging marker, retrieve records starting at this position in the list
	 * @param {Function} [callback] - Passed a list of collaborations if successful, error otherwise
	 * @returns {Promise<Object>} A promise resolving to the collection of collaborations for the group
	 */
	getCollaborations(
		groupID: string,
		options?: {
			limit?: number;
			offset?: number;
		},
		callback?: Function
	) {
		var apiPath = urlPath(BASE_PATH, groupID, COLLABORATIONS_SUBRESOURCE),
			params = {
				qs: options,
			};

		return this.client.wrapWithDefaultHandler(this.client.get)(
			apiPath,
			params,
			callback
		);
	}


	/**
	 * Validates the roles and permissions of the group,
	 * and creates asynchronous jobs to terminate the group's sessions.
	 * 
	 * API Endpoint: '/groups/terminate_sessions'
	 * Method: POST
	 * 
	 * @param {string[]} groupIDs A list of group IDs
	 * @returns {Promise<Object>} A promise resolving a message about the request status.
	 */
	 terminateSession(groupIDs: string[], callback?: Function) {
		var apiPath = urlPath(BASE_PATH, 'terminate_sessions'),
			params = {
				body: {
					group_ids: groupIDs
				}
			};

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

/**
 * Enum of valid access levels for groups, which are used to specify who can
 * perform certain actions on the group.
 * @enum {GroupAccessLevel}
 */
Groups.prototype.accessLevels = GroupAccessLevel;

/**
 * Enum of valid user roles within a group
 * @enum {GroupUserRole}
 */
Groups.prototype.userRoles = GroupUserRole;

export = Groups;