carrierwave 0.9.0 → 3.0.2
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 +7 -0
- data/README.md +508 -158
- data/lib/carrierwave/compatibility/paperclip.rb +31 -21
- data/lib/carrierwave/downloader/base.rb +101 -0
- data/lib/carrierwave/downloader/remote_file.rb +68 -0
- data/lib/carrierwave/error.rb +1 -0
- data/lib/carrierwave/locale/en.yml +11 -5
- data/lib/carrierwave/mount.rb +220 -187
- data/lib/carrierwave/mounter.rb +255 -0
- data/lib/carrierwave/orm/activerecord.rb +24 -34
- data/lib/carrierwave/processing/mini_magick.rb +142 -79
- data/lib/carrierwave/processing/rmagick.rb +76 -35
- data/lib/carrierwave/processing/vips.rb +284 -0
- data/lib/carrierwave/processing.rb +1 -1
- data/lib/carrierwave/sanitized_file.rb +89 -70
- data/lib/carrierwave/storage/abstract.rb +16 -3
- data/lib/carrierwave/storage/file.rb +71 -3
- data/lib/carrierwave/storage/fog.rb +215 -58
- data/lib/carrierwave/storage.rb +1 -7
- data/lib/carrierwave/test/matchers.rb +88 -19
- data/lib/carrierwave/uploader/cache.rb +88 -44
- data/lib/carrierwave/uploader/callbacks.rb +1 -3
- data/lib/carrierwave/uploader/configuration.rb +81 -9
- data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
- data/lib/carrierwave/uploader/content_type_denylist.rb +62 -0
- data/lib/carrierwave/uploader/default_url.rb +3 -5
- data/lib/carrierwave/uploader/dimension.rb +66 -0
- data/lib/carrierwave/uploader/download.rb +5 -69
- 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 +43 -0
- data/lib/carrierwave/uploader/mountable.rb +13 -8
- data/lib/carrierwave/uploader/processing.rb +54 -21
- data/lib/carrierwave/uploader/proxy.rb +30 -8
- data/lib/carrierwave/uploader/remove.rb +0 -2
- data/lib/carrierwave/uploader/serialization.rb +3 -5
- data/lib/carrierwave/uploader/store.rb +59 -28
- data/lib/carrierwave/uploader/url.rb +8 -7
- data/lib/carrierwave/uploader/versions.rb +173 -124
- data/lib/carrierwave/uploader.rb +12 -6
- data/lib/carrierwave/utilities/file_name.rb +47 -0
- data/lib/carrierwave/utilities/uri.rb +14 -12
- data/lib/carrierwave/utilities.rb +2 -3
- data/lib/carrierwave/validations/active_model.rb +7 -13
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +41 -16
- data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +5 -9
- data/lib/generators/uploader_generator.rb +3 -3
- metadata +224 -100
- data/lib/carrierwave/locale/cs.yml +0 -11
- data/lib/carrierwave/locale/de.yml +0 -11
- data/lib/carrierwave/locale/nl.yml +0 -11
- data/lib/carrierwave/locale/sk.yml +0 -11
- data/lib/carrierwave/processing/mime_types.rb +0 -73
- data/lib/carrierwave/uploader/extension_blacklist.rb +0 -47
- data/lib/carrierwave/uploader/extension_whitelist.rb +0 -49
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module CarrierWave
|
4
2
|
module Uploader
|
5
3
|
module Mountable
|
@@ -7,13 +5,14 @@ module CarrierWave
|
|
7
5
|
attr_reader :model, :mounted_as
|
8
6
|
|
9
7
|
##
|
10
|
-
# If a model is given as the first parameter, it will be stored in the
|
11
|
-
# available
|
12
|
-
# where this instance of the uploader is mounted.
|
13
|
-
# your uploader.
|
8
|
+
# If a model is given as the first parameter, it will be stored in the
|
9
|
+
# uploader, and available through +#model+. Likewise, mounted_as stores
|
10
|
+
# the name of the column where this instance of the uploader is mounted.
|
11
|
+
# These values can then be used inside your uploader.
|
14
12
|
#
|
15
|
-
# If you do not wish to mount your uploaders with the ORM extensions in
|
16
|
-
# can override this method inside your uploader. Just be
|
13
|
+
# If you do not wish to mount your uploaders with the ORM extensions in
|
14
|
+
# -more then you can override this method inside your uploader. Just be
|
15
|
+
# sure to call +super+
|
17
16
|
#
|
18
17
|
# === Parameters
|
19
18
|
#
|
@@ -34,6 +33,12 @@ module CarrierWave
|
|
34
33
|
@mounted_as = mounted_as
|
35
34
|
end
|
36
35
|
|
36
|
+
##
|
37
|
+
# Returns array index of given uploader within currently mounted uploaders
|
38
|
+
#
|
39
|
+
def index
|
40
|
+
model.__send__(:_mounter, mounted_as).uploaders.index(self)
|
41
|
+
end
|
37
42
|
end # Mountable
|
38
43
|
end # Uploader
|
39
44
|
end # CarrierWave
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module CarrierWave
|
4
2
|
module Uploader
|
5
3
|
module Processing
|
@@ -11,7 +9,7 @@ module CarrierWave
|
|
11
9
|
class_attribute :processors, :instance_writer => false
|
12
10
|
self.processors = []
|
13
11
|
|
14
|
-
|
12
|
+
before :cache, :process!
|
15
13
|
end
|
16
14
|
|
17
15
|
module ClassMethods
|
@@ -20,7 +18,7 @@ module CarrierWave
|
|
20
18
|
# Adds a processor callback which applies operations as a file is uploaded.
|
21
19
|
# The argument may be the name of any method of the uploader, expressed as a symbol,
|
22
20
|
# or a list of such methods, or a hash where the key is a method and the value is
|
23
|
-
# an array of arguments to call the method with
|
21
|
+
# an array of arguments to call the method with. Also accepts an :if or :unless condition
|
24
22
|
#
|
25
23
|
# === Parameters
|
26
24
|
#
|
@@ -33,6 +31,7 @@ module CarrierWave
|
|
33
31
|
# process :sepiatone, :vignette
|
34
32
|
# process :scale => [200, 200]
|
35
33
|
# process :scale => [200, 200], :if => :image?
|
34
|
+
# process :scale => [200, 200], :unless => :disallowed_image_type?
|
36
35
|
# process :sepiatone, :if => :image?
|
37
36
|
#
|
38
37
|
# def sepiatone
|
@@ -51,42 +50,76 @@ module CarrierWave
|
|
51
50
|
# ...
|
52
51
|
# end
|
53
52
|
#
|
53
|
+
# def disallowed_image_type?
|
54
|
+
# ...
|
55
|
+
# end
|
56
|
+
#
|
54
57
|
# end
|
55
58
|
#
|
56
59
|
def process(*args)
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
+
new_processors = args.inject({}) do |hash, arg|
|
61
|
+
arg = { arg => [] } unless arg.is_a?(Hash)
|
62
|
+
hash.merge!(arg)
|
60
63
|
end
|
61
64
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
condition_type = new_processors.keys.detect { |key| [:if, :unless].include?(key) }
|
66
|
+
condition = new_processors.delete(:if) || new_processors.delete(:unless)
|
67
|
+
new_processors.each do |processor, processor_args|
|
68
|
+
self.processors += [[processor, processor_args, condition, condition_type]]
|
69
|
+
|
70
|
+
if processor == :convert
|
71
|
+
# Treat :convert specially, since it should trigger the file extension change
|
72
|
+
force_extension processor_args
|
70
73
|
end
|
71
74
|
end
|
72
75
|
end
|
73
|
-
|
74
76
|
end # ClassMethods
|
75
77
|
|
76
78
|
##
|
77
79
|
# Apply all process callbacks added through CarrierWave.process
|
78
80
|
#
|
79
81
|
def process!(new_file=nil)
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
82
|
+
return unless enable_processing
|
83
|
+
|
84
|
+
with_callbacks(:process, new_file) do
|
85
|
+
self.class.processors.each do |method, args, condition, condition_type|
|
86
|
+
if condition && condition_type == :if
|
87
|
+
if condition.respond_to?(:call)
|
88
|
+
next unless condition.call(self, :args => args, :method => method, :file => new_file)
|
89
|
+
else
|
90
|
+
next unless self.send(condition, new_file)
|
91
|
+
end
|
92
|
+
elsif condition && condition_type == :unless
|
93
|
+
if condition.respond_to?(:call)
|
94
|
+
next if condition.call(self, :args => args, :method => method, :file => new_file)
|
95
|
+
elsif self.send(condition, new_file)
|
96
|
+
next
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
if args.is_a? Array
|
101
|
+
kwargs, args = args.partition { |arg| arg.is_a? Hash }
|
102
|
+
end
|
103
|
+
|
104
|
+
if kwargs.present?
|
105
|
+
kwargs = kwargs.reduce(:merge)
|
106
|
+
self.send(method, *args, **kwargs)
|
107
|
+
else
|
108
|
+
self.send(method, *args)
|
84
109
|
end
|
85
|
-
self.send(method, *args)
|
86
110
|
end
|
87
111
|
end
|
88
112
|
end
|
89
113
|
|
114
|
+
private
|
115
|
+
|
116
|
+
def forcing_extension(filename)
|
117
|
+
if force_extension && filename
|
118
|
+
Pathname.new(filename).sub_ext(".#{force_extension.to_s.delete_prefix('.')}").to_s
|
119
|
+
else
|
120
|
+
filename
|
121
|
+
end
|
122
|
+
end
|
90
123
|
end # Processing
|
91
124
|
end # Uploader
|
92
125
|
end # CarrierWave
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module CarrierWave
|
4
2
|
module Uploader
|
5
3
|
module Proxy
|
@@ -19,20 +17,33 @@ module CarrierWave
|
|
19
17
|
# [String] the path where the file is currently located.
|
20
18
|
#
|
21
19
|
def current_path
|
22
|
-
file.
|
20
|
+
file.try(:path)
|
23
21
|
end
|
24
22
|
|
25
23
|
alias_method :path, :current_path
|
26
24
|
|
27
25
|
##
|
28
|
-
# Returns a string that uniquely identifies the last stored file
|
26
|
+
# Returns a string that uniquely identifies the retrieved or last stored file
|
29
27
|
#
|
30
28
|
# === Returns
|
31
29
|
#
|
32
30
|
# [String] uniquely identifies a file
|
33
31
|
#
|
34
32
|
def identifier
|
35
|
-
|
33
|
+
@identifier || (file && storage.try(:identifier))
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Returns a String which is to be used as a temporary value which gets assigned to the column.
|
38
|
+
# The purpose is to mark the column that it will be updated. Finally before the save it will be
|
39
|
+
# overwritten by the #identifier value, which is usually #filename.
|
40
|
+
#
|
41
|
+
# === Returns
|
42
|
+
#
|
43
|
+
# [String] a temporary_identifier, by default @original_filename is used
|
44
|
+
#
|
45
|
+
def temporary_identifier
|
46
|
+
@original_filename || @identifier
|
36
47
|
end
|
37
48
|
|
38
49
|
##
|
@@ -42,8 +53,8 @@ module CarrierWave
|
|
42
53
|
#
|
43
54
|
# [String] contents of the file
|
44
55
|
#
|
45
|
-
def read
|
46
|
-
file.
|
56
|
+
def read(*args)
|
57
|
+
file.try(:read, *args)
|
47
58
|
end
|
48
59
|
|
49
60
|
##
|
@@ -54,7 +65,7 @@ module CarrierWave
|
|
54
65
|
# [Integer] size of the file
|
55
66
|
#
|
56
67
|
def size
|
57
|
-
file.
|
68
|
+
file.try(:size) || 0
|
58
69
|
end
|
59
70
|
|
60
71
|
##
|
@@ -72,6 +83,17 @@ module CarrierWave
|
|
72
83
|
size
|
73
84
|
end
|
74
85
|
|
86
|
+
##
|
87
|
+
# Read the content type of the file
|
88
|
+
#
|
89
|
+
# === Returns
|
90
|
+
#
|
91
|
+
# [String] content type of the file
|
92
|
+
#
|
93
|
+
def content_type
|
94
|
+
file.try(:content_type)
|
95
|
+
end
|
96
|
+
|
75
97
|
end # Proxy
|
76
98
|
end # Uploader
|
77
99
|
end # CarrierWave
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
require "json"
|
4
2
|
require "active_support/core_ext/hash"
|
5
3
|
|
@@ -8,12 +6,12 @@ module CarrierWave
|
|
8
6
|
module Serialization
|
9
7
|
extend ActiveSupport::Concern
|
10
8
|
|
11
|
-
def serializable_hash
|
12
|
-
{"url" => url}.merge Hash[versions.map { |name, version| [name, { "url" => version.url }] }]
|
9
|
+
def serializable_hash(options = nil)
|
10
|
+
{"url" => url}.merge Hash[versions.map { |name, version| [name.to_s, { "url" => version.url }] }]
|
13
11
|
end
|
14
12
|
|
15
13
|
def as_json(options=nil)
|
16
|
-
|
14
|
+
serializable_hash
|
17
15
|
end
|
18
16
|
|
19
17
|
def to_json(options=nil)
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module CarrierWave
|
4
2
|
module Uploader
|
5
3
|
module Store
|
@@ -9,6 +7,15 @@ module CarrierWave
|
|
9
7
|
include CarrierWave::Uploader::Configuration
|
10
8
|
include CarrierWave::Uploader::Cache
|
11
9
|
|
10
|
+
included do
|
11
|
+
prepend Module.new {
|
12
|
+
def initialize(*)
|
13
|
+
super
|
14
|
+
@file, @filename, @cache_id, @identifier, @deduplication_index = nil
|
15
|
+
end
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
12
19
|
##
|
13
20
|
# Override this in your Uploader to change the filename.
|
14
21
|
#
|
@@ -27,9 +34,26 @@ module CarrierWave
|
|
27
34
|
@filename
|
28
35
|
end
|
29
36
|
|
37
|
+
##
|
38
|
+
# Returns a filename which doesn't conflict with already-stored files.
|
39
|
+
#
|
40
|
+
# === Returns
|
41
|
+
#
|
42
|
+
# [String] the filename with suffix added for deduplication
|
43
|
+
#
|
44
|
+
def deduplicated_filename
|
45
|
+
return unless filename
|
46
|
+
return filename unless @deduplication_index
|
47
|
+
|
48
|
+
parts = filename.split('.')
|
49
|
+
basename = parts.shift
|
50
|
+
basename.sub!(/ ?\(\d+\)\z/, '')
|
51
|
+
([basename.to_s + (@deduplication_index > 1 ? "(#{@deduplication_index})" : '')] + parts).join('.')
|
52
|
+
end
|
53
|
+
|
30
54
|
##
|
31
55
|
# Calculates the path where the file should be stored. If +for_file+ is given, it will be
|
32
|
-
# used as the
|
56
|
+
# used as the identifier, otherwise +CarrierWave::Uploader#identifier+ is assumed.
|
33
57
|
#
|
34
58
|
# === Parameters
|
35
59
|
#
|
@@ -39,7 +63,7 @@ module CarrierWave
|
|
39
63
|
#
|
40
64
|
# [String] the store path
|
41
65
|
#
|
42
|
-
def store_path(for_file=
|
66
|
+
def store_path(for_file=identifier)
|
43
67
|
File.join([store_dir, full_filename(for_file)].compact)
|
44
68
|
end
|
45
69
|
|
@@ -53,32 +77,18 @@ module CarrierWave
|
|
53
77
|
# [new_file (File, IOString, Tempfile)] any kind of file object
|
54
78
|
#
|
55
79
|
def store!(new_file=nil)
|
56
|
-
cache!(new_file) if new_file &&
|
57
|
-
if @file
|
80
|
+
cache!(new_file) if new_file && !cached?
|
81
|
+
if !cache_only && @file && @cache_id
|
58
82
|
with_callbacks(:store, new_file) do
|
59
83
|
new_file = storage.store!(@file)
|
60
|
-
|
61
|
-
|
84
|
+
if delete_tmp_file_after_storage
|
85
|
+
@file.delete unless move_to_store
|
86
|
+
cache_storage.delete_dir!(cache_path(nil))
|
87
|
+
end
|
62
88
|
@file = new_file
|
63
|
-
@
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
##
|
69
|
-
# Deletes a cache id (tmp dir in cache)
|
70
|
-
#
|
71
|
-
def delete_cache_id
|
72
|
-
if @cache_id
|
73
|
-
path = File.expand_path(File.join(cache_dir, @cache_id), CarrierWave.root)
|
74
|
-
begin
|
75
|
-
Dir.rmdir(path)
|
76
|
-
rescue Errno::ENOENT
|
77
|
-
# Ignore: path does not exist
|
78
|
-
rescue Errno::ENOTDIR
|
79
|
-
# Ignore: path is not a dir
|
80
|
-
rescue Errno::ENOTEMPTY, Errno::EEXIST
|
81
|
-
# Ignore: dir is not empty
|
89
|
+
@identifier = storage.identifier
|
90
|
+
@cache_id = @deduplication_index = nil
|
91
|
+
@staged = false
|
82
92
|
end
|
83
93
|
end
|
84
94
|
end
|
@@ -93,13 +103,34 @@ module CarrierWave
|
|
93
103
|
def retrieve_from_store!(identifier)
|
94
104
|
with_callbacks(:retrieve_from_store, identifier) do
|
95
105
|
@file = storage.retrieve!(identifier)
|
106
|
+
@identifier = identifier
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# Look for an identifier which doesn't collide with the given already-stored identifiers.
|
112
|
+
# It is done by adding a index number as the suffix.
|
113
|
+
# For example, if there's 'image.jpg' and the @deduplication_index is set to 2,
|
114
|
+
# The stored file will be named as 'image(2).jpg'.
|
115
|
+
#
|
116
|
+
# === Parameters
|
117
|
+
#
|
118
|
+
# [current_identifiers (Array[String])] List of identifiers for already-stored files
|
119
|
+
#
|
120
|
+
def deduplicate(current_identifiers)
|
121
|
+
@deduplication_index = nil
|
122
|
+
return unless current_identifiers.include?(identifier)
|
123
|
+
|
124
|
+
(1..current_identifiers.size + 1).each do |i|
|
125
|
+
@deduplication_index = i
|
126
|
+
break unless current_identifiers.include?(identifier)
|
96
127
|
end
|
97
128
|
end
|
98
129
|
|
99
130
|
private
|
100
131
|
|
101
132
|
def full_filename(for_file)
|
102
|
-
for_file
|
133
|
+
forcing_extension(for_file)
|
103
134
|
end
|
104
135
|
|
105
136
|
def storage
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module CarrierWave
|
4
2
|
module Uploader
|
5
3
|
module Url
|
@@ -17,12 +15,15 @@ module CarrierWave
|
|
17
15
|
# [String] the location where this file is accessible via a url
|
18
16
|
#
|
19
17
|
def url(options = {})
|
20
|
-
if file.respond_to?(:url)
|
21
|
-
file.method(:url).arity
|
22
|
-
|
23
|
-
|
18
|
+
if file.respond_to?(:url)
|
19
|
+
tmp_url = file.method(:url).arity.zero? ? file.url : file.url(options)
|
20
|
+
return tmp_url if tmp_url.present?
|
21
|
+
end
|
22
|
+
|
23
|
+
if file.respond_to?(:path)
|
24
|
+
path = encode_path(file.path.sub(File.expand_path(root), ''))
|
24
25
|
|
25
|
-
if host = asset_host
|
26
|
+
if (host = asset_host)
|
26
27
|
if host.respond_to? :call
|
27
28
|
"#{host.call(file)}#{path}"
|
28
29
|
else
|