Source: managers/events.ts

  1. /**
  2. * @fileoverview Manager for the Box Events Resource
  3. */
  4. // ------------------------------------------------------------------------------
  5. // Requirements
  6. // ------------------------------------------------------------------------------
  7. import { Promise } from 'bluebird';
  8. import httpStatusCodes from 'http-status';
  9. import BoxClient from '../box-client';
  10. import EnterpriseEventStream from '../enterprise-event-stream';
  11. import EventStream from '../event-stream';
  12. import errors from '../util/errors';
  13. import urlPath from '../util/url-path';
  14. // -----------------------------------------------------------------------------
  15. // Typedefs
  16. // -----------------------------------------------------------------------------
  17. /**
  18. * Enum of enterprise event types
  19. *
  20. * @readonly
  21. * @enum {EventType}
  22. */
  23. enum EventType {
  24. ADD_DEVICE_ASSOCIATION = 'ADD_DEVICE_ASSOCIATION',
  25. ADD_LOGIN_ACTIVITY_DEVICE = 'ADD_LOGIN_ACTIVITY_DEVICE',
  26. ADMIN_INVITE_ACCEPT = 'MASTER_INVITE_ACCEPT',
  27. ADMIN_INVITE_REJECT = 'MASTER_INVITE_REJECT',
  28. ADMIN_LOGIN = 'ADMIN_LOGIN',
  29. APPLICATION_PUBLIC_KEY_ADDED = 'APPLICATION_PUBLIC_KEY_ADDED',
  30. APPLICATION_PUBLIC_KEY_DELETED = 'APPLICATION_PUBLIC_KEY_DELETED',
  31. CHANGE_ADMIN_ROLE = 'CHANGE_ADMIN_ROLE',
  32. COLLABORATION_ACCEPT = 'COLLABORATION_ACCEPT',
  33. COLLABORATION_EXPIRATION = 'COLLABORATION_EXPIRATION',
  34. COLLABORATION_INVITE = 'COLLABORATION_INVITE',
  35. COLLABORATION_REMOVE = 'COLLABORATION_REMOVE',
  36. COLLABORATION_ROLE_CHANGE = 'COLLABORATION_ROLE_CHANGE',
  37. COMMENT_CREATE = 'COMMENT_CREATE',
  38. COMMENT_DELETE = 'COMMENT_DELETE',
  39. COMMENT_EDIT = 'COMMENT_EDIT',
  40. CONTENT_ACCESS = 'CONTENT_ACCESS',
  41. CONTENT_WORKFLOW_AUTOMATION_ADD = 'CONTENT_WORKFLOW_AUTOMATION_ADD',
  42. CONTENT_WORKFLOW_UPLOAD_POLICY_VIOLATION = 'CONTENT_WORKFLOW_UPLOAD_POLICY_VIOLATION',
  43. COPY = 'COPY',
  44. DELETE = 'DELETE',
  45. DELETE_USER = 'DELETE_USER',
  46. DOWNLOAD = 'DOWNLOAD',
  47. EDIT = 'EDIT',
  48. EDIT_USER = 'EDIT_USER',
  49. EMAIL_ALIAS_CONFIRM = 'EMAIL_ALIAS_CONFIRM',
  50. ENABLE_TWO_FACTOR_AUTH = 'ENABLE_TWO_FACTOR_AUTH',
  51. ENTERPRISE_APP_AUTHORIZATION_DELETE = 'ENTERPRISE_APP_AUTHORIZATION_DELETE',
  52. FAILED_LOGIN = 'FAILED_LOGIN',
  53. FILE_MARKED_MALICIOUS = 'FILE_MARKED_MALICIOUS',
  54. FILE_WATERMARKED_DOWNLOAD = 'FILE_WATERMARKED_DOWNLOAD',
  55. GROUP_ADD_FILE = 'GROUP_ADD_FILE',
  56. GROUP_ADD_FOLDER = 'GROUP_ADD_FOLDER',
  57. GROUP_ADD_ITEM = 'GROUP_ADD_ITEM',
  58. GROUP_ADD_USER = 'GROUP_ADD_USER',
  59. GROUP_CREATION = 'GROUP_CREATION',
  60. GROUP_DELETION = 'GROUP_DELETION',
  61. GROUP_EDITED = 'GROUP_EDITED',
  62. GROUP_REMOVE_FILE = 'GROUP_REMOVE_FILE',
  63. GROUP_REMOVE_FOLDER = 'GROUP_REMOVE_FOLDER',
  64. GROUP_REMOVE_USER = 'GROUP_REMOVE_USER',
  65. ITEM_MODIFY = 'ITEM_MODIFY',
  66. ITEM_OPEN = 'ITEM_OPEN',
  67. ITEM_SHARED_UPDATE = 'ITEM_SHARED_UPDATE',
  68. ITEM_SYNC = 'ITEM_SYNC',
  69. ITEM_UNSYNC = 'ITEM_UNSYNC',
  70. LOCK = 'LOCK',
  71. LOGIN = 'LOGIN',
  72. METADATA_INSTANCE_CREATE = 'METADATA_INSTANCE_CREATE',
  73. METADATA_INSTANCE_DELETE = 'METADATA_INSTANCE_DELETE',
  74. METADATA_INSTANCE_UPDATE = 'METADATA_INSTANCE_UPDATE',
  75. METADATA_TEMPLATE_CREATE = 'METADATA_TEMPLATE_CREATE',
  76. METADATA_TEMPLATE_UPDATE = 'METADATA_TEMPLATE_UPDATE',
  77. MOVE = 'MOVE',
  78. NEW_USER = 'NEW_USER',
  79. PREVIEW = 'PREVIEW',
  80. REMOVE_DEVICE_ASSOCIATION = 'REMOVE_DEVICE_ASSOCIATION',
  81. REMOVE_LOGIN_ACTIVITY_DEVICE = 'REMOVE_LOGIN_ACTIVITY_DEVICE',
  82. RENAME = 'RENAME',
  83. SHARE = 'SHARE',
  84. SHARE_EXPIRATION = 'SHARE_EXPIRATION',
  85. STORAGE_EXPIRATION = 'STORAGE_EXPIRATION',
  86. TASK_ASSIGNMENT_CREATE = 'TASK_ASSIGNMENT_CREATE',
  87. TASK_ASSIGNMENT_UPDATE = 'TASK_ASSIGNMENT_UPDATE',
  88. TASK_CREATE = 'TASK_CREATE',
  89. TERMS_OF_SERVICE_AGREE = 'TERMS_OF_SERVICE_AGREE',
  90. TERMS_OF_SERVICE_REJECT = 'TERMS_OF_SERVICE_REJECT',
  91. UNDELETE = 'UNDELETE',
  92. UNLOCK = 'UNLOCK',
  93. UNSHARE = 'UNSHARE',
  94. UPDATE_COLLABORATION_EXPIRATION = 'UPDATE_COLLABORATION_EXPIRATION',
  95. UPDATE_SHARE_EXPIRATION = 'UPDATE_SHARE_EXPIRATION',
  96. UPLOAD = 'UPLOAD',
  97. WATERMARK_LABEL_CREATE = 'WATERMARK_LABEL_CREATE',
  98. WATERMARK_LABEL_DELETE = 'WATERMARK_LABEL_DELETE',
  99. }
  100. // ------------------------------------------------------------------------------
  101. // Private
  102. // ------------------------------------------------------------------------------
  103. // Base path for all files endpoints
  104. const BASE_PATH = '/events';
  105. /** @const {string} */
  106. const CURRENT_STREAM_POSITION = 'now';
  107. // ------------------------------------------------------------------------------
  108. // Public
  109. // ------------------------------------------------------------------------------
  110. /**
  111. * Simple manager for interacting with all 'Events' endpoints and actions.
  112. *
  113. * @param {BoxClient} client The Box API Client that is responsible for making calls to the API
  114. * @constructor
  115. */
  116. class Events {
  117. client: BoxClient;
  118. CURRENT_STREAM_POSITION!: string;
  119. enterpriseEventTypes!: typeof EventType;
  120. constructor(client: BoxClient) {
  121. // Attach the client, for making API calls
  122. this.client = client;
  123. }
  124. /**
  125. * Get the current stream position.
  126. *
  127. * API Endpoint: '/events'
  128. * Method: GET
  129. *
  130. * @param {Function} [callback] Passed the current stream position if successful
  131. * @returns {Promise<string>} A promise resolving to the stream position
  132. */
  133. getCurrentStreamPosition(callback?: Function) {
  134. var params = {
  135. qs: {
  136. stream_position: CURRENT_STREAM_POSITION,
  137. },
  138. };
  139. var apiPath = urlPath(BASE_PATH);
  140. return this.client
  141. .get(apiPath, params)
  142. .then((response: any /* FIXME */) => {
  143. if (response.statusCode !== httpStatusCodes.OK) {
  144. throw errors.buildUnexpectedResponseError(response);
  145. }
  146. return response.body.next_stream_position;
  147. })
  148. .asCallback(callback);
  149. }
  150. /**
  151. * Get a chunk of events
  152. *
  153. * API Endpoint: '/events'
  154. * Method: GET
  155. *
  156. * To get events from admin events stream you have to pick stream_type from `admin_logs` or `admin_logs_streaming`.
  157. * The `admin_logs` stream emphasis is on completeness over latency,
  158. * which means that Box will deliver admin events in chronological order and without duplicates,
  159. * but with higher latency. You can specify start and end time/dates.
  160. *
  161. * To monitor recent events that have been generated within Box across the enterprise use
  162. * `admin_logs_streaming` as stream type. The emphasis for this feed is on low latency rather than chronological
  163. * accuracy, which means that Box may return events more than once and out of chronological order.
  164. * Events are returned via the API around 12 seconds after they are processed by Box
  165. * (the 12 seconds buffer ensures that new events are not written after your cursor position).
  166. * Only two weeks of events are available via this feed, and you cannot set start and end time/dates.
  167. *
  168. * @param {Object} [options] - Additional options for the request. Can be left null in most cases.
  169. * @param {string} [options.stream_type] - From which stream events should be selected.
  170. * Possible values are `admin_logs` and `admin_logs_streaming`
  171. * @param {string} [options.created_after] - The date to start from in ISO-8601 timestamp format: '2001-01-01T00:00:00-08:00'
  172. * @param {string} [options.created_before] - The date to end at in ISO-8601 timestamp format: '2001-01-01T00:00:00-08:00'
  173. * @param {string} [options.event_type] - String of event types to return coma separated: for example 'DOWNLOAD,UPLOAD'
  174. * @param {number} [options.limit] - Number of events to fetch per call
  175. * @param {string} [options.stream_position] - The stream position to start from (pass '0' for all past events)
  176. * @param {Function} [callback] Passed the current stream position if successful
  177. * @returns {Promise<Object>} A promise resolving to the collection of events
  178. */
  179. get(options?: {
  180. [key: string]: any;
  181. stream_type?: string,
  182. created_after?: string,
  183. created_before?: string,
  184. event_type?: string,
  185. limit?: number,
  186. stream_position?: string
  187. }, callback?: Function) {
  188. const params = {
  189. qs: options,
  190. };
  191. if(options && options.stream_type && options.stream_type === 'admin_logs_streaming') {
  192. const {created_after, created_before, ...filteredOptions} = options;
  193. params.qs = filteredOptions;
  194. }
  195. const apiPath = urlPath(BASE_PATH);
  196. return this.client.wrapWithDefaultHandler(this.client.get)(
  197. apiPath,
  198. params,
  199. callback
  200. );
  201. }
  202. /**
  203. * Get information for long-polling until new events are available
  204. *
  205. * API Endpoint: '/events'
  206. * Method: OPTIONS
  207. *
  208. * @param {Function} [callback] Passed the long poll info if successful
  209. * @returns {Promise<Object>} A promise resolving to the long poll info
  210. */
  211. getLongPollInfo(callback?: Function) {
  212. const apiPath = urlPath(BASE_PATH);
  213. return this.client
  214. .options(apiPath, {})
  215. .then((response: any /* FIXME */) => {
  216. if (response.statusCode !== httpStatusCodes.OK) {
  217. throw errors.buildUnexpectedResponseError(response);
  218. }
  219. let longpollInfo = response.body.entries.find(
  220. (entry: any /* FIXME */) => entry.type === 'realtime_server'
  221. );
  222. if (!longpollInfo) {
  223. throw errors.buildResponseError(
  224. 'No valid long poll server specified',
  225. response
  226. );
  227. }
  228. return longpollInfo;
  229. })
  230. .asCallback(callback);
  231. }
  232. /**
  233. * Create a stream of events, using the long-poll API to wait for new events.
  234. *
  235. * API Endpoint: '/events'
  236. * Method: OPTIONS
  237. *
  238. * @param {string} [streamPosition] Starting stream position
  239. * @param {Object} [options] Optional parameters for the event stream
  240. * @param {int} [options.retryDelay=1000] Number of ms to wait before retrying after an error
  241. * @param {int} [options.deduplicationFilterSize=5000] Number of IDs to track for deduplication
  242. * @param {int} [options.fetchInterval=1000] Minimunm number of ms between calls for more events
  243. * @param {Function} [callback] Passed the events stream if successful
  244. * @returns {Promise<EventStream>} A promise resolving to the event stream
  245. */
  246. getEventStream(
  247. streamPosition: string,
  248. options?:
  249. | {
  250. retryDelay?: number;
  251. deduplicationFilterSize?: number;
  252. fetchInterval?: number;
  253. }
  254. | Function,
  255. callback?: Function
  256. ) {
  257. const self = this;
  258. if (typeof streamPosition === 'string') {
  259. if (typeof options === 'function') {
  260. callback = options;
  261. options = {};
  262. }
  263. return Promise.resolve(
  264. new EventStream(self.client, streamPosition, options)
  265. ).asCallback(callback);
  266. }
  267. // Fix up optional arguments
  268. callback = options as any /* FIXME */;
  269. options = streamPosition;
  270. if (typeof options === 'function') {
  271. callback = options;
  272. options = {};
  273. }
  274. return this.getCurrentStreamPosition()
  275. .then(
  276. (currentStreamPosition: any /* FIXME */) =>
  277. new EventStream(
  278. self.client,
  279. currentStreamPosition,
  280. options as Record<string, any>
  281. )
  282. )
  283. .asCallback(callback);
  284. }
  285. /**
  286. * Create a stream of enterprise events.
  287. *
  288. * By default, the stream starts from the current time.
  289. * Pass 'startDate' to start from a specific time.
  290. * Pass 'streamPosition' to start from a previous stream position, or '0' for all available past events (~1 year).
  291. * Once the stream catches up to the current time, it will begin polling every 'pollingInterval' seconds.
  292. * If 'pollingInterval' = 0, then the stream will end when it catches up to the current time (no polling).
  293. *
  294. * By default, stream pools `admin_logs` for events. The emphasis for this stream is on completeness over latency,
  295. * which means that Box will deliver admin events in chronological order and without duplicates,
  296. * but with higher latency. You can specify start and end time/dates.
  297. *
  298. * To monitor recent events that have been generated within Box across the enterprise use
  299. * `admin_logs_streaming` as stream type. The emphasis for this feed is on low latency rather than chronological
  300. * accuracy, which means that Box may return events more than once and out of chronological order.
  301. * Events are returned via the API around 12 seconds after they are processed by Box
  302. * (the 12 seconds buffer ensures that new events are not written after your cursor position).
  303. * Only two weeks of events are available via this feed, and you cannot set start and end time/dates.
  304. *
  305. * This method will only work with an API connection for an enterprise admin account
  306. * or service account with a manage enterprise properties.
  307. *
  308. * @param {Object} [options] - Options
  309. * @param {string} [options.streamPosition] - The stream position to start from (pass '0' for all past events)
  310. * @param {string} [options.startDate] - The date to start from
  311. * @param {string} [options.endDate] - The date to end at
  312. * @param {EventType[]} [options.eventTypeFilter] - Array of event types to return
  313. * @param {int} [options.pollingInterval=60] - Polling interval (in seconds). Pass 0 for no polling.
  314. * @param {int} [options.chunkSize=500] - Number of events to fetch per call (max = 500)
  315. * @param {string} [options.streamType] - From which stream events should be selected.
  316. * Possible values are `admin_logs` and `admin_logs_streaming`
  317. * @param {Function} [callback] Passed the events stream if successful
  318. * @returns {Promise<EnterpriseEventStream>} A promise resolving to the enterprise event stream
  319. */
  320. getEnterpriseEventStream(
  321. options?: {
  322. streamPosition?: string;
  323. startDate?: string;
  324. endDate?: string;
  325. eventTypeFilter?: EventType[];
  326. pollingInterval?: number;
  327. chunkSize?: number;
  328. streamType?: 'admin_logs' | 'admin_logs_streaming';
  329. },
  330. callback?: Function
  331. ) {
  332. const self = this;
  333. return Promise.resolve(
  334. new EnterpriseEventStream(self.client, options)
  335. ).asCallback(callback);
  336. }
  337. }
  338. Events.prototype.CURRENT_STREAM_POSITION = CURRENT_STREAM_POSITION;
  339. Events.prototype.enterpriseEventTypes = EventType;
  340. export = Events;