carrierwave 1.3.4 → 3.1.4
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/README.md +278 -86
- data/lib/carrierwave/compatibility/paperclip.rb +4 -2
- data/lib/carrierwave/downloader/base.rb +101 -0
- data/lib/carrierwave/downloader/remote_file.rb +68 -0
- data/lib/carrierwave/locale/en.yml +9 -6
- data/lib/carrierwave/mount.rb +53 -61
- data/lib/carrierwave/mounter.rb +169 -77
- data/lib/carrierwave/orm/activerecord.rb +23 -58
- data/lib/carrierwave/processing/mini_magick.rb +137 -123
- data/lib/carrierwave/processing/rmagick.rb +47 -20
- data/lib/carrierwave/processing/vips.rb +315 -0
- data/lib/carrierwave/processing.rb +1 -0
- data/lib/carrierwave/sanitized_file.rb +91 -70
- data/lib/carrierwave/storage/abstract.rb +5 -5
- data/lib/carrierwave/storage/file.rb +6 -5
- data/lib/carrierwave/storage/fog.rb +114 -62
- data/lib/carrierwave/storage.rb +1 -0
- data/lib/carrierwave/test/matchers.rb +11 -7
- data/lib/carrierwave/uploader/cache.rb +40 -24
- data/lib/carrierwave/uploader/callbacks.rb +1 -1
- data/lib/carrierwave/uploader/configuration.rb +43 -20
- data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
- data/lib/carrierwave/uploader/content_type_denylist.rb +65 -0
- data/lib/carrierwave/uploader/dimension.rb +66 -0
- data/lib/carrierwave/uploader/download.rb +2 -123
- data/lib/carrierwave/uploader/extension_allowlist.rb +63 -0
- data/lib/carrierwave/uploader/extension_denylist.rb +64 -0
- data/lib/carrierwave/uploader/file_size.rb +2 -2
- data/lib/carrierwave/uploader/mountable.rb +6 -0
- data/lib/carrierwave/uploader/processing.rb +45 -7
- data/lib/carrierwave/uploader/proxy.rb +17 -4
- data/lib/carrierwave/uploader/serialization.rb +1 -1
- data/lib/carrierwave/uploader/store.rb +73 -7
- data/lib/carrierwave/uploader/url.rb +7 -4
- data/lib/carrierwave/uploader/versions.rb +161 -111
- data/lib/carrierwave/uploader.rb +10 -17
- data/lib/carrierwave/utilities/file_name.rb +47 -0
- data/lib/carrierwave/utilities/uri.rb +14 -11
- data/lib/carrierwave/utilities.rb +1 -0
- data/lib/carrierwave/validations/active_model.rb +7 -9
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +22 -17
- data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +13 -4
- data/lib/generators/uploader_generator.rb +3 -3
- metadata +115 -44
- data/lib/carrierwave/uploader/content_type_blacklist.rb +0 -48
- data/lib/carrierwave/uploader/content_type_whitelist.rb +0 -48
- data/lib/carrierwave/uploader/extension_blacklist.rb +0 -51
- data/lib/carrierwave/uploader/extension_whitelist.rb +0 -52
|
@@ -18,6 +18,8 @@ module CarrierWave
|
|
|
18
18
|
# [:fog_use_ssl_for_aws] (optional) #public_url will use https for the AWS generated URL]
|
|
19
19
|
# [:fog_aws_accelerate] (optional) #public_url will use s3-accelerate subdomain
|
|
20
20
|
# instead of s3, defaults to false
|
|
21
|
+
# [:fog_aws_fips] (optional) #public_url will use s3-fips subdomain
|
|
22
|
+
# instead of s3, defaults to false
|
|
21
23
|
#
|
|
22
24
|
#
|
|
23
25
|
# AWS credentials contain the following keys:
|
|
@@ -30,7 +32,7 @@ module CarrierWave
|
|
|
30
32
|
#
|
|
31
33
|
# Google credentials contain the following keys:
|
|
32
34
|
# [:google_storage_access_key_id]
|
|
33
|
-
# [:
|
|
35
|
+
# [:google_storage_secret_access_key]
|
|
34
36
|
#
|
|
35
37
|
#
|
|
36
38
|
# Local credentials contain the following keys:
|
|
@@ -60,6 +62,14 @@ module CarrierWave
|
|
|
60
62
|
def connection_cache
|
|
61
63
|
@connection_cache ||= {}
|
|
62
64
|
end
|
|
65
|
+
|
|
66
|
+
def eager_load
|
|
67
|
+
# see #1198. This will hopefully no longer be necessary in future release of fog
|
|
68
|
+
fog_credentials = CarrierWave::Uploader::Base.fog_credentials
|
|
69
|
+
if fog_credentials.present?
|
|
70
|
+
CarrierWave::Storage::Fog.connection_cache[fog_credentials] ||= ::Fog::Storage.new(fog_credentials)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
63
73
|
end
|
|
64
74
|
|
|
65
75
|
##
|
|
@@ -138,9 +148,10 @@ module CarrierWave
|
|
|
138
148
|
:key => uploader.fog_directory,
|
|
139
149
|
:public => uploader.fog_public
|
|
140
150
|
).files.all(:prefix => uploader.cache_dir).each do |file|
|
|
141
|
-
# generate_cache_id returns key
|
|
142
|
-
|
|
143
|
-
|
|
151
|
+
# generate_cache_id returns key formatted TIMEINT-PID(-COUNTER)-RND
|
|
152
|
+
matched = file.key.match(/(\d+)-\d+-\d+(?:-\d+)?/)
|
|
153
|
+
next unless matched
|
|
154
|
+
time = Time.at(matched[1].to_i)
|
|
144
155
|
file.destroy if time < (Time.now.utc - seconds)
|
|
145
156
|
end
|
|
146
157
|
end
|
|
@@ -153,7 +164,10 @@ module CarrierWave
|
|
|
153
164
|
end
|
|
154
165
|
|
|
155
166
|
class File
|
|
167
|
+
DEFAULT_S3_REGION = 'us-east-1'.freeze
|
|
168
|
+
|
|
156
169
|
include CarrierWave::Utilities::Uri
|
|
170
|
+
include CarrierWave::Utilities::FileName
|
|
157
171
|
|
|
158
172
|
##
|
|
159
173
|
# Current local path to file
|
|
@@ -177,7 +191,7 @@ module CarrierWave
|
|
|
177
191
|
|
|
178
192
|
##
|
|
179
193
|
# Return a temporary authenticated url to a private file, if available
|
|
180
|
-
# Only supported for AWS, Rackspace, Google and
|
|
194
|
+
# Only supported for AWS, Rackspace, Google, AzureRM and Aliyun providers
|
|
181
195
|
#
|
|
182
196
|
# === Returns
|
|
183
197
|
#
|
|
@@ -186,24 +200,27 @@ module CarrierWave
|
|
|
186
200
|
# [NilClass] no authenticated url available
|
|
187
201
|
#
|
|
188
202
|
def authenticated_url(options = {})
|
|
189
|
-
if ['AWS', 'Google', 'Rackspace', 'OpenStack', 'AzureRM'].include?(
|
|
203
|
+
if ['AWS', 'Google', 'Rackspace', 'OpenStack', 'AzureRM', 'Aliyun', 'backblaze'].include?(fog_provider)
|
|
190
204
|
# avoid a get by using local references
|
|
191
205
|
local_directory = connection.directories.new(:key => @uploader.fog_directory)
|
|
192
206
|
local_file = local_directory.files.new(:key => path)
|
|
193
|
-
expire_at = ::Fog::Time.now
|
|
194
|
-
case
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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', 'OpenStack'
|
|
204
|
-
connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
|
|
207
|
+
expire_at = options[:expire_at] || ::Fog::Time.now.since(@uploader.fog_authenticated_url_expiration.to_i)
|
|
208
|
+
case fog_provider
|
|
209
|
+
when 'AWS', 'Google'
|
|
210
|
+
# Older versions of fog-google do not support options as a parameter
|
|
211
|
+
if url_options_supported?(local_file)
|
|
212
|
+
local_file.url(expire_at, options)
|
|
205
213
|
else
|
|
214
|
+
warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
|
|
206
215
|
local_file.url(expire_at)
|
|
216
|
+
end
|
|
217
|
+
when 'Rackspace', 'OpenStack'
|
|
218
|
+
connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
|
|
219
|
+
when 'Aliyun'
|
|
220
|
+
expire_at -= Time.now
|
|
221
|
+
local_file.url(expire_at)
|
|
222
|
+
else
|
|
223
|
+
local_file.url(expire_at)
|
|
207
224
|
end
|
|
208
225
|
end
|
|
209
226
|
end
|
|
@@ -216,7 +233,7 @@ module CarrierWave
|
|
|
216
233
|
# [String] value of content-type
|
|
217
234
|
#
|
|
218
235
|
def content_type
|
|
219
|
-
@content_type ||
|
|
236
|
+
@content_type || file.try(:content_type)
|
|
220
237
|
end
|
|
221
238
|
|
|
222
239
|
##
|
|
@@ -239,19 +256,9 @@ module CarrierWave
|
|
|
239
256
|
#
|
|
240
257
|
def delete
|
|
241
258
|
# avoid a get by just using local reference
|
|
242
|
-
directory.files.new(:key => path).destroy
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
##
|
|
246
|
-
# Return extension of file
|
|
247
|
-
#
|
|
248
|
-
# === Returns
|
|
249
|
-
#
|
|
250
|
-
# [String] extension of file or nil if the file has no extension
|
|
251
|
-
#
|
|
252
|
-
def extension
|
|
253
|
-
path_elements = path.split('.')
|
|
254
|
-
path_elements.last if path_elements.size > 1
|
|
259
|
+
directory.files.new(:key => path).destroy.tap do |result|
|
|
260
|
+
@file = nil if result
|
|
261
|
+
end
|
|
255
262
|
end
|
|
256
263
|
|
|
257
264
|
##
|
|
@@ -280,16 +287,16 @@ module CarrierWave
|
|
|
280
287
|
#
|
|
281
288
|
# [String] contents of file
|
|
282
289
|
def read
|
|
283
|
-
file_body = file
|
|
290
|
+
file_body = file&.body
|
|
284
291
|
|
|
285
292
|
return if file_body.nil?
|
|
286
293
|
return file_body unless file_body.is_a?(::File)
|
|
287
294
|
|
|
288
|
-
# Fog::Storage::XXX::File#body could return the source file which was
|
|
289
|
-
read_source_file
|
|
295
|
+
# Fog::Storage::XXX::File#body could return the source file which was uploaded to the remote server.
|
|
296
|
+
return read_source_file if ::File.exist?(file_body.path)
|
|
290
297
|
|
|
291
298
|
# If the source file doesn't exist, the remote content is read
|
|
292
|
-
@file = nil
|
|
299
|
+
@file = nil
|
|
293
300
|
file.body
|
|
294
301
|
end
|
|
295
302
|
|
|
@@ -304,6 +311,15 @@ module CarrierWave
|
|
|
304
311
|
file.nil? ? 0 : file.content_length
|
|
305
312
|
end
|
|
306
313
|
|
|
314
|
+
##
|
|
315
|
+
# === Returns
|
|
316
|
+
#
|
|
317
|
+
# [Boolean] whether the file is non-existent or empty
|
|
318
|
+
#
|
|
319
|
+
def empty?
|
|
320
|
+
!exists? || size.zero?
|
|
321
|
+
end
|
|
322
|
+
|
|
307
323
|
##
|
|
308
324
|
# Check if the file exists on the remote service
|
|
309
325
|
#
|
|
@@ -327,7 +343,7 @@ module CarrierWave
|
|
|
327
343
|
fog_file = new_file.to_file
|
|
328
344
|
@content_type ||= new_file.content_type
|
|
329
345
|
@file = directory.files.create({
|
|
330
|
-
:body => fog_file
|
|
346
|
+
:body => fog_file || new_file.read,
|
|
331
347
|
:content_type => @content_type,
|
|
332
348
|
:key => path,
|
|
333
349
|
:public => @uploader.fog_public
|
|
@@ -348,7 +364,7 @@ module CarrierWave
|
|
|
348
364
|
#
|
|
349
365
|
def public_url
|
|
350
366
|
encoded_path = encode_path(path)
|
|
351
|
-
if host = @uploader.asset_host
|
|
367
|
+
if (host = @uploader.asset_host)
|
|
352
368
|
if host.respond_to? :call
|
|
353
369
|
"#{host.call(self)}/#{encoded_path}"
|
|
354
370
|
else
|
|
@@ -360,20 +376,29 @@ module CarrierWave
|
|
|
360
376
|
when 'AWS'
|
|
361
377
|
# check if some endpoint is set in fog_credentials
|
|
362
378
|
if @uploader.fog_credentials.has_key?(:endpoint)
|
|
379
|
+
raise 'fog_aws_fips = true is incompatible with :endpoint, as FIPS endpoints do not support path-style URLs.' if @uploader.fog_aws_fips
|
|
363
380
|
"#{@uploader.fog_credentials[:endpoint]}/#{@uploader.fog_directory}/#{encoded_path}"
|
|
364
381
|
else
|
|
365
382
|
protocol = @uploader.fog_use_ssl_for_aws ? "https" : "http"
|
|
366
383
|
|
|
367
384
|
subdomain_regex = /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9\.]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
"
|
|
385
|
+
# To use the virtual-hosted style, the bucket name needs to be representable as a subdomain
|
|
386
|
+
use_virtual_hosted_style = @uploader.fog_directory.to_s =~ subdomain_regex && !(protocol == 'https' && @uploader.fog_directory =~ /\./)
|
|
387
|
+
|
|
388
|
+
region = @uploader.fog_credentials[:region].to_s
|
|
389
|
+
regional_host = 's3.amazonaws.com' # used for DEFAULT_S3_REGION or no region set
|
|
390
|
+
if @uploader.fog_aws_fips
|
|
391
|
+
regional_host = "s3-fips.#{region}.amazonaws.com" # https://aws.amazon.com/compliance/fips/
|
|
392
|
+
elsif ![DEFAULT_S3_REGION, ''].include?(region)
|
|
393
|
+
regional_host = "s3.#{region}.amazonaws.com"
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
if use_virtual_hosted_style
|
|
397
|
+
regional_host = 's3-accelerate.amazonaws.com' if @uploader.fog_aws_accelerate
|
|
398
|
+
"#{protocol}://#{@uploader.fog_directory}.#{regional_host}/#{encoded_path}"
|
|
399
|
+
else # directory is not a valid subdomain, so use path style for access
|
|
400
|
+
raise 'FIPS Endpoints can only be used with Virtual Hosted-Style addressing.' if @uploader.fog_aws_fips
|
|
401
|
+
"#{protocol}://#{regional_host}/#{@uploader.fog_directory}/#{encoded_path}"
|
|
377
402
|
end
|
|
378
403
|
end
|
|
379
404
|
when 'Google'
|
|
@@ -387,7 +412,7 @@ module CarrierWave
|
|
|
387
412
|
end
|
|
388
413
|
|
|
389
414
|
##
|
|
390
|
-
# Return url to file, if
|
|
415
|
+
# Return url to file, if available
|
|
391
416
|
#
|
|
392
417
|
# === Returns
|
|
393
418
|
#
|
|
@@ -413,7 +438,7 @@ module CarrierWave
|
|
|
413
438
|
# [NilClass] no file name available
|
|
414
439
|
#
|
|
415
440
|
def filename(options = {})
|
|
416
|
-
return unless file_url = url(options)
|
|
441
|
+
return unless (file_url = url(options))
|
|
417
442
|
CGI.unescape(file_url.split('?').first).gsub(/.*\/(.*?$)/, '\1')
|
|
418
443
|
end
|
|
419
444
|
|
|
@@ -429,10 +454,29 @@ module CarrierWave
|
|
|
429
454
|
# @return [CarrierWave::Storage::Fog::File] the location where the file will be stored.
|
|
430
455
|
#
|
|
431
456
|
def copy_to(new_path)
|
|
432
|
-
|
|
457
|
+
file.copy(@uploader.fog_directory, new_path, copy_options)
|
|
433
458
|
CarrierWave::Storage::Fog::File.new(@uploader, @base, new_path)
|
|
434
459
|
end
|
|
435
460
|
|
|
461
|
+
##
|
|
462
|
+
# Return the local file
|
|
463
|
+
#
|
|
464
|
+
# === Returns
|
|
465
|
+
#
|
|
466
|
+
# [File] The local file as Ruby's File class
|
|
467
|
+
# or
|
|
468
|
+
# [NilClass] When there's no file, or the file is remotely stored
|
|
469
|
+
#
|
|
470
|
+
def to_file
|
|
471
|
+
return nil unless file.body.is_a? ::File
|
|
472
|
+
|
|
473
|
+
if file.body.closed?
|
|
474
|
+
::File.open(file.body.path) # Reopen if it's already closed
|
|
475
|
+
else
|
|
476
|
+
file.body
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
|
|
436
480
|
private
|
|
437
481
|
|
|
438
482
|
##
|
|
@@ -454,12 +498,10 @@ module CarrierWave
|
|
|
454
498
|
# [Fog::#{provider}::Directory] containing directory
|
|
455
499
|
#
|
|
456
500
|
def directory
|
|
457
|
-
@directory ||=
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
)
|
|
462
|
-
end
|
|
501
|
+
@directory ||= connection.directories.new(
|
|
502
|
+
:key => @uploader.fog_directory,
|
|
503
|
+
:public => @uploader.fog_public
|
|
504
|
+
)
|
|
463
505
|
end
|
|
464
506
|
|
|
465
507
|
##
|
|
@@ -473,9 +515,19 @@ module CarrierWave
|
|
|
473
515
|
@file ||= directory.files.head(path)
|
|
474
516
|
end
|
|
475
517
|
|
|
518
|
+
def copy_options
|
|
519
|
+
options = {}
|
|
520
|
+
options.merge!(acl_header) if acl_header.present?
|
|
521
|
+
options[fog_provider == "Google" ? :content_type : 'Content-Type'] ||= content_type if content_type
|
|
522
|
+
options.merge(@uploader.fog_attributes)
|
|
523
|
+
end
|
|
524
|
+
|
|
476
525
|
def acl_header
|
|
477
|
-
|
|
526
|
+
case fog_provider
|
|
527
|
+
when 'AWS'
|
|
478
528
|
{ 'x-amz-acl' => @uploader.fog_public ? 'public-read' : 'private' }
|
|
529
|
+
when "Google"
|
|
530
|
+
@uploader.fog_public ? { destination_predefined_acl: "publicRead" } : {}
|
|
479
531
|
else
|
|
480
532
|
{}
|
|
481
533
|
end
|
|
@@ -485,14 +537,14 @@ module CarrierWave
|
|
|
485
537
|
@uploader.fog_credentials[:provider].to_s
|
|
486
538
|
end
|
|
487
539
|
|
|
488
|
-
def read_source_file
|
|
489
|
-
|
|
540
|
+
def read_source_file
|
|
541
|
+
source_file = to_file
|
|
542
|
+
return unless source_file
|
|
490
543
|
|
|
491
544
|
begin
|
|
492
|
-
|
|
493
|
-
file_body.read
|
|
545
|
+
source_file.read
|
|
494
546
|
ensure
|
|
495
|
-
|
|
547
|
+
source_file.close
|
|
496
548
|
end
|
|
497
549
|
end
|
|
498
550
|
|
data/lib/carrierwave/storage.rb
CHANGED
|
@@ -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 &
|
|
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 &
|
|
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
|
|
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 &
|
|
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
|
-
|
|
345
|
-
|
|
346
|
-
|
|
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
|
-
[
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'%04d' %
|
|
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(
|
|
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
|
-
|
|
80
|
+
!!@cache_id
|
|
68
81
|
end
|
|
69
82
|
|
|
70
83
|
##
|
|
@@ -78,15 +91,9 @@ module CarrierWave
|
|
|
78
91
|
end
|
|
79
92
|
|
|
80
93
|
def sanitized_file
|
|
81
|
-
|
|
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
|
+
file
|
|
89
95
|
end
|
|
96
|
+
CarrierWave.deprecator.deprecate_methods(self, sanitized_file: :file)
|
|
90
97
|
|
|
91
98
|
##
|
|
92
99
|
# Returns a String which uniquely identifies the currently cached file for later retrieval
|
|
@@ -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,
|
|
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
|
-
#
|
|
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 =
|
|
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!(
|
|
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=
|
|
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 :
|
|
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
|