11# coding: utf-8
22
33from __future__ import unicode_literals
4+
45from requests .exceptions import Timeout
6+ from six import with_metaclass
57
68from boxsdk .object .base_endpoint import BaseEndpoint
9+ from boxsdk .util .enum import ExtendableEnumMeta
710from boxsdk .util .lru_cache import LRUCache
11+ from boxsdk .util .text_enum import TextEnum
12+
13+
14+ # pylint:disable=too-many-ancestors
15+ class EventsStreamType (with_metaclass (ExtendableEnumMeta , TextEnum )):
16+ """An enum of all possible values of the `stream_type` parameter for user events.
17+
18+ The value of the `stream_type` parameter determines the type of events
19+ returned by the endpoint.
20+
21+ <https://box-content.readme.io/reference#events>
22+ """
23+
24+
25+ class UserEventsStreamType (EventsStreamType ):
26+ """An enum of all possible values of the `stream_type` parameter for user events.
27+
28+ - ALL: Returns all user events.
29+ - CHANGES: Returns tree changes.
30+ - SYNC: Returns tree changes only for sync folders.
31+
32+ <https://box-content.readme.io/reference#standard-user-events>
33+ """
34+ ALL = 'all'
35+ CHANGES = 'changes'
36+ SYNC = 'sync'
37+
38+
39+ class EnterpriseEventsStreamType (EventsStreamType ):
40+ """An enum of all possible values of the `stream_type` parameter for enterprise events.
41+
42+ - ADMIN_LOGS: Retrieves up to a year's events for all users in the enterprise.
43+
44+ NOTE: Requires Admin: These stream types will only work with an auth token
45+ from an enterprise admin account.
46+
47+ <https://box-content.readme.io/reference#enterprise-events>
48+ """
49+ ADMIN_LOGS = 'admin_logs'
50+ # pylint:enable=too-many-ancestors
851
952
1053class Events (BaseEndpoint ):
@@ -14,7 +57,7 @@ def get_url(self, *args):
1457 """Base class override."""
1558 return super (Events , self ).get_url ('events' , * args )
1659
17- def get_events (self , limit = 100 , stream_position = 0 , stream_type = 'all' ):
60+ def get_events (self , limit = 100 , stream_position = 0 , stream_type = UserEventsStreamType . ALL ):
1861 """
1962 Get Box events from a given stream position for a given stream type.
2063
@@ -25,12 +68,16 @@ def get_events(self, limit=100, stream_position=0, stream_type='all'):
2568 :param stream_position:
2669 The location in the stream from which to start getting events. 0 is the beginning of time. 'now' will
2770 return no events and just current stream position.
71+
72+ NOTE: Currently, 'now' is only valid for user events stream types. The request will fail if an
73+ enterprise events stream type is passed.
2874 :type stream_position:
2975 `unicode`
3076 :param stream_type:
31- Which type of events to return. Can be 'all', 'tree', or 'sync'.
77+ (optional) Which type of events to return.
78+ Defaults to `UserEventsStreamType.ALL`.
3279 :type stream_type:
33- `unicode `
80+ :enum:`EventsStreamType `
3481 :returns:
3582 JSON response from the Box /events endpoint. Contains the next stream position to use for the next call,
3683 along with some number of events.
@@ -46,26 +93,38 @@ def get_events(self, limit=100, stream_position=0, stream_type='all'):
4693 box_response = self ._session .get (url , params = params )
4794 return box_response .json ()
4895
49- def get_latest_stream_position (self ):
96+ def get_latest_stream_position (self , stream_type = UserEventsStreamType . ALL ):
5097 """
5198 Get the latest stream position. The return value can be used with :meth:`get_events` or
5299 :meth:`generate_events_with_long_polling`.
53100
101+ :param stream_type:
102+ (optional) Which events stream to query.
103+ Defaults to `UserEventsStreamType.ALL`.
104+
105+ NOTE: Currently, the Box API requires this to be one of the user
106+ events stream types. The request will fail if an enterprise events
107+ stream type is passed.
108+ :type stream_type:
109+ :enum:`UserEventsStreamType`
54110 :returns:
55111 The latest stream position.
56112 :rtype:
57113 `unicode`
58114 """
59- url = self .get_url ()
60- params = {
61- 'stream_position' : 'now' ,
62- }
63- return self ._session .get (url , params = params ).json ()['next_stream_position' ]
115+ return self .get_events (limit = 0 , stream_position = 'now' , stream_type = stream_type )['next_stream_position' ]
64116
65- def _get_all_events_since (self , stream_position ):
117+ def _get_all_events_since (self , stream_position , stream_type = UserEventsStreamType .ALL ):
118+ """
119+ :param stream_type:
120+ (optional) Which type of events to return.
121+ Defaults to `UserEventsStreamType.ALL`.
122+ :type stream_type:
123+ :enum:`EventsStreamType`
124+ """
66125 next_stream_position = stream_position
67126 while True :
68- events = self .get_events (stream_position = next_stream_position , limit = 100 )
127+ events = self .get_events (stream_position = next_stream_position , limit = 100 , stream_type = stream_type )
69128 next_stream_position = events ['next_stream_position' ]
70129 events = events ['entries' ]
71130 if not events :
@@ -102,7 +161,7 @@ def long_poll(self, options, stream_position):
102161 )
103162 return long_poll_response
104163
105- def generate_events_with_long_polling (self , stream_position = None ):
164+ def generate_events_with_long_polling (self , stream_position = None , stream_type = UserEventsStreamType . ALL ):
106165 """
107166 Subscribe to events from the given stream position.
108167
@@ -111,15 +170,24 @@ def generate_events_with_long_polling(self, stream_position=None):
111170 return no events and just current stream position.
112171 :type stream_position:
113172 `unicode`
173+ :param stream_type:
174+ (optional) Which type of events to return.
175+ Defaults to `UserEventsStreamType.ALL`.
176+
177+ NOTE: Currently, the Box API requires this to be one of the user
178+ events stream types. The request will fail if an enterprise events
179+ stream type is passed.
180+ :type stream_type:
181+ :enum:`UserEventsStreamType`
114182 :returns:
115183 Events corresponding to changes on Box in realtime, as they come in.
116184 :rtype:
117185 `generator` of :class:`Event`
118186 """
119187 event_ids = LRUCache ()
120- stream_position = stream_position if stream_position is not None else self .get_latest_stream_position ()
188+ stream_position = stream_position if stream_position is not None else self .get_latest_stream_position (stream_type = stream_type )
121189 while True :
122- options = self .get_long_poll_options ()
190+ options = self .get_long_poll_options (stream_type = stream_type )
123191 while True :
124192 try :
125193 long_poll_response = self .long_poll (options , stream_position )
@@ -129,7 +197,7 @@ def generate_events_with_long_polling(self, stream_position=None):
129197 message = long_poll_response .json ()['message' ]
130198 if message == 'new_change' :
131199 next_stream_position = stream_position
132- for event , next_stream_position in self ._get_all_events_since (stream_position ):
200+ for event , next_stream_position in self ._get_all_events_since (stream_position , stream_type = stream_type ):
133201 try :
134202 event_ids .get (event ['event_id' ])
135203 except KeyError :
@@ -142,10 +210,15 @@ def generate_events_with_long_polling(self, stream_position=None):
142210 else :
143211 break
144212
145- def get_long_poll_options (self ):
213+ def get_long_poll_options (self , stream_type = UserEventsStreamType . ALL ):
146214 """
147215 Get the url and retry timeout for setting up a long polling connection.
148216
217+ :param stream_type:
218+ (optional) Which type of events to return.
219+ Defaults to `UserEventsStreamType.ALL`.
220+ :type stream_type:
221+ :enum:`EventsStreamType`
149222 :returns:
150223 A `dict` including a long poll url, retry timeout, etc.
151224 E.g.
@@ -160,5 +233,6 @@ def get_long_poll_options(self):
160233 `dict`
161234 """
162235 url = self .get_url ()
163- box_response = self ._session .options (url )
236+ params = {'stream_type' : stream_type }
237+ box_response = self ._session .options (url , params = params )
164238 return box_response .json ()['entries' ][0 ]
0 commit comments