carrierwave 2.2.4 → 3.0.4
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.
- checksums.yaml +4 -4
- data/README.md +137 -67
- data/lib/carrierwave/compatibility/paperclip.rb +4 -2
- data/lib/carrierwave/downloader/base.rb +19 -11
- data/lib/carrierwave/downloader/remote_file.rb +12 -9
- data/lib/carrierwave/locale/en.yml +5 -3
- data/lib/carrierwave/mount.rb +36 -50
- data/lib/carrierwave/mounter.rb +117 -50
- data/lib/carrierwave/orm/activerecord.rb +14 -60
- data/lib/carrierwave/processing/mini_magick.rb +15 -13
- data/lib/carrierwave/processing/rmagick.rb +11 -15
- data/lib/carrierwave/processing/vips.rb +12 -12
- data/lib/carrierwave/sanitized_file.rb +49 -77
- data/lib/carrierwave/storage/abstract.rb +5 -5
- data/lib/carrierwave/storage/file.rb +6 -5
- data/lib/carrierwave/storage/fog.rb +74 -66
- data/lib/carrierwave/test/matchers.rb +11 -7
- data/lib/carrierwave/uploader/cache.rb +18 -10
- data/lib/carrierwave/uploader/callbacks.rb +1 -1
- data/lib/carrierwave/uploader/configuration.rb +10 -4
- data/lib/carrierwave/uploader/{content_type_whitelist.rb → content_type_allowlist.rb} +17 -15
- data/lib/carrierwave/uploader/{content_type_blacklist.rb → content_type_denylist.rb} +19 -14
- data/lib/carrierwave/uploader/dimension.rb +66 -0
- data/lib/carrierwave/uploader/{extension_whitelist.rb → extension_allowlist.rb} +17 -15
- data/lib/carrierwave/uploader/{extension_blacklist.rb → extension_denylist.rb} +18 -13
- data/lib/carrierwave/uploader/file_size.rb +2 -2
- data/lib/carrierwave/uploader/processing.rb +31 -6
- data/lib/carrierwave/uploader/proxy.rb +16 -3
- data/lib/carrierwave/uploader/store.rb +44 -6
- data/lib/carrierwave/uploader/url.rb +1 -1
- data/lib/carrierwave/uploader/versions.rb +150 -132
- data/lib/carrierwave/uploader.rb +10 -8
- 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 +4 -6
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +9 -17
- data/lib/generators/uploader_generator.rb +3 -3
- metadata +31 -43
- /data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +0 -0
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'pathname'
|
2
2
|
require 'active_support/core_ext/string/multibyte'
|
3
|
-
require 'mini_mime'
|
4
3
|
require 'marcel'
|
5
4
|
|
6
5
|
module CarrierWave
|
@@ -14,6 +13,7 @@ module CarrierWave
|
|
14
13
|
# It's probably needlessly comprehensive and complex. Help is appreciated.
|
15
14
|
#
|
16
15
|
class SanitizedFile
|
16
|
+
include CarrierWave::Utilities::FileName
|
17
17
|
|
18
18
|
attr_reader :file
|
19
19
|
|
@@ -27,7 +27,7 @@ module CarrierWave
|
|
27
27
|
|
28
28
|
def initialize(file)
|
29
29
|
self.file = file
|
30
|
-
@content = nil
|
30
|
+
@content = @content_type = nil
|
31
31
|
end
|
32
32
|
|
33
33
|
##
|
@@ -39,7 +39,7 @@ module CarrierWave
|
|
39
39
|
#
|
40
40
|
def original_filename
|
41
41
|
return @original_filename if @original_filename
|
42
|
-
if @file
|
42
|
+
if @file && @file.respond_to?(:original_filename)
|
43
43
|
@file.original_filename
|
44
44
|
elsif path
|
45
45
|
File.basename(path)
|
@@ -59,29 +59,6 @@ module CarrierWave
|
|
59
59
|
|
60
60
|
alias_method :identifier, :filename
|
61
61
|
|
62
|
-
##
|
63
|
-
# Returns the part of the filename before the extension. So if a file is called 'test.jpeg'
|
64
|
-
# this would return 'test'
|
65
|
-
#
|
66
|
-
# === Returns
|
67
|
-
#
|
68
|
-
# [String] the first part of the filename
|
69
|
-
#
|
70
|
-
def basename
|
71
|
-
split_extension(filename)[0] if filename
|
72
|
-
end
|
73
|
-
|
74
|
-
##
|
75
|
-
# Returns the file extension
|
76
|
-
#
|
77
|
-
# === Returns
|
78
|
-
#
|
79
|
-
# [String] the extension
|
80
|
-
#
|
81
|
-
def extension
|
82
|
-
split_extension(filename)[1] if filename
|
83
|
-
end
|
84
|
-
|
85
62
|
##
|
86
63
|
# Returns the file's size.
|
87
64
|
#
|
@@ -132,7 +109,7 @@ module CarrierWave
|
|
132
109
|
# [Boolean] whether the file is valid and has a non-zero size
|
133
110
|
#
|
134
111
|
def empty?
|
135
|
-
@file.nil? || self.size.nil? || (self.size.zero? && !
|
112
|
+
@file.nil? || self.size.nil? || (self.size.zero? && !self.exists?)
|
136
113
|
end
|
137
114
|
|
138
115
|
##
|
@@ -151,15 +128,21 @@ module CarrierWave
|
|
151
128
|
#
|
152
129
|
# [String] contents of the file
|
153
130
|
#
|
154
|
-
def read
|
131
|
+
def read(*args)
|
155
132
|
if @content
|
156
|
-
|
133
|
+
if args.empty?
|
134
|
+
@content
|
135
|
+
else
|
136
|
+
length, outbuf = args
|
137
|
+
raise ArgumentError, "outbuf argument not supported since the content is already loaded" if outbuf
|
138
|
+
@content[0, length]
|
139
|
+
end
|
157
140
|
elsif is_path?
|
158
|
-
File.open(@file, "rb") {|file| file.read}
|
141
|
+
File.open(@file, "rb") {|file| file.read(*args)}
|
159
142
|
else
|
160
143
|
@file.try(:rewind)
|
161
|
-
@content = @file.read
|
162
|
-
@file.try(:close) unless @file.try(:closed?)
|
144
|
+
@content = @file.read(*args)
|
145
|
+
@file.try(:close) unless @file.class.ancestors.include?(::StringIO) || @file.try(:closed?)
|
163
146
|
@content
|
164
147
|
end
|
165
148
|
end
|
@@ -180,13 +163,10 @@ module CarrierWave
|
|
180
163
|
mkdir!(new_path, directory_permissions)
|
181
164
|
move!(new_path)
|
182
165
|
chmod!(new_path, permissions)
|
183
|
-
|
184
|
-
self.file = {:tempfile => new_path, :filename => original_filename, :content_type => @content_type}
|
185
|
-
else
|
186
|
-
self.file = {:tempfile => new_path, :content_type => @content_type}
|
187
|
-
end
|
166
|
+
self.file = {tempfile: new_path, filename: keep_filename ? original_filename : nil, content_type: declared_content_type}
|
188
167
|
self
|
189
168
|
end
|
169
|
+
|
190
170
|
##
|
191
171
|
# Helper to move file to new path.
|
192
172
|
#
|
@@ -218,7 +198,7 @@ module CarrierWave
|
|
218
198
|
mkdir!(new_path, directory_permissions)
|
219
199
|
copy!(new_path)
|
220
200
|
chmod!(new_path, permissions)
|
221
|
-
self.class.new({:
|
201
|
+
self.class.new({tempfile: new_path, content_type: declared_content_type})
|
222
202
|
end
|
223
203
|
|
224
204
|
##
|
@@ -260,9 +240,10 @@ module CarrierWave
|
|
260
240
|
#
|
261
241
|
def content_type
|
262
242
|
@content_type ||=
|
263
|
-
|
264
|
-
|
265
|
-
|
243
|
+
identified_content_type ||
|
244
|
+
declared_content_type ||
|
245
|
+
guessed_safe_content_type ||
|
246
|
+
Marcel::MimeType::BINARY
|
266
247
|
end
|
267
248
|
|
268
249
|
##
|
@@ -293,11 +274,11 @@ module CarrierWave
|
|
293
274
|
if file.is_a?(Hash)
|
294
275
|
@file = file["tempfile"] || file[:tempfile]
|
295
276
|
@original_filename = file["filename"] || file[:filename]
|
296
|
-
@
|
277
|
+
@declared_content_type = file["content_type"] || file[:content_type] || file["type"] || file[:type]
|
297
278
|
else
|
298
279
|
@file = file
|
299
280
|
@original_filename = nil
|
300
|
-
@
|
281
|
+
@declared_content_type = nil
|
301
282
|
end
|
302
283
|
end
|
303
284
|
|
@@ -314,57 +295,48 @@ module CarrierWave
|
|
314
295
|
|
315
296
|
# Sanitize the filename, to prevent hacking
|
316
297
|
def sanitize(name)
|
298
|
+
name = name.scrub
|
317
299
|
name = name.tr("\\", "/") # work-around for IE
|
318
300
|
name = File.basename(name)
|
319
|
-
name = name.gsub(sanitize_regexp,"_")
|
301
|
+
name = name.gsub(sanitize_regexp, "_")
|
320
302
|
name = "_#{name}" if name =~ /\A\.+\z/
|
321
303
|
name = "unnamed" if name.size.zero?
|
322
|
-
|
304
|
+
name.mb_chars.to_s
|
323
305
|
end
|
324
306
|
|
325
|
-
def
|
326
|
-
|
327
|
-
@file.content_type.
|
328
|
-
|
307
|
+
def declared_content_type
|
308
|
+
@declared_content_type ||
|
309
|
+
if @file.respond_to?(:content_type) && @file.content_type
|
310
|
+
@file.content_type.to_s.chomp
|
311
|
+
end
|
329
312
|
end
|
330
313
|
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
Marcel::Magic.by_magic(file).try(:type)
|
335
|
-
end
|
314
|
+
# Guess content type from its file extension. Limit what to be returned to prevent spoofing.
|
315
|
+
def guessed_safe_content_type
|
316
|
+
return unless path
|
336
317
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
end
|
318
|
+
type = Marcel::Magic.by_path(original_filename).to_s
|
319
|
+
type if type.start_with?('text/') || type.start_with?('application/json')
|
320
|
+
end
|
341
321
|
|
342
|
-
|
322
|
+
def identified_content_type
|
323
|
+
with_io do |io|
|
324
|
+
Marcel::Magic.by_magic(io).try(:type)
|
343
325
|
end
|
344
326
|
rescue Errno::ENOENT
|
345
327
|
nil
|
346
328
|
end
|
347
329
|
|
348
|
-
def
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
def split_extension(filename)
|
355
|
-
# regular expressions to try for identifying extensions
|
356
|
-
extension_matchers = [
|
357
|
-
/\A(.+)\.(tar\.([glx]?z|bz2))\z/, # matches "something.tar.gz"
|
358
|
-
/\A(.+)\.([^\.]+)\z/ # matches "something.jpg"
|
359
|
-
]
|
360
|
-
|
361
|
-
extension_matchers.each do |regexp|
|
362
|
-
if filename =~ regexp
|
363
|
-
return $1, $2
|
330
|
+
def with_io(&block)
|
331
|
+
if file.is_a?(IO)
|
332
|
+
begin
|
333
|
+
yield file
|
334
|
+
ensure
|
335
|
+
file.try(:rewind)
|
364
336
|
end
|
337
|
+
elsif path
|
338
|
+
File.open(path, &block)
|
365
339
|
end
|
366
|
-
return filename, "" # In case we weren't able to split the extension
|
367
340
|
end
|
368
|
-
|
369
341
|
end # SanitizedFile
|
370
342
|
end # CarrierWave
|
@@ -14,7 +14,7 @@ module CarrierWave
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def identifier
|
17
|
-
uploader.
|
17
|
+
uploader.deduplicated_filename
|
18
18
|
end
|
19
19
|
|
20
20
|
def store!(file)
|
@@ -24,19 +24,19 @@ module CarrierWave
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def cache!(new_file)
|
27
|
-
raise NotImplementedError
|
27
|
+
raise NotImplementedError, "Need to implement #cache! if you want to use #{self.class.name} as a cache storage."
|
28
28
|
end
|
29
29
|
|
30
30
|
def retrieve_from_cache!(identifier)
|
31
|
-
raise NotImplementedError
|
31
|
+
raise NotImplementedError, "Need to implement #retrieve_from_cache! if you want to use #{self.class.name} as a cache storage."
|
32
32
|
end
|
33
33
|
|
34
34
|
def delete_dir!(path)
|
35
|
-
raise NotImplementedError
|
35
|
+
raise NotImplementedError, "Need to implement #delete_dir! if you want to use #{self.class.name} as a cache storage."
|
36
36
|
end
|
37
37
|
|
38
38
|
def clean_cache!(seconds)
|
39
|
-
raise NotImplementedError
|
39
|
+
raise NotImplementedError, "Need to implement #clean_cache! if you want to use #{self.class.name} as a cache storage."
|
40
40
|
end
|
41
41
|
end # Abstract
|
42
42
|
end # Storage
|
@@ -17,7 +17,7 @@ module CarrierWave
|
|
17
17
|
#
|
18
18
|
# By default, store!() uses copy_to(), which operates by copying the file
|
19
19
|
# from the cache to the store, then deleting the file from the cache.
|
20
|
-
# If move_to_store() is
|
20
|
+
# If move_to_store() is overridden to return true, then store!() uses move_to(),
|
21
21
|
# which simply moves the file from cache to store. Useful for large files.
|
22
22
|
#
|
23
23
|
# === Parameters
|
@@ -109,10 +109,11 @@ module CarrierWave
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def clean_cache!(seconds)
|
112
|
-
Dir.glob(::File.expand_path(::File.join(uploader.cache_dir, '*'),
|
113
|
-
# generate_cache_id returns key
|
114
|
-
|
115
|
-
|
112
|
+
Dir.glob(::File.expand_path(::File.join(uploader.cache_dir, '*'), uploader.root)).each do |dir|
|
113
|
+
# generate_cache_id returns key formatted TIMEINT-PID(-COUNTER)-RND
|
114
|
+
matched = dir.scan(/(\d+)-\d+-\d+(?:-\d+)?/).first
|
115
|
+
next unless matched
|
116
|
+
time = Time.at(matched[0].to_i)
|
116
117
|
if time < (Time.now.utc - seconds)
|
117
118
|
FileUtils.rm_rf(dir)
|
118
119
|
end
|
@@ -146,7 +146,7 @@ module CarrierWave
|
|
146
146
|
:key => uploader.fog_directory,
|
147
147
|
:public => uploader.fog_public
|
148
148
|
).files.all(:prefix => uploader.cache_dir).each do |file|
|
149
|
-
# generate_cache_id returns key
|
149
|
+
# generate_cache_id returns key formatted TIMEINT-PID(-COUNTER)-RND
|
150
150
|
matched = file.key.match(/(\d+)-\d+-\d+(?:-\d+)?/)
|
151
151
|
next unless matched
|
152
152
|
time = Time.at(matched[1].to_i)
|
@@ -162,9 +162,10 @@ module CarrierWave
|
|
162
162
|
end
|
163
163
|
|
164
164
|
class File
|
165
|
-
DEFAULT_S3_REGION = 'us-east-1'
|
165
|
+
DEFAULT_S3_REGION = 'us-east-1'.freeze
|
166
166
|
|
167
167
|
include CarrierWave::Utilities::Uri
|
168
|
+
include CarrierWave::Utilities::FileName
|
168
169
|
|
169
170
|
##
|
170
171
|
# Current local path to file
|
@@ -197,27 +198,27 @@ module CarrierWave
|
|
197
198
|
# [NilClass] no authenticated url available
|
198
199
|
#
|
199
200
|
def authenticated_url(options = {})
|
200
|
-
if ['AWS', 'Google', 'Rackspace', 'OpenStack', 'AzureRM', 'Aliyun', 'backblaze'].include?(
|
201
|
+
if ['AWS', 'Google', 'Rackspace', 'OpenStack', 'AzureRM', 'Aliyun', 'backblaze'].include?(fog_provider)
|
201
202
|
# avoid a get by using local references
|
202
203
|
local_directory = connection.directories.new(:key => @uploader.fog_directory)
|
203
204
|
local_file = local_directory.files.new(:key => path)
|
204
205
|
expire_at = options[:expire_at] || ::Fog::Time.now.since(@uploader.fog_authenticated_url_expiration.to_i)
|
205
|
-
case
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
else
|
211
|
-
warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
|
212
|
-
local_file.url(expire_at)
|
213
|
-
end
|
214
|
-
when 'Rackspace', 'OpenStack'
|
215
|
-
connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
|
216
|
-
when 'Aliyun'
|
217
|
-
expire_at = expire_at - Time.now
|
218
|
-
local_file.url(expire_at)
|
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)
|
219
211
|
else
|
212
|
+
warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
|
220
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)
|
221
222
|
end
|
222
223
|
end
|
223
224
|
end
|
@@ -258,18 +259,6 @@ module CarrierWave
|
|
258
259
|
end
|
259
260
|
end
|
260
261
|
|
261
|
-
##
|
262
|
-
# Return extension of file
|
263
|
-
#
|
264
|
-
# === Returns
|
265
|
-
#
|
266
|
-
# [String] extension of file or nil if the file has no extension
|
267
|
-
#
|
268
|
-
def extension
|
269
|
-
path_elements = path.split('.')
|
270
|
-
path_elements.last if path_elements.size > 1
|
271
|
-
end
|
272
|
-
|
273
262
|
##
|
274
263
|
# deprecated: All attributes from file (includes headers)
|
275
264
|
#
|
@@ -296,16 +285,16 @@ module CarrierWave
|
|
296
285
|
#
|
297
286
|
# [String] contents of file
|
298
287
|
def read
|
299
|
-
file_body = file
|
288
|
+
file_body = file&.body
|
300
289
|
|
301
290
|
return if file_body.nil?
|
302
291
|
return file_body unless file_body.is_a?(::File)
|
303
292
|
|
304
|
-
# Fog::Storage::XXX::File#body could return the source file which was
|
305
|
-
read_source_file
|
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)
|
306
295
|
|
307
296
|
# If the source file doesn't exist, the remote content is read
|
308
|
-
@file = nil
|
297
|
+
@file = nil
|
309
298
|
file.body
|
310
299
|
end
|
311
300
|
|
@@ -343,7 +332,7 @@ module CarrierWave
|
|
343
332
|
fog_file = new_file.to_file
|
344
333
|
@content_type ||= new_file.content_type
|
345
334
|
@file = directory.files.create({
|
346
|
-
:body => fog_file
|
335
|
+
:body => fog_file || new_file.read,
|
347
336
|
:content_type => @content_type,
|
348
337
|
:key => path,
|
349
338
|
:public => @uploader.fog_public
|
@@ -364,7 +353,7 @@ module CarrierWave
|
|
364
353
|
#
|
365
354
|
def public_url
|
366
355
|
encoded_path = encode_path(path)
|
367
|
-
if host = @uploader.asset_host
|
356
|
+
if (host = @uploader.asset_host)
|
368
357
|
if host.respond_to? :call
|
369
358
|
"#{host.call(self)}/#{encoded_path}"
|
370
359
|
else
|
@@ -381,21 +370,22 @@ module CarrierWave
|
|
381
370
|
protocol = @uploader.fog_use_ssl_for_aws ? "https" : "http"
|
382
371
|
|
383
372
|
subdomain_regex = /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9\.]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
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}"
|
390
387
|
else # directory is not a valid subdomain, so use path style for access
|
391
|
-
|
392
|
-
host = case region
|
393
|
-
when DEFAULT_S3_REGION, ''
|
394
|
-
's3.amazonaws.com'
|
395
|
-
else
|
396
|
-
"s3.#{region}.amazonaws.com"
|
397
|
-
end
|
398
|
-
"#{protocol}://#{host}/#{@uploader.fog_directory}/#{encoded_path}"
|
388
|
+
"#{protocol}://#{regional_host}/#{@uploader.fog_directory}/#{encoded_path}"
|
399
389
|
end
|
400
390
|
end
|
401
391
|
when 'Google'
|
@@ -409,7 +399,7 @@ module CarrierWave
|
|
409
399
|
end
|
410
400
|
|
411
401
|
##
|
412
|
-
# Return url to file, if
|
402
|
+
# Return url to file, if available
|
413
403
|
#
|
414
404
|
# === Returns
|
415
405
|
#
|
@@ -435,7 +425,7 @@ module CarrierWave
|
|
435
425
|
# [NilClass] no file name available
|
436
426
|
#
|
437
427
|
def filename(options = {})
|
438
|
-
return unless file_url = url(options)
|
428
|
+
return unless (file_url = url(options))
|
439
429
|
CGI.unescape(file_url.split('?').first).gsub(/.*\/(.*?$)/, '\1')
|
440
430
|
end
|
441
431
|
|
@@ -451,10 +441,29 @@ module CarrierWave
|
|
451
441
|
# @return [CarrierWave::Storage::Fog::File] the location where the file will be stored.
|
452
442
|
#
|
453
443
|
def copy_to(new_path)
|
454
|
-
|
444
|
+
file.copy(@uploader.fog_directory, new_path, copy_options)
|
455
445
|
CarrierWave::Storage::Fog::File.new(@uploader, @base, new_path)
|
456
446
|
end
|
457
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
|
+
|
458
467
|
private
|
459
468
|
|
460
469
|
##
|
@@ -476,12 +485,10 @@ module CarrierWave
|
|
476
485
|
# [Fog::#{provider}::Directory] containing directory
|
477
486
|
#
|
478
487
|
def directory
|
479
|
-
@directory ||=
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
)
|
484
|
-
end
|
488
|
+
@directory ||= connection.directories.new(
|
489
|
+
:key => @uploader.fog_directory,
|
490
|
+
:public => @uploader.fog_public
|
491
|
+
)
|
485
492
|
end
|
486
493
|
|
487
494
|
##
|
@@ -498,14 +505,15 @@ module CarrierWave
|
|
498
505
|
def copy_options
|
499
506
|
options = {}
|
500
507
|
options.merge!(acl_header) if acl_header.present?
|
501
|
-
options['Content-Type'] ||= content_type if content_type
|
508
|
+
options[fog_provider == "Google" ? :content_type : 'Content-Type'] ||= content_type if content_type
|
502
509
|
options.merge(@uploader.fog_attributes)
|
503
510
|
end
|
504
511
|
|
505
512
|
def acl_header
|
506
|
-
|
513
|
+
case fog_provider
|
514
|
+
when 'AWS'
|
507
515
|
{ 'x-amz-acl' => @uploader.fog_public ? 'public-read' : 'private' }
|
508
|
-
|
516
|
+
when "Google"
|
509
517
|
@uploader.fog_public ? { destination_predefined_acl: "publicRead" } : {}
|
510
518
|
else
|
511
519
|
{}
|
@@ -516,14 +524,14 @@ module CarrierWave
|
|
516
524
|
@uploader.fog_credentials[:provider].to_s
|
517
525
|
end
|
518
526
|
|
519
|
-
def read_source_file
|
520
|
-
|
527
|
+
def read_source_file
|
528
|
+
source_file = to_file
|
529
|
+
return unless source_file
|
521
530
|
|
522
531
|
begin
|
523
|
-
|
524
|
-
file_body.read
|
532
|
+
source_file.read
|
525
533
|
ensure
|
526
|
-
|
534
|
+
source_file.close
|
527
535
|
end
|
528
536
|
end
|
529
537
|
|
@@ -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
|