browse-everything 0.12.0 → 0.13.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: 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