browse-everything 1.0.0 → 1.1.2
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 +4 -4
- data/.circleci/config.yml +82 -133
- data/.gitignore +1 -0
- data/.rubocop.yml +43 -35
- data/CONTRIBUTING.md +3 -3
- data/Gemfile +3 -6
- data/LICENSE.txt +205 -22
- data/README.md +7 -6
- data/app/assets/javascripts/browse_everything/behavior.js +16 -8
- data/app/assets/javascripts/treetable.webpack.js +687 -0
- data/app/controllers/browse_everything_controller.rb +60 -60
- data/app/helpers/browse_everything_helper.rb +4 -0
- data/app/views/browse_everything/_files.html.erb +4 -2
- data/browse-everything.gemspec +6 -7
- data/lib/browse_everything.rb +2 -1
- data/lib/browse_everything/auth/google/credentials.rb +5 -5
- data/lib/browse_everything/auth/google/request_parameters.rb +38 -38
- data/lib/browse_everything/driver/base.rb +14 -14
- data/lib/browse_everything/driver/box.rb +62 -55
- data/lib/browse_everything/driver/dropbox.rb +34 -33
- data/lib/browse_everything/driver/file_system.rb +30 -18
- data/lib/browse_everything/driver/google_drive.rb +40 -39
- data/lib/browse_everything/driver/s3.rb +61 -45
- data/lib/browse_everything/file_entry.rb +1 -1
- data/lib/browse_everything/retriever.rb +69 -69
- data/lib/browse_everything/version.rb +1 -1
- data/spec/features/test_compiling_stylesheets_spec.rb +1 -1
- data/spec/lib/browse_everything/driver_spec.rb +43 -3
- data/spec/spec_helper.rb +9 -3
- data/spec/support/capybara.rb +0 -5
- data/spec/test_app_templates/Gemfile.extra +9 -0
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +54 -3
- metadata +49 -45
- data/.travis.yml +0 -30
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require File.expand_path('../helpers/browse_everything_helper', __dir__)
|
4
4
|
|
5
|
-
class BrowseEverythingController <
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
80
|
-
|
81
|
-
|
79
|
+
def connector_response_url_options
|
80
|
+
{ protocol: request.protocol, host: request.host, port: request.port }
|
81
|
+
end
|
82
82
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
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
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
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
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
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
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
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
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
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
|
@@ -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:
|
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
|
-
<%=
|
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>
|
data/browse-everything.gemspec
CHANGED
@@ -23,18 +23,16 @@ 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', '
|
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'
|
32
31
|
spec.add_dependency 'typhoeus'
|
33
32
|
|
34
|
-
spec.add_development_dependency 'bixby', '
|
35
|
-
spec.add_development_dependency 'bundler', '
|
33
|
+
spec.add_development_dependency 'bixby', '~> 3.0'
|
34
|
+
spec.add_development_dependency 'bundler', '>= 1.3'
|
36
35
|
spec.add_development_dependency 'capybara'
|
37
|
-
spec.add_development_dependency 'chromedriver-helper', '~> 2.1'
|
38
36
|
spec.add_development_dependency 'coveralls'
|
39
37
|
spec.add_development_dependency 'engine_cart', '~> 2.0'
|
40
38
|
spec.add_development_dependency 'factory_bot_rails'
|
@@ -50,5 +48,6 @@ Gem::Specification.new do |spec|
|
|
50
48
|
spec.add_development_dependency 'selenium-webdriver'
|
51
49
|
spec.add_development_dependency 'simplecov'
|
52
50
|
spec.add_development_dependency 'sqlite3'
|
51
|
+
spec.add_development_dependency 'webdrivers'
|
53
52
|
spec.add_development_dependency 'webmock'
|
54
53
|
end
|
data/lib/browse_everything.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
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
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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<
|
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
|
-
|
41
|
+
values = []
|
41
42
|
|
42
43
|
folder.items(ITEM_LIMIT, 0, %w[name size created_at]).collect do |f|
|
43
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
80
|
+
def token_expired?
|
81
|
+
return true if expiration_time.nil?
|
82
|
+
Time.now.to_i > expiration_time
|
83
|
+
end
|
81
84
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
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
|
-
|
101
|
-
|
102
|
-
|
103
|
+
def authenticate
|
104
|
+
session.authenticate
|
105
|
+
end
|
103
106
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
+
def box_session
|
108
|
+
authenticate
|
109
|
+
end
|
107
110
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
124
|
+
def box_token
|
125
|
+
return unless @token
|
126
|
+
@token.fetch('token', nil)
|
127
|
+
end
|
125
128
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
129
|
+
def box_refresh_token
|
130
|
+
return unless @token
|
131
|
+
@token.fetch('refresh_token', nil)
|
132
|
+
end
|
130
133
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
134
|
+
def expiration_time
|
135
|
+
return unless @token
|
136
|
+
@token.fetch('expires_at', nil).to_i
|
137
|
+
end
|
135
138
|
|
136
|
-
|
137
|
-
|
138
|
-
|
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
|