browse-everything 0.12.0 → 0.13.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
  SHA1:
3
- metadata.gz: d1321ca84320f83f10929d0559cb09f897f30f24
4
- data.tar.gz: 1dca717478b686eebded6fb96b4822f636bdc8c3
3
+ metadata.gz: 517bf8920fbeb90a14f3f2e1d3c33f73d68c0578
4
+ data.tar.gz: 3abe80da837a6adafc95893c3a9a0cbba89bdd1c
5
5
  SHA512:
6
- metadata.gz: 2cbc9788fa805c061a81278640f3cca1f736f63a0df3e618d5761773a511c534cc3b4598f81989d3eeef0997ceb58ee26272bda85e57c9c495a68f8eda72493e
7
- data.tar.gz: eddf4834ffde69d653627116e60178015152238258fbb2e56f3ce3257dc8ae082b3daf5e0da47b11c21227289e827e329d0bfcc0d19afd8e5b6e1e2bf0414987
6
+ metadata.gz: efdb8266d087e847282d2822a49a4363e33c5e070f65df84a16156077df9fd8704a0c1289ec7ece5df5244fec5a08f18c0a7fa64fc2daf78a9cef21f9bbdd6e5
7
+ data.tar.gz: 1b5a31483ea411070cc6fcbeb790ada41cc34afd102f5df8d28561e70e7f8a05fa5f7df98608adc51c543dcd12b7ee9bd6c32c4c8b4f64249db0354fc6d05f87
data/.engine_cart.yml ADDED
@@ -0,0 +1 @@
1
+ rails_options: "<%= '--skip-listen' if ENV.fetch('RAILS_VERSION', '') < '5.0' %>"
data/.rubocop.yml CHANGED
@@ -11,6 +11,9 @@ AllCops:
11
11
  Rails:
12
12
  Enabled: true
13
13
 
14
+ Metrics/ClassLength:
15
+ Max: 130
16
+
14
17
  # Configuration parameters: AllowURI, URISchemes.
15
18
  Metrics/LineLength:
16
19
  Max: 400
@@ -26,3 +29,6 @@ RSpec/LeadingSubject:
26
29
 
27
30
  Style/NumericLiterals:
28
31
  MinDigits: 7
32
+
33
+ Style/IndentationConsistency:
34
+ EnforcedStyle: rails
data/.rubocop_todo.yml CHANGED
@@ -2,7 +2,7 @@ require: rubocop-rspec
2
2
 
3
3
  # This configuration was generated by
4
4
  # `rubocop --auto-gen-config`
5
- # on 2017-02-28 11:01:25 -0500 using RuboCop version 0.42.0.
5
+ # on 2017-03-22 15:27:02 -0400 using RuboCop version 0.42.0.
6
6
  # The point is for the user to remove these configuration records
7
7
  # one by one as the offenses are removed from the code base.
8
8
  # Note that changes in the inspected code, or installation of new
@@ -13,15 +13,15 @@ Lint/Loop:
13
13
  Exclude:
14
14
  - 'lib/browse_everything/driver/google_drive.rb'
15
15
 
16
- # Offense count: 11
16
+ # Offense count: 6
17
17
  Metrics/AbcSize:
18
- Max: 43
18
+ Max: 31
19
19
 
20
- # Offense count: 3
20
+ # Offense count: 2
21
21
  Metrics/CyclomaticComplexity:
22
22
  Max: 7
23
23
 
24
- # Offense count: 14
24
+ # Offense count: 10
25
25
  # Configuration parameters: CountComments.
26
26
  Metrics/MethodLength:
27
27
  Max: 26
@@ -31,10 +31,6 @@ Metrics/MethodLength:
31
31
  Metrics/ParameterLists:
32
32
  Max: 7
33
33
 
34
- # Offense count: 1
35
- Metrics/PerceivedComplexity:
36
- Max: 9
37
-
38
34
  # Offense count: 1
39
35
  RSpec/DescribeClass:
40
36
  Exclude:
@@ -62,13 +58,11 @@ Rails/OutputSafety:
62
58
  Exclude:
63
59
  - 'app/helpers/browse_everything_helper.rb'
64
60
 
65
- # Offense count: 14
61
+ # Offense count: 11
66
62
  # Configuration parameters: EnforcedStyle, SupportedStyles.
67
63
  # SupportedStyles: strict, flexible
68
64
  Rails/TimeZone:
69
65
  Exclude:
70
- - 'lib/browse_everything/driver/box.rb'
71
- - 'lib/browse_everything/driver/dropbox.rb'
72
66
  - 'lib/browse_everything/driver/google_drive.rb'
73
67
  - 'lib/browse_everything/driver/sky_drive.rb'
74
68
  - 'lib/browse_everything/retriever.rb'
@@ -87,7 +81,7 @@ Style/ClassAndModuleChildren:
87
81
  - 'lib/generators/browse_everything/config_generator.rb'
88
82
  - 'lib/generators/browse_everything/install_generator.rb'
89
83
 
90
- # Offense count: 19
84
+ # Offense count: 18
91
85
  Style/Documentation:
92
86
  Enabled: false
93
87
 
@@ -97,13 +91,10 @@ Style/FileName:
97
91
  Exclude:
98
92
  - 'lib/browse-everything.rb'
99
93
 
100
- # Offense count: 5
94
+ # Offense count: 2
101
95
  # Configuration parameters: MinBodyLength.
102
96
  Style/GuardClause:
103
97
  Exclude:
104
- - 'lib/browse_everything/driver/box.rb'
105
- - 'lib/browse_everything/driver/dropbox.rb'
106
- - 'lib/browse_everything/driver/file_system.rb'
107
98
  - 'lib/browse_everything/driver/google_drive.rb'
108
99
  - 'lib/browse_everything/driver/sky_drive.rb'
109
100
 
@@ -143,18 +134,3 @@ Style/PredicateName:
143
134
  Exclude:
144
135
  - 'spec/**/*'
145
136
  - 'app/helpers/browse_everything_helper.rb'
146
-
147
- # Offense count: 2
148
- # Cop supports --auto-correct.
149
- # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
150
- # SupportedStyles: slashes, percent_r, mixed
151
- Style/RegexpLiteral:
152
- Exclude:
153
- - 'lib/browse_everything/driver/box.rb'
154
- - 'lib/browse_everything/driver/dropbox.rb'
155
-
156
- # Offense count: 1
157
- # Cop supports --auto-correct.
158
- Style/RescueModifier:
159
- Exclude:
160
- - 'lib/browse_everything/driver/file_system.rb'
data/README.md CHANGED
@@ -7,7 +7,8 @@
7
7
  This Gem allows your rails application to access user files from cloud storage.
8
8
  Currently there are drivers implemented for [Dropbox](http://www.dropbox.com),
9
9
  [Skydrive](https://skydrive.live.com/), [Google Drive](http://drive.google.com),
10
- [Box](http://www.box.com), and a server-side directory share.
10
+ [Box](http://www.box.com), [Amazon S3](https://aws.amazon.com/s3/),
11
+ and a server-side directory share.
11
12
 
12
13
  The gem uses [OAuth](http://oauth.net/) to connect to a user's account and
13
14
  generate a list of single use urls that your application can then use to
@@ -118,8 +118,7 @@ $ ->
118
118
  table.treetable("unloadBranch", node)
119
119
  onNodeExpand: ->
120
120
  node = this
121
- $('body').css('cursor','wait')
122
- $("html").addClass("wait")
121
+ startWait()
123
122
  size = $(node.row).find('td.ev-file-size').text().trim()
124
123
  start = 1
125
124
  increment = 1
@@ -173,17 +172,28 @@ $ ->
173
172
  selectAll(rows)
174
173
  .always ->
175
174
  clearInterval progressIntervalID
176
- $('body').css('cursor','default')
177
- $("html").removeClass("wait")
175
+ stopWait()
178
176
 
179
177
  setProgress = (done)->
180
- $('#loading_progress').css('width',done+'%')
181
- $('#loading_progress').html(done+'% complete')
182
- $('#loading_progress').attr('aria-valuenow', done)
178
+ $('.loading-text').text(done+'% complete')
183
179
 
184
180
  refreshFiles = ->
185
181
  $('.ev-providers select').change()
186
182
 
183
+ startWait = ->
184
+ $('.loading-progress').removeClass("hidden")
185
+ $('body').css('cursor','wait')
186
+ $("html").addClass("wait")
187
+ $(".ev-browser").addClass("loading")
188
+ $('.ev-submit').attr('disabled', true)
189
+
190
+ stopWait = ->
191
+ $('.loading-progress').addClass("hidden")
192
+ $('body').css('cursor','default')
193
+ $("html").removeClass("wait")
194
+ $(".ev-browser").removeClass("loading")
195
+ $('.ev-submit').attr('disabled', false)
196
+
187
197
  $(window).on('resize', -> sizeColumns($('table#file-list')))
188
198
 
189
199
  $.fn.browseEverything = (options) ->
@@ -224,7 +234,7 @@ $ ->
224
234
  $(document).on 'click', 'button.ev-submit', (event) ->
225
235
  event.preventDefault()
226
236
  $(this).button('loading')
227
- $('body').css('cursor','wait')
237
+ startWait()
228
238
  main_form = $(this).closest('form')
229
239
  resolver_url = main_form.data('resolver')
230
240
  ctx = dialog.data('ev-state')
@@ -255,7 +265,7 @@ $ ->
255
265
 
256
266
  $(document).on 'change', '.ev-providers select', (event) ->
257
267
  event.preventDefault()
258
- $('body').css('cursor','wait')
268
+ startWait()
259
269
  $.ajax
260
270
  url: $(this).val(),
261
271
  data:
@@ -272,7 +282,7 @@ $ ->
272
282
  else
273
283
  $('.ev-files').html(xhr.responseText)
274
284
  .always ->
275
- $('body').css('cursor','default')
285
+ stopWait()
276
286
 
277
287
  $(document).on 'click', '.ev-providers a', (event) ->
278
288
  $('.ev-providers li').removeClass('ev-selected')
@@ -73,22 +73,6 @@
73
73
  padding: 4px;
74
74
  }
75
75
 
76
- .fa3 .ev-selected .indenter {
77
- font-family: FontAwesome;
78
- font-weight: normal;
79
- font-style: normal;
80
- text-decoration: inherit;
81
- -webkit-font-smoothing: antialiased;
82
- *margin-right: .3em;
83
- @extend .icon-check !optional;
84
- }
85
-
86
- .fa4 .ev-selected .indenter {
87
- background-color: inherit;
88
- @extend .fa;
89
- @extend .fa-check !optional;
90
- }
91
-
92
76
  .ev-files {
93
77
  table {
94
78
  width: 100%;
@@ -114,4 +98,19 @@
114
98
  select { width: 30% }
115
99
  }
116
100
 
101
+ .loading {
102
+ pointer-events: none;
103
+ opacity: 0.2;
104
+ }
105
+
106
+ .loading-progress {
107
+ position: absolute;
108
+ top: 8em;
109
+ left: 4em;
110
+ }
111
+
112
+ // Massively large text instead of something more artistic
113
+ .loading-text {
114
+ font-size: 4em;
115
+ }
117
116
  }
@@ -37,40 +37,40 @@ class BrowseEverythingController < ActionController::Base
37
37
 
38
38
  private
39
39
 
40
- def auth_link
41
- @auth_link ||= if provider.present?
42
- link, data = provider.auth_link
43
- session["#{provider_name}_data"] = data
44
- link = "#{link}&state=#{provider.key}" unless link.to_s.include?('state')
45
- link
46
- end # else nil, implicitly
47
- end
40
+ def auth_link
41
+ @auth_link ||= if provider.present?
42
+ link, data = provider.auth_link
43
+ session["#{provider_name}_data"] = data
44
+ link = "#{link}&state=#{provider.key}" unless link.to_s.include?('state')
45
+ link
46
+ end # else nil, implicitly
47
+ end
48
48
 
49
- def browser
50
- if @browser.nil?
51
- @browser = BrowseEverything::Browser.new(url_options)
52
- @browser.providers.values.each do |p|
53
- p.token = session["#{p.key}_token"]
49
+ def browser
50
+ if @browser.nil?
51
+ @browser = BrowseEverything::Browser.new(url_options)
52
+ @browser.providers.values.each do |p|
53
+ p.token = session["#{p.key}_token"]
54
+ end
54
55
  end
56
+ @browser
55
57
  end
56
- @browser
57
- end
58
58
 
59
- def browse_path
60
- @path ||= params[:path] || ''
61
- end
59
+ def browse_path
60
+ @path ||= params[:path] || ''
61
+ end
62
62
 
63
- def provider
64
- @provider ||= browser.providers[provider_name]
65
- end
63
+ def provider
64
+ @provider ||= browser.providers[provider_name]
65
+ end
66
66
 
67
- def provider_name
68
- @provider_name ||= params[:provider] || params[:state].to_s.split(/\|/).last
69
- end
67
+ def provider_name
68
+ @provider_name ||= params[:provider] || params[:state].to_s.split(/\|/).last
69
+ end
70
70
 
71
- helper_method :auth_link
72
- helper_method :browser
73
- helper_method :browse_path
74
- helper_method :provider
75
- helper_method :provider_name
71
+ helper_method :auth_link
72
+ helper_method :browser
73
+ helper_method :browse_path
74
+ helper_method :provider
75
+ helper_method :provider_name
76
76
  end
@@ -1,8 +1,3 @@
1
- <div class="progress" id="loading_progress" aria-live="polite">
2
- <div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 100%;">
3
- 100% Complete
4
- </div>
5
- </div>
6
1
  <table id="file-list" role="grid" tabindex="-1" title="Choose files to upload from the table below" aria-live="polite">
7
2
  <thead>
8
3
  <tr role="row" tabindex="-1">
@@ -6,6 +6,9 @@
6
6
  </div>
7
7
  </div>
8
8
  <div class="modal-body ev-body" tabindex="-1">
9
+ <div class="loading-progress" aria-live="assertive">
10
+ <span class="loading-text">Loading...</span>
11
+ </div>
9
12
  <div class="ev-browser row<%=bs2('-fluid')%>" aria-live="polite">
10
13
  <div class="<%=fa3or4('fa3','fa4')%> <%=bs2or3('bs2 span','bs3 col-xs-')%>12 ev-files list">
11
14
  <%= render :partial => 'files' if provider.present? %>
@@ -44,7 +44,7 @@ Gem::Specification.new do |spec|
44
44
  spec.add_development_dependency 'vcr'
45
45
  spec.add_development_dependency 'sqlite3'
46
46
  spec.add_development_dependency 'factory_girl_rails'
47
- spec.add_development_dependency 'engine_cart', '~> 0.10'
47
+ spec.add_development_dependency 'engine_cart', '~> 1.0'
48
48
  spec.add_development_dependency 'capybara'
49
49
  spec.add_development_dependency 'jasmine', '~> 2.3'
50
50
  spec.add_development_dependency 'coveralls'
@@ -16,7 +16,7 @@ module BrowseEverything
16
16
  begin
17
17
  driver_klass = BrowseEverything::Driver.const_get((config[:driver] || driver.to_s).camelize.to_sym)
18
18
  @providers[driver] = driver_klass.new(config.merge(url_options: url_options))
19
- rescue
19
+ rescue NameError
20
20
  Rails.logger.warn "Unknown provider: #{driver}"
21
21
  end
22
22
  end
@@ -53,15 +53,15 @@ module BrowseEverything
53
53
 
54
54
  private
55
55
 
56
- def callback
57
- connector_response_url(callback_options)
58
- end
56
+ def callback
57
+ connector_response_url(callback_options)
58
+ end
59
59
 
60
- # remove the script_name parameter from the url_options since that is causing issues
61
- # with the route not containing the engine path in rails 4.2.0
62
- def callback_options
63
- config[:url_options].reject { |k, _v| k == :script_name }
64
- end
60
+ # remove the script_name parameter from the url_options since that is causing issues
61
+ # with the route not containing the engine path in rails 4.2.0
62
+ def callback_options
63
+ config[:url_options].reject { |k, _v| k == :script_name }
64
+ end
65
65
  end
66
66
  end
67
67
  end
@@ -1,5 +1,6 @@
1
1
  module BrowseEverything
2
2
  module Driver
3
+ # Driver for accessing the Box API (https://www.box.com/home)
3
4
  class Box < Base
4
5
  require 'ruby-box'
5
6
 
@@ -10,104 +11,112 @@ module BrowseEverything
10
11
  end
11
12
 
12
13
  def validate_config
13
- unless config[:client_id]
14
- raise BrowseEverything::InitializationError, 'Box driver requires a :client_id argument'
15
- end
16
- unless config[:client_secret]
17
- raise BrowseEverything::InitializationError, 'Box driver requires a :client_secret argument'
18
- end
14
+ return if config[:client_id] && config[:client_secret]
15
+ raise BrowseEverything::InitializationError, 'Box driver requires both :client_id and :client_secret argument'
19
16
  end
20
17
 
21
- def contents(path = '')
22
- path.sub!(/^[\/.]+/, '')
23
- result = []
24
- unless path.empty?
25
- result << BrowseEverything::FileEntry.new(
26
- Pathname(path).join('..'),
27
- '', '..', 0, Time.now, true
28
- )
18
+ # @param [String] id of the file or folder in Box
19
+ # @return [Array<RubyBox::File>]
20
+ def contents(id = '')
21
+ if id.empty?
22
+ folder = box_client.root_folder
23
+ results = []
24
+ else
25
+ folder = box_client.folder_by_id(id)
26
+ results = [parent_directory(folder)]
29
27
  end
30
- folder = path.empty? ? box_client.root_folder : box_client.folder(path)
31
- result += folder.items(ITEM_LIMIT, 0, %w(name size created_at)).collect do |f|
32
- BrowseEverything::FileEntry.new(
33
- File.join(path, f.name), # id here
34
- "#{key}:#{File.join(path, f.name)}", # single use link
35
- f.name,
36
- f.size,
37
- f.created_at,
38
- f.type == 'folder'
39
- )
28
+
29
+ folder.items(ITEM_LIMIT, 0, %w(name size created_at)).collect do |f|
30
+ results << directory_entry(f)
40
31
  end
41
- result
32
+ results
42
33
  end
43
34
 
44
- def link_for(path)
45
- file = box_client.file(path)
35
+ # @param [String] id of the file in Box
36
+ # @return [Array<String, Hash>]
37
+ def link_for(id)
38
+ file = box_client.file_by_id(id)
46
39
  download_url = file.download_url
47
40
  auth_header = { 'Authorization' => "Bearer #{@token}" }
48
41
  extras = { auth_header: auth_header, expires: 1.hour.from_now, file_name: file.name, file_size: file.size.to_i }
49
42
  [download_url, extras]
50
43
  end
51
44
 
45
+ # @return [String]
46
+ # Authorization url that is used to request the initial access code from Box
52
47
  def auth_link
53
- oauth_client.authorize_url(callback.to_s)
48
+ box_session.authorize_url(callback.to_s)
54
49
  end
55
50
 
51
+ # @return [Boolean]
56
52
  def authorized?
57
- @token.present? && @token['token'].present?
53
+ box_token.present? && box_refresh_token.present? && !token_expired?
58
54
  end
59
55
 
56
+ # @return [Hash]
57
+ # Gets the appropriate tokens from Box using the access code returned from :auth_link:
60
58
  def connect(params, _data)
61
- access_token = oauth_client.get_access_token(params[:code])
62
- @token = { 'token' => access_token.token, 'refresh_token' => access_token.refresh_token }
59
+ register_access_token(box_session.get_access_token(params[:code]))
63
60
  end
64
61
 
65
62
  private
66
63
 
67
- def oauth_client
68
- RubyBox::Session.new(client_id: config[:client_id],
69
- client_secret: config[:client_secret])
70
- # TODO: error checking here
71
- end
64
+ def token_expired?
65
+ return true if expiration_time.nil?
66
+ Time.now.to_i > expiration_time
67
+ end
72
68
 
73
- def token_expired?(token)
74
- return false unless @token.present? && @token['token'].present?
75
- new_session = RubyBox::Session.new(
76
- client_id: config[:client_id],
77
- client_secret: config[:client_secret],
78
- access_token: token
79
- )
80
- result = new_session.get("#{RubyBox::API_URL}/users/me")
81
- result['status'] != 200
82
- rescue RubyBox::AuthError => e
83
- Rails.logger.error("AuthError occured when checking token. Exception #{e.class.name} : #{e.message}. token as expired and need to refresh it")
84
- return true
85
- end
69
+ def box_client
70
+ if token_expired?
71
+ session = box_session(box_token)
72
+ register_access_token(session.refresh_token(box_refresh_token))
73
+ end
74
+ RubyBox::Client.new(box_session(box_token, box_refresh_token))
75
+ end
86
76
 
87
- def refresh_token
88
- refresh_token = @token['refresh_token']
89
- token = @token['token']
90
- session = RubyBox::Session.new(
91
- client_id: config[:client_id],
92
- client_secret: config[:client_secret],
93
- access_token: token
94
- )
95
- access_token = session.refresh_token(refresh_token)
96
- @token = { 'token' => access_token.token, 'refresh_token' => access_token.refresh_token }
97
- end
77
+ def box_session(token = nil, refresh_token = nil)
78
+ RubyBox::Session.new(client_id: config[:client_id],
79
+ client_secret: config[:client_secret],
80
+ access_token: token,
81
+ refresh_token: refresh_token)
82
+ end
98
83
 
99
- def box_client
100
- refresh_token if token_expired?(@token['token'])
101
- token = @token['token']
102
- refresh_token = @token['refresh_token']
103
- session = RubyBox::Session.new(
104
- client_id: config[:client_id],
105
- client_secret: config[:client_secret],
106
- access_token: token,
107
- refresh_token: refresh_token
108
- )
109
- RubyBox::Client.new(session)
110
- end
84
+ # If there is an active session, {@token} will be set by {BrowseEverythingController} using data stored in the
85
+ # session. However, if there is no prior session, or the token has expired, we reset it here using # a new
86
+ # access_token received from {#box_session}.
87
+ #
88
+ # @param [OAuth2::AccessToken] access_token
89
+ def register_access_token(access_token)
90
+ @token = {
91
+ 'token' => access_token.token,
92
+ 'refresh_token' => access_token.refresh_token,
93
+ 'expires_at' => access_token.expires_at
94
+ }
95
+ end
96
+
97
+ def box_token
98
+ return unless @token
99
+ @token.fetch('token', nil)
100
+ end
101
+
102
+ def box_refresh_token
103
+ return unless @token
104
+ @token.fetch('refresh_token', nil)
105
+ end
106
+
107
+ def expiration_time
108
+ return unless @token
109
+ @token.fetch('expires_at', nil).to_i
110
+ end
111
+
112
+ # Used to represent the ".." parent directory of the folder
113
+ def parent_directory(folder)
114
+ BrowseEverything::FileEntry.new(Pathname(folder.name).join('..'), '', '..', 0, Time.current, true)
115
+ end
116
+
117
+ def directory_entry(f)
118
+ BrowseEverything::FileEntry.new(f.id, "#{key}:#{f.id}", f.name, f.size, f.created_at, f.type == 'folder')
119
+ end
111
120
  end
112
121
  end
113
122
  end