carrierwave 1.3.1 → 3.0.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of carrierwave might be problematic. Click here for more details.

Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +238 -91
  3. data/lib/carrierwave/compatibility/paperclip.rb +4 -2
  4. data/lib/carrierwave/downloader/base.rb +101 -0
  5. data/lib/carrierwave/downloader/remote_file.rb +68 -0
  6. data/lib/carrierwave/locale/en.yml +9 -6
  7. data/lib/carrierwave/mount.rb +53 -61
  8. data/lib/carrierwave/mounter.rb +167 -77
  9. data/lib/carrierwave/orm/activerecord.rb +15 -55
  10. data/lib/carrierwave/processing/mini_magick.rb +108 -123
  11. data/lib/carrierwave/processing/rmagick.rb +20 -18
  12. data/lib/carrierwave/processing/vips.rb +284 -0
  13. data/lib/carrierwave/processing.rb +1 -0
  14. data/lib/carrierwave/sanitized_file.rb +66 -73
  15. data/lib/carrierwave/storage/abstract.rb +5 -5
  16. data/lib/carrierwave/storage/file.rb +6 -5
  17. data/lib/carrierwave/storage/fog.rb +101 -64
  18. data/lib/carrierwave/storage.rb +1 -0
  19. data/lib/carrierwave/test/matchers.rb +11 -7
  20. data/lib/carrierwave/uploader/cache.rb +40 -24
  21. data/lib/carrierwave/uploader/callbacks.rb +1 -1
  22. data/lib/carrierwave/uploader/configuration.rb +38 -19
  23. data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
  24. data/lib/carrierwave/uploader/content_type_denylist.rb +62 -0
  25. data/lib/carrierwave/uploader/dimension.rb +66 -0
  26. data/lib/carrierwave/uploader/download.rb +2 -80
  27. data/lib/carrierwave/uploader/extension_allowlist.rb +63 -0
  28. data/lib/carrierwave/uploader/extension_denylist.rb +64 -0
  29. data/lib/carrierwave/uploader/file_size.rb +2 -2
  30. data/lib/carrierwave/uploader/mountable.rb +6 -0
  31. data/lib/carrierwave/uploader/processing.rb +42 -7
  32. data/lib/carrierwave/uploader/proxy.rb +17 -4
  33. data/lib/carrierwave/uploader/serialization.rb +1 -1
  34. data/lib/carrierwave/uploader/store.rb +47 -7
  35. data/lib/carrierwave/uploader/url.rb +7 -4
  36. data/lib/carrierwave/uploader/versions.rb +153 -105
  37. data/lib/carrierwave/uploader.rb +10 -17
  38. data/lib/carrierwave/utilities/file_name.rb +47 -0
  39. data/lib/carrierwave/utilities/uri.rb +14 -11
  40. data/lib/carrierwave/utilities.rb +1 -0
  41. data/lib/carrierwave/validations/active_model.rb +7 -9
  42. data/lib/carrierwave/version.rb +1 -1
  43. data/lib/carrierwave.rb +13 -17
  44. data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +3 -3
  45. data/lib/generators/uploader_generator.rb +3 -3
  46. metadata +104 -38
  47. data/lib/carrierwave/uploader/content_type_blacklist.rb +0 -48
  48. data/lib/carrierwave/uploader/content_type_whitelist.rb +0 -48
  49. data/lib/carrierwave/uploader/extension_blacklist.rb +0 -51
  50. data/lib/carrierwave/uploader/extension_whitelist.rb +0 -52
@@ -30,7 +30,7 @@ module CarrierWave
30
30
  #
31
31
  # Google credentials contain the following keys:
32
32
  # [:google_storage_access_key_id]
33
- # [:google_storage_secrete_access_key]
33
+ # [:google_storage_secret_access_key]
34
34
  #
35
35
  #
36
36
  # Local credentials contain the following keys:
@@ -60,6 +60,14 @@ module CarrierWave
60
60
  def connection_cache
61
61
  @connection_cache ||= {}
62
62
  end
63
+
64
+ def eager_load
65
+ # see #1198. This will hopefully no longer be necessary in future release of fog
66
+ fog_credentials = CarrierWave::Uploader::Base.fog_credentials
67
+ if fog_credentials.present?
68
+ CarrierWave::Storage::Fog.connection_cache[fog_credentials] ||= ::Fog::Storage.new(fog_credentials)
69
+ end
70
+ end
63
71
  end
64
72
 
65
73
  ##
@@ -138,9 +146,10 @@ module CarrierWave
138
146
  :key => uploader.fog_directory,
139
147
  :public => uploader.fog_public
140
148
  ).files.all(:prefix => uploader.cache_dir).each do |file|
141
- # generate_cache_id returns key formated TIMEINT-PID-COUNTER-RND
142
- time = file.key.scan(/(\d+)-\d+-\d+-\d+/).first.map { |t| t.to_i }
143
- time = Time.at(*time)
149
+ # generate_cache_id returns key formatted TIMEINT-PID(-COUNTER)-RND
150
+ matched = file.key.match(/(\d+)-\d+-\d+(?:-\d+)?/)
151
+ next unless matched
152
+ time = Time.at(matched[1].to_i)
144
153
  file.destroy if time < (Time.now.utc - seconds)
145
154
  end
146
155
  end
@@ -153,7 +162,10 @@ module CarrierWave
153
162
  end
154
163
 
155
164
  class File
165
+ DEFAULT_S3_REGION = 'us-east-1'.freeze
166
+
156
167
  include CarrierWave::Utilities::Uri
168
+ include CarrierWave::Utilities::FileName
157
169
 
158
170
  ##
159
171
  # Current local path to file
@@ -177,7 +189,7 @@ module CarrierWave
177
189
 
178
190
  ##
179
191
  # Return a temporary authenticated url to a private file, if available
180
- # Only supported for AWS, Rackspace and Google providers
192
+ # Only supported for AWS, Rackspace, Google, AzureRM and Aliyun providers
181
193
  #
182
194
  # === Returns
183
195
  #
@@ -186,26 +198,27 @@ module CarrierWave
186
198
  # [NilClass] no authenticated url available
187
199
  #
188
200
  def authenticated_url(options = {})
189
- if ['AWS', 'Google', 'Rackspace', 'OpenStack'].include?(@uploader.fog_credentials[:provider])
201
+ if ['AWS', 'Google', 'Rackspace', 'OpenStack', 'AzureRM', 'Aliyun', 'backblaze'].include?(fog_provider)
190
202
  # avoid a get by using local references
191
203
  local_directory = connection.directories.new(:key => @uploader.fog_directory)
192
204
  local_file = local_directory.files.new(:key => path)
193
- expire_at = ::Fog::Time.now + @uploader.fog_authenticated_url_expiration
194
- case @uploader.fog_credentials[:provider]
195
- when 'AWS', 'Google'
196
- # Older versions of fog-google do not support options as a parameter
197
- if url_options_supported?(local_file)
198
- local_file.url(expire_at, options)
199
- else
200
- warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
201
- local_file.url(expire_at)
202
- end
203
- when 'Rackspace'
204
- connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
205
- when 'OpenStack'
206
- connection.get_object_https_url(@uploader.fog_directory, path, expire_at)
205
+ expire_at = options[:expire_at] || ::Fog::Time.now.since(@uploader.fog_authenticated_url_expiration.to_i)
206
+ case fog_provider
207
+ when 'AWS', 'Google'
208
+ # Older versions of fog-google do not support options as a parameter
209
+ if url_options_supported?(local_file)
210
+ local_file.url(expire_at, options)
207
211
  else
212
+ warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
208
213
  local_file.url(expire_at)
214
+ end
215
+ when 'Rackspace', 'OpenStack'
216
+ connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
217
+ when 'Aliyun'
218
+ expire_at -= Time.now
219
+ local_file.url(expire_at)
220
+ else
221
+ local_file.url(expire_at)
209
222
  end
210
223
  end
211
224
  end
@@ -218,7 +231,7 @@ module CarrierWave
218
231
  # [String] value of content-type
219
232
  #
220
233
  def content_type
221
- @content_type || !file.nil? && file.content_type
234
+ @content_type || file.try(:content_type)
222
235
  end
223
236
 
224
237
  ##
@@ -241,19 +254,9 @@ module CarrierWave
241
254
  #
242
255
  def delete
243
256
  # avoid a get by just using local reference
244
- directory.files.new(:key => path).destroy
245
- end
246
-
247
- ##
248
- # Return extension of file
249
- #
250
- # === Returns
251
- #
252
- # [String] extension of file or nil if the file has no extension
253
- #
254
- def extension
255
- path_elements = path.split('.')
256
- path_elements.last if path_elements.size > 1
257
+ directory.files.new(:key => path).destroy.tap do |result|
258
+ @file = nil if result
259
+ end
257
260
  end
258
261
 
259
262
  ##
@@ -282,16 +285,16 @@ module CarrierWave
282
285
  #
283
286
  # [String] contents of file
284
287
  def read
285
- file_body = file.body
288
+ file_body = file&.body
286
289
 
287
290
  return if file_body.nil?
288
291
  return file_body unless file_body.is_a?(::File)
289
292
 
290
- # Fog::Storage::XXX::File#body could return the source file which was upoloaded to the remote server.
291
- read_source_file(file_body) if ::File.exist?(file_body.path)
293
+ # Fog::Storage::XXX::File#body could return the source file which was uploaded to the remote server.
294
+ return read_source_file if ::File.exist?(file_body.path)
292
295
 
293
296
  # If the source file doesn't exist, the remote content is read
294
- @file = nil # rubocop:disable Gitlab/ModuleWithInstanceVariables
297
+ @file = nil
295
298
  file.body
296
299
  end
297
300
 
@@ -329,7 +332,7 @@ module CarrierWave
329
332
  fog_file = new_file.to_file
330
333
  @content_type ||= new_file.content_type
331
334
  @file = directory.files.create({
332
- :body => fog_file ? fog_file : new_file.read,
335
+ :body => fog_file || new_file.read,
333
336
  :content_type => @content_type,
334
337
  :key => path,
335
338
  :public => @uploader.fog_public
@@ -350,7 +353,7 @@ module CarrierWave
350
353
  #
351
354
  def public_url
352
355
  encoded_path = encode_path(path)
353
- if host = @uploader.asset_host
356
+ if (host = @uploader.asset_host)
354
357
  if host.respond_to? :call
355
358
  "#{host.call(self)}/#{encoded_path}"
356
359
  else
@@ -367,15 +370,22 @@ module CarrierWave
367
370
  protocol = @uploader.fog_use_ssl_for_aws ? "https" : "http"
368
371
 
369
372
  subdomain_regex = /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9\.]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
370
- valid_subdomain = @uploader.fog_directory.to_s =~ subdomain_regex && !(protocol == 'https' && @uploader.fog_directory =~ /\./)
371
-
372
- # if directory is a valid subdomain, use that style for access
373
- if valid_subdomain
374
- s3_subdomain = @uploader.fog_aws_accelerate ? "s3-accelerate" : "s3"
375
- "#{protocol}://#{@uploader.fog_directory}.#{s3_subdomain}.amazonaws.com/#{encoded_path}"
376
- else
377
- # directory is not a valid subdomain, so use path style for access
378
- "#{protocol}://s3.amazonaws.com/#{@uploader.fog_directory}/#{encoded_path}"
373
+ # To use the virtual-hosted style, the bucket name needs to be representable as a subdomain
374
+ use_virtual_hosted_style = @uploader.fog_directory.to_s =~ subdomain_regex && !(protocol == 'https' && @uploader.fog_directory =~ /\./)
375
+
376
+ region = @uploader.fog_credentials[:region].to_s
377
+ regional_host = case region
378
+ when DEFAULT_S3_REGION, ''
379
+ 's3.amazonaws.com'
380
+ else
381
+ "s3.#{region}.amazonaws.com"
382
+ end
383
+
384
+ if use_virtual_hosted_style
385
+ regional_host = 's3-accelerate.amazonaws.com' if @uploader.fog_aws_accelerate
386
+ "#{protocol}://#{@uploader.fog_directory}.#{regional_host}/#{encoded_path}"
387
+ else # directory is not a valid subdomain, so use path style for access
388
+ "#{protocol}://#{regional_host}/#{@uploader.fog_directory}/#{encoded_path}"
379
389
  end
380
390
  end
381
391
  when 'Google'
@@ -389,7 +399,7 @@ module CarrierWave
389
399
  end
390
400
 
391
401
  ##
392
- # Return url to file, if avaliable
402
+ # Return url to file, if available
393
403
  #
394
404
  # === Returns
395
405
  #
@@ -415,7 +425,7 @@ module CarrierWave
415
425
  # [NilClass] no file name available
416
426
  #
417
427
  def filename(options = {})
418
- return unless file_url = url(options)
428
+ return unless (file_url = url(options))
419
429
  CGI.unescape(file_url.split('?').first).gsub(/.*\/(.*?$)/, '\1')
420
430
  end
421
431
 
@@ -431,10 +441,29 @@ module CarrierWave
431
441
  # @return [CarrierWave::Storage::Fog::File] the location where the file will be stored.
432
442
  #
433
443
  def copy_to(new_path)
434
- connection.copy_object(@uploader.fog_directory, file.key, @uploader.fog_directory, new_path, acl_header)
444
+ file.copy(@uploader.fog_directory, new_path, copy_options)
435
445
  CarrierWave::Storage::Fog::File.new(@uploader, @base, new_path)
436
446
  end
437
447
 
448
+ ##
449
+ # Return the local file
450
+ #
451
+ # === Returns
452
+ #
453
+ # [File] The local file as Ruby's File class
454
+ # or
455
+ # [NilClass] When there's no file, or the file is remotely stored
456
+ #
457
+ def to_file
458
+ return nil unless file.body.is_a? ::File
459
+
460
+ if file.body.closed?
461
+ ::File.open(file.body.path) # Reopen if it's already closed
462
+ else
463
+ file.body
464
+ end
465
+ end
466
+
438
467
  private
439
468
 
440
469
  ##
@@ -456,12 +485,10 @@ module CarrierWave
456
485
  # [Fog::#{provider}::Directory] containing directory
457
486
  #
458
487
  def directory
459
- @directory ||= begin
460
- connection.directories.new(
461
- :key => @uploader.fog_directory,
462
- :public => @uploader.fog_public
463
- )
464
- end
488
+ @directory ||= connection.directories.new(
489
+ :key => @uploader.fog_directory,
490
+ :public => @uploader.fog_public
491
+ )
465
492
  end
466
493
 
467
494
  ##
@@ -475,9 +502,19 @@ module CarrierWave
475
502
  @file ||= directory.files.head(path)
476
503
  end
477
504
 
505
+ def copy_options
506
+ options = {}
507
+ options.merge!(acl_header) if acl_header.present?
508
+ options[fog_provider == "Google" ? :content_type : 'Content-Type'] ||= content_type if content_type
509
+ options.merge(@uploader.fog_attributes)
510
+ end
511
+
478
512
  def acl_header
479
- if fog_provider == 'AWS'
513
+ case fog_provider
514
+ when 'AWS'
480
515
  { 'x-amz-acl' => @uploader.fog_public ? 'public-read' : 'private' }
516
+ when "Google"
517
+ @uploader.fog_public ? { destination_predefined_acl: "publicRead" } : {}
481
518
  else
482
519
  {}
483
520
  end
@@ -487,14 +524,14 @@ module CarrierWave
487
524
  @uploader.fog_credentials[:provider].to_s
488
525
  end
489
526
 
490
- def read_source_file(file_body)
491
- return unless ::File.exist?(file_body.path)
527
+ def read_source_file
528
+ source_file = to_file
529
+ return unless source_file
492
530
 
493
531
  begin
494
- file_body = ::File.open(file_body.path) if file_body.closed? # Reopen if it's already closed
495
- file_body.read
532
+ source_file.read
496
533
  ensure
497
- file_body.close
534
+ source_file.close
498
535
  end
499
536
  end
500
537
 
@@ -1,2 +1,3 @@
1
1
  require "carrierwave/storage/abstract"
2
2
  require "carrierwave/storage/file"
3
+ require "carrierwave/storage/fog"
@@ -45,11 +45,11 @@ module CarrierWave
45
45
  def matches?(actual)
46
46
  @actual = actual
47
47
  # Satisfy expectation here. Return false or raise an error if it's not met.
48
- (File.stat(@actual.path).mode & 0777) == @expected
48
+ (File.stat(@actual.path).mode & 0o777) == @expected
49
49
  end
50
50
 
51
51
  def failure_message
52
- "expected #{@actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0777).to_s(8)}"
52
+ "expected #{@actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0o777).to_s(8)}"
53
53
  end
54
54
 
55
55
  def failure_message_when_negated
@@ -76,11 +76,11 @@ module CarrierWave
76
76
  def matches?(actual)
77
77
  @actual = actual
78
78
  # Satisfy expectation here. Return false or raise an error if it's not met.
79
- (File.stat(File.dirname @actual.path).mode & 0777) == @expected
79
+ (File.stat(File.dirname(@actual.path)).mode & 0o777) == @expected
80
80
  end
81
81
 
82
82
  def failure_message
83
- "expected #{File.dirname @actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0777).to_s(8)}"
83
+ "expected #{File.dirname @actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0o777).to_s(8)}"
84
84
  end
85
85
 
86
86
  def failure_message_when_negated
@@ -341,9 +341,11 @@ module CarrierWave
341
341
  begin
342
342
  require 'rmagick'
343
343
  rescue LoadError
344
- require 'RMagick'
345
- rescue LoadError
346
- puts "WARNING: Failed to require rmagick, image processing may fail!"
344
+ begin
345
+ require 'RMagick'
346
+ rescue LoadError
347
+ puts "WARNING: Failed to require rmagick, image processing may fail!"
348
+ end
347
349
  end
348
350
  end
349
351
  MagickWrapper.new(filename)
@@ -353,6 +355,7 @@ module CarrierWave
353
355
 
354
356
  class MagickWrapper # :nodoc:
355
357
  attr_reader :image
358
+
356
359
  def width
357
360
  image.columns
358
361
  end
@@ -372,6 +375,7 @@ module CarrierWave
372
375
 
373
376
  class MiniMagickWrapper # :nodoc:
374
377
  attr_reader :image
378
+
375
379
  def width
376
380
  image[:width]
377
381
  end
@@ -1,3 +1,5 @@
1
+ require 'securerandom'
2
+
1
3
  module CarrierWave
2
4
 
3
5
  class FormNotMultipart < UploadError
@@ -22,10 +24,11 @@ module CarrierWave
22
24
  # [String] a cache id in the format TIMEINT-PID-COUNTER-RND
23
25
  #
24
26
  def self.generate_cache_id
25
- [Time.now.utc.to_i,
26
- Process.pid,
27
- '%04d' % (CarrierWave::CacheCounter.increment % 1000),
28
- '%04d' % rand(9999)
27
+ [
28
+ Time.now.utc.to_i,
29
+ SecureRandom.random_number(1_000_000_000_000_000),
30
+ '%04d' % (CarrierWave::CacheCounter.increment % 10_000),
31
+ '%04d' % SecureRandom.random_number(10_000)
29
32
  ].map(&:to_s).join('-')
30
33
  end
31
34
 
@@ -36,6 +39,16 @@ module CarrierWave
36
39
  include CarrierWave::Uploader::Callbacks
37
40
  include CarrierWave::Uploader::Configuration
38
41
 
42
+ included do
43
+ prepend Module.new {
44
+ def initialize(*)
45
+ super
46
+ @staged = false
47
+ end
48
+ }
49
+ attr_accessor :staged
50
+ end
51
+
39
52
  module ClassMethods
40
53
 
41
54
  ##
@@ -52,7 +65,7 @@ module CarrierWave
52
65
  # It's recommended that you keep cache files in one place only.
53
66
  #
54
67
  def clean_cached_files!(seconds=60*60*24)
55
- cache_storage.new(CarrierWave::Uploader::Base.new).clean_cache!(seconds)
68
+ (cache_storage || storage).new(new).clean_cache!(seconds)
56
69
  end
57
70
  end
58
71
 
@@ -64,7 +77,7 @@ module CarrierWave
64
77
  # [Bool] whether the current file is cached
65
78
  #
66
79
  def cached?
67
- @cache_id
80
+ !!@cache_id
68
81
  end
69
82
 
70
83
  ##
@@ -78,14 +91,8 @@ module CarrierWave
78
91
  end
79
92
 
80
93
  def sanitized_file
81
- _content = file.read
82
- if _content.is_a?(File) # could be if storage is Fog
83
- sanitized = CarrierWave::Storage::Fog.new(self).retrieve!(File.basename(_content.path))
84
- else
85
- sanitized = SanitizedFile.new :tempfile => StringIO.new(_content),
86
- :filename => File.basename(path), :content_type => file.content_type
87
- end
88
- sanitized
94
+ ActiveSupport::Deprecation.warn('#sanitized_file is deprecated, use #file instead.')
95
+ file
89
96
  end
90
97
 
91
98
  ##
@@ -96,7 +103,7 @@ module CarrierWave
96
103
  # [String] a cache name, in the format TIMEINT-PID-COUNTER-RND/filename.txt
97
104
  #
98
105
  def cache_name
99
- File.join(cache_id, full_original_filename) if cache_id and original_filename
106
+ File.join(cache_id, original_filename) if cache_id && original_filename
100
107
  end
101
108
 
102
109
  ##
@@ -104,7 +111,7 @@ module CarrierWave
104
111
  #
105
112
  # By default, cache!() uses copy_to(), which operates by copying the file
106
113
  # to the cache, then deleting the original file. If move_to_cache() is
107
- # overriden to return true, then cache!() uses move_to(), which simply
114
+ # overridden to return true, then cache!() uses move_to(), which simply
108
115
  # moves the file to the cache. Useful for large files.
109
116
  #
110
117
  # === Parameters
@@ -115,7 +122,7 @@ module CarrierWave
115
122
  #
116
123
  # [CarrierWave::FormNotMultipart] if the assigned parameter is a string
117
124
  #
118
- def cache!(new_file = sanitized_file)
125
+ def cache!(new_file = file)
119
126
  new_file = CarrierWave::SanitizedFile.new(new_file)
120
127
  return if new_file.empty?
121
128
 
@@ -123,6 +130,8 @@ module CarrierWave
123
130
 
124
131
  self.cache_id = CarrierWave.generate_cache_id unless cache_id
125
132
 
133
+ @identifier = nil
134
+ @staged = true
126
135
  @filename = new_file.filename
127
136
  self.original_filename = new_file.filename
128
137
 
@@ -156,8 +165,9 @@ module CarrierWave
156
165
  def retrieve_from_cache!(cache_name)
157
166
  with_callbacks(:retrieve_from_cache, cache_name) do
158
167
  self.cache_id, self.original_filename = cache_name.to_s.split('/', 2)
168
+ @staged = true
159
169
  @filename = original_filename
160
- @file = cache_storage.retrieve_from_cache!(full_filename(original_filename))
170
+ @file = cache_storage.retrieve_from_cache!(full_original_filename)
161
171
  end
162
172
  end
163
173
 
@@ -172,20 +182,21 @@ module CarrierWave
172
182
  #
173
183
  # [String] the cache path
174
184
  #
175
- def cache_path(for_file=full_filename(original_filename))
185
+ def cache_path(for_file=full_original_filename)
176
186
  File.join(*[cache_dir, @cache_id, for_file].compact)
177
187
  end
178
188
 
189
+ protected
190
+
191
+ attr_reader :cache_id
192
+
179
193
  private
180
194
 
181
195
  def workfile_path(for_file=original_filename)
182
196
  File.join(CarrierWave.tmp_path, @cache_id, version_name.to_s, for_file)
183
197
  end
184
198
 
185
- attr_reader :cache_id, :original_filename
186
-
187
- # We can override the full_original_filename method in other modules
188
- alias_method :full_original_filename, :original_filename
199
+ attr_reader :original_filename
189
200
 
190
201
  def cache_id=(cache_id)
191
202
  # Earlier version used 3 part cache_id. Thus we should allow for
@@ -200,7 +211,12 @@ module CarrierWave
200
211
  end
201
212
 
202
213
  def cache_storage
203
- @cache_storage ||= self.class.cache_storage.new(self)
214
+ @cache_storage ||= (self.class.cache_storage || self.class.storage).new(self)
215
+ end
216
+
217
+ # We can override the full_original_filename method in other modules
218
+ def full_original_filename
219
+ forcing_extension(original_filename)
204
220
  end
205
221
  end # Cache
206
222
  end # Uploader
@@ -5,7 +5,7 @@ module CarrierWave
5
5
 
6
6
  included do
7
7
  class_attribute :_before_callbacks, :_after_callbacks,
8
- :instance_writer => false
8
+ :instance_writer => false
9
9
  self._before_callbacks = Hash.new []
10
10
  self._after_callbacks = Hash.new []
11
11
  end
@@ -1,3 +1,5 @@
1
+ require 'carrierwave/downloader/base'
2
+
1
3
  module CarrierWave
2
4
 
3
5
  module Uploader
@@ -21,9 +23,11 @@ module CarrierWave
21
23
  add_config :move_to_cache
22
24
  add_config :move_to_store
23
25
  add_config :remove_previously_stored_files_after_update
26
+ add_config :downloader
27
+ add_config :force_extension
24
28
 
25
29
  # fog
26
- add_config :fog_provider
30
+ add_deprecated_config :fog_provider
27
31
  add_config :fog_attributes
28
32
  add_config :fog_credentials
29
33
  add_config :fog_directory
@@ -41,6 +45,8 @@ module CarrierWave
41
45
  add_config :validate_download
42
46
  add_config :mount_on
43
47
  add_config :cache_only
48
+ add_config :download_retry_count
49
+ add_config :download_retry_wait_time
44
50
 
45
51
  # set default values
46
52
  reset_config
@@ -74,7 +80,7 @@ module CarrierWave
74
80
  def storage(storage = nil)
75
81
  case storage
76
82
  when Symbol
77
- if storage_engine = storage_engines[storage]
83
+ if (storage_engine = storage_engines[storage])
78
84
  self._storage = eval storage_engine
79
85
  else
80
86
  raise CarrierWave::UnknownStorageError, "Unknown storage: #{storage}"
@@ -107,8 +113,8 @@ module CarrierWave
107
113
  # cache_storage CarrierWave::Storage::File
108
114
  # cache_storage MyCustomStorageEngine
109
115
  #
110
- def cache_storage(storage = nil)
111
- if storage
116
+ def cache_storage(storage = false)
117
+ unless storage == false
112
118
  self._cache_storage = storage.is_a?(Symbol) ? eval(storage_engines[storage]) : storage
113
119
  end
114
120
  _cache_storage
@@ -119,16 +125,8 @@ module CarrierWave
119
125
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
120
126
  @#{name} = nil
121
127
 
122
- def self.eager_load_fog(fog_credentials)
123
- # see #1198. This will hopefully no longer be necessary after fog 2.0
124
- require self.fog_provider
125
- require 'carrierwave/storage/fog'
126
- Fog::Storage.new(fog_credentials) if fog_credentials.present?
127
- end unless defined? eager_load_fog
128
-
129
128
  def self.#{name}(value=nil)
130
- @#{name} = value if value
131
- eager_load_fog(value) if value && '#{name}' == 'fog_credentials'
129
+ @#{name} = value unless value.nil?
132
130
  return @#{name} if self.object_id == #{self.object_id} || defined?(@#{name})
133
131
  name = superclass.#{name}
134
132
  return nil if name.nil? && !instance_variable_defined?(:@#{name})
@@ -136,12 +134,10 @@ module CarrierWave
136
134
  end
137
135
 
138
136
  def self.#{name}=(value)
139
- eager_load_fog(value) if '#{name}' == 'fog_credentials' && value.present?
140
137
  @#{name} = value
141
138
  end
142
139
 
143
140
  def #{name}=(value)
144
- self.class.eager_load_fog(value) if '#{name}' == 'fog_credentials' && value.present?
145
141
  @#{name} = value
146
142
  end
147
143
 
@@ -157,6 +153,26 @@ module CarrierWave
157
153
  RUBY
158
154
  end
159
155
 
156
+ def add_deprecated_config(name)
157
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
158
+ def self.#{name}(value=nil)
159
+ ActiveSupport::Deprecation.warn "##{name} is deprecated and has no effect"
160
+ end
161
+
162
+ def self.#{name}=(value)
163
+ ActiveSupport::Deprecation.warn "##{name} is deprecated and has no effect"
164
+ end
165
+
166
+ def #{name}=(value)
167
+ ActiveSupport::Deprecation.warn "##{name} is deprecated and has no effect"
168
+ end
169
+
170
+ def #{name}
171
+ ActiveSupport::Deprecation.warn "##{name} is deprecated and has no effect"
172
+ end
173
+ RUBY
174
+ end
175
+
160
176
  def configure
161
177
  yield self
162
178
  end
@@ -166,15 +182,14 @@ module CarrierWave
166
182
  #
167
183
  def reset_config
168
184
  configure do |config|
169
- config.permissions = 0644
170
- config.directory_permissions = 0755
185
+ config.permissions = 0o644
186
+ config.directory_permissions = 0o755
171
187
  config.storage_engines = {
172
188
  :file => "CarrierWave::Storage::File",
173
189
  :fog => "CarrierWave::Storage::Fog"
174
190
  }
175
191
  config.storage = :file
176
- config.cache_storage = :file
177
- config.fog_provider = 'fog'
192
+ config.cache_storage = nil
178
193
  config.fog_attributes = {}
179
194
  config.fog_credentials = {}
180
195
  config.fog_public = true
@@ -187,6 +202,8 @@ module CarrierWave
187
202
  config.move_to_cache = false
188
203
  config.move_to_store = false
189
204
  config.remove_previously_stored_files_after_update = true
205
+ config.downloader = CarrierWave::Downloader::Base
206
+ config.force_extension = false
190
207
  config.ignore_integrity_errors = true
191
208
  config.ignore_processing_errors = true
192
209
  config.ignore_download_errors = true
@@ -197,6 +214,8 @@ module CarrierWave
197
214
  config.base_path = CarrierWave.base_path
198
215
  config.enable_processing = true
199
216
  config.ensure_multipart_form = true
217
+ config.download_retry_count = 0
218
+ config.download_retry_wait_time = 5
200
219
  end
201
220
  end
202
221
  end