browse-everything 0.10.5 → 0.11.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 +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +16 -0
- data/.rubocop_todo.yml +149 -0
- data/.travis.yml +5 -6
- data/Rakefile +2 -2
- data/app/controllers/browse_everything_controller.rb +19 -22
- data/app/helpers/bootstrap_version_helper.rb +9 -11
- data/app/helpers/browse_everything_helper.rb +11 -22
- data/app/views/browse_everything/_file.html.erb +7 -11
- data/app/views/browse_everything/_files.html.erb +4 -7
- data/app/views/browse_everything/index.html.erb +1 -1
- data/browse-everything.gemspec +37 -34
- data/config/routes.rb +3 -3
- data/lib/browse-everything.rb +1 -1
- data/lib/browse_everything.rb +9 -8
- data/lib/browse_everything/browser.rb +4 -4
- data/lib/browse_everything/driver/base.rb +14 -14
- data/lib/browse_everything/driver/box.rb +48 -59
- data/lib/browse_everything/driver/dropbox.rb +10 -11
- data/lib/browse_everything/driver/file_system.rb +19 -24
- data/lib/browse_everything/driver/google_drive.rb +58 -82
- data/lib/browse_everything/driver/s3.rb +87 -0
- data/lib/browse_everything/driver/sky_drive.rb +41 -47
- data/lib/browse_everything/engine.rb +2 -2
- data/lib/browse_everything/file_entry.rb +3 -3
- data/lib/browse_everything/retriever.rb +19 -20
- data/lib/browse_everything/version.rb +1 -1
- data/lib/generators/browse_everything/assets_generator.rb +2 -4
- data/lib/generators/browse_everything/config_generator.rb +12 -12
- data/lib/generators/browse_everything/install_generator.rb +2 -4
- data/lib/generators/browse_everything/templates/browse_everything_providers.yml.example +6 -0
- data/spec/features/select_files_spec.rb +12 -12
- data/spec/features/test_compiling_stylesheets_spec.rb +2 -2
- data/spec/helper/browse_everything_controller_helper_spec.rb +8 -8
- data/spec/javascripts/jasmine_spec.rb +5 -5
- data/spec/javascripts/support/jasmine_helper.rb +9 -9
- data/spec/spec_helper.rb +26 -23
- data/spec/support/app/controllers/file_handler_controller.rb +3 -3
- data/spec/support/rake.rb +1 -1
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +21 -22
- data/spec/unit/base_spec.rb +6 -6
- data/spec/unit/browse_everything_helper_spec.rb +9 -9
- data/spec/unit/browser_spec.rb +19 -19
- data/spec/unit/dropbox_spec.rb +44 -43
- data/spec/unit/file_entry_spec.rb +31 -31
- data/spec/unit/file_system_spec.rb +26 -26
- data/spec/unit/retriever_spec.rb +42 -43
- data/spec/unit/s3_spec.rb +77 -0
- data/spec/unit/sky_drive_spec.rb +31 -31
- data/spec/views/browse_everything/_file.html.erb_spec.rb +37 -37
- data/tasks/ci.rake +3 -3
- metadata +52 -7
- data/app/.DS_Store +0 -0
- data/app/views/.DS_Store +0 -0
@@ -1,30 +1,29 @@
|
|
1
1
|
module BrowseEverything
|
2
2
|
module Driver
|
3
3
|
class FileSystem < Base
|
4
|
-
|
5
4
|
def icon
|
6
5
|
'file'
|
7
6
|
end
|
8
|
-
|
7
|
+
|
9
8
|
def validate_config
|
10
9
|
unless config[:home]
|
11
|
-
raise BrowseEverything::InitializationError,
|
10
|
+
raise BrowseEverything::InitializationError, 'FileSystem driver requires a :home argument'
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
|
-
def contents(path='')
|
16
|
-
relative_path = path.sub(%r{^[\/.]+},'')
|
14
|
+
def contents(path = '')
|
15
|
+
relative_path = path.sub(%r{^[\/.]+}, '')
|
17
16
|
real_path = File.join(config[:home], relative_path)
|
18
17
|
result = []
|
19
18
|
if File.directory?(real_path)
|
20
19
|
if relative_path.present?
|
21
|
-
result << details(File.expand_path('..',real_path),'..')
|
20
|
+
result << details(File.expand_path('..', real_path), '..')
|
22
21
|
end
|
23
|
-
result += Dir[File.join(real_path,'*')].collect { |f| details(f) }
|
24
|
-
elsif File.
|
22
|
+
result += Dir[File.join(real_path, '*')].collect { |f| details(f) }
|
23
|
+
elsif File.exist?(real_path)
|
25
24
|
result += [details(real_path)]
|
26
25
|
end
|
27
|
-
result.sort do |a,b|
|
26
|
+
result.sort do |a, b|
|
28
27
|
if b.container?
|
29
28
|
a.container? ? a.name.downcase <=> b.name.downcase : 1
|
30
29
|
else
|
@@ -33,20 +32,17 @@ module BrowseEverything
|
|
33
32
|
end
|
34
33
|
end
|
35
34
|
|
36
|
-
def details(path,display=nil)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
else
|
48
|
-
nil
|
49
|
-
end
|
35
|
+
def details(path, display = nil)
|
36
|
+
return nil unless File.exist?(path)
|
37
|
+
info = File::Stat.new(path)
|
38
|
+
BrowseEverything::FileEntry.new(
|
39
|
+
Pathname.new(File.expand_path(path)).relative_path_from(Pathname.new(config[:home])),
|
40
|
+
[key, path].join(':'),
|
41
|
+
display || File.basename(path),
|
42
|
+
info.size,
|
43
|
+
info.mtime,
|
44
|
+
info.directory?
|
45
|
+
)
|
50
46
|
end
|
51
47
|
|
52
48
|
def link_for(path)
|
@@ -59,6 +55,5 @@ module BrowseEverything
|
|
59
55
|
true
|
60
56
|
end
|
61
57
|
end
|
62
|
-
|
63
58
|
end
|
64
59
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module BrowseEverything
|
2
2
|
module Driver
|
3
3
|
class GoogleDrive < Base
|
4
|
-
|
5
|
-
require '
|
4
|
+
require 'google/apis/drive_v3'
|
5
|
+
require 'signet'
|
6
6
|
|
7
7
|
def icon
|
8
8
|
'google-plus-sign'
|
@@ -10,121 +10,97 @@ module BrowseEverything
|
|
10
10
|
|
11
11
|
def validate_config
|
12
12
|
unless config[:client_id]
|
13
|
-
raise BrowseEverything::InitializationError,
|
13
|
+
raise BrowseEverything::InitializationError, 'GoogleDrive driver requires a :client_id argument'
|
14
14
|
end
|
15
15
|
unless config[:client_secret]
|
16
|
-
raise BrowseEverything::InitializationError,
|
16
|
+
raise BrowseEverything::InitializationError, 'GoogleDrive driver requires a :client_secret argument'
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def contents(path='')
|
21
|
-
|
20
|
+
def contents(path = '')
|
21
|
+
return to_enum(:contents, path) unless block_given?
|
22
|
+
default_params = {
|
23
|
+
order_by: 'folder,modifiedTime desc,name',
|
24
|
+
fields: 'nextPageToken,files(name,id,mimeType,size,modifiedTime,parents,web_content_link)'
|
25
|
+
# page_size: 100
|
26
|
+
}
|
22
27
|
page_token = nil
|
23
|
-
files = []
|
24
28
|
begin
|
25
|
-
unless path.blank?
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
api_result = oauth_client.execute( api_method: drive.files.list, parameters: default_params )
|
32
|
-
response = JSON.parse(api_result.response.body)
|
33
|
-
page_token = response["nextPageToken"]
|
34
|
-
response["items"].select do |file|
|
35
|
-
path.blank? ? (file["parents"].blank? or file["parents"].any?{|p| p["isRoot"] }) : true
|
29
|
+
default_params[:q] = "'#{path}' in parents" unless path.blank?
|
30
|
+
default_params[:page_token] = page_token unless page_token.blank?
|
31
|
+
response = drive.list_files(default_params)
|
32
|
+
page_token = response.next_page_token
|
33
|
+
response.files.select do |file|
|
34
|
+
path.blank? ? (file.parents.blank? || file.parents.any? { |p| p == 'root' }) : true
|
36
35
|
end.each do |file|
|
37
|
-
|
36
|
+
d = details(file, path)
|
37
|
+
yield d if d
|
38
38
|
end
|
39
39
|
end while !page_token.blank?
|
40
|
-
files.compact
|
41
40
|
end
|
42
41
|
|
43
|
-
def details(file,
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
file["mimeType"]
|
55
|
-
)
|
56
|
-
end
|
42
|
+
def details(file, _path = '')
|
43
|
+
mime_folder = file.mime_type == 'application/vnd.google-apps.folder'
|
44
|
+
BrowseEverything::FileEntry.new(
|
45
|
+
file.id,
|
46
|
+
"#{key}:#{file.id}",
|
47
|
+
file.name,
|
48
|
+
file.size.to_i,
|
49
|
+
file.modified_time || DateTime.new,
|
50
|
+
mime_folder,
|
51
|
+
mime_folder ? 'directory' : file.mime_type
|
52
|
+
)
|
57
53
|
end
|
58
54
|
|
59
55
|
def link_for(id)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
auth_header = {'Authorization' => "Bearer #{oauth_client.authorization.access_token.to_s}"}
|
64
|
-
extras = {
|
56
|
+
file = drive.get_file(id)
|
57
|
+
auth_header = { 'Authorization' => "Bearer #{auth_client.access_token}" }
|
58
|
+
extras = {
|
65
59
|
auth_header: auth_header,
|
66
|
-
expires: 1.hour.from_now,
|
67
|
-
file_name:
|
68
|
-
file_size:
|
60
|
+
expires: 1.hour.from_now,
|
61
|
+
file_name: file.name,
|
62
|
+
file_size: file.size.to_i
|
69
63
|
}
|
70
|
-
[
|
64
|
+
[file.web_content_link, extras]
|
71
65
|
end
|
72
66
|
|
73
67
|
def auth_link
|
74
|
-
|
68
|
+
auth_client.authorization_uri
|
75
69
|
end
|
76
70
|
|
77
71
|
def authorized?
|
78
|
-
|
72
|
+
token.present?
|
79
73
|
end
|
80
74
|
|
81
|
-
def connect(params,
|
82
|
-
|
83
|
-
|
75
|
+
def connect(params, _data)
|
76
|
+
auth_client.code = params[:code]
|
77
|
+
self.token = auth_client.fetch_access_token!
|
84
78
|
end
|
85
79
|
|
86
80
|
def drive
|
87
|
-
|
81
|
+
@drive ||= Google::Apis::DriveV3::DriveService.new.tap do |s|
|
82
|
+
s.authorization = authorization
|
83
|
+
end
|
88
84
|
end
|
89
85
|
|
90
86
|
private
|
91
87
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
(result.status != 200)
|
99
|
-
end
|
100
|
-
|
101
|
-
def exchange_refresh_token( refresh_token )
|
102
|
-
client=oauth_client
|
103
|
-
client.authorization.grant_type = 'refresh_token'
|
104
|
-
client.authorization.refresh_token = refresh_token
|
105
|
-
client.authorization.fetch_access_token!
|
106
|
-
client.authorization
|
107
|
-
client
|
88
|
+
def authorization
|
89
|
+
return @auth_client unless @auth_client.nil?
|
90
|
+
return nil unless token.present?
|
91
|
+
auth_client.update_token!(token)
|
92
|
+
self.token = auth_client.fetch_access_token! if auth_client.expired?
|
93
|
+
auth_client
|
108
94
|
end
|
109
|
-
#patch end
|
110
95
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
@client.authorization.update_token!(@token) if @token.present?
|
119
|
-
#Patch start
|
120
|
-
@client = exchange_refresh_token(@token["refresh_token"]) if @token.present? && token_expired?(@token)
|
121
|
-
#Patch end
|
122
|
-
end
|
123
|
-
#todo error checking here
|
124
|
-
@client
|
96
|
+
def auth_client
|
97
|
+
@auth_client ||= Signet::OAuth2::Client.new token_credential_uri: 'https://www.googleapis.com/oauth2/v3/token',
|
98
|
+
authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
|
99
|
+
scope: 'https://www.googleapis.com/auth/drive',
|
100
|
+
client_id: config[:client_id],
|
101
|
+
client_secret: config[:client_secret],
|
102
|
+
redirect_uri: callback
|
125
103
|
end
|
126
|
-
|
127
104
|
end
|
128
|
-
|
129
105
|
end
|
130
106
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
|
3
|
+
module BrowseEverything
|
4
|
+
module Driver
|
5
|
+
class S3 < Base
|
6
|
+
DEFAULTS = { signed_url: true, region: 'us-east-1' }
|
7
|
+
|
8
|
+
def initialize config, *args
|
9
|
+
config = DEFAULTS.merge(config)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def icon
|
14
|
+
'amazon'
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate_config
|
18
|
+
unless [:app_key, :app_secret, :bucket].all? { |key| config[key].present? }
|
19
|
+
raise BrowseEverything::InitializationError, 'Amazon S3 driver requires :bucket, :app_key and :app_secret'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def contents(path = '')
|
24
|
+
path = File.join(path,'') unless path.empty?
|
25
|
+
result = []
|
26
|
+
listing = client.list_objects(bucket: config[:bucket], delimiter: '/', prefix: path)
|
27
|
+
unless path.empty?
|
28
|
+
result << BrowseEverything::FileEntry.new(
|
29
|
+
Pathname(path).join('..'),
|
30
|
+
'', '..', 0, Time.now, true
|
31
|
+
)
|
32
|
+
end
|
33
|
+
listing.common_prefixes.each do |prefix|
|
34
|
+
result << entry_for(prefix.prefix, 0, Time.now, true)
|
35
|
+
end
|
36
|
+
listing.contents.reject { |entry| entry.key == path }.each do |entry|
|
37
|
+
result << entry_for(entry.key, entry.size, entry.last_modified, false)
|
38
|
+
end
|
39
|
+
result.sort do |a, b|
|
40
|
+
if b.container?
|
41
|
+
a.container? ? a.name.downcase <=> b.name.downcase : 1
|
42
|
+
else
|
43
|
+
a.container? ? -1 : a.name.downcase <=> b.name.downcase
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def entry_for(name, size, date, dir)
|
49
|
+
BrowseEverything::FileEntry.new(name, [key,name].join(':'), File.basename(name), size, date, dir)
|
50
|
+
end
|
51
|
+
|
52
|
+
def details(path)
|
53
|
+
entry = client.head_object(path)
|
54
|
+
BrowseEverything::FileEntry.new(
|
55
|
+
entry.key,
|
56
|
+
[key,entry.key].join(':'),
|
57
|
+
File.basename(entry.key),
|
58
|
+
entry.size,
|
59
|
+
entry.last_modified,
|
60
|
+
false
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def link_for(path)
|
65
|
+
obj = bucket.object(path)
|
66
|
+
if config[:signed_url]
|
67
|
+
obj.presigned_url(:get, expires_in: 14400)
|
68
|
+
else
|
69
|
+
obj.public_url
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def authorized?
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
def bucket
|
78
|
+
@bucket ||= Aws::S3::Bucket.new(config[:bucket], client: client)
|
79
|
+
end
|
80
|
+
|
81
|
+
def client
|
82
|
+
@client ||= Aws::S3::Client.new(credentials: Aws::Credentials.new(config[:app_key], config[:app_secret]), region: config[:region])
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module BrowseEverything
|
2
2
|
module Driver
|
3
3
|
class SkyDrive < Base
|
4
|
-
|
5
4
|
require 'skydrive'
|
6
5
|
|
7
6
|
def icon
|
@@ -9,27 +8,27 @@ module BrowseEverything
|
|
9
8
|
end
|
10
9
|
|
11
10
|
def container_items
|
12
|
-
|
11
|
+
%w(folder album)
|
13
12
|
end
|
14
13
|
|
15
14
|
def validate_config
|
16
15
|
unless config[:client_id]
|
17
|
-
raise BrowseEverything::InitializationError,
|
16
|
+
raise BrowseEverything::InitializationError, 'SkyDrive driver requires a :client_id argument'
|
18
17
|
end
|
19
18
|
unless config[:client_secret]
|
20
|
-
raise BrowseEverything::InitializationError,
|
19
|
+
raise BrowseEverything::InitializationError, 'SkyDrive driver requires a :client_secret argument'
|
21
20
|
end
|
22
21
|
end
|
23
22
|
|
24
|
-
def contents(path='')
|
23
|
+
def contents(path = '')
|
25
24
|
result = []
|
26
25
|
token_obj = rehydrate_token
|
27
26
|
client = Skydrive::Client.new(token_obj)
|
28
|
-
if
|
27
|
+
if path == ''
|
29
28
|
folder = client.my_skydrive
|
30
|
-
#
|
29
|
+
# TODO: do some loop to get down to my path
|
31
30
|
else
|
32
|
-
folder = client.get("/#{path.
|
31
|
+
folder = client.get("/#{path.tr('-', '.')}/")
|
33
32
|
result += [parent_folder_details(folder)] if folder.parent_id
|
34
33
|
end
|
35
34
|
|
@@ -47,68 +46,63 @@ module BrowseEverything
|
|
47
46
|
|
48
47
|
def link_for(path)
|
49
48
|
response = Skydrive::Client.new(rehydrate_token).get("/#{real_id(path)}/")
|
50
|
-
[response.download_link, {expires: 1.hour.from_now, file_name: File.basename(path), file_size: response.size.to_i}]
|
49
|
+
[response.download_link, { expires: 1.hour.from_now, file_name: File.basename(path), file_size: response.size.to_i }]
|
51
50
|
end
|
52
51
|
|
53
|
-
|
54
|
-
|
55
52
|
def file_details(file)
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
53
|
+
BrowseEverything::FileEntry.new(
|
54
|
+
safe_id(file.id),
|
55
|
+
"#{key}:#{safe_id(file.id)}",
|
56
|
+
file.name,
|
57
|
+
file.size,
|
58
|
+
file.updated_time,
|
59
|
+
false
|
60
|
+
)
|
64
61
|
end
|
65
62
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
63
|
+
def parent_folder_details(file)
|
64
|
+
BrowseEverything::FileEntry.new(
|
65
|
+
safe_id(file.parent_id),
|
66
|
+
"#{key}:#{safe_id(file.parent_id)}",
|
67
|
+
'..',
|
68
|
+
0,
|
69
|
+
Time.now,
|
70
|
+
true
|
71
|
+
)
|
75
72
|
end
|
76
73
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
74
|
def folder_details(folder)
|
81
75
|
BrowseEverything::FileEntry.new(
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
76
|
+
safe_id(folder.id),
|
77
|
+
"#{key}:#{safe_id(folder.id)}",
|
78
|
+
folder.name,
|
79
|
+
0,
|
80
|
+
folder.updated_time,
|
81
|
+
true,
|
82
|
+
'directory' # TODO: how are we getting mime type
|
89
83
|
)
|
90
84
|
end
|
91
85
|
|
92
|
-
|
93
86
|
def auth_link
|
94
87
|
oauth_client.authorize_url
|
95
88
|
end
|
96
89
|
|
97
90
|
def authorized?
|
98
91
|
return false unless @token.present?
|
99
|
-
|
92
|
+
!rehydrate_token.expired?
|
100
93
|
end
|
101
94
|
|
102
|
-
def connect(params,
|
95
|
+
def connect(params, _data)
|
103
96
|
Rails.logger.warn "params #{params.inspect}"
|
104
97
|
token = oauth_client.get_access_token(params[:code])
|
105
|
-
@token = {token:token.token, expires_at:token.expires_at}
|
98
|
+
@token = { token: token.token, expires_at: token.expires_at }
|
106
99
|
end
|
107
100
|
|
108
101
|
private
|
102
|
+
|
109
103
|
def oauth_client
|
110
|
-
Skydrive::Oauth::Client.new(config[:client_id], config[:client_secret], callback.to_s,
|
111
|
-
#
|
104
|
+
Skydrive::Oauth::Client.new(config[:client_id], config[:client_secret], callback.to_s, 'wl.skydrive')
|
105
|
+
# TODO: error checking here
|
112
106
|
end
|
113
107
|
|
114
108
|
def rehydrate_token
|
@@ -116,15 +110,15 @@ module BrowseEverything
|
|
116
110
|
token_str = @token[:token]
|
117
111
|
token_expires = @token[:expires_at]
|
118
112
|
Rails.logger.warn "\n\n Rehydrating: #{@token} #{token_str} #{token_expires}"
|
119
|
-
@rehydrate_token = oauth_client.get_access_token_from_hash(token_str,
|
113
|
+
@rehydrate_token = oauth_client.get_access_token_from_hash(token_str, expires_at: token_expires)
|
120
114
|
end
|
121
115
|
|
122
116
|
def safe_id(id)
|
123
|
-
id.
|
117
|
+
id.tr('.', '-')
|
124
118
|
end
|
125
119
|
|
126
120
|
def real_id(id)
|
127
|
-
id.
|
121
|
+
id.tr('-', '.')
|
128
122
|
end
|
129
123
|
end
|
130
124
|
end
|