browse-everything 0.10.5 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|