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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +16 -0
  4. data/.rubocop_todo.yml +149 -0
  5. data/.travis.yml +5 -6
  6. data/Rakefile +2 -2
  7. data/app/controllers/browse_everything_controller.rb +19 -22
  8. data/app/helpers/bootstrap_version_helper.rb +9 -11
  9. data/app/helpers/browse_everything_helper.rb +11 -22
  10. data/app/views/browse_everything/_file.html.erb +7 -11
  11. data/app/views/browse_everything/_files.html.erb +4 -7
  12. data/app/views/browse_everything/index.html.erb +1 -1
  13. data/browse-everything.gemspec +37 -34
  14. data/config/routes.rb +3 -3
  15. data/lib/browse-everything.rb +1 -1
  16. data/lib/browse_everything.rb +9 -8
  17. data/lib/browse_everything/browser.rb +4 -4
  18. data/lib/browse_everything/driver/base.rb +14 -14
  19. data/lib/browse_everything/driver/box.rb +48 -59
  20. data/lib/browse_everything/driver/dropbox.rb +10 -11
  21. data/lib/browse_everything/driver/file_system.rb +19 -24
  22. data/lib/browse_everything/driver/google_drive.rb +58 -82
  23. data/lib/browse_everything/driver/s3.rb +87 -0
  24. data/lib/browse_everything/driver/sky_drive.rb +41 -47
  25. data/lib/browse_everything/engine.rb +2 -2
  26. data/lib/browse_everything/file_entry.rb +3 -3
  27. data/lib/browse_everything/retriever.rb +19 -20
  28. data/lib/browse_everything/version.rb +1 -1
  29. data/lib/generators/browse_everything/assets_generator.rb +2 -4
  30. data/lib/generators/browse_everything/config_generator.rb +12 -12
  31. data/lib/generators/browse_everything/install_generator.rb +2 -4
  32. data/lib/generators/browse_everything/templates/browse_everything_providers.yml.example +6 -0
  33. data/spec/features/select_files_spec.rb +12 -12
  34. data/spec/features/test_compiling_stylesheets_spec.rb +2 -2
  35. data/spec/helper/browse_everything_controller_helper_spec.rb +8 -8
  36. data/spec/javascripts/jasmine_spec.rb +5 -5
  37. data/spec/javascripts/support/jasmine_helper.rb +9 -9
  38. data/spec/spec_helper.rb +26 -23
  39. data/spec/support/app/controllers/file_handler_controller.rb +3 -3
  40. data/spec/support/rake.rb +1 -1
  41. data/spec/test_app_templates/lib/generators/test_app_generator.rb +21 -22
  42. data/spec/unit/base_spec.rb +6 -6
  43. data/spec/unit/browse_everything_helper_spec.rb +9 -9
  44. data/spec/unit/browser_spec.rb +19 -19
  45. data/spec/unit/dropbox_spec.rb +44 -43
  46. data/spec/unit/file_entry_spec.rb +31 -31
  47. data/spec/unit/file_system_spec.rb +26 -26
  48. data/spec/unit/retriever_spec.rb +42 -43
  49. data/spec/unit/s3_spec.rb +77 -0
  50. data/spec/unit/sky_drive_spec.rb +31 -31
  51. data/spec/views/browse_everything/_file.html.erb_spec.rb +37 -37
  52. data/tasks/ci.rake +3 -3
  53. metadata +52 -7
  54. data/app/.DS_Store +0 -0
  55. 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, "FileSystem driver requires a :home argument"
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.exists?(real_path)
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
- if File.exists?(path)
38
- info = File::Stat.new(path)
39
- BrowseEverything::FileEntry.new(
40
- Pathname.new(File.expand_path(path)).relative_path_from(Pathname.new(config[:home])),
41
- [self.key,path].join(':'),
42
- display || File.basename(path),
43
- info.size,
44
- info.mtime,
45
- info.directory?
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 'google/api_client'
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, "GoogleDrive driver requires a :client_id argument"
13
+ raise BrowseEverything::InitializationError, 'GoogleDrive driver requires a :client_id argument'
14
14
  end
15
15
  unless config[:client_secret]
16
- raise BrowseEverything::InitializationError, "GoogleDrive driver requires a :client_secret argument"
16
+ raise BrowseEverything::InitializationError, 'GoogleDrive driver requires a :client_secret argument'
17
17
  end
18
18
  end
19
19
 
20
- def contents(path='')
21
- default_params = { }
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
- default_params[:q] = "'#{path}' in parents"
27
- end
28
- unless page_token.blank?
29
- default_params[:pageToken] = page_token
30
- end
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
- files << details(file, path)
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, path='')
44
- if file["downloadUrl"] or file["mimeType"] == "application/vnd.google-apps.folder"
45
- BrowseEverything::FileEntry.new(
46
- file["id"],
47
- "#{self.key}:#{file["id"]}",
48
- file["title"],
49
- (file["fileSize"] || 0),
50
- Time.parse(file["modifiedDate"]),
51
- file["mimeType"] == "application/vnd.google-apps.folder",
52
- file["mimeType"] == "application/vnd.google-apps.folder" ?
53
- "directory" :
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
- api_method = drive.files.get
61
- api_result = oauth_client.execute(api_method: api_method, parameters: {fileId: id})
62
- download_url = JSON.parse(api_result.response.body)["downloadUrl"]
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: api_result.data.title,
68
- file_size: api_result.data.fileSize.to_i
60
+ expires: 1.hour.from_now,
61
+ file_name: file.name,
62
+ file_size: file.size.to_i
69
63
  }
70
- [download_url, extras]
64
+ [file.web_content_link, extras]
71
65
  end
72
66
 
73
67
  def auth_link
74
- oauth_client.authorization.authorization_uri.to_s
68
+ auth_client.authorization_uri
75
69
  end
76
70
 
77
71
  def authorized?
78
- @token.present?
72
+ token.present?
79
73
  end
80
74
 
81
- def connect(params, data)
82
- oauth_client.authorization.code = params[:code]
83
- @token = oauth_client.authorization.fetch_access_token!
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
- oauth_client.discovered_api('drive', 'v2')
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
- #As per issue http://stackoverflow.com/questions/12572723/rails-google-client-api-unable-to-exchange-a-refresh-token-for-access-token
93
-
94
- #patch start
95
- def token_expired?(token)
96
- client=@client
97
- result = client.execute( api_method: drive.files.list, parameters: {} )
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 oauth_client
112
- if @client.nil?
113
- @client = Google::APIClient.new
114
- @client.authorization.client_id = config[:client_id]
115
- @client.authorization.client_secret = config[:client_secret]
116
- @client.authorization.scope = "https://www.googleapis.com/auth/drive"
117
- @client.authorization.redirect_uri = callback
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
- ["folder","album"]
11
+ %w(folder album)
13
12
  end
14
13
 
15
14
  def validate_config
16
15
  unless config[:client_id]
17
- raise BrowseEverything::InitializationError, "SkyDrive driver requires a :client_id argument"
16
+ raise BrowseEverything::InitializationError, 'SkyDrive driver requires a :client_id argument'
18
17
  end
19
18
  unless config[:client_secret]
20
- raise BrowseEverything::InitializationError, "SkyDrive driver requires a :client_secret argument"
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 (path == '')
27
+ if path == ''
29
28
  folder = client.my_skydrive
30
- #todo do some loop to get down to my path
29
+ # TODO: do some loop to get down to my path
31
30
  else
32
- folder = client.get("/#{path.gsub("-",".")}/")
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
- BrowseEverything::FileEntry.new(
57
- safe_id(file.id),
58
- "#{key}:#{safe_id(file.id)}",
59
- file.name,
60
- file.size,
61
- file.updated_time,
62
- false
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
- def parent_folder_details(file)
67
- BrowseEverything::FileEntry.new(
68
- safe_id(file.parent_id),
69
- "#{key}:#{safe_id(file.parent_id)}",
70
- "..",
71
- 0,
72
- Time.now,
73
- true
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
- safe_id(folder.id),
83
- "#{key}:#{safe_id(folder.id)}",
84
- folder.name,
85
- 0,
86
- folder.updated_time,
87
- true,
88
- 'directory'#todo how are we getting mime type
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
- return !rehydrate_token.expired?
92
+ !rehydrate_token.expired?
100
93
  end
101
94
 
102
- def connect(params,data)
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,"wl.skydrive")
111
- #todo error checking here
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,{expires_at:token_expires})
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.gsub(".","-")
117
+ id.tr('.', '-')
124
118
  end
125
119
 
126
120
  def real_id(id)
127
- id.gsub("-",".")
121
+ id.tr('-', '.')
128
122
  end
129
123
  end
130
124
  end