browse-everything 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +105 -30
  3. data/.gitignore +4 -2
  4. data/.rubocop.yml +54 -34
  5. data/.rubocop_todo.yml +0 -5
  6. data/.tool-versions +2 -0
  7. data/CONTRIBUTING.md +22 -0
  8. data/Gemfile +41 -33
  9. data/README.md +66 -31
  10. data/Rakefile +9 -1
  11. data/app/assets/javascripts/browse_everything/behavior.js +45 -31
  12. data/app/assets/javascripts/browse_everything.js +1 -1
  13. data/app/assets/javascripts/treetable.webpack.js +687 -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 +3 -2
  17. data/bin/rails +14 -0
  18. data/browse-everything.gemspec +13 -12
  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 +15 -14
  22. data/lib/browse_everything/driver/box.rb +56 -56
  23. data/lib/browse_everything/driver/dropbox.rb +44 -41
  24. data/lib/browse_everything/driver/file_system.rb +31 -18
  25. data/lib/browse_everything/driver/google_drive.rb +38 -38
  26. data/lib/browse_everything/driver/s3.rb +61 -61
  27. data/lib/browse_everything/engine.rb +10 -3
  28. data/lib/browse_everything/file_entry.rb +1 -1
  29. data/lib/browse_everything/retriever.rb +69 -69
  30. data/lib/browse_everything/version.rb +1 -1
  31. data/lib/browse_everything.rb +1 -1
  32. data/spec/dummy_test_app/Rakefile +6 -0
  33. data/spec/dummy_test_app/app/assets/config/manifest.js +3 -0
  34. data/spec/dummy_test_app/app/assets/images/.keep +0 -0
  35. data/spec/dummy_test_app/app/assets/javascripts/application.js +25 -0
  36. data/spec/dummy_test_app/app/assets/javascripts/cable.js +13 -0
  37. data/spec/dummy_test_app/app/assets/javascripts/channels/.keep +0 -0
  38. data/spec/dummy_test_app/app/assets/stylesheets/application.scss +18 -0
  39. data/spec/dummy_test_app/app/channels/application_cable/channel.rb +4 -0
  40. data/spec/dummy_test_app/app/channels/application_cable/connection.rb +4 -0
  41. data/spec/dummy_test_app/app/controllers/application_controller.rb +3 -0
  42. data/spec/dummy_test_app/app/controllers/concerns/.keep +0 -0
  43. data/spec/{support → dummy_test_app}/app/controllers/file_handler_controller.rb +0 -0
  44. data/spec/dummy_test_app/app/helpers/application_helper.rb +2 -0
  45. data/spec/dummy_test_app/app/jobs/application_job.rb +2 -0
  46. data/spec/dummy_test_app/app/mailers/application_mailer.rb +4 -0
  47. data/spec/dummy_test_app/app/models/application_record.rb +3 -0
  48. data/spec/dummy_test_app/app/models/concerns/.keep +0 -0
  49. data/spec/dummy_test_app/app/views/file_handler/index.html.erb +10 -0
  50. data/spec/{support → dummy_test_app}/app/views/file_handler/main.html.erb +6 -3
  51. data/spec/dummy_test_app/app/views/layouts/application.html.erb +14 -0
  52. data/spec/dummy_test_app/app/views/layouts/mailer.html.erb +13 -0
  53. data/spec/dummy_test_app/app/views/layouts/mailer.text.erb +1 -0
  54. data/spec/dummy_test_app/bin/bundle +3 -0
  55. data/spec/dummy_test_app/bin/rails +4 -0
  56. data/spec/dummy_test_app/bin/rake +4 -0
  57. data/spec/dummy_test_app/bin/setup +38 -0
  58. data/spec/dummy_test_app/bin/update +29 -0
  59. data/spec/dummy_test_app/bin/yarn +11 -0
  60. data/spec/dummy_test_app/config/application.rb +27 -0
  61. data/spec/dummy_test_app/config/boot.rb +5 -0
  62. data/spec/dummy_test_app/config/browse_everything_providers.yml +25 -0
  63. data/spec/dummy_test_app/config/cable.yml +10 -0
  64. data/spec/dummy_test_app/config/database.yml +25 -0
  65. data/spec/dummy_test_app/config/environment.rb +5 -0
  66. data/spec/dummy_test_app/config/environments/development.rb +54 -0
  67. data/spec/dummy_test_app/config/environments/production.rb +91 -0
  68. data/spec/dummy_test_app/config/environments/test.rb +42 -0
  69. data/spec/dummy_test_app/config/initializers/application_controller_renderer.rb +8 -0
  70. data/spec/dummy_test_app/config/initializers/assets.rb +14 -0
  71. data/spec/dummy_test_app/config/initializers/backtrace_silencers.rb +7 -0
  72. data/spec/dummy_test_app/config/initializers/cookies_serializer.rb +5 -0
  73. data/spec/dummy_test_app/config/initializers/filter_parameter_logging.rb +4 -0
  74. data/spec/dummy_test_app/config/initializers/inflections.rb +16 -0
  75. data/spec/dummy_test_app/config/initializers/mime_types.rb +4 -0
  76. data/spec/dummy_test_app/config/initializers/wrap_parameters.rb +14 -0
  77. data/spec/dummy_test_app/config/locales/en.yml +33 -0
  78. data/spec/dummy_test_app/config/puma.rb +56 -0
  79. data/spec/dummy_test_app/config/routes.rb +9 -0
  80. data/spec/dummy_test_app/config/secrets.yml +32 -0
  81. data/spec/dummy_test_app/config/spring.rb +6 -0
  82. data/spec/dummy_test_app/config.ru +5 -0
  83. data/spec/dummy_test_app/lib/assets/.keep +0 -0
  84. data/spec/dummy_test_app/log/.keep +0 -0
  85. data/spec/dummy_test_app/package.json +5 -0
  86. data/spec/dummy_test_app/public/404.html +67 -0
  87. data/spec/dummy_test_app/public/422.html +67 -0
  88. data/spec/dummy_test_app/public/500.html +66 -0
  89. data/spec/dummy_test_app/public/apple-touch-icon-precomposed.png +0 -0
  90. data/spec/dummy_test_app/public/apple-touch-icon.png +0 -0
  91. data/spec/dummy_test_app/public/favicon.ico +0 -0
  92. data/spec/dummy_test_app/tmp/.gitkeep +0 -0
  93. data/spec/features/select_files_spec.rb +1 -0
  94. data/spec/features/test_compiling_stylesheets_spec.rb +1 -1
  95. data/spec/lib/browse_everything/driver_spec.rb +43 -3
  96. data/spec/spec_helper.rb +3 -28
  97. data/tasks/ci.rake +1 -1
  98. metadata +180 -94
  99. data/karma.conf.js +0 -71
  100. data/spec/javascripts/behavior_spec.js +0 -7
  101. data/spec/javascripts/helpers/jasmine-jquery.js +0 -838
  102. data/spec/javascripts/helpers/jquery.js +0 -11008
  103. data/spec/javascripts/karma_spec.rb +0 -16
  104. data/spec/support/app/views/file_handler/index.html.erb +0 -6
  105. data/spec/test_app_templates/Gemfile.extra +0 -9
  106. data/spec/test_app_templates/lib/generators/test_app_generator.rb +0 -61
@@ -9,13 +9,17 @@ module BrowseEverything
9
9
 
10
10
  def validate_config
11
11
  raise BrowseEverything::InitializationError, 'FileSystem driver requires a :home argument' if config[:home].blank?
12
+
13
+ unless config[:home].start_with?("/") || config[:allow_relative_home] == true
14
+ raise BrowseEverything::InitializationError, 'FileSystem driver :home argument must be absolute unless :allow_relative_home is set'
15
+ end
12
16
  end
13
17
 
14
18
  # Retrieve the contents of a directory
15
19
  # @param path [String] the path to a file system resource
16
20
  # @return [Array<BrowseEverything::FileEntry>]
17
21
  def contents(path = '')
18
- real_path = File.join(config[:home], path)
22
+ real_path = File.join(home_path, path)
19
23
  values = if File.directory?(real_path)
20
24
  make_directory_entry real_path
21
25
  else
@@ -55,25 +59,34 @@ module BrowseEverything
55
59
 
56
60
  private
57
61
 
58
- # Construct an array of FileEntry objects for the contents of a
59
- # directory
60
- # @param real_path [String] path to the file system directory
61
- # @return [Array<BrowseEverything::FileEntry>]
62
- def make_directory_entry(real_path)
63
- entries = []
64
- entries + Dir[File.join(real_path, '*')].collect { |f| details(f) }
65
- end
62
+ def home_path
63
+ @home_path ||= if config[:allow_relative_home] == true
64
+ # expand relative to Rails.root, mainly test CI use-case
65
+ File.expand_path(config[:home], Rails.root)
66
+ else
67
+ config[:home]
68
+ end
69
+ end
66
70
 
67
- def make_pathname(path)
68
- Pathname.new(File.expand_path(path)).relative_path_from(Pathname.new(config[:home]))
69
- end
71
+ # Construct an array of FileEntry objects for the contents of a
72
+ # directory
73
+ # @param real_path [String] path to the file system directory
74
+ # @return [Array<BrowseEverything::FileEntry>]
75
+ def make_directory_entry(real_path)
76
+ entries = []
77
+ entries + Dir[File.join(real_path, '*')].collect { |f| details(f) }
78
+ end
70
79
 
71
- def file_size(path)
72
- File.size(path).to_i
73
- rescue StandardError => error
74
- Rails.logger.error "Failed to find the file size for #{path}: #{error}"
75
- 0
76
- end
80
+ def make_pathname(path)
81
+ Pathname.new(File.expand_path(path)).relative_path_from(Pathname.new(home_path))
82
+ end
83
+
84
+ def file_size(path)
85
+ File.size(path).to_i
86
+ rescue StandardError => error
87
+ Rails.logger.error "Failed to find the file size for #{path}: #{error}"
88
+ 0
89
+ end
77
90
  end
78
91
  end
79
92
  end
@@ -191,50 +191,50 @@ module BrowseEverything
191
191
 
192
192
  private
193
193
 
194
- def client_secrets
195
- {
196
- Google::Auth::ClientId::WEB_APP => {
197
- Google::Auth::ClientId::CLIENT_ID => config[:client_id],
198
- Google::Auth::ClientId::CLIENT_SECRET => config[:client_secret]
199
- }
194
+ def client_secrets
195
+ {
196
+ Google::Auth::ClientId::WEB_APP => {
197
+ Google::Auth::ClientId::CLIENT_ID => config[:client_id],
198
+ Google::Auth::ClientId::CLIENT_SECRET => config[:client_secret]
200
199
  }
201
- end
200
+ }
201
+ end
202
202
 
203
- # This is required for using the googleauth Gem
204
- # @see http://www.rubydoc.info/gems/googleauth/Google/Auth/Stores/FileTokenStore FileTokenStore for googleauth
205
- # @return [Tempfile] temporary file within which to cache credentials
206
- def file_token_store_path
207
- Tempfile.new('gdrive.yaml')
208
- end
203
+ # This is required for using the googleauth Gem
204
+ # @see http://www.rubydoc.info/gems/googleauth/Google/Auth/Stores/FileTokenStore FileTokenStore for googleauth
205
+ # @return [Tempfile] temporary file within which to cache credentials
206
+ def file_token_store_path
207
+ Tempfile.new('gdrive.yaml')
208
+ end
209
209
 
210
- def scope
211
- Google::Apis::DriveV3::AUTH_DRIVE
212
- end
210
+ def scope
211
+ Google::Apis::DriveV3::AUTH_DRIVE
212
+ end
213
213
 
214
- # Provides the user ID for caching access tokens
215
- # (This is a hack which attempts to anonymize the access tokens)
216
- # @return [String] the ID for the user
217
- def user_id
218
- 'current_user'
219
- end
214
+ # Provides the user ID for caching access tokens
215
+ # (This is a hack which attempts to anonymize the access tokens)
216
+ # @return [String] the ID for the user
217
+ def user_id
218
+ 'current_user'
219
+ end
220
220
 
221
- # Please see https://developers.google.com/drive/v3/web/manage-downloads
222
- # @param id [String] the ID for the Google Drive File
223
- # @return [String] the URL for the file download
224
- def download_url(id)
225
- "https://www.googleapis.com/drive/v3/files/#{id}?alt=media"
226
- end
221
+ # Please see https://developers.google.com/drive/v3/web/manage-downloads
222
+ # @param id [String] the ID for the Google Drive File
223
+ # @return [String] the URL for the file download
224
+ def download_url(id)
225
+ "https://www.googleapis.com/drive/v3/files/#{id}?alt=media"
226
+ end
227
227
 
228
- # Restore the credentials for the Google API
229
- # @param access_token [String] the access token redeemed using an authorization code
230
- # @return Credentials credentials restored from a cached access token
231
- def restore_credentials(access_token)
232
- client = Auth::Google::Credentials.new
233
- client.client_id = client_id.id
234
- client.client_secret = client_id.secret
235
- client.update_token!('access_token' => access_token)
236
- @credentials = client
237
- end
228
+ # Restore the credentials for the Google API
229
+ # @param access_token [String] the access token redeemed using an authorization code
230
+ # @return Credentials credentials restored from a cached access token
231
+ def restore_credentials(access_token)
232
+ client = Auth::Google::Credentials.new
233
+ client.client_id = client_id.id
234
+ client.client_secret = client_id.secret
235
+ client.update_token!('access_token' => access_token)
236
+ @credentials = client
237
+ end
238
238
  end
239
239
  end
240
240
  end
@@ -79,79 +79,79 @@ module BrowseEverything
79
79
 
80
80
  private
81
81
 
82
- def strip(path)
83
- path.sub %r{^/?(.+?)/?$}, '\1'
84
- end
82
+ def strip(path)
83
+ path.sub %r{^/?(.+?)/?$}, '\1'
84
+ end
85
85
 
86
- def from_base(key)
87
- Pathname.new(key).relative_path_from(Pathname.new(config[:base].to_s)).to_s
88
- end
86
+ def from_base(key)
87
+ Pathname.new(key).relative_path_from(Pathname.new(config[:base].to_s)).to_s
88
+ end
89
89
 
90
- def full_path(path)
91
- config[:base].present? ? File.join(config[:base], path) : path
92
- end
90
+ def full_path(path)
91
+ config[:base].present? ? File.join(config[:base], path) : path
92
+ end
93
93
 
94
- def aws_config
95
- result = {}
96
- result[:credentials] = Aws::Credentials.new(config[:app_key], config[:app_secret]) if config[:app_key].present?
97
- result[:region] = config[:region] if config.key?(:region)
98
- result
99
- end
94
+ def aws_config
95
+ result = {}
96
+ result[:credentials] = Aws::Credentials.new(config[:app_key], config[:app_secret]) if config[:app_key].present?
97
+ result[:region] = config[:region] if config.key?(:region)
98
+ result
99
+ end
100
100
 
101
- def session
102
- AuthenticationFactory.new(
103
- self.class.authentication_klass,
104
- aws_config
105
- )
106
- end
101
+ def session
102
+ AuthenticationFactory.new(
103
+ self.class.authentication_klass,
104
+ aws_config
105
+ )
106
+ end
107
107
 
108
- def authenticate
109
- session.authenticate
110
- end
108
+ def authenticate
109
+ session.authenticate
110
+ end
111
111
 
112
- def client
113
- @client ||= authenticate
114
- end
112
+ def client
113
+ @client ||= authenticate
114
+ end
115
115
 
116
- # Construct a BrowseEverything::FileEntry object
117
- # @param name [String]
118
- # @param size [String]
119
- # @param date [DateTime]
120
- # @param dir [String]
121
- # @return [BrowseEverything::FileEntry]
122
- def entry_for(name, size, date, dir)
123
- BrowseEverything::FileEntry.new(name, [key, name].join(':'), File.basename(name), size, date, dir)
124
- end
116
+ # Construct a BrowseEverything::FileEntry object
117
+ # @param name [String]
118
+ # @param size [String]
119
+ # @param date [DateTime]
120
+ # @param dir [String]
121
+ # @return [BrowseEverything::FileEntry]
122
+ def entry_for(name, size, date, dir)
123
+ BrowseEverything::FileEntry.new(name, [key, name].join(':'), File.basename(name), size, date, dir)
124
+ end
125
125
 
126
- # Populate the entries with FileEntry objects from an S3 listing
127
- # @param listing [Seahorse::Client::Response]
128
- def add_directories(listing)
129
- listing.common_prefixes.each do |prefix|
130
- new_entry = entry_for(from_base(prefix.prefix), 0, Time.current, true)
131
- @entries << new_entry unless new_entry.nil?
132
- end
126
+ # Populate the entries with FileEntry objects from an S3 listing
127
+ # @param listing [Seahorse::Client::Response]
128
+ def add_directories(listing)
129
+ listing.common_prefixes.each do |prefix|
130
+ new_entry = entry_for(from_base(prefix.prefix), 0, Time.current, true)
131
+ @entries << new_entry unless new_entry.nil?
133
132
  end
133
+ end
134
134
 
135
- # Given a listing and a S3 listing and path, populate the entries
136
- # @param listing [Seahorse::Client::Response]
137
- # @param path [String]
138
- def add_files(listing, path)
139
- listing.contents.each do |entry|
140
- key = from_base(entry.key)
141
- new_entry = entry_for(key, entry.size, entry.last_modified, false)
142
- @entries << new_entry unless strip(key) == strip(path) || new_entry.nil?
143
- end
135
+ # Given a listing and a S3 listing and path, populate the entries
136
+ # @param listing [Seahorse::Client::Response]
137
+ # @param path [String]
138
+ def add_files(listing, path)
139
+ listing.contents.each do |entry|
140
+ key = from_base(entry.key)
141
+ new_entry = entry_for(key, entry.size, entry.last_modified, false)
142
+ @entries << new_entry unless strip(key) == strip(path) || new_entry.nil?
144
143
  end
144
+ end
145
145
 
146
- # For a given path to a S3 resource, retrieve the listing object and
147
- # construct the file entries
148
- # @param path [String]
149
- def generate_listing(path)
150
- client
151
- listing = client.list_objects(bucket: config[:bucket], delimiter: '/', prefix: full_path(path))
152
- add_directories(listing)
153
- add_files(listing, path)
154
- end
146
+ # For a given path to a S3 resource, retrieve the listing object and
147
+ # construct the file entries
148
+ # @param path [String]
149
+ def generate_listing(path)
150
+ client
151
+ listing = client.list_objects(bucket: config[:bucket], delimiter: '/', prefix: full_path(path))
152
+ add_directories(listing)
153
+ add_files(listing, path)
154
+ end
155
155
  end
156
156
  end
157
157
  end
@@ -2,8 +2,15 @@
2
2
 
3
3
  module BrowseEverything
4
4
  class Engine < ::Rails::Engine
5
- config.assets.paths << config.root.join('vendor', 'assets', 'javascripts')
6
- config.assets.paths << config.root.join('vendor', 'assets', 'stylesheets')
7
- config.assets.precompile += %w[browse_everything.js browse_everything.css]
5
+ # As of Rails 7, sprockets is optional in Rails. If you don't have sprockets-rails
6
+ # installed, you don't have a config.assets. Without sprockets, you may
7
+ # or may not be able to figure out how to get browse-everything JS and CSS to load,
8
+ # but we should at least let you load the engine and try, so we don't try
9
+ # to configure sprockets unless it is installed...
10
+ if config.respond_to?(:assets)
11
+ config.assets.paths << config.root.join('vendor', 'assets', 'javascripts')
12
+ config.assets.paths << config.root.join('vendor', 'assets', 'stylesheets')
13
+ config.assets.precompile += %w[browse_everything.js browse_everything.css]
14
+ end
8
15
  end
9
16
  end
@@ -15,7 +15,7 @@ module BrowseEverything
15
15
  end
16
16
 
17
17
  def relative_parent_path?
18
- name =~ /^\.\.?$/ ? true : false
18
+ name.match?(/^\.\.?$/)
19
19
  end
20
20
 
21
21
  def container?
@@ -89,81 +89,81 @@ module BrowseEverything
89
89
 
90
90
  private
91
91
 
92
- # Extract and parse options used to download a file or resource from an HTTP API
93
- # @param options [Hash]
94
- # @return [Hash]
95
- def extract_download_options(options)
96
- url = options.fetch('url')
97
-
98
- # This avoids the potential for a KeyError
99
- headers = options.fetch('headers', {}) || {}
100
-
101
- file_size_value = options.fetch('file_size', 0)
102
- file_size = file_size_value.to_i
103
-
104
- output = {
105
- url: ::Addressable::URI.parse(url),
106
- headers: headers,
107
- file_size: file_size
108
- }
109
-
110
- output[:file_size] = get_file_size(output) if output[:file_size] < 1
111
- output
112
- end
92
+ # Extract and parse options used to download a file or resource from an HTTP API
93
+ # @param options [Hash]
94
+ # @return [Hash]
95
+ def extract_download_options(options)
96
+ url = options.fetch('url')
113
97
 
114
- # Retrieve the file from the file system
115
- # @param options [Hash]
116
- def retrieve_file(options)
117
- file_uri = options.fetch(:url)
118
- file_size = options.fetch(:file_size)
119
-
120
- retrieved = 0
121
- File.open(file_uri.path, 'rb') do |f|
122
- until f.eof?
123
- chunk = f.read(chunk_size)
124
- retrieved += chunk.length
125
- yield(chunk, retrieved, file_size)
126
- end
127
- end
128
- end
98
+ # This avoids the potential for a KeyError
99
+ headers = options.fetch('headers', {}) || {}
129
100
 
130
- # Retrieve a resource over the HTTP
131
- # @param options [Hash]
132
- def retrieve_http(options)
133
- file_size = options.fetch(:file_size)
134
- headers = options.fetch(:headers)
135
- url = options.fetch(:url)
136
- retrieved = 0
137
-
138
- request = Typhoeus::Request.new(url.to_s, method: :get, headers: headers)
139
- request.on_headers do |response|
140
- raise DownloadError.new("#{self.class}: Failed to download #{url}: Status Code: #{response.code}", response) unless response.code == 200
141
- end
142
- request.on_body do |chunk|
143
- retrieved += chunk.bytesize
101
+ file_size_value = options.fetch('file_size', 0)
102
+ file_size = file_size_value.to_i
103
+
104
+ output = {
105
+ url: ::Addressable::URI.parse(url),
106
+ headers: headers,
107
+ file_size: file_size
108
+ }
109
+
110
+ output[:file_size] = get_file_size(output) if output[:file_size] < 1
111
+ output
112
+ end
113
+
114
+ # Retrieve the file from the file system
115
+ # @param options [Hash]
116
+ def retrieve_file(options)
117
+ file_uri = options.fetch(:url)
118
+ file_size = options.fetch(:file_size)
119
+
120
+ retrieved = 0
121
+ File.open(file_uri.path, 'rb') do |f|
122
+ until f.eof?
123
+ chunk = f.read(chunk_size)
124
+ retrieved += chunk.length
144
125
  yield(chunk, retrieved, file_size)
145
126
  end
146
- request.run
147
127
  end
128
+ end
148
129
 
149
- # Retrieve the file size
150
- # @param options [Hash]
151
- # @return [Integer] the size of the requested file
152
- def get_file_size(options)
153
- url = options.fetch(:url)
154
- headers = options.fetch(:headers)
155
- file_size = options.fetch(:file_size)
156
-
157
- case url.scheme
158
- when 'file'
159
- File.size(url.path)
160
- when /https?/
161
- response = Typhoeus.head(url.to_s, headers: headers)
162
- length_value = response.headers['Content-Length'] || file_size
163
- length_value.to_i
164
- else
165
- raise URI::BadURIError, "Unknown URI scheme: #{url.scheme}"
166
- end
130
+ # Retrieve a resource over the HTTP
131
+ # @param options [Hash]
132
+ def retrieve_http(options)
133
+ file_size = options.fetch(:file_size)
134
+ headers = options.fetch(:headers)
135
+ url = options.fetch(:url)
136
+ retrieved = 0
137
+
138
+ request = Typhoeus::Request.new(url.to_s, method: :get, headers: headers)
139
+ request.on_headers do |response|
140
+ raise DownloadError.new("#{self.class}: Failed to download #{url}: Status Code: #{response.code}", response) unless response.code == 200
167
141
  end
142
+ request.on_body do |chunk|
143
+ retrieved += chunk.bytesize
144
+ yield(chunk, retrieved, file_size)
145
+ end
146
+ request.run
147
+ end
148
+
149
+ # Retrieve the file size
150
+ # @param options [Hash]
151
+ # @return [Integer] the size of the requested file
152
+ def get_file_size(options)
153
+ url = options.fetch(:url)
154
+ headers = options.fetch(:headers)
155
+ file_size = options.fetch(:file_size)
156
+
157
+ case url.scheme
158
+ when 'file'
159
+ File.size(url.path)
160
+ when /https?/
161
+ response = Typhoeus.head(url.to_s, headers: headers)
162
+ length_value = response.headers['Content-Length'] || file_size
163
+ length_value.to_i
164
+ else
165
+ raise URI::BadURIError, "Unknown URI scheme: #{url.scheme}"
166
+ end
167
+ end
168
168
  end
169
169
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BrowseEverything
4
- VERSION = '1.1.0'
4
+ VERSION = '1.2.0'
5
5
  end
@@ -55,7 +55,7 @@ module BrowseEverything
55
55
  begin
56
56
  config_file_content = File.read(value)
57
57
  config_file_template = ERB.new(config_file_content)
58
- config_values = YAML.safe_load(config_file_template.result, [Symbol])
58
+ config_values = YAML.safe_load(config_file_template.result, permitted_classes: [Symbol])
59
59
  @config = ActiveSupport::HashWithIndifferentAccess.new config_values
60
60
  @config.deep_symbolize_keys
61
61
  rescue Errno::ENOENT
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative 'config/application'
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link application.css
3
+ //= link application.js
File without changes
@@ -0,0 +1,25 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+
14
+ // We want to test with turbolinks, which our code also requires rails-ujs to deal with:
15
+
16
+ //= require rails-ujs
17
+ //= require turbolinks
18
+
19
+ // Actual stack required for current browse-everything JS
20
+
21
+ //= require jquery3
22
+ //= require bootstrap
23
+ //= require browse_everything
24
+
25
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ // Action Cable provides the framework to deal with WebSockets in Rails.
2
+ // You can generate new channels where WebSocket features live using the `rails generate channel` command.
3
+ //
4
+ //= require action_cable
5
+ //= require_self
6
+ //= require_tree ./channels
7
+
8
+ (function() {
9
+ this.App || (this.App = {});
10
+
11
+ App.cable = ActionCable.createConsumer();
12
+
13
+ }).call(this);
@@ -0,0 +1,18 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
16
+
17
+ @import "bootstrap";
18
+ @import "browse_everything/browse_everything_bootstrap4";
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Connection < ActionCable::Connection::Base
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery with: :exception
3
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ class ApplicationJob < ActiveJob::Base
2
+ end
@@ -0,0 +1,4 @@
1
+ class ApplicationMailer < ActionMailer::Base
2
+ default from: 'from@example.com'
3
+ layout 'mailer'
4
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationRecord < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ end
File without changes
@@ -0,0 +1,10 @@
1
+ <div class="panel panel-default">
2
+ <div class="panel-body">
3
+ <a href="main" class="btn btn-large btn-primary" role="button">Enter Test App (Turbolinks)</a>
4
+
5
+ <%# this doesn't REALLY test no Turbolinks, as there will still be a `window.Turbolinks` object,
6
+ and a `turbolinks:load` event. It just tests as if the page we are navigating to were the FIRST
7
+ page loaded under turbolinks %>
8
+ <a href="main" class="btn btn-large btn-primary" role="button" data-turbolinks="false" data-no-turbolink>Enter Test App (No Turbolinks)</a>
9
+ </div>
10
+ </div>