carrierwave 1.3.2 → 3.0.0
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 +165 -77
- data/lib/carrierwave/orm/activerecord.rb +13 -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 +46 -7
- data/lib/carrierwave/uploader/url.rb +7 -4
- data/lib/carrierwave/uploader/versions.rb +140 -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
|
9
20
|
|
10
|
-
|
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
|
33
|
+
|
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,55 @@ 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
|
+
additions, remains = uploaders.partition(&:cached?)
|
143
|
+
existing_paths = (@removed_uploaders + remains).map(&:store_path)
|
144
|
+
additions.each do |uploader|
|
145
|
+
uploader.deduplicate(existing_paths)
|
146
|
+
uploader.store!
|
147
|
+
existing_paths << uploader.store_path
|
101
148
|
end
|
149
|
+
@added_uploaders += additions
|
150
|
+
end
|
151
|
+
|
152
|
+
def write_identifier
|
153
|
+
return if record.frozen?
|
154
|
+
|
155
|
+
clear! if remove?
|
156
|
+
record.write_uploader(serialization_column, identifier)
|
102
157
|
end
|
103
158
|
|
104
159
|
def urls(*args)
|
@@ -109,50 +164,50 @@ module CarrierWave
|
|
109
164
|
uploaders.none?(&:present?)
|
110
165
|
end
|
111
166
|
|
167
|
+
def remove=(value)
|
168
|
+
@remove = value
|
169
|
+
write_temporary_identifier
|
170
|
+
end
|
171
|
+
|
112
172
|
def remove?
|
113
|
-
remove.present? && remove !~ /\A0|false$\z/
|
173
|
+
remove.present? && (remove.to_s !~ /\A0|false$\z/)
|
114
174
|
end
|
115
175
|
|
116
176
|
def remove!
|
117
|
-
uploaders.
|
177
|
+
uploaders.each(&:remove!)
|
178
|
+
clear!
|
179
|
+
end
|
180
|
+
|
181
|
+
def clear!
|
182
|
+
@removed_uploaders += uploaders
|
183
|
+
@remove = nil
|
118
184
|
@uploaders = []
|
119
185
|
end
|
120
186
|
|
187
|
+
def reset_changes!
|
188
|
+
@removed_uploaders = []
|
189
|
+
@added_uploaders = []
|
190
|
+
end
|
191
|
+
|
121
192
|
def serialization_column
|
122
193
|
option(:mount_on) || column
|
123
194
|
end
|
124
195
|
|
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
|
196
|
+
def remove_previous
|
197
|
+
current_paths = uploaders.map(&:path)
|
198
|
+
@removed_uploaders
|
199
|
+
.reject {|uploader| current_paths.include?(uploader.path) }
|
200
|
+
.each { |uploader| uploader.remove! if uploader.remove_previously_stored_files_after_update }
|
201
|
+
reset_changes!
|
153
202
|
end
|
154
203
|
|
155
|
-
|
204
|
+
def remove_added
|
205
|
+
current_paths = (@removed_uploaders + @uploaders.select(&:staged)).map(&:path)
|
206
|
+
@added_uploaders
|
207
|
+
.reject {|uploader| current_paths.include?(uploader.path) }
|
208
|
+
.each { |uploader| uploader.remove! }
|
209
|
+
reset_changes!
|
210
|
+
end
|
156
211
|
|
157
212
|
private
|
158
213
|
|
@@ -161,5 +216,38 @@ module CarrierWave
|
|
161
216
|
self.uploader_options[name] ||= record.class.uploader_option(column, name)
|
162
217
|
end
|
163
218
|
|
219
|
+
def clear_unstaged
|
220
|
+
@uploaders ||= []
|
221
|
+
staged, unstaged = @uploaders.partition(&:staged)
|
222
|
+
@uploaders = staged
|
223
|
+
@removed_uploaders += unstaged
|
224
|
+
end
|
225
|
+
|
226
|
+
def handle_error
|
227
|
+
yield
|
228
|
+
rescue CarrierWave::DownloadError => e
|
229
|
+
@download_errors << e
|
230
|
+
raise e unless option(:ignore_download_errors)
|
231
|
+
rescue CarrierWave::ProcessingError => e
|
232
|
+
@processing_errors << e
|
233
|
+
raise e unless option(:ignore_processing_errors)
|
234
|
+
rescue CarrierWave::IntegrityError => e
|
235
|
+
@integrity_errors << e
|
236
|
+
raise e unless option(:ignore_integrity_errors)
|
237
|
+
end
|
238
|
+
|
239
|
+
def write_temporary_identifier
|
240
|
+
return if record.frozen?
|
241
|
+
|
242
|
+
record.write_uploader(serialization_column, temporary_identifier)
|
243
|
+
end
|
244
|
+
|
245
|
+
def temporary_identifiers
|
246
|
+
if remove?
|
247
|
+
[]
|
248
|
+
else
|
249
|
+
uploaders.map { |uploader| uploader.temporary_identifier }
|
250
|
+
end
|
251
|
+
end
|
164
252
|
end # Mounter
|
165
253
|
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,14 @@ 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
|
+
_mounter(:"#{column}").cache(old_uploaders)
|
49
|
+
end
|
50
|
+
|
51
|
+
def write_#{column}_identifier
|
52
|
+
return unless has_attribute?(_mounter(:#{column}).serialization_column)
|
95
53
|
super
|
96
54
|
end
|
97
55
|
RUBY
|