boxr 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 67e27a5d8aa317d4f5367ca297a6effba37f940c
4
- data.tar.gz: b3541ffde249148cbdde2f1666479c1377993b7e
3
+ metadata.gz: 85a9e52479cab2e593a06741ba16b2e4a44f60d6
4
+ data.tar.gz: 20e2668309a30f3adbd07a0f494ccb97788144a0
5
5
  SHA512:
6
- metadata.gz: 9837ce765c7cf63b3df57ab8fbf513b2e9f6745d447291bcedfd7a9bdc672028b185b93b52797c1fc9e36600f931fe6f40f0824122f659eff96ca052d3a3ae0d
7
- data.tar.gz: bd84a9467ad8df991be52c8832cd63e0e5bb112352e20d7d1418b3ad7ddc77d98d4dbbb6c71eee253eeeb5d70a926fe10b4d1188ec4ec7df45c31aad7d536e01
6
+ metadata.gz: 46f24ca8c3bfb93a098c5dfbd63b69eeff3a316e662d119d096a0c92264608d755629fe933955d9ab5ad7b78d960c870ffb05bcc6427ee9bc78e1dda7568ca30
7
+ data.tar.gz: 7f62b487fe1526578ab85386dda281b6cabcf1f21a69fcc83b39cd469dc7109b060dea139a4775016e2f060269045b2641bff38dfcc144478335b7939f08d274
@@ -3,7 +3,10 @@
3
3
  #3. click 'Edit Application'
4
4
  #4. check the boxes for 'Read and write all files and folders' and 'Manage an enterprise'
5
5
  #5. click 'Create a developer token'
6
- #6. paste the value below
7
- #7. save this file as .env
6
+ #6. copy and paste the developer token below
7
+ #7. copy and paste the client id and client secret of your Box app below
8
+ #8. save this file as .env
8
9
 
9
- BOX_DEVELOPER_TOKEN=bsuwpLRJYN123NJTOisOvdvBCloboMqW
10
+ BOX_DEVELOPER_TOKEN={a valid developer token for your Box app}
11
+ BOX_CLIENT_ID={client id of your Box app}
12
+ BOX_CLIENT_SECRET={client secret of your Box app}
data/Rakefile CHANGED
@@ -1,5 +1,3 @@
1
- import "./lib/tasks/oauth.rake"
2
-
3
1
  require 'rspec/core/rake_task'
4
2
  require "bundler/gem_tasks"
5
3
 
@@ -5,17 +5,17 @@ require 'awesome_print'
5
5
  client = Boxr::Client.new(ENV['BOX_DEVELOPER_TOKEN'])
6
6
 
7
7
  now = Time.now
8
- start_date = now - (60*60*24*30) #three days ago
9
- end_date = now - (60*60*24) #one day ago
8
+ start_date = now - (60*60*24) #one day ago
9
+ end_date = now
10
10
 
11
11
  stream_position = 0
12
12
  puts "fetching enterprise events..."
13
13
  loop do
14
- event_response = client.enterprise_events(stream_position: stream_position, created_after: start_date.utc, created_before: end_date.utc)
15
- event_response.events.each do |event|
16
- ap event
17
- end
18
- stream_position = event_response.next_stream_position
14
+ event_response = client.enterprise_events(stream_position: stream_position, created_after: start_date.utc, created_before: end_date.utc)
15
+ event_response.events.each do |event|
16
+ puts "#{event.event_type}, #{event.created_by.name}"
17
+ end
18
+ stream_position = event_response.next_stream_position
19
19
 
20
- break if event_response.events.empty?
20
+ break if event_response.events.empty?
21
21
  end
@@ -0,0 +1,27 @@
1
+ require 'dotenv'; Dotenv.load("../.env")
2
+ require 'boxr'
3
+ require 'uri'
4
+ require 'awesome_print'
5
+
6
+ #make sure you have BOX_CLIENT_ID and BOX_CLIENT_SECRET set in your .env file
7
+ #make sure you have the redirect_uri for your application set to something like https://localhost:1234 in the developer portal
8
+
9
+ oauth_url = Boxr::oauth_url(URI.encode_www_form_component('your-anti-forgery-token'))
10
+
11
+ puts "Copy the URL below and paste into a browser. Go through the OAuth flow using the desired Box account. \
12
+ When you are finished your browser will redirect to a 404 error page. This is expected behavior. Look at the URL in the address \
13
+ bar and copy the 'code' parameter value. Paste it into the prompt below. You only have 30 seconds to complete this task so be quick about it! \
14
+ You will then see your access token and refresh token."
15
+
16
+ puts
17
+ puts "URL: #{oauth_url}"
18
+ puts
19
+
20
+ print "Enter the code: "
21
+ code = STDIN.gets.chomp.split('=').last
22
+
23
+ ap Boxr::get_tokens(code)
24
+
25
+
26
+
27
+
@@ -8,17 +8,17 @@ cache = LruRedux::Cache.new(1000)
8
8
 
9
9
  stream_position = :now
10
10
  loop do
11
- puts "fetching events..."
12
- event_response = client.user_events(stream_position: stream_position)
13
- event_response.events.each do |event|
14
- key = "/box-event/id/#{event.event_id}"
11
+ puts "fetching events..."
12
+ event_response = client.user_events(stream_position: stream_position)
13
+ event_response.events.each do |event|
14
+ key = "/box-event/id/#{event.event_id}"
15
15
 
16
- #we need to de-dupe the events because we will receive multiple events with the same event_id; this is to ensure that we get the event
17
- if (cache.fetch(event.event_id)==nil)
18
- cache[event.event_id] = true
19
- puts event.event_type
20
- end
21
- end
22
- stream_position = event_response.next_stream_position
23
- sleep 2
16
+ #we need to de-dupe the events because we will receive multiple events with the same event_id; this is to ensure that we get the event
17
+ if (cache.fetch(event.event_id)==nil)
18
+ cache[event.event_id] = true
19
+ puts event.event_type
20
+ end
21
+ end
22
+ stream_position = event_response.next_stream_position
23
+ sleep 2
24
24
  end
@@ -16,24 +16,25 @@ require 'boxr/search'
16
16
  require 'boxr/tasks'
17
17
  require 'boxr/metadata'
18
18
  require 'boxr/events'
19
+ require 'boxr/auth'
19
20
 
20
21
  module Enumerable
21
- def files
22
- self.select{|i| i.type == 'file'}
23
- end
22
+ def files
23
+ self.select{|i| i.type == 'file'}
24
+ end
24
25
 
25
- def folders
26
- self.select{|i| i.type == 'folder'}
27
- end
26
+ def folders
27
+ self.select{|i| i.type == 'folder'}
28
+ end
28
29
 
29
- def web_links
30
- self.select{|i| i.type == 'web_link'}
31
- end
30
+ def web_links
31
+ self.select{|i| i.type == 'web_link'}
32
+ end
32
33
  end
33
34
 
34
35
  module Boxr
35
36
  Oj.default_options = {:mode => :compat }
36
37
 
37
- #The root folder in Box is always identified by 0
38
- ROOT = 0
38
+ #The root folder in Box is always identified by 0
39
+ ROOT = 0
39
40
  end
@@ -0,0 +1,46 @@
1
+ module Boxr
2
+
3
+ def self.oauth_url(state, response_type: "code", scope: nil, folder_id: nil, box_client_id: ENV['BOX_CLIENT_ID'])
4
+ uri = "https://app.box.com/api/oauth2/authorize?response_type=#{response_type}&state=#{state}&client_id=#{box_client_id}"
5
+ uri = uri + "&scope=#{scope}" unless scope.nil?
6
+ uri = uri + "&folder_id=#{folder_id}" unless folder_id.nil?
7
+ uri
8
+ end
9
+
10
+ def self.get_tokens(code, grant_type: "authorization_code", username: nil, box_client_id: ENV['BOX_CLIENT_ID'], box_client_secret: ENV['BOX_CLIENT_SECRET'])
11
+ uri = "https://api.box.com/oauth2/token"
12
+ body = "code=#{code}&grant_type=#{grant_type}&client_id=#{box_client_id}&client_secret=#{box_client_secret}"
13
+ body = body + "&username=#{username}" unless username.nil?
14
+
15
+ auth_post(uri, body)
16
+ end
17
+
18
+ def self.refresh_tokens(refresh_token, box_client_id: ENV['BOX_CLIENT_ID'], box_client_secret: ENV['BOX_CLIENT_SECRET'])
19
+ uri = "https://api.box.com/oauth2/token"
20
+ body = "grant_type=refresh_token&refresh_token=#{refresh_token}&client_id=#{box_client_id}&client_secret=#{box_client_secret}"
21
+
22
+ auth_post(uri, body)
23
+ end
24
+
25
+ def self.revoke_tokens(token, box_client_id: ENV['BOX_CLIENT_ID'], box_client_secret: ENV['BOX_CLIENT_SECRET'])
26
+ uri = "https://api.box.com/oauth2/revoke"
27
+ body = "client_id=#{box_client_id}&client_secret=#{box_client_secret}&token=#{token}"
28
+
29
+ auth_post(uri, body)
30
+ end
31
+
32
+ private
33
+
34
+ def self.auth_post(uri, body)
35
+ client = HTTPClient.new
36
+ res = client.post(uri, body: body)
37
+
38
+ if(res.status==200)
39
+ body_json = Oj.load(res.body)
40
+ return Hashie::Mash.new(body_json)
41
+ else
42
+ raise BoxrException.new(status: res.status, body: res.body, header: res.header)
43
+ end
44
+ end
45
+
46
+ end
@@ -1,217 +1,258 @@
1
1
  module Boxr
2
-
3
- class Client
4
-
5
- API_URI = "https://api.box.com/2.0"
6
- UPLOAD_URI = "https://upload.box.com/api/2.0"
7
- FILES_URI = "#{API_URI}/files"
8
- FILES_UPLOAD_URI = "#{UPLOAD_URI}/files/content"
9
- FOLDERS_URI = "#{API_URI}/folders"
10
- USERS_URI = "#{API_URI}/users"
11
- GROUPS_URI = "#{API_URI}/groups"
12
- GROUP_MEMBERSHIPS_URI = "#{API_URI}/group_memberships"
13
- COLLABORATIONS_URI = "#{API_URI}/collaborations"
14
- COMMENTS_URI = "#{API_URI}/comments"
15
- SEARCH_URI = "#{API_URI}/search"
16
- TASKS_URI = "#{API_URI}/tasks"
17
- TASK_ASSIGNMENTS_URI = "#{API_URI}/task_assignments"
18
- SHARED_ITEMS_URI = "#{API_URI}/shared_items"
19
- METADATA_URI = "#{API_URI}/files"
20
- EVENTS_URI = "#{API_URI}/events"
21
-
22
- DEFAULT_LIMIT = 100
23
- FOLDER_ITEMS_LIMIT = 1000
24
-
25
- FOLDER_AND_FILE_FIELDS = [:type,:id,:sequence_id,:etag,:name,:created_at,:modified_at,:description,
26
- :size,:path_collection,:created_by,:modified_by,:trashed_at,:purged_at,
27
- :content_created_at,:content_modified_at,:owned_by,:shared_link,:folder_upload_email,
28
- :parent,:item_status,:item_collection,:sync_state,:has_collaborations,:permissions,:tags,
29
- :sha1,:shared_link,:version_number,:comment_count,:lock,:extension,:is_package,:can_non_owners_invite]
30
- FOLDER_AND_FILE_FIELDS_QUERY = FOLDER_AND_FILE_FIELDS.join(',')
31
-
32
- COMMENT_FIELDS = [:type,:id,:is_reply_comment,:message,:tagged_message,:created_by,:created_at,:item,:modified_at]
33
- COMMENT_FIELDS_QUERY = COMMENT_FIELDS.join(',')
34
-
35
- TASK_FIELDS = [:type,:id,:item,:due_at,:action,:message,:task_assignment_collection,:is_completed,:created_by,:created_at]
36
- TASK_FIELDS_QUERY = TASK_FIELDS.join(',')
37
-
38
- COLLABORATION_FIELDS = [:type,:id,:created_by,:created_at,:modified_at,:expires_at,:status,:accessible_by,:role,:acknowledged_at,:item]
39
- COLLABORATION_FIELDS_QUERY = COLLABORATION_FIELDS.join(',')
40
-
41
- USER_FIELDS = [:type,:id,:name,:login,:created_at,:modified_at,:role,:language,:timezone,:space_amount,:space_used,
42
- :max_upload_size,:tracking_codes,:can_see_managed_users,:is_sync_enabled,:is_external_collab_restricted,
43
- :status,:job_title,:phone,:address,:avatar_uri,:is_exempt_from_device_limits,:is_exempt_from_login_verification,
44
- :enterprise,:my_tags]
45
- USER_FIELDS_QUERY = USER_FIELDS.join(',')
46
-
47
- GROUP_FIELDS = [:type, :id, :name, :created_at, :modified_at]
48
- GROUP_FIELDS_QUERY = GROUP_FIELDS.join(',')
49
-
50
- #Read this to see why the httpclient gem was chosen: http://bibwild.wordpress.com/2012/04/30/ruby-http-performance-shootout-redux/
51
- #All instances of Boxr::Client will use this one class instance of HTTPClient; that way persistent HTTPS connections work.
52
- #Plus, httpclient is thread-safe so we can use the same class instance with multiple instances of Boxr::Client
53
- BOX_CLIENT = HTTPClient.new
54
- BOX_CLIENT.send_timeout = 3600 #one hour; needed for lengthy uploads
55
- BOX_CLIENT.transparent_gzip_decompression = true
56
-
57
- def initialize(token, as_user_id: nil)
58
- @token = token
59
- @as_user_id = as_user_id
60
- end
61
-
62
- def debug_device=(device)
63
- if device
64
- BOX_CLIENT.debug_dev = device
65
- BOX_CLIENT.transparent_gzip_decompression = false
66
- else
67
- BOX_CLIENT.debug_dev = nil
68
- BOX_CLIENT.transparent_gzip_decompression = true
69
- end
70
- end
71
-
72
-
73
-
74
- private
75
-
76
- def get(uri, query: nil, success_codes: [200], process_response: true, if_match: nil, box_api_header: nil)
77
- headers = standard_headers()
78
- headers['If-Match'] = if_match unless if_match.nil?
79
- headers['BoxApi'] = box_api_header unless box_api_header.nil?
80
-
81
- res = BOX_CLIENT.get(uri, query: query, header: headers)
82
- check_response_status(res, success_codes)
83
-
84
- if process_response
85
- return processed_response res
86
- else
87
- return res.body, res
88
- end
89
- end
90
-
91
- def get_with_pagination(uri, query: {}, limit: DEFAULT_LIMIT)
92
- entries = []
93
- offset = 0
94
- headers = standard_headers()
95
-
96
- begin
97
- query[:limit] = limit
98
- query[:offset] = offset
99
- res = BOX_CLIENT.get(uri, query: query, header: headers)
100
-
101
- if (res.status==200)
102
- body_json = Oj.load(res.body)
103
- total_count = body_json["total_count"]
104
- offset = offset + limit
105
-
106
- entries << body_json["entries"]
107
- else
108
- raise BoxrException.new(status: res.status, body: res.body, header: res.header)
109
- end
110
- end until offset - total_count >= 0
111
-
112
- entries.flatten.map{|i| Hashie::Mash.new(i)}
113
- end
114
-
115
- def post(uri, body, query: nil, success_codes: [201], process_body: true, content_md5: nil, content_type: nil, if_match: nil)
116
- body = Oj.dump(body) if process_body
117
-
118
- headers = standard_headers()
119
- headers['If-Match'] = if_match unless if_match.nil?
120
- headers["Content-MD5"] = content_md5 unless content_md5.nil?
121
- headers["Content-Type"] = content_type unless content_type.nil?
122
-
123
- res = BOX_CLIENT.post(uri, body: body, query: query, header: headers)
124
- check_response_status(res, success_codes)
125
-
126
- processed_response res
127
- end
128
-
129
- def put(uri, body, query: nil, success_codes: [200], content_type: nil, if_match: nil)
130
- headers = standard_headers()
131
- headers['If-Match'] = if_match unless if_match.nil?
132
- headers["Content-Type"] = content_type unless content_type.nil?
133
-
134
- res = BOX_CLIENT.put(uri, body: Oj.dump(body), query: query, header: headers)
135
- check_response_status(res, success_codes)
136
-
137
- processed_response res
138
- end
139
-
140
- def delete(uri, query: nil, success_codes: [204], if_match: nil)
141
- headers = standard_headers()
142
- headers['If-Match'] = if_match unless if_match.nil?
143
-
144
- res = BOX_CLIENT.delete(uri, query: query, header: headers)
145
- check_response_status(res, success_codes)
146
-
147
- processed_response res
148
- end
149
-
150
- def options(uri, body, success_codes: [200])
151
- headers = standard_headers()
152
-
153
- res = BOX_CLIENT.options(uri, body: Oj.dump(body), header: headers)
154
- check_response_status(res, success_codes)
155
-
156
- processed_response res
157
- end
158
-
159
- def standard_headers()
160
- headers = {"Authorization" => "Bearer #{@token}"}
161
- headers['As-User'] = "#{@as_user_id}" unless @as_user_id.nil?
162
- headers
163
- end
164
-
165
- def check_response_status(res, success_codes)
166
- raise BoxrException.new(status: res.status, body: res.body, header: res.header) unless success_codes.include?(res.status)
167
- end
168
-
169
- def processed_response(res)
170
- body_json = Oj.load(res.body)
171
- return Hashie::Mash.new(body_json), res
172
- end
173
-
174
- def build_fields_query(fields, all_fields_query)
175
- if fields == :all
176
- {:fields => all_fields_query}
177
- elsif fields.is_a?(Array) && fields.length > 0
178
- {:fields => fields.join(',')}
179
- else
180
- {}
181
- end
182
- end
183
-
184
- def restore_trashed_item(uri, name, parent_id)
185
- attributes = {}
186
- attributes[:name] = name unless name.nil?
187
- attributes[:parent] = {id: parent_id} unless parent_id.nil?
188
-
189
- restored_item, response = post uri, attributes
190
- restored_item
191
- end
192
-
193
- def create_shared_link(uri, item_id, access, unshared_at, can_download, can_preview)
194
- if access.nil?
195
- attributes = {shared_link: {}}
196
- else
197
- attributes = {shared_link: {access: access}}
198
- attributes[:shared_link][:unshared_at] = unshared_at.to_datetime.rfc3339 if unshared_at
199
- attributes[:shared_link][:permissions] = {} unless can_download.nil? && can_preview.nil?
200
- attributes[:shared_link][:permissions][:can_download] = can_download unless can_download.nil?
201
- attributes[:shared_link][:permissions][:can_preview] = can_preview unless can_preview.nil?
202
- end
203
-
204
- updated_item, response = put uri, attributes
205
- updated_item
206
- end
207
-
208
- def disable_shared_link(uri, item_id)
209
- attributes = {shared_link: nil}
210
-
211
- updated_item, response = put uri, attributes
212
- updated_item
213
- end
214
-
215
- end
2
+
3
+ class Client
4
+
5
+ attr_reader :access_token, :refresh_token, :box_client_id, :box_client_secret, :identifier, :as_user_id
6
+
7
+ API_URI = "https://api.box.com/2.0"
8
+ UPLOAD_URI = "https://upload.box.com/api/2.0"
9
+ FILES_URI = "#{API_URI}/files"
10
+ FILES_UPLOAD_URI = "#{UPLOAD_URI}/files/content"
11
+ FOLDERS_URI = "#{API_URI}/folders"
12
+ USERS_URI = "#{API_URI}/users"
13
+ GROUPS_URI = "#{API_URI}/groups"
14
+ GROUP_MEMBERSHIPS_URI = "#{API_URI}/group_memberships"
15
+ COLLABORATIONS_URI = "#{API_URI}/collaborations"
16
+ COMMENTS_URI = "#{API_URI}/comments"
17
+ SEARCH_URI = "#{API_URI}/search"
18
+ TASKS_URI = "#{API_URI}/tasks"
19
+ TASK_ASSIGNMENTS_URI = "#{API_URI}/task_assignments"
20
+ SHARED_ITEMS_URI = "#{API_URI}/shared_items"
21
+ METADATA_URI = "#{API_URI}/files"
22
+ EVENTS_URI = "#{API_URI}/events"
23
+
24
+ DEFAULT_LIMIT = 100
25
+ FOLDER_ITEMS_LIMIT = 1000
26
+
27
+ FOLDER_AND_FILE_FIELDS = [:type,:id,:sequence_id,:etag,:name,:created_at,:modified_at,:description,
28
+ :size,:path_collection,:created_by,:modified_by,:trashed_at,:purged_at,
29
+ :content_created_at,:content_modified_at,:owned_by,:shared_link,:folder_upload_email,
30
+ :parent,:item_status,:item_collection,:sync_state,:has_collaborations,:permissions,:tags,
31
+ :sha1,:shared_link,:version_number,:comment_count,:lock,:extension,:is_package,:can_non_owners_invite]
32
+ FOLDER_AND_FILE_FIELDS_QUERY = FOLDER_AND_FILE_FIELDS.join(',')
33
+
34
+ COMMENT_FIELDS = [:type,:id,:is_reply_comment,:message,:tagged_message,:created_by,:created_at,:item,:modified_at]
35
+ COMMENT_FIELDS_QUERY = COMMENT_FIELDS.join(',')
36
+
37
+ TASK_FIELDS = [:type,:id,:item,:due_at,:action,:message,:task_assignment_collection,:is_completed,:created_by,:created_at]
38
+ TASK_FIELDS_QUERY = TASK_FIELDS.join(',')
39
+
40
+ COLLABORATION_FIELDS = [:type,:id,:created_by,:created_at,:modified_at,:expires_at,:status,:accessible_by,:role,:acknowledged_at,:item]
41
+ COLLABORATION_FIELDS_QUERY = COLLABORATION_FIELDS.join(',')
42
+
43
+ USER_FIELDS = [:type,:id,:name,:login,:created_at,:modified_at,:role,:language,:timezone,:space_amount,:space_used,
44
+ :max_upload_size,:tracking_codes,:can_see_managed_users,:is_sync_enabled,:is_external_collab_restricted,
45
+ :status,:job_title,:phone,:address,:avatar_uri,:is_exempt_from_device_limits,:is_exempt_from_login_verification,
46
+ :enterprise,:my_tags]
47
+ USER_FIELDS_QUERY = USER_FIELDS.join(',')
48
+
49
+ GROUP_FIELDS = [:type, :id, :name, :created_at, :modified_at]
50
+ GROUP_FIELDS_QUERY = GROUP_FIELDS.join(',')
51
+
52
+ #Read this to see why the httpclient gem was chosen: http://bibwild.wordpress.com/2012/04/30/ruby-http-performance-shootout-redux/
53
+ #All instances of Boxr::Client will use this one class instance of HTTPClient; that way persistent HTTPS connections work.
54
+ #Plus, httpclient is thread-safe so we can use the same class instance with multiple instances of Boxr::Client
55
+ BOX_CLIENT = HTTPClient.new
56
+ BOX_CLIENT.send_timeout = 3600 #one hour; needed for lengthy uploads
57
+ BOX_CLIENT.transparent_gzip_decompression = true
58
+
59
+ def self.turn_on_debugging(device=STDOUT)
60
+ BOX_CLIENT.debug_dev = device
61
+ BOX_CLIENT.transparent_gzip_decompression = false
62
+ end
63
+
64
+ def self.turn_off_debugging
65
+ BOX_CLIENT.debug_dev = nil
66
+ BOX_CLIENT.transparent_gzip_decompression = true
67
+ end
68
+
69
+ def initialize(access_token, refresh_token: nil, box_client_id: ENV['BOX_CLIENT_ID'], box_client_secret: ENV['BOX_CLIENT_SECRET'],
70
+ identifier: nil, as_user_id: nil, &token_refresh_listener)
71
+ @access_token = access_token
72
+ @refresh_token = refresh_token
73
+ @box_client_id = box_client_id
74
+ @box_client_secret = box_client_secret
75
+ @identifier = identifier
76
+ @as_user_id = as_user_id
77
+ @token_refresh_listener = token_refresh_listener
78
+ end
79
+
80
+
81
+ private
82
+
83
+ def get(uri, query: nil, success_codes: [200], process_response: true, if_match: nil, box_api_header: nil)
84
+ res = with_auto_token_refresh do
85
+ headers = standard_headers()
86
+ headers['If-Match'] = if_match unless if_match.nil?
87
+ headers['BoxApi'] = box_api_header unless box_api_header.nil?
88
+
89
+ BOX_CLIENT.get(uri, query: query, header: headers)
90
+ end
91
+
92
+ check_response_status(res, success_codes)
93
+
94
+ if process_response
95
+ return processed_response res
96
+ else
97
+ return res.body, res
98
+ end
99
+ end
100
+
101
+ def get_with_pagination(uri, query: {}, limit: DEFAULT_LIMIT)
102
+ entries = []
103
+ offset = 0
104
+
105
+ begin
106
+ query[:limit] = limit
107
+ query[:offset] = offset
108
+ res = with_auto_token_refresh do
109
+ headers = standard_headers()
110
+ BOX_CLIENT.get(uri, query: query, header: headers)
111
+ end
112
+
113
+ if (res.status==200)
114
+ body_json = Oj.load(res.body)
115
+ total_count = body_json["total_count"]
116
+ offset = offset + limit
117
+
118
+ entries << body_json["entries"]
119
+ else
120
+ raise BoxrException.new(status: res.status, body: res.body, header: res.header)
121
+ end
122
+ end until offset - total_count >= 0
123
+
124
+ entries.flatten.map{|i| Hashie::Mash.new(i)}
125
+ end
126
+
127
+ def post(uri, body, query: nil, success_codes: [201], process_body: true, content_md5: nil, content_type: nil, if_match: nil)
128
+ body = Oj.dump(body) if process_body
129
+
130
+ res = with_auto_token_refresh do
131
+ headers = standard_headers()
132
+ headers['If-Match'] = if_match unless if_match.nil?
133
+ headers["Content-MD5"] = content_md5 unless content_md5.nil?
134
+ headers["Content-Type"] = content_type unless content_type.nil?
135
+
136
+ BOX_CLIENT.post(uri, body: body, query: query, header: headers)
137
+ end
138
+
139
+ check_response_status(res, success_codes)
140
+
141
+ processed_response res
142
+ end
143
+
144
+ def put(uri, body, query: nil, success_codes: [200], content_type: nil, if_match: nil)
145
+ res = with_auto_token_refresh do
146
+ headers = standard_headers()
147
+ headers['If-Match'] = if_match unless if_match.nil?
148
+ headers["Content-Type"] = content_type unless content_type.nil?
149
+
150
+ BOX_CLIENT.put(uri, body: Oj.dump(body), query: query, header: headers)
151
+ end
152
+
153
+ check_response_status(res, success_codes)
154
+
155
+ processed_response res
156
+ end
157
+
158
+ def delete(uri, query: nil, success_codes: [204], if_match: nil)
159
+ res = with_auto_token_refresh do
160
+ headers = standard_headers()
161
+ headers['If-Match'] = if_match unless if_match.nil?
162
+
163
+ BOX_CLIENT.delete(uri, query: query, header: headers)
164
+ end
165
+
166
+ check_response_status(res, success_codes)
167
+
168
+ processed_response res
169
+ end
170
+
171
+ def options(uri, body, success_codes: [200])
172
+ res = with_auto_token_refresh do
173
+ headers = standard_headers()
174
+ BOX_CLIENT.options(uri, body: Oj.dump(body), header: headers)
175
+ end
176
+
177
+ check_response_status(res, success_codes)
178
+
179
+ processed_response res
180
+ end
181
+
182
+ def standard_headers()
183
+ headers = {"Authorization" => "Bearer #{@access_token}"}
184
+ headers['As-User'] = "#{@as_user_id}" unless @as_user_id.nil?
185
+ headers
186
+ end
187
+
188
+ def with_auto_token_refresh
189
+ return yield unless @refresh_token
190
+
191
+ res = yield
192
+ if res.status == 401
193
+ auth_header = res.header['WWW-Authenticate'][0]
194
+ if auth_header && auth_header.include?('invalid_token')
195
+ new_tokens = Boxr::refresh_tokens(@refresh_token, box_client_id: box_client_id, box_client_secret: box_client_secret)
196
+ @access_token = new_tokens.access_token
197
+ @refresh_token = new_tokens.refresh_token
198
+ @token_refresh_listener.call(@access_token, @refresh_token, @identifier) if @token_refresh_listener
199
+ res = yield
200
+ end
201
+ end
202
+
203
+ res
204
+ end
205
+
206
+ def check_response_status(res, success_codes)
207
+ raise BoxrException.new(status: res.status, body: res.body, header: res.header) unless success_codes.include?(res.status)
208
+ end
209
+
210
+ def processed_response(res)
211
+ body_json = Oj.load(res.body)
212
+ return Hashie::Mash.new(body_json), res
213
+ end
214
+
215
+ def build_fields_query(fields, all_fields_query)
216
+ if fields == :all
217
+ {:fields => all_fields_query}
218
+ elsif fields.is_a?(Array) && fields.length > 0
219
+ {:fields => fields.join(',')}
220
+ else
221
+ {}
222
+ end
223
+ end
224
+
225
+ def restore_trashed_item(uri, name, parent_id)
226
+ attributes = {}
227
+ attributes[:name] = name unless name.nil?
228
+ attributes[:parent] = {id: parent_id} unless parent_id.nil?
229
+
230
+ restored_item, response = post uri, attributes
231
+ restored_item
232
+ end
233
+
234
+ def create_shared_link(uri, item_id, access, unshared_at, can_download, can_preview)
235
+ if access.nil?
236
+ attributes = {shared_link: {}}
237
+ else
238
+ attributes = {shared_link: {access: access}}
239
+ attributes[:shared_link][:unshared_at] = unshared_at.to_datetime.rfc3339 unless unshared_at.nil?
240
+ attributes[:shared_link][:permissions] = {} unless can_download.nil? && can_preview.nil?
241
+ attributes[:shared_link][:permissions][:can_download] = can_download unless can_download.nil?
242
+ attributes[:shared_link][:permissions][:can_preview] = can_preview unless can_preview.nil?
243
+ end
244
+
245
+ updated_item, response = put uri, attributes
246
+ updated_item
247
+ end
248
+
249
+ def disable_shared_link(uri, item_id)
250
+ attributes = {shared_link: nil}
251
+
252
+ updated_item, response = put uri, attributes
253
+ updated_item
254
+ end
255
+
256
+ end
216
257
 
217
258
  end