carrierwave 1.3.2 → 3.0.3
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 +235 -91
- 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 +48 -61
- data/lib/carrierwave/mounter.rb +167 -77
- data/lib/carrierwave/orm/activerecord.rb +15 -55
- data/lib/carrierwave/processing/mini_magick.rb +108 -123
- data/lib/carrierwave/processing/rmagick.rb +11 -15
- data/lib/carrierwave/processing/vips.rb +284 -0
- data/lib/carrierwave/processing.rb +1 -0
- data/lib/carrierwave/sanitized_file.rb +60 -66
- data/lib/carrierwave/storage/abstract.rb +5 -5
- data/lib/carrierwave/storage/file.rb +6 -5
- data/lib/carrierwave/storage/fog.rb +101 -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 +38 -19
- data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
- data/lib/carrierwave/uploader/content_type_denylist.rb +62 -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 +42 -7
- data/lib/carrierwave/uploader/proxy.rb +17 -4
- data/lib/carrierwave/uploader/serialization.rb +1 -1
- data/lib/carrierwave/uploader/store.rb +47 -7
- data/lib/carrierwave/uploader/url.rb +7 -4
- data/lib/carrierwave/uploader/versions.rb +153 -105
- 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 +13 -17
- data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +2 -2
- data/lib/generators/uploader_generator.rb +3 -3
- metadata +100 -33
- 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
data/lib/carrierwave/mounter.rb
CHANGED
@@ -2,15 +2,49 @@ module CarrierWave
|
|
2
2
|
|
3
3
|
# this is an internal class, used by CarrierWave::Mount so that
|
4
4
|
# we don't pollute the model with a lot of methods.
|
5
|
-
class Mounter
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
class Mounter # :nodoc:
|
6
|
+
class Single < Mounter # :nodoc
|
7
|
+
def identifier
|
8
|
+
uploaders.first&.identifier
|
9
|
+
end
|
10
|
+
|
11
|
+
def temporary_identifier
|
12
|
+
temporary_identifiers.first
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Multiple < Mounter # :nodoc
|
17
|
+
def identifier
|
18
|
+
uploaders.map(&:identifier).presence
|
19
|
+
end
|
20
|
+
|
21
|
+
def temporary_identifier
|
22
|
+
temporary_identifiers.presence
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.build(record, column)
|
27
|
+
if record.class.uploader_options[column][:multiple]
|
28
|
+
Multiple.new(record, column)
|
29
|
+
else
|
30
|
+
Single.new(record, column)
|
31
|
+
end
|
32
|
+
end
|
9
33
|
|
10
|
-
|
34
|
+
attr_reader :column, :record, :remote_urls, :remove,
|
35
|
+
:integrity_errors, :processing_errors, :download_errors
|
36
|
+
attr_accessor :remote_request_headers, :uploader_options
|
37
|
+
|
38
|
+
def initialize(record, column)
|
11
39
|
@record = record
|
12
40
|
@column = column
|
13
41
|
@options = record.class.uploader_options[column]
|
42
|
+
@download_errors = []
|
43
|
+
@processing_errors = []
|
44
|
+
@integrity_errors = []
|
45
|
+
|
46
|
+
@removed_uploaders = []
|
47
|
+
@added_uploaders = []
|
14
48
|
end
|
15
49
|
|
16
50
|
def uploader_class
|
@@ -32,27 +66,38 @@ module CarrierWave
|
|
32
66
|
def uploaders
|
33
67
|
@uploaders ||= read_identifiers.map do |identifier|
|
34
68
|
uploader = blank_uploader
|
35
|
-
uploader.retrieve_from_store!(identifier)
|
69
|
+
uploader.retrieve_from_store!(identifier)
|
36
70
|
uploader
|
37
71
|
end
|
38
72
|
end
|
39
73
|
|
40
74
|
def cache(new_files)
|
41
|
-
return if
|
75
|
+
return if !new_files.is_a?(Array) && new_files.blank?
|
76
|
+
old_uploaders = uploaders
|
42
77
|
@uploaders = new_files.map do |new_file|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
78
|
+
handle_error do
|
79
|
+
if new_file.is_a?(String)
|
80
|
+
if (uploader = old_uploaders.detect { |old_uploader| old_uploader.identifier == new_file })
|
81
|
+
uploader.staged = true
|
82
|
+
uploader
|
83
|
+
else
|
84
|
+
begin
|
85
|
+
uploader = blank_uploader
|
86
|
+
uploader.retrieve_from_cache!(new_file)
|
87
|
+
uploader
|
88
|
+
rescue CarrierWave::InvalidParameter
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
else
|
93
|
+
uploader = blank_uploader
|
94
|
+
uploader.cache!(new_file)
|
95
|
+
uploader
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end.reject(&:blank?)
|
99
|
+
@removed_uploaders += (old_uploaders - @uploaders)
|
100
|
+
write_temporary_identifier
|
56
101
|
end
|
57
102
|
|
58
103
|
def cache_names
|
@@ -60,45 +105,57 @@ module CarrierWave
|
|
60
105
|
end
|
61
106
|
|
62
107
|
def cache_names=(cache_names)
|
63
|
-
|
64
|
-
|
108
|
+
cache_names = cache_names.reject(&:blank?)
|
109
|
+
return if cache_names.blank?
|
110
|
+
clear_unstaged
|
111
|
+
cache_names.each do |cache_name|
|
65
112
|
uploader = blank_uploader
|
66
113
|
uploader.retrieve_from_cache!(cache_name)
|
67
|
-
uploader
|
114
|
+
@uploaders << uploader
|
115
|
+
rescue CarrierWave::InvalidParameter
|
116
|
+
# ignore
|
68
117
|
end
|
69
|
-
|
118
|
+
write_temporary_identifier
|
70
119
|
end
|
71
120
|
|
72
121
|
def remote_urls=(urls)
|
73
|
-
|
74
|
-
|
122
|
+
if urls.nil?
|
123
|
+
urls = []
|
124
|
+
else
|
125
|
+
urls = Array.wrap(urls).reject(&:blank?)
|
126
|
+
return if urls.blank?
|
127
|
+
end
|
75
128
|
@remote_urls = urls
|
76
|
-
@download_error = nil
|
77
|
-
@integrity_error = nil
|
78
129
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
130
|
+
clear_unstaged
|
131
|
+
@remote_urls.zip(remote_request_headers || []) do |url, header|
|
132
|
+
handle_error do
|
133
|
+
uploader = blank_uploader
|
134
|
+
uploader.download!(url, header || {})
|
135
|
+
@uploaders << uploader
|
136
|
+
end
|
83
137
|
end
|
84
|
-
|
85
|
-
rescue CarrierWave::DownloadError => e
|
86
|
-
@download_error = e
|
87
|
-
raise e unless option(:ignore_download_errors)
|
88
|
-
rescue CarrierWave::ProcessingError => e
|
89
|
-
@processing_error = e
|
90
|
-
raise e unless option(:ignore_processing_errors)
|
91
|
-
rescue CarrierWave::IntegrityError => e
|
92
|
-
@integrity_error = e
|
93
|
-
raise e unless option(:ignore_integrity_errors)
|
138
|
+
write_temporary_identifier
|
94
139
|
end
|
95
140
|
|
96
141
|
def store!
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
142
|
+
uploaders.each(&:store!)
|
143
|
+
end
|
144
|
+
|
145
|
+
def write_identifier
|
146
|
+
return if record.frozen?
|
147
|
+
|
148
|
+
clear! if remove?
|
149
|
+
|
150
|
+
additions, remains = uploaders.partition(&:cached?)
|
151
|
+
existing_identifiers = (@removed_uploaders + remains).map(&:identifier)
|
152
|
+
additions.each do |uploader|
|
153
|
+
uploader.deduplicate(existing_identifiers)
|
154
|
+
existing_identifiers << uploader.identifier
|
101
155
|
end
|
156
|
+
@added_uploaders += additions
|
157
|
+
|
158
|
+
record.write_uploader(serialization_column, identifier)
|
102
159
|
end
|
103
160
|
|
104
161
|
def urls(*args)
|
@@ -109,50 +166,50 @@ module CarrierWave
|
|
109
166
|
uploaders.none?(&:present?)
|
110
167
|
end
|
111
168
|
|
169
|
+
def remove=(value)
|
170
|
+
@remove = value
|
171
|
+
write_temporary_identifier
|
172
|
+
end
|
173
|
+
|
112
174
|
def remove?
|
113
|
-
remove.present? && remove !~ /\A0|false$\z/
|
175
|
+
remove.present? && (remove.to_s !~ /\A0|false$\z/)
|
114
176
|
end
|
115
177
|
|
116
178
|
def remove!
|
117
|
-
uploaders.
|
179
|
+
uploaders.each(&:remove!)
|
180
|
+
clear!
|
181
|
+
end
|
182
|
+
|
183
|
+
def clear!
|
184
|
+
@removed_uploaders += uploaders
|
185
|
+
@remove = nil
|
118
186
|
@uploaders = []
|
119
187
|
end
|
120
188
|
|
189
|
+
def reset_changes!
|
190
|
+
@removed_uploaders = []
|
191
|
+
@added_uploaders = []
|
192
|
+
end
|
193
|
+
|
121
194
|
def serialization_column
|
122
195
|
option(:mount_on) || column
|
123
196
|
end
|
124
197
|
|
125
|
-
def remove_previous
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
if value.is_a?(String)
|
132
|
-
uploader = blank_uploader
|
133
|
-
uploader.retrieve_from_store!(value)
|
134
|
-
uploader
|
135
|
-
else
|
136
|
-
value
|
137
|
-
end
|
138
|
-
end
|
139
|
-
after_paths = after.reject(&:blank?).map do |value|
|
140
|
-
if value.is_a?(String)
|
141
|
-
uploader = blank_uploader
|
142
|
-
uploader.retrieve_from_store!(value)
|
143
|
-
uploader
|
144
|
-
else
|
145
|
-
value
|
146
|
-
end.path
|
147
|
-
end
|
148
|
-
before.each do |uploader|
|
149
|
-
if uploader.remove_previously_stored_files_after_update and not after_paths.include?(uploader.path)
|
150
|
-
uploader.remove!
|
151
|
-
end
|
152
|
-
end
|
198
|
+
def remove_previous
|
199
|
+
current_paths = uploaders.map(&:path)
|
200
|
+
@removed_uploaders
|
201
|
+
.reject {|uploader| current_paths.include?(uploader.path) }
|
202
|
+
.each { |uploader| uploader.remove! if uploader.remove_previously_stored_files_after_update }
|
203
|
+
reset_changes!
|
153
204
|
end
|
154
205
|
|
155
|
-
|
206
|
+
def remove_added
|
207
|
+
current_paths = (@removed_uploaders + uploaders.select(&:staged)).map(&:path)
|
208
|
+
@added_uploaders
|
209
|
+
.reject {|uploader| current_paths.include?(uploader.path) }
|
210
|
+
.each { |uploader| uploader.remove! }
|
211
|
+
reset_changes!
|
212
|
+
end
|
156
213
|
|
157
214
|
private
|
158
215
|
|
@@ -161,5 +218,38 @@ module CarrierWave
|
|
161
218
|
self.uploader_options[name] ||= record.class.uploader_option(column, name)
|
162
219
|
end
|
163
220
|
|
221
|
+
def clear_unstaged
|
222
|
+
@uploaders ||= []
|
223
|
+
staged, unstaged = @uploaders.partition(&:staged)
|
224
|
+
@uploaders = staged
|
225
|
+
@removed_uploaders += unstaged
|
226
|
+
end
|
227
|
+
|
228
|
+
def handle_error
|
229
|
+
yield
|
230
|
+
rescue CarrierWave::DownloadError => e
|
231
|
+
@download_errors << e
|
232
|
+
raise e unless option(:ignore_download_errors)
|
233
|
+
rescue CarrierWave::ProcessingError => e
|
234
|
+
@processing_errors << e
|
235
|
+
raise e unless option(:ignore_processing_errors)
|
236
|
+
rescue CarrierWave::IntegrityError => e
|
237
|
+
@integrity_errors << e
|
238
|
+
raise e unless option(:ignore_integrity_errors)
|
239
|
+
end
|
240
|
+
|
241
|
+
def write_temporary_identifier
|
242
|
+
return if record.frozen?
|
243
|
+
|
244
|
+
record.write_uploader(serialization_column, temporary_identifier)
|
245
|
+
end
|
246
|
+
|
247
|
+
def temporary_identifiers
|
248
|
+
if remove?
|
249
|
+
[]
|
250
|
+
else
|
251
|
+
uploaders.map { |uploader| uploader.temporary_identifier }
|
252
|
+
end
|
253
|
+
end
|
164
254
|
end # Mounter
|
165
255
|
end # CarrierWave
|
@@ -6,36 +6,6 @@ module CarrierWave
|
|
6
6
|
|
7
7
|
include CarrierWave::Mount
|
8
8
|
|
9
|
-
##
|
10
|
-
# See +CarrierWave::Mount#mount_uploader+ for documentation
|
11
|
-
#
|
12
|
-
def mount_uploader(column, uploader=nil, options={}, &block)
|
13
|
-
super
|
14
|
-
|
15
|
-
class_eval <<-RUBY, __FILE__, __LINE__+1
|
16
|
-
def remote_#{column}_url=(url)
|
17
|
-
column = _mounter(:#{column}).serialization_column
|
18
|
-
__send__(:"\#{column}_will_change!")
|
19
|
-
super
|
20
|
-
end
|
21
|
-
RUBY
|
22
|
-
end
|
23
|
-
|
24
|
-
##
|
25
|
-
# See +CarrierWave::Mount#mount_uploaders+ for documentation
|
26
|
-
#
|
27
|
-
def mount_uploaders(column, uploader=nil, options={}, &block)
|
28
|
-
super
|
29
|
-
|
30
|
-
class_eval <<-RUBY, __FILE__, __LINE__+1
|
31
|
-
def remote_#{column}_urls=(url)
|
32
|
-
column = _mounter(:#{column}).serialization_column
|
33
|
-
__send__(:"\#{column}_will_change!")
|
34
|
-
super
|
35
|
-
end
|
36
|
-
RUBY
|
37
|
-
end
|
38
|
-
|
39
9
|
private
|
40
10
|
|
41
11
|
def mount_base(column, uploader=nil, options={}, &block)
|
@@ -57,32 +27,13 @@ module CarrierWave
|
|
57
27
|
after_commit :"remove_#{column}!", :on => :destroy
|
58
28
|
after_commit :"mark_remove_#{column}_false", :on => :update
|
59
29
|
|
60
|
-
|
30
|
+
after_commit :"reset_previous_changes_for_#{column}"
|
61
31
|
after_commit :"remove_previously_stored_#{column}", :on => :update
|
32
|
+
after_rollback :"remove_rolled_back_#{column}"
|
62
33
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
if !(new_file.blank? && __send__(:#{column}).blank?)
|
67
|
-
__send__(:"\#{column}_will_change!")
|
68
|
-
end
|
69
|
-
|
70
|
-
super
|
71
|
-
end
|
72
|
-
|
73
|
-
def remove_#{column}=(value)
|
74
|
-
column = _mounter(:#{column}).serialization_column
|
75
|
-
__send__(:"\#{column}_will_change!")
|
76
|
-
super
|
77
|
-
end
|
78
|
-
|
79
|
-
def remove_#{column}!
|
80
|
-
self.remove_#{column} = true
|
81
|
-
write_#{column}_identifier
|
82
|
-
self.remove_#{column} = false
|
83
|
-
super
|
84
|
-
end
|
85
|
-
|
34
|
+
mod = Module.new
|
35
|
+
prepend mod
|
36
|
+
mod.class_eval <<-RUBY, __FILE__, __LINE__+1
|
86
37
|
# Reset cached mounter on record reload
|
87
38
|
def reload(*)
|
88
39
|
@_mounters = nil
|
@@ -91,7 +42,16 @@ module CarrierWave
|
|
91
42
|
|
92
43
|
# Reset cached mounter on record dup
|
93
44
|
def initialize_dup(other)
|
94
|
-
|
45
|
+
old_uploaders = _mounter(:"#{column}").uploaders
|
46
|
+
@_mounters[:"#{column}"] = nil
|
47
|
+
super
|
48
|
+
# The attribute needs to be cleared to prevent it from picked up as identifier
|
49
|
+
write_attribute(:"#{column}", nil)
|
50
|
+
_mounter(:"#{column}").cache(old_uploaders)
|
51
|
+
end
|
52
|
+
|
53
|
+
def write_#{column}_identifier
|
54
|
+
return unless has_attribute?(_mounter(:#{column}).serialization_column)
|
95
55
|
super
|
96
56
|
end
|
97
57
|
RUBY
|