boxr 1.23.1 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61830d438f70d8585c435bf00b719911cba3a4687ce9df4310f7232d50b4bd5b
4
- data.tar.gz: 677ffb4ccd6ea0ef5478e1dd879e202c2c8605e12561a72c865b05689295a4a1
3
+ metadata.gz: 61cea90fb968b5080ce842d650aafd74224bdc6caf7cbe11e168aa0f3ef7c4c3
4
+ data.tar.gz: 9de8543da3e1029de8ea4d9c0c346cfd6a05563a8119f7a3a81356bafd7a6831
5
5
  SHA512:
6
- metadata.gz: cf1a95e4d924c7e7c64bfda48f7c33524cb3c4a6a1de8d443044c92b56dd80a6747cfe2229e9cfd5d60ff68f147538d47aa06682cec6e059ef20e69f8ed342e9
7
- data.tar.gz: bbbdcbdeab436de980d16a6d9e3dd4def18068421094b75787991fee3f79bd6b530d7df2e5255171340d838ae2c6df8b7c54e525be5b73b7435c1558987048d1
6
+ metadata.gz: 4b16ccaec58eaa114cfb7c41f62e10cc05e8d07c45ce3e73c4e03d5ebf9407e022cb381cde5ceab0c88ace21a1d3b27b3564cf3b3b49be6fd8a3955e4006f771
7
+ data.tar.gz: c3eb8f6e86e09ceffd43f6a6eccd6d38f1dac13b32a924fc3ef588168e0dc2d76672bc982a0f2036a362db1bc75431c9df0b851fe41b6040016689b0c2fb9330
data/boxr.gemspec CHANGED
@@ -38,5 +38,5 @@ Gem::Specification.new do |spec|
38
38
  spec.add_runtime_dependency 'addressable', '~> 2.8'
39
39
  spec.add_runtime_dependency 'hashie', '>= 3.5', '< 6'
40
40
  spec.add_runtime_dependency 'httpclient', '~> 2.8'
41
- spec.add_runtime_dependency 'jwt', '>= 1.4', '< 3'
41
+ spec.add_runtime_dependency 'jwt', '>= 1.4', '< 4'
42
42
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Boxr
4
+ class Client
5
+ def get_user_avatar(user_id)
6
+ user_id = ensure_id(user_id)
7
+ uri = "#{USERS_URI}/#{user_id}/avatar"
8
+
9
+ avatar_data, = get(uri, process_response: false)
10
+ avatar_data
11
+ end
12
+
13
+ def create_user_avatar(user_id, pic, pic_file_name: nil, pic_content_type: nil)
14
+ user_id = ensure_id(user_id)
15
+ uri = "#{USERS_URI}/#{user_id}/avatar"
16
+
17
+ body = { pic: pic }
18
+ body[:pic_file_name] = pic_file_name unless pic_file_name.nil?
19
+ body[:pic_content_type] = pic_content_type unless pic_content_type.nil?
20
+
21
+ avatar, = post(uri, body, process_body: false, content_type: 'multipart/form-data')
22
+ avatar
23
+ end
24
+
25
+ def delete_user_avatar(user_id)
26
+ user_id = ensure_id(user_id)
27
+ uri = "#{USERS_URI}/#{user_id}/avatar"
28
+
29
+ result, = delete(uri)
30
+ result
31
+ end
32
+ end
33
+ end
@@ -17,7 +17,6 @@ module Boxr
17
17
  body = { folder_id: parent_id, file_size: io.size, file_name: name }
18
18
  session_info, = post(uri, body, content_type: 'application/json',
19
19
  success_codes: [200, 201, 202])
20
-
21
20
  session_info
22
21
  end
23
22
 
@@ -35,14 +34,12 @@ module Boxr
35
34
  body = { file_size: io.size, file_name: name }
36
35
  session_info, = post(uri, body, content_type: 'application/json',
37
36
  success_codes: [200, 201, 202])
38
-
39
37
  session_info
40
38
  end
41
39
 
42
40
  def chunked_upload_get_session(session_id)
43
41
  uri = "#{UPLOAD_URI}/files/upload_sessions/#{session_id}"
44
42
  session_info, = get(uri)
45
-
46
43
  session_info
47
44
  end
48
45
 
@@ -52,20 +49,20 @@ module Boxr
52
49
  end
53
50
  end
54
51
 
55
- def chunked_upload_part_from_io(io, session_id, content_range)
52
+ def chunked_upload_part_from_io(io, session_id, content_range) # rubocop:disable Metrics
56
53
  io.pos = content_range.min
57
54
  part_size = content_range.max - content_range.min + 1
58
- data = io.read(part_size)
55
+ body = io.read(part_size)
59
56
  io.rewind
60
57
 
61
- digest = "sha=#{Digest::SHA1.base64digest(data)}"
58
+ digest = "sha=#{Digest::SHA1.base64digest(body)}"
62
59
  range = "bytes #{content_range.min}-#{content_range.max}/#{io.size}"
63
60
 
64
61
  uri = "#{UPLOAD_URI}/files/upload_sessions/#{session_id}"
65
- body = data
66
- part_info, = put(uri, body, process_body: false, digest: digest,
67
- content_type: 'application/octet-stream', content_range: range, success_codes: [200, 201, 202])
68
-
62
+ part_info, = put(
63
+ uri, body, process_body: false, digest: digest, content_type: 'application/octet-stream',
64
+ content_range: range, success_codes: [200, 201, 202]
65
+ )
69
66
  part_info.part
70
67
  end
71
68
 
@@ -75,140 +72,158 @@ module Boxr
75
72
  query[:limit] = limit unless limit.nil?
76
73
  query[:offset] = offset unless offset.nil?
77
74
  parts_info, = get(uri, query: query)
78
-
79
75
  parts_info.entries
80
76
  end
81
77
 
82
- def chunked_upload_commit(path_to_file, session_id, parts, content_created_at: nil,
78
+ def chunked_upload_commit(path_to_file, session_id, parts, content_created_at: nil, # rubocop:disable Metrics
83
79
  content_modified_at: nil, if_match: nil, if_non_match: nil)
84
80
  File.open(path_to_file) do |file|
85
- chunked_upload_commit_from_io(file, session_id, parts,
86
- content_created_at: content_created_at, content_modified_at: content_modified_at, if_match: if_match, if_non_match: if_non_match)
81
+ chunked_upload_commit_from_io(
82
+ file, session_id, parts,
83
+ content_created_at: content_created_at, content_modified_at: content_modified_at,
84
+ if_match: if_match, if_non_match: if_non_match
85
+ )
87
86
  end
88
87
  end
89
88
 
90
- def chunked_upload_commit_from_io(io, session_id, parts, content_created_at: nil,
89
+ def chunked_upload_commit_from_io(io, session_id, parts, content_created_at: nil, # rubocop:disable Metrics
91
90
  content_modified_at: nil, if_match: nil, if_non_match: nil)
92
91
  io.pos = 0
93
- digest = Digest::SHA1.new
94
- while (buf = io.read(8 * 1024**2)) && buf.size.positive?
95
- digest.update(buf)
96
- end
97
- io.rewind
98
- digest = "sha=#{digest.base64digest}"
92
+ cca = content_created_at
93
+ cma = content_modified_at
94
+ digest = "sha=#{calculate_chunked_upload_digest(io).base64digest}"
99
95
 
100
96
  attributes = {}
101
- unless content_created_at.nil?
102
- attributes[:content_created_at] =
103
- content_created_at.to_datetime.rfc3339
104
- end
105
- unless content_modified_at.nil?
106
- attributes[:content_modified_at] =
107
- content_modified_at.to_datetime.rfc3339
108
- end
97
+ attributes[:content_created_at] = cca.to_datetime.rfc3339 if cca
98
+ attributes[:content_modified_at] = cma.to_datetime.rfc3339 if cma
109
99
 
110
100
  uri = "#{UPLOAD_URI}/files/upload_sessions/#{session_id}/commit"
111
- body = {
112
- parts: parts,
113
- attributes: attributes
114
- }
115
- commit_info, = post(uri, body, process_body: true, digest: digest,
116
- content_type: 'application/json', if_match: if_match, if_non_match: if_non_match, success_codes: [200, 201, 202])
101
+ body = { parts: parts, attributes: attributes }
117
102
 
118
- commit_info
103
+ loop do
104
+ commit_info, response = post(
105
+ uri, body,
106
+ process_body: true, digest: digest, content_type: 'application/json',
107
+ if_match: if_match, if_non_match: if_non_match, success_codes: [200, 201, 202]
108
+ )
109
+ return commit_info if response.status != 202
110
+
111
+ sleep response.header['Retry-After'][0].to_i
112
+ end
119
113
  end
120
114
 
121
115
  def chunked_upload_abort_session(session_id)
122
116
  uri = "#{UPLOAD_URI}/files/upload_sessions/#{session_id}"
123
117
  abort_info, = delete(uri)
124
-
125
118
  abort_info
119
+ rescue BoxrError # Ignore errors from aborting session
120
+ nil
126
121
  end
127
122
 
128
- def chunked_upload_file(path_to_file, parent, name: nil, n_threads: 1, content_created_at: nil,
129
- content_modified_at: nil)
123
+ def chunked_upload_file(path_to_file, parent, name: nil, n_threads: 1, # rubocop:disable Metrics
124
+ content_created_at: nil, content_modified_at: nil)
130
125
  filename = name || File.basename(path_to_file)
131
126
 
132
127
  File.open(path_to_file) do |file|
133
- chunked_upload_file_from_io(file, parent, filename, n_threads: n_threads,
134
- content_created_at: content_created_at, content_modified_at: content_modified_at)
128
+ chunked_upload_file_from_io(
129
+ file, parent, filename,
130
+ n_threads: n_threads, content_created_at: content_created_at,
131
+ content_modified_at: content_modified_at
132
+ )
135
133
  end
136
134
  end
137
135
 
138
- def chunked_upload_file_from_io(io, parent, name, n_threads: 1, content_created_at: nil,
139
- content_modified_at: nil)
140
- session = nil
141
- file_info = nil
142
-
136
+ def chunked_upload_file_from_io(io, parent, name, n_threads: 1, # rubocop:disable Metrics
137
+ content_created_at: nil, content_modified_at: nil)
143
138
  session = chunked_upload_create_session_new_file_from_io(io, parent, name)
144
-
145
- file_info = chunked_upload_to_session_from_io(io, session, n_threads: n_threads,
146
- content_created_at: nil, content_modified_at: nil)
147
- file_info
148
- ensure
149
- chunked_upload_abort_session(session.id) if file_info.nil? && !session.nil?
139
+ chunked_upload_to_session_from_io(
140
+ io, session,
141
+ n_threads: n_threads, content_created_at: content_created_at,
142
+ content_modified_at: content_modified_at
143
+ )
150
144
  end
151
145
 
152
- def chunked_upload_new_version_of_file(path_to_file, file, name: nil, n_threads: 1,
146
+ def chunked_upload_new_version_of_file(path_to_file, file, name: nil, n_threads: 1, # rubocop:disable Metrics
153
147
  content_created_at: nil, content_modified_at: nil)
154
148
  filename = name || File.basename(path_to_file)
155
149
 
156
150
  File.open(path_to_file) do |io|
157
- chunked_upload_new_version_of_file_from_io(io, file, filename, n_threads: n_threads,
158
- content_created_at: content_created_at, content_modified_at: content_modified_at)
151
+ chunked_upload_new_version_of_file_from_io(
152
+ io, file, filename,
153
+ n_threads: n_threads, content_created_at: content_created_at,
154
+ content_modified_at: content_modified_at
155
+ )
159
156
  end
160
157
  end
161
158
 
162
- def chunked_upload_new_version_of_file_from_io(io, file, name, n_threads: 1,
163
- content_created_at: nil, content_modified_at: nil)
164
- session = nil
165
- file_info = nil
166
-
159
+ def chunked_upload_new_version_of_file_from_io( # rubocop:disable Metrics
160
+ io, file, name, n_threads: 1, content_created_at: nil, content_modified_at: nil
161
+ )
167
162
  session = chunked_upload_create_session_new_version_from_io(io, file, name)
168
-
169
- file_info = chunked_upload_to_session_from_io(io, session, n_threads: n_threads,
170
- content_created_at: nil, content_modified_at: nil)
171
- file_info
172
- ensure
173
- chunked_upload_abort_session(session.id) if file_info.nil? && !session.nil?
163
+ chunked_upload_to_session_from_io(
164
+ io, session,
165
+ n_threads: n_threads, content_created_at: content_created_at,
166
+ content_modified_at: content_modified_at
167
+ )
174
168
  end
175
169
 
176
170
  private
177
171
 
178
172
  PARALLEL_GEM_REQUIREMENT = Gem::Requirement.create('~> 1.0').freeze
179
173
 
180
- def chunked_upload_to_session_from_io(io, session, n_threads: 1, content_created_at: nil,
181
- content_modified_at: nil)
174
+ def chunked_upload_to_session_from_io(io, session, n_threads: 1, # rubocop:disable Metrics
175
+ content_created_at: nil, content_modified_at: nil)
182
176
  content_ranges = []
183
- offset = 0
184
- loop do
185
- limit = [offset + session.part_size, io.size].min - 1
186
- content_ranges << (offset..limit)
187
- break if limit == io.size - 1
188
-
189
- offset = limit + 1
177
+ start_offset = 0
178
+ part_size = session.part_size
179
+ file_size = io.size
180
+ commit_info = nil
181
+
182
+ while start_offset < file_size
183
+ end_offset = [start_offset + part_size, file_size].min - 1
184
+ content_ranges << (start_offset..end_offset)
185
+ start_offset += part_size
190
186
  end
191
187
 
192
188
  parts =
193
189
  if n_threads > 1
194
- unless gem_parallel_available?
195
- raise BoxrError.new(boxr_message: "parallel chunked uploads requires gem parallel (#{PARALLEL_GEM_REQUIREMENT}) to be loaded")
196
- end
197
-
198
- Parallel.map(content_ranges, in_threads: n_threads) do |content_range|
199
- File.open(io.path) do |io_dup|
200
- chunked_upload_part_from_io(io_dup, session.id, content_range)
201
- end
202
- end
190
+ threaded_chunked_upload_part_from_io(io, session.id, content_ranges, n_threads)
203
191
  else
192
+ # Single thread
204
193
  content_ranges.map do |content_range|
205
194
  chunked_upload_part_from_io(io, session.id, content_range)
206
195
  end
207
196
  end
208
197
 
209
- commit_info = chunked_upload_commit_from_io(io, session.id, parts,
210
- content_created_at: content_created_at, content_modified_at: content_modified_at)
198
+ commit_info = chunked_upload_commit_from_io(
199
+ io, session.id, parts,
200
+ content_created_at: content_created_at, content_modified_at: content_modified_at
201
+ )
211
202
  commit_info.entries[0]
203
+ ensure
204
+ chunked_upload_abort_session(session.id) if commit_info.nil? && session
205
+ end
206
+
207
+ def threaded_chunked_upload_part_from_io(io, session_id, content_ranges, n_threads)
208
+ unless gem_parallel_available?
209
+ msg = "parallel chunked uploads requires gem 'parallel'"
210
+ raise BoxrError.new(boxr_message: msg)
211
+ end
212
+
213
+ Parallel.map(content_ranges, in_threads: n_threads) do |content_range|
214
+ File.open(io.path) do |io_dup|
215
+ chunked_upload_part_from_io(io_dup, session_id, content_range)
216
+ end
217
+ end
218
+ end
219
+
220
+ def calculate_chunked_upload_digest(io)
221
+ digest = Digest::SHA1.new
222
+ while (buf = io.read(8 * 1024**2)) && buf.size.positive?
223
+ digest.update(buf)
224
+ end
225
+ io.rewind
226
+ digest
212
227
  end
213
228
 
214
229
  def gem_parallel_available?
data/lib/boxr/client.rb CHANGED
@@ -1,37 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Boxr
4
- class Client
4
+ class Client # rubocop:disable Metrics/ClassLength
5
5
  attr_reader :access_token, :refresh_token, :client_id, :client_secret, :identifier, :as_user_id
6
6
 
7
- # API_URI = "https://wcheng.inside-box.net/api/2.0"
8
- # UPLOAD_URI = "https://upload.wcheng.inside-box.net/api/2.0"
9
-
10
7
  API_URI = 'https://api.box.com/2.0'
11
8
  AUTH_URI = 'https://api.box.com/oauth2/token'
12
9
  REVOKE_AUTH_URI = 'https://api.box.com/oauth2/revoke'
13
10
  UPLOAD_URI = 'https://upload.box.com/api/2.0'
14
- FILES_URI = "#{API_URI}/files"
15
- FILES_UPLOAD_URI = "#{UPLOAD_URI}/files/content"
16
- FOLDERS_URI = "#{API_URI}/folders"
17
- USERS_URI = "#{API_URI}/users"
18
- GROUPS_URI = "#{API_URI}/groups"
19
- GROUP_MEMBERSHIPS_URI = "#{API_URI}/group_memberships"
11
+
12
+ ARCHIVES_URI = "#{API_URI}/archives"
20
13
  COLLABORATIONS_URI = "#{API_URI}/collaborations"
21
14
  COLLECTIONS_URI = "#{API_URI}/collections"
22
15
  COMMENTS_URI = "#{API_URI}/comments"
23
- SEARCH_URI = "#{API_URI}/search"
24
- TASKS_URI = "#{API_URI}/tasks"
25
- TASK_ASSIGNMENTS_URI = "#{API_URI}/task_assignments"
26
- SHARED_ITEMS_URI = "#{API_URI}/shared_items"
16
+ EVENTS_URI = "#{API_URI}/events"
27
17
  FILE_METADATA_URI = "#{API_URI}/files"
18
+ FILES_UPLOAD_URI = "#{UPLOAD_URI}/files/content"
19
+ FILES_URI = "#{API_URI}/files"
28
20
  FOLDER_METADATA_URI = "#{API_URI}/folders"
21
+ FOLDERS_URI = "#{API_URI}/folders"
22
+ GROUP_MEMBERSHIPS_URI = "#{API_URI}/group_memberships"
23
+ GROUPS_URI = "#{API_URI}/groups"
29
24
  METADATA_TEMPLATES_URI = "#{API_URI}/metadata_templates"
30
- EVENTS_URI = "#{API_URI}/events"
25
+ SEARCH_URI = "#{API_URI}/search"
26
+ SHARED_ITEMS_URI = "#{API_URI}/shared_items"
27
+ TASK_ASSIGNMENTS_URI = "#{API_URI}/task_assignments"
28
+ TASKS_URI = "#{API_URI}/tasks"
29
+ USERS_URI = "#{API_URI}/users"
31
30
  WEB_LINKS_URI = "#{API_URI}/web_links"
32
31
  WEBHOOKS_URI = "#{API_URI}/webhooks"
33
32
  ZIP_DOWNLOADS_URI = "#{API_URI}/zip_downloads"
34
33
 
34
+ BOX_VERSION_HEADER_2025 = { 'box-version' => '2025.0' }.freeze
35
+
35
36
  DEFAULT_LIMIT = 100
36
37
  FOLDER_ITEMS_LIMIT = 1000
37
38
 
@@ -101,13 +102,14 @@ module Boxr
101
102
  private
102
103
 
103
104
  def get(uri, query: nil, success_codes: [200], process_response: true, if_match: nil,
104
- box_api_header: nil, follow_redirect: true)
105
+ box_api_header: nil, follow_redirect: true, extra_headers: nil)
105
106
  uri = Addressable::URI.encode(uri)
106
107
 
107
108
  res = with_auto_token_refresh do
108
109
  headers = standard_headers
109
110
  headers['If-Match'] = if_match unless if_match.nil?
110
111
  headers['BoxApi'] = box_api_header unless box_api_header.nil?
112
+ headers.merge!(extra_headers) unless extra_headers.nil?
111
113
 
112
114
  BOX_CLIENT.get(uri, query: query, header: headers, follow_redirect: follow_redirect)
113
115
  end
@@ -151,7 +153,7 @@ module Boxr
151
153
  end
152
154
 
153
155
  def post(uri, body, query: nil, success_codes: [201], process_body: true, digest: nil,
154
- content_md5: nil, content_type: nil, if_match: nil, if_non_match: nil)
156
+ content_md5: nil, content_type: nil, if_match: nil, if_non_match: nil, extra_headers: nil)
155
157
  uri = Addressable::URI.encode(uri)
156
158
  body = JSON.dump(body) if process_body
157
159
 
@@ -162,6 +164,7 @@ module Boxr
162
164
  headers['Content-MD5'] = content_md5 unless content_md5.nil?
163
165
  headers['Content-Type'] = content_type unless content_type.nil?
164
166
  headers['Digest'] = digest unless digest.nil?
167
+ headers.merge!(extra_headers) unless extra_headers.nil?
165
168
 
166
169
  BOX_CLIENT.post(uri, body: body, query: query, header: headers)
167
170
  end
@@ -172,7 +175,7 @@ module Boxr
172
175
  end
173
176
 
174
177
  def put(uri, body, query: nil, success_codes: [200, 201], process_body: true,
175
- content_type: nil, content_range: nil, digest: nil, if_match: nil)
178
+ content_type: nil, content_range: nil, digest: nil, if_match: nil, extra_headers: nil)
176
179
  uri = Addressable::URI.encode(uri)
177
180
  body = JSON.dump(body) if process_body
178
181
 
@@ -182,6 +185,7 @@ module Boxr
182
185
  headers['Content-Type'] = content_type unless content_type.nil?
183
186
  headers['Content-Range'] = content_range unless content_range.nil?
184
187
  headers['Digest'] = digest unless digest.nil?
188
+ headers.merge!(extra_headers) unless extra_headers.nil?
185
189
 
186
190
  BOX_CLIENT.put(uri, body: body, query: query, header: headers)
187
191
  end
@@ -191,12 +195,13 @@ module Boxr
191
195
  processed_response(res)
192
196
  end
193
197
 
194
- def delete(uri, query: nil, success_codes: [204], if_match: nil)
198
+ def delete(uri, query: nil, success_codes: [204], if_match: nil, extra_headers: nil)
195
199
  uri = Addressable::URI.encode(uri)
196
200
 
197
201
  res = with_auto_token_refresh do
198
202
  headers = standard_headers
199
203
  headers['If-Match'] = if_match unless if_match.nil?
204
+ headers.merge!(extra_headers) unless extra_headers.nil?
200
205
 
201
206
  BOX_CLIENT.delete(uri, query: query, header: headers)
202
207
  end
@@ -2,6 +2,15 @@
2
2
 
3
3
  module Boxr
4
4
  class Client
5
+ def collection_from_id(collection_id)
6
+ collection_id = ensure_id(collection_id)
7
+ uri = "#{COLLECTIONS_URI}/#{collection_id}"
8
+
9
+ collection, = get(uri)
10
+ collection
11
+ end
12
+ alias collection collection_from_id
13
+
5
14
  def collections
6
15
  get_all_with_pagination(COLLECTIONS_URI, offset: 0, limit: DEFAULT_LIMIT)
7
16
  end
data/lib/boxr/files.rb CHANGED
@@ -34,8 +34,8 @@ module Boxr
34
34
  alias preview_url embed_url
35
35
  alias preview_link embed_url
36
36
 
37
- def update_file(file, name: nil, description: nil, parent: nil, shared_link: nil, tags: nil,
38
- lock: nil, if_match: nil)
37
+ def update_file(file, name: nil, description: nil, parent: nil, # rubocop:disable Metrics
38
+ shared_link: nil, tags: nil, lock: nil, if_match: nil)
39
39
  file_id = ensure_id(file)
40
40
  parent_id = ensure_id(parent)
41
41
  uri = "#{FILES_URI}/#{file_id}"
@@ -73,14 +73,18 @@ module Boxr
73
73
  update_file(file, parent: new_parent, name: name, if_match: if_match)
74
74
  end
75
75
 
76
- def download_file(file, version: nil, follow_redirect: true)
76
+ def download_file(file, version: nil, follow_redirect: true) # rubocop:disable Metrics
77
77
  file_id = ensure_id(file)
78
+ uri = "#{FILES_URI}/#{file_id}/content"
79
+ query = {}
80
+ query[:version] = version unless version.nil?
78
81
 
79
82
  loop do
80
- uri = "#{FILES_URI}/#{file_id}/content"
81
- query = {}
82
- query[:version] = version unless version.nil?
83
- _, response = get(uri, query: query, success_codes: [302, 202], process_response: false, follow_redirect: false) # we don't want httpclient to automatically follow the redirect; we need to grab it
83
+ # Don't automatically follow the redirect
84
+ _, response = get(uri, query: query, success_codes: [302, 202],
85
+ process_response: false, follow_redirect: false)
86
+
87
+ # By default, Box always returns a 302
84
88
  if response.status == 302
85
89
  location = response.header['Location'][0]
86
90
  return location unless follow_redirect
@@ -88,13 +92,9 @@ module Boxr
88
92
  file_content, = get(location, process_response: false)
89
93
  return file_content
90
94
 
91
- # simply return the url
92
-
93
95
  elsif response.status == 202
94
- retry_after_seconds = response.header['Retry-After'][0]
95
- sleep retry_after_seconds.to_i
96
+ sleep response.header['Retry-After'][0].to_i
96
97
  end
97
- break if file_content
98
98
  end
99
99
  end
100
100
 
@@ -102,18 +102,21 @@ module Boxr
102
102
  download_file(file, version: version, follow_redirect: false)
103
103
  end
104
104
 
105
- def upload_file(path_to_file, parent, name: nil, content_created_at: nil, content_modified_at: nil,
106
- preflight_check: true, send_content_md5: true)
105
+ def upload_file(path_to_file, parent, name: nil, content_created_at: nil, # rubocop:disable Metrics
106
+ content_modified_at: nil, preflight_check: true, send_content_md5: true)
107
107
  filename = name || File.basename(path_to_file)
108
108
 
109
109
  File.open(path_to_file) do |file|
110
- upload_file_from_io(file, parent, name: filename, content_created_at: content_created_at,
111
- content_modified_at: content_modified_at, preflight_check: preflight_check, send_content_md5: send_content_md5)
110
+ upload_file_from_io(
111
+ file, parent, name: filename, content_created_at: content_created_at,
112
+ content_modified_at: content_modified_at, preflight_check: preflight_check,
113
+ send_content_md5: send_content_md5
114
+ )
112
115
  end
113
116
  end
114
117
 
115
- def upload_file_from_io(io, parent, name:, content_created_at: nil, content_modified_at: nil,
116
- preflight_check: true, send_content_md5: true)
118
+ def upload_file_from_io(io, parent, name:, content_created_at: nil, # rubocop:disable Metrics
119
+ content_modified_at: nil, preflight_check: true, send_content_md5: true)
117
120
  parent_id = ensure_id(parent)
118
121
 
119
122
  preflight_check(io, name, parent_id) if preflight_check
@@ -141,18 +144,25 @@ module Boxr
141
144
  file_info.entries[0]
142
145
  end
143
146
 
144
- def upload_new_version_of_file(path_to_file, file, content_modified_at: nil, send_content_md5: true,
145
- preflight_check: true, if_match: nil, name: nil)
147
+ def upload_new_version_of_file( # rubocop:disable Metrics
148
+ path_to_file, file, content_modified_at: nil,
149
+ send_content_md5: true, preflight_check: true, if_match: nil, name: nil
150
+ )
146
151
  filename = name || File.basename(path_to_file)
147
152
 
148
153
  File.open(path_to_file) do |io|
149
- upload_new_version_of_file_from_io(io, file, name: filename,
150
- content_modified_at: content_modified_at, preflight_check: preflight_check, send_content_md5: send_content_md5, if_match: if_match)
154
+ upload_new_version_of_file_from_io(
155
+ io, file,
156
+ name: filename, content_modified_at: content_modified_at,
157
+ preflight_check: preflight_check, send_content_md5: send_content_md5, if_match: if_match
158
+ )
151
159
  end
152
160
  end
153
161
 
154
- def upload_new_version_of_file_from_io(io, file, name: nil, content_modified_at: nil, send_content_md5: true,
155
- preflight_check: true, if_match: nil)
162
+ def upload_new_version_of_file_from_io( # rubocop:disable Metrics
163
+ io, file, name: nil, content_modified_at: nil,
164
+ send_content_md5: true, preflight_check: true, if_match: nil
165
+ )
156
166
  name || file.name
157
167
 
158
168
  file_id = ensure_id(file)
@@ -173,8 +183,9 @@ module Boxr
173
183
 
174
184
  body = { attributes: JSON.dump(attributes), file: io }
175
185
 
176
- file_info, = post(uri, body, process_body: false, content_md5: content_md5,
177
- if_match: if_match)
186
+ file_info, = post(
187
+ uri, body, process_body: false, content_md5: content_md5, if_match: if_match
188
+ )
178
189
 
179
190
  file_info.entries[0]
180
191
  end
@@ -225,7 +236,7 @@ module Boxr
225
236
  new_file
226
237
  end
227
238
 
228
- def thumbnail(file, min_height: nil, min_width: nil, max_height: nil, max_width: nil)
239
+ def thumbnail(file, min_height: nil, min_width: nil, max_height: nil, max_width: nil) # rubocop:disable Metrics
229
240
  file_id = ensure_id(file)
230
241
  uri = "#{FILES_URI}/#{file_id}/thumbnail.png"
231
242
  query = {}
@@ -246,8 +257,8 @@ module Boxr
246
257
  thumbnail
247
258
  end
248
259
 
249
- def create_shared_link_for_file(file, access: nil, unshared_at: nil, can_download: nil,
250
- can_preview: nil, password: nil)
260
+ def create_shared_link_for_file(file, access: nil, unshared_at: nil, # rubocop:disable Metrics
261
+ can_download: nil, can_preview: nil, password: nil)
251
262
  file_id = ensure_id(file)
252
263
  uri = "#{FILES_URI}/#{file_id}"
253
264
  create_shared_link(uri, file_id, access, unshared_at, can_download, can_preview, password)
data/lib/boxr/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Boxr
4
- VERSION = '1.23.1'
4
+ VERSION = '1.24.0'
5
5
  end
data/lib/boxr.rb CHANGED
@@ -7,27 +7,28 @@ require 'addressable/template'
7
7
  require 'jwt'
8
8
  require 'securerandom'
9
9
 
10
- require 'boxr/version'
11
- require 'boxr/errors'
12
- require 'boxr/client'
13
- require 'boxr/shared_items'
14
- require 'boxr/folders'
15
- require 'boxr/files'
10
+ require 'boxr/auth'
11
+ require 'boxr/avatars'
16
12
  require 'boxr/chunked_uploads'
17
- require 'boxr/comments'
18
- require 'boxr/users'
19
- require 'boxr/groups'
13
+ require 'boxr/client'
20
14
  require 'boxr/collaborations'
21
15
  require 'boxr/collections'
16
+ require 'boxr/comments'
17
+ require 'boxr/errors'
18
+ require 'boxr/events'
19
+ require 'boxr/files'
20
+ require 'boxr/folders'
21
+ require 'boxr/groups'
22
+ require 'boxr/metadata'
22
23
  require 'boxr/search'
24
+ require 'boxr/shared_items'
23
25
  require 'boxr/tasks'
24
- require 'boxr/metadata'
25
- require 'boxr/events'
26
- require 'boxr/auth'
27
- require 'boxr/web_links'
26
+ require 'boxr/users'
27
+ require 'boxr/version'
28
28
  require 'boxr/watermarking'
29
- require 'boxr/webhooks'
29
+ require 'boxr/web_links'
30
30
  require 'boxr/webhook_validator'
31
+ require 'boxr/webhooks'
31
32
  require 'boxr/zip_downloads'
32
33
 
33
34
  # Simple wrapper around Array
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boxr
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.23.1
4
+ version: 1.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chad Burnette
8
8
  - Xavier Hocquet
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2025-09-25 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: awesome_print
@@ -250,7 +249,7 @@ dependencies:
250
249
  version: '1.4'
251
250
  - - "<"
252
251
  - !ruby/object:Gem::Version
253
- version: '3'
252
+ version: '4'
254
253
  type: :runtime
255
254
  prerelease: false
256
255
  version_requirements: !ruby/object:Gem::Requirement
@@ -260,7 +259,7 @@ dependencies:
260
259
  version: '1.4'
261
260
  - - "<"
262
261
  - !ruby/object:Gem::Version
263
- version: '3'
262
+ version: '4'
264
263
  description: ''
265
264
  email:
266
265
  - chadburnette@me.com
@@ -293,6 +292,7 @@ files:
293
292
  - examples/user_events.rb
294
293
  - lib/boxr.rb
295
294
  - lib/boxr/auth.rb
295
+ - lib/boxr/avatars.rb
296
296
  - lib/boxr/chunked_uploads.rb
297
297
  - lib/boxr/client.rb
298
298
  - lib/boxr/collaborations.rb
@@ -318,7 +318,6 @@ homepage: https://github.com/cburnette/boxr
318
318
  licenses:
319
319
  - MIT
320
320
  metadata: {}
321
- post_install_message:
322
321
  rdoc_options: []
323
322
  require_paths:
324
323
  - lib
@@ -333,8 +332,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
333
332
  - !ruby/object:Gem::Version
334
333
  version: '0'
335
334
  requirements: []
336
- rubygems_version: 3.1.6
337
- signing_key:
335
+ rubygems_version: 4.0.3
338
336
  specification_version: 4
339
337
  summary: A Ruby client library for the Box V2 Content API.
340
338
  test_files: []