browse-everything 1.0.0.rc2 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +93 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +43 -35
  5. data/CONTRIBUTING.md +3 -3
  6. data/Gemfile +3 -6
  7. data/LICENSE.txt +205 -22
  8. data/README.md +17 -15
  9. data/app/assets/javascripts/browse_everything/behavior.js +201 -158
  10. data/app/assets/javascripts/treetable.webpack.js +687 -0
  11. data/app/assets/stylesheets/browse_everything.scss +0 -0
  12. data/app/assets/stylesheets/{_browse_everything_bootstrap3.scss → browse_everything/_browse_everything_bootstrap3.scss} +6 -5
  13. data/app/assets/stylesheets/{_browse_everything_bootstrap4.scss → browse_everything/_browse_everything_bootstrap4.scss} +0 -0
  14. data/app/controllers/browse_everything_controller.rb +60 -60
  15. data/app/helpers/browse_everything_helper.rb +4 -0
  16. data/app/views/browse_everything/_files.html.erb +4 -2
  17. data/browse-everything.gemspec +8 -7
  18. data/lib/browse_everything.rb +2 -1
  19. data/lib/browse_everything/auth/google/credentials.rb +5 -5
  20. data/lib/browse_everything/auth/google/request_parameters.rb +38 -38
  21. data/lib/browse_everything/driver/base.rb +14 -14
  22. data/lib/browse_everything/driver/box.rb +62 -55
  23. data/lib/browse_everything/driver/dropbox.rb +37 -21
  24. data/lib/browse_everything/driver/file_system.rb +30 -18
  25. data/lib/browse_everything/driver/google_drive.rb +40 -39
  26. data/lib/browse_everything/driver/s3.rb +61 -45
  27. data/lib/browse_everything/file_entry.rb +1 -1
  28. data/lib/browse_everything/retriever.rb +72 -67
  29. data/lib/browse_everything/version.rb +1 -1
  30. data/lib/generators/browse_everything/templates/browse_everything_providers.yml.example +1 -0
  31. data/spec/features/test_compiling_stylesheets_spec.rb +1 -1
  32. data/spec/lib/browse_everything/browser_spec.rb +5 -3
  33. data/spec/lib/browse_everything/driver/dropbox_spec.rb +20 -1
  34. data/spec/lib/browse_everything/driver_spec.rb +43 -3
  35. data/spec/spec_helper.rb +9 -2
  36. data/spec/support/capybara.rb +0 -5
  37. data/spec/test_app_templates/Gemfile.extra +9 -0
  38. data/spec/test_app_templates/lib/generators/test_app_generator.rb +56 -5
  39. metadata +72 -39
  40. data/.travis.yml +0 -33
@@ -59,9 +59,6 @@
59
59
  border-top: none;
60
60
  }
61
61
 
62
- &.detail {
63
- }
64
-
65
62
  &.list ul {
66
63
  @include content-columns(3);
67
64
  }
@@ -97,11 +94,15 @@
97
94
 
98
95
  .ev-files {
99
96
  height: 50vh;
100
- li { @include ev-link; }
97
+ li {
98
+ @include ev-link;
99
+ }
101
100
  }
102
101
 
103
102
  .ev-providers {
104
- select { width: 30% }
103
+ select {
104
+ width: 30%
105
+ }
105
106
  }
106
107
 
107
108
  .loading {
@@ -2,7 +2,7 @@
2
2
 
3
3
  require File.expand_path('../helpers/browse_everything_helper', __dir__)
4
4
 
5
- class BrowseEverythingController < ActionController::Base
5
+ class BrowseEverythingController < ApplicationController
6
6
  layout 'browse_everything'
7
7
  helper BrowseEverythingHelper
8
8
 
@@ -61,72 +61,72 @@ class BrowseEverythingController < ActionController::Base
61
61
 
62
62
  private
63
63
 
64
- # Constructs or accesses an existing session manager Object
65
- # @return [BrowseEverythingSession::ProviderSession] the session manager
66
- def provider_session
67
- BrowseEverythingSession::ProviderSession.new(session: session, name: provider_name)
68
- end
64
+ # Constructs or accesses an existing session manager Object
65
+ # @return [BrowseEverythingSession::ProviderSession] the session manager
66
+ def provider_session
67
+ BrowseEverythingSession::ProviderSession.new(session: session, name: provider_name)
68
+ end
69
69
 
70
- # Clears all authentication tokens, codes, and other data from the Rails session
71
- def reset_provider_session!
72
- return unless @provider_session
73
- @provider_session.token = nil
74
- @provider_session.code = nil
75
- @provider_session.data = nil
76
- @provider_session = nil
77
- end
70
+ # Clears all authentication tokens, codes, and other data from the Rails session
71
+ def reset_provider_session!
72
+ return unless @provider_session
73
+ @provider_session.token = nil
74
+ @provider_session.code = nil
75
+ @provider_session.data = nil
76
+ @provider_session = nil
77
+ end
78
78
 
79
- def connector_response_url_options
80
- { protocol: request.protocol, host: request.host, port: request.port }
81
- end
79
+ def connector_response_url_options
80
+ { protocol: request.protocol, host: request.host, port: request.port }
81
+ end
82
82
 
83
- # Generates the authentication link for a given provider service
84
- # @return [String] the authentication link
85
- def auth_link
86
- @auth_link ||= if provider.present?
87
- link, data = provider.auth_link(connector_response_url_options)
88
- provider_session.data = data
89
- link = "#{link}&state=#{provider.key}" unless link.to_s.include?('state')
90
- link
91
- end
92
- end
83
+ # Generates the authentication link for a given provider service
84
+ # @return [String] the authentication link
85
+ def auth_link
86
+ @auth_link ||= if provider.present?
87
+ link, data = provider.auth_link(connector_response_url_options)
88
+ provider_session.data = data
89
+ link = "#{link}&state=#{provider.key}" unless link.to_s.include?('state')
90
+ link
91
+ end
92
+ end
93
93
 
94
- # Accesses the relative path for browsing from the Rails session
95
- # @return [String]
96
- def browse_path
97
- params[:path] || ''
98
- end
94
+ # Accesses the relative path for browsing from the Rails session
95
+ # @return [String]
96
+ def browse_path
97
+ params[:path] || ''
98
+ end
99
99
 
100
- # Generate the provider name from the Rails session state value
101
- # @return [String]
102
- def provider_name_from_state
103
- params[:state].to_s.split(/\|/).last
104
- end
100
+ # Generate the provider name from the Rails session state value
101
+ # @return [String]
102
+ def provider_name_from_state
103
+ params[:state].to_s.split(/\|/).last
104
+ end
105
105
 
106
- # Generates the name of the provider using Rails session values
107
- # @return [String]
108
- def provider_name
109
- params[:provider] || provider_name_from_state || browser.providers.each_key.to_a.first
110
- end
106
+ # Generates the name of the provider using Rails session values
107
+ # @return [String]
108
+ def provider_name
109
+ params[:provider] || provider_name_from_state || browser.providers.each_key.to_a.first
110
+ end
111
111
 
112
- # Retrieve the Driver for each request
113
- # @return [BrowseEverything::Driver::Base]
114
- def provider
115
- browser.providers[provider_name.to_sym] || browser.first_provider
116
- end
112
+ # Retrieve the Driver for each request
113
+ # @return [BrowseEverything::Driver::Base]
114
+ def provider
115
+ browser.providers[provider_name.to_sym] || browser.first_provider
116
+ end
117
117
 
118
- # Constructs a browser manager Object
119
- # Browser state cannot persist between requests to the Controller
120
- # Hence, a Browser must be reinstantiated for each request using the state provided in the Rails session
121
- # @return [BrowseEverything::Browser]
122
- def browser
123
- BrowserFactory.build(session: session, url_options: url_options)
124
- end
118
+ # Constructs a browser manager Object
119
+ # Browser state cannot persist between requests to the Controller
120
+ # Hence, a Browser must be reinstantiated for each request using the state provided in the Rails session
121
+ # @return [BrowseEverything::Browser]
122
+ def browser
123
+ BrowserFactory.build(session: session, url_options: url_options)
124
+ end
125
125
 
126
- helper_method :auth_link
127
- helper_method :browser
128
- helper_method :browse_path
129
- helper_method :provider
130
- helper_method :provider_name
131
- helper_method :provider_contents
126
+ helper_method :auth_link
127
+ helper_method :browser
128
+ helper_method :browse_path
129
+ helper_method :provider
130
+ helper_method :provider_name
131
+ helper_method :provider_contents
132
132
  end
@@ -20,4 +20,8 @@ module BrowseEverythingHelper
20
20
  acceptable_types << 'application/x-directory'
21
21
  acceptable_types.any? { |type| mime_match?(file.type, type) }
22
22
  end
23
+
24
+ def file_size_to_human_size(file_size)
25
+ "#{file_size} bytes"
26
+ end
23
27
  end
@@ -9,12 +9,14 @@
9
9
  </tr>
10
10
  </thead>
11
11
  <% provider_contents.each_with_index do |file, index| %>
12
+ <% next if file.nil? %>
12
13
  <% path = browse_everything_engine.contents_path(provider_name, file.id) %>
13
14
  <% parent = params[:parent] %>
14
15
  <% if file.container? || provider.config[:max_upload_file_size].blank? %>
15
16
  <% disabled = false %>
16
17
  <% else %>
17
18
  <% max_size = provider.config[:max_upload_file_size].to_i %>
19
+ <% max_human_size = file_size_to_human_size(max_size) %>
18
20
  <% disabled = file.size > max_size %>
19
21
  <% end %>
20
22
 
@@ -27,7 +29,7 @@
27
29
 
28
30
  <td role="gridcell" title="<%= file.name %>" class="<%=file.container? ? 'ev-container' : 'ev-file'%> ev-file-name">
29
31
  <% if disabled %>
30
- <span title="<%= t('browse_everything.size_disabled', max_size: number_to_human_size(max_size)) %>"
32
+ <span title="<%= t('browse_everything.size_disabled', max_size: max_human_size) %>"
31
33
  class="<%=file.container? ? 'folder' : 'file'%>" aria-hidden="true">
32
34
  <%= file.name %>
33
35
  </span>
@@ -52,7 +54,7 @@
52
54
 
53
55
  <% if file.size %>
54
56
  <td role="gridcell" class="ev-file-size">
55
- <%= number_to_human_size(file.size).sub(/Bytes/,'bytes') %>
57
+ <%= file_size_to_human_size(file.size) %>
56
58
  </td>
57
59
  <% else %>
58
60
  <td role="gridcell" class="ev-file-size">Unknown</td>
@@ -23,18 +23,17 @@ Gem::Specification.new do |spec|
23
23
  spec.add_dependency 'aws-sdk-s3'
24
24
  spec.add_dependency 'dropbox_api', '>= 0.1.10'
25
25
  spec.add_dependency 'google-api-client', '~> 0.23'
26
- spec.add_dependency 'google_drive', '~> 2.1'
27
- spec.add_dependency 'googleauth', '0.6.6'
28
- spec.add_dependency 'rails', '>= 4.2'
26
+ spec.add_dependency 'google_drive', '>= 2.1', "< 4"
27
+ spec.add_dependency 'googleauth', '>= 0.6.6', '< 1.0'
28
+ spec.add_dependency 'rails', '>= 4.2', '< 7.0'
29
29
  spec.add_dependency 'ruby-box'
30
30
  spec.add_dependency 'signet', '~> 0.8'
31
- spec.add_dependency 'thor', '~> 0.19'
31
+ spec.add_dependency 'sprockets', '~> 3.7'
32
32
  spec.add_dependency 'typhoeus'
33
33
 
34
- spec.add_development_dependency 'bixby', '>= 1.0'
35
- spec.add_development_dependency 'bundler', '~> 1.3'
34
+ spec.add_development_dependency 'bixby', '~> 3.0'
35
+ spec.add_development_dependency 'bundler', '>= 1.3'
36
36
  spec.add_development_dependency 'capybara'
37
- spec.add_development_dependency 'chromedriver-helper', '1.2.0'
38
37
  spec.add_development_dependency 'coveralls'
39
38
  spec.add_development_dependency 'engine_cart', '~> 2.0'
40
39
  spec.add_development_dependency 'factory_bot_rails'
@@ -45,9 +44,11 @@ Gem::Specification.new do |spec|
45
44
  spec.add_development_dependency 'rspec', '~> 3.0'
46
45
  spec.add_development_dependency 'rspec-its'
47
46
  spec.add_development_dependency 'rspec-rails'
47
+ spec.add_development_dependency 'rspec_junit_formatter'
48
48
  spec.add_development_dependency 'rubocop-rspec'
49
49
  spec.add_development_dependency 'selenium-webdriver'
50
50
  spec.add_development_dependency 'simplecov'
51
51
  spec.add_development_dependency 'sqlite3'
52
+ spec.add_development_dependency 'webdrivers'
52
53
  spec.add_development_dependency 'webmock'
53
54
  end
@@ -59,7 +59,8 @@ module BrowseEverything
59
59
  @config = ActiveSupport::HashWithIndifferentAccess.new config_values
60
60
  @config.deep_symbolize_keys
61
61
  rescue Errno::ENOENT
62
- raise ConfigurationError, 'Missing browse_everything_providers.yml configuration file'
62
+ Rails.logger.warn 'Missing browse_everything_providers.yml configuration file'
63
+ @config = ActiveSupport::HashWithIndifferentAccess.new({})
63
64
  end
64
65
  else
65
66
  raise InitializationError, "Unrecognized configuration: #{value.inspect}"
@@ -17,11 +17,11 @@ module BrowseEverything
17
17
 
18
18
  private
19
19
 
20
- # Structure a hash from existing access token values (usually cached within a Cookie)
21
- # @return [Hash]
22
- def build_token_hash
23
- { 'access_token' => access_token }
24
- end
20
+ # Structure a hash from existing access token values (usually cached within a Cookie)
21
+ # @return [Hash]
22
+ def build_token_hash
23
+ { 'access_token' => access_token }
24
+ end
25
25
  end
26
26
  end
27
27
  end
@@ -14,47 +14,47 @@ module BrowseEverything
14
14
 
15
15
  private
16
16
 
17
- # The default query parameters for the Google Drive API
18
- # @return [Hash]
19
- def default_params
20
- {
21
- q: default_query,
22
- order_by: 'modifiedTime desc,folder,name',
23
- fields: 'nextPageToken,files(name,id,mimeType,size,modifiedTime,parents,web_content_link)',
24
- supports_team_drives: true,
25
- include_team_drive_items: true,
26
- corpora: 'user,allTeamDrives',
27
- page_size: 1000
28
- }
29
- end
17
+ # The default query parameters for the Google Drive API
18
+ # @return [Hash]
19
+ def default_params
20
+ {
21
+ q: default_query,
22
+ order_by: 'modifiedTime desc,folder,name',
23
+ fields: 'nextPageToken,files(name,id,mimeType,size,modifiedTime,parents,web_content_link)',
24
+ supports_team_drives: true,
25
+ include_team_drive_items: true,
26
+ corpora: 'user,allTeamDrives',
27
+ page_size: 1000
28
+ }
29
+ end
30
30
 
31
- def default_query
32
- field_queries = []
33
- contraints.each_pair do |field, constraints|
34
- field_constraint = constraints.join(" and #{field} ")
35
- field_queries << "#{field} #{field_constraint}"
36
- end
37
- field_queries.join(' ')
31
+ def default_query
32
+ field_queries = []
33
+ contraints.each_pair do |field, constraints|
34
+ field_constraint = constraints.join(" and #{field} ")
35
+ field_queries << "#{field} #{field_constraint}"
38
36
  end
37
+ field_queries.join(' ')
38
+ end
39
39
 
40
- def contraints
41
- {
42
- 'mimeType' => [
43
- '!= \'application/vnd.google-apps.audio\'',
44
- '!= \'application/vnd.google-apps.document\'',
45
- '!= \'application/vnd.google-apps.drawing\'',
46
- '!= \'application/vnd.google-apps.form\'',
47
- '!= \'application/vnd.google-apps.fusiontable\'',
48
- '!= \'application/vnd.google-apps.map\'',
49
- '!= \'application/vnd.google-apps.photo\'',
50
- '!= \'application/vnd.google-apps.presentation\'',
51
- '!= \'application/vnd.google-apps.script\'',
52
- '!= \'application/vnd.google-apps.site\'',
53
- '!= \'application/vnd.google-apps.spreadsheet\'',
54
- '!= \'application/vnd.google-apps.video\''
55
- ]
56
- }
57
- end
40
+ def contraints
41
+ {
42
+ 'mimeType' => [
43
+ '!= \'application/vnd.google-apps.audio\'',
44
+ '!= \'application/vnd.google-apps.document\'',
45
+ '!= \'application/vnd.google-apps.drawing\'',
46
+ '!= \'application/vnd.google-apps.form\'',
47
+ '!= \'application/vnd.google-apps.fusiontable\'',
48
+ '!= \'application/vnd.google-apps.map\'',
49
+ '!= \'application/vnd.google-apps.photo\'',
50
+ '!= \'application/vnd.google-apps.presentation\'',
51
+ '!= \'application/vnd.google-apps.script\'',
52
+ '!= \'application/vnd.google-apps.site\'',
53
+ '!= \'application/vnd.google-apps.spreadsheet\'',
54
+ '!= \'application/vnd.google-apps.video\''
55
+ ]
56
+ }
57
+ end
58
58
  end
59
59
  end
60
60
  end
@@ -100,21 +100,21 @@ module BrowseEverything
100
100
 
101
101
  private
102
102
 
103
- # Generate the options for the Rails URL generation for API callbacks
104
- # remove the script_name parameter from the url_options since that is causing issues
105
- # with the route not containing the engine path in rails 4.2.0
106
- # @return [Hash]
107
- def callback_options
108
- options = config.to_hash
109
- options.deep_symbolize_keys!
110
- options[:url_options].reject { |k, _v| k == :script_name }
111
- end
103
+ # Generate the options for the Rails URL generation for API callbacks
104
+ # remove the script_name parameter from the url_options since that is causing issues
105
+ # with the route not containing the engine path in rails 4.2.0
106
+ # @return [Hash]
107
+ def callback_options
108
+ options = config.to_hash
109
+ options.deep_symbolize_keys!
110
+ options[:url_options].reject { |k, _v| k == :script_name }
111
+ end
112
112
 
113
- # Generate the URL for the API callback
114
- # @return [String]
115
- def callback
116
- connector_response_url(callback_options)
117
- end
113
+ # Generate the URL for the API callback
114
+ # @return [String]
115
+ def callback
116
+ connector_response_url(callback_options)
117
+ end
118
118
  end
119
119
  end
120
120
  end
@@ -33,15 +33,18 @@ module BrowseEverything
33
33
  raise InitializationError, 'Box driver requires both :client_id and :client_secret argument'
34
34
  end
35
35
 
36
+ # Retrieves the file entry objects for a given path to Box resource
36
37
  # @param [String] id of the file or folder in Box
37
- # @return [Array<RubyBox::File>]
38
+ # @return [Array<BrowseEverything::FileEntry>]
38
39
  def contents(id = '')
39
40
  folder = id.empty? ? box_client.root_folder : box_client.folder_by_id(id)
40
- @entries = []
41
+ values = []
41
42
 
42
43
  folder.items(ITEM_LIMIT, 0, %w[name size created_at]).collect do |f|
43
- @entries << directory_entry(f)
44
+ values << directory_entry(f)
44
45
  end
46
+ @entries = values.compact
47
+
45
48
  @sorter.call(@entries)
46
49
  end
47
50
 
@@ -74,68 +77,72 @@ module BrowseEverything
74
77
 
75
78
  private
76
79
 
77
- def token_expired?
78
- return true if expiration_time.nil?
79
- Time.now.to_i > expiration_time
80
- end
80
+ def token_expired?
81
+ return true if expiration_time.nil?
82
+ Time.now.to_i > expiration_time
83
+ end
81
84
 
82
- def box_client
83
- if token_expired?
84
- session = box_session
85
- register_access_token(session.refresh_token(box_refresh_token))
86
- end
87
- RubyBox::Client.new(box_session)
85
+ def box_client
86
+ if token_expired?
87
+ session = box_session
88
+ register_access_token(session.refresh_token(box_refresh_token))
88
89
  end
90
+ RubyBox::Client.new(box_session)
91
+ end
89
92
 
90
- def session
91
- AuthenticationFactory.new(
92
- self.class.authentication_klass,
93
- client_id: config[:client_id],
94
- client_secret: config[:client_secret],
95
- access_token: box_token,
96
- refresh_token: box_refresh_token
97
- )
98
- end
93
+ def session
94
+ AuthenticationFactory.new(
95
+ self.class.authentication_klass,
96
+ client_id: config[:client_id],
97
+ client_secret: config[:client_secret],
98
+ access_token: box_token,
99
+ refresh_token: box_refresh_token
100
+ )
101
+ end
99
102
 
100
- def authenticate
101
- session.authenticate
102
- end
103
+ def authenticate
104
+ session.authenticate
105
+ end
103
106
 
104
- def box_session
105
- authenticate
106
- end
107
+ def box_session
108
+ authenticate
109
+ end
107
110
 
108
- # If there is an active session, {@token} will be set by {BrowseEverythingController} using data stored in the
109
- # session. However, if there is no prior session, or the token has expired, we reset it here using # a new
110
- # access_token received from {#box_session}.
111
- #
112
- # @param [OAuth2::AccessToken] access_token
113
- def register_access_token(access_token)
114
- @token = {
115
- 'token' => access_token.token,
116
- 'refresh_token' => access_token.refresh_token,
117
- 'expires_at' => access_token.expires_at
118
- }
119
- end
111
+ # If there is an active session, {@token} will be set by {BrowseEverythingController} using data stored in the
112
+ # session. However, if there is no prior session, or the token has expired, we reset it here using # a new
113
+ # access_token received from {#box_session}.
114
+ #
115
+ # @param [OAuth2::AccessToken] access_token
116
+ def register_access_token(access_token)
117
+ @token = {
118
+ 'token' => access_token.token,
119
+ 'refresh_token' => access_token.refresh_token,
120
+ 'expires_at' => access_token.expires_at
121
+ }
122
+ end
120
123
 
121
- def box_token
122
- return unless @token
123
- @token.fetch('token', nil)
124
- end
124
+ def box_token
125
+ return unless @token
126
+ @token.fetch('token', nil)
127
+ end
125
128
 
126
- def box_refresh_token
127
- return unless @token
128
- @token.fetch('refresh_token', nil)
129
- end
129
+ def box_refresh_token
130
+ return unless @token
131
+ @token.fetch('refresh_token', nil)
132
+ end
130
133
 
131
- def expiration_time
132
- return unless @token
133
- @token.fetch('expires_at', nil).to_i
134
- end
134
+ def expiration_time
135
+ return unless @token
136
+ @token.fetch('expires_at', nil).to_i
137
+ end
135
138
 
136
- def directory_entry(file)
137
- BrowseEverything::FileEntry.new(file.id, "#{key}:#{file.id}", file.name, file.size, file.created_at, file.type == 'folder')
138
- end
139
+ # Constructs a BrowseEverything::FileEntry object for a Box file
140
+ # resource
141
+ # @param file [String] ID to the file resource
142
+ # @return [BrowseEverything::File]
143
+ def directory_entry(file)
144
+ BrowseEverything::FileEntry.new(file.id, "#{key}:#{file.id}", file.name, file.size, file.created_at, file.type == 'folder')
145
+ end
139
146
  end
140
147
  end
141
148
  end