carrierwave 0.11.2 → 3.1.2

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.
Files changed (69) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +495 -173
  3. data/lib/carrierwave/compatibility/paperclip.rb +4 -4
  4. data/lib/carrierwave/downloader/base.rb +101 -0
  5. data/lib/carrierwave/downloader/remote_file.rb +68 -0
  6. data/lib/carrierwave/error.rb +1 -0
  7. data/lib/carrierwave/locale/en.yml +11 -5
  8. data/lib/carrierwave/mount.rb +217 -182
  9. data/lib/carrierwave/mounter.rb +257 -0
  10. data/lib/carrierwave/orm/activerecord.rb +29 -35
  11. data/lib/carrierwave/processing/mini_magick.rb +169 -84
  12. data/lib/carrierwave/processing/rmagick.rb +107 -25
  13. data/lib/carrierwave/processing/vips.rb +315 -0
  14. data/lib/carrierwave/processing.rb +1 -1
  15. data/lib/carrierwave/sanitized_file.rb +105 -87
  16. data/lib/carrierwave/storage/abstract.rb +16 -3
  17. data/lib/carrierwave/storage/file.rb +71 -3
  18. data/lib/carrierwave/storage/fog.rb +228 -57
  19. data/lib/carrierwave/storage.rb +1 -9
  20. data/lib/carrierwave/test/matchers.rb +88 -19
  21. data/lib/carrierwave/uploader/cache.rb +75 -45
  22. data/lib/carrierwave/uploader/callbacks.rb +1 -3
  23. data/lib/carrierwave/uploader/configuration.rb +84 -16
  24. data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
  25. data/lib/carrierwave/uploader/content_type_denylist.rb +62 -0
  26. data/lib/carrierwave/uploader/default_url.rb +3 -5
  27. data/lib/carrierwave/uploader/dimension.rb +66 -0
  28. data/lib/carrierwave/uploader/download.rb +4 -74
  29. data/lib/carrierwave/uploader/extension_allowlist.rb +63 -0
  30. data/lib/carrierwave/uploader/extension_denylist.rb +64 -0
  31. data/lib/carrierwave/uploader/file_size.rb +43 -0
  32. data/lib/carrierwave/uploader/mountable.rb +13 -8
  33. data/lib/carrierwave/uploader/processing.rb +51 -13
  34. data/lib/carrierwave/uploader/proxy.rb +20 -9
  35. data/lib/carrierwave/uploader/remove.rb +0 -2
  36. data/lib/carrierwave/uploader/serialization.rb +2 -4
  37. data/lib/carrierwave/uploader/store.rb +85 -28
  38. data/lib/carrierwave/uploader/url.rb +8 -7
  39. data/lib/carrierwave/uploader/versions.rb +175 -125
  40. data/lib/carrierwave/uploader.rb +12 -10
  41. data/lib/carrierwave/utilities/file_name.rb +47 -0
  42. data/lib/carrierwave/utilities/uri.rb +14 -12
  43. data/lib/carrierwave/utilities.rb +1 -3
  44. data/lib/carrierwave/validations/active_model.rb +7 -11
  45. data/lib/carrierwave/version.rb +1 -1
  46. data/lib/carrierwave.rb +48 -21
  47. data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +8 -11
  48. data/lib/generators/uploader_generator.rb +3 -3
  49. metadata +124 -86
  50. data/lib/carrierwave/locale/cs.yml +0 -11
  51. data/lib/carrierwave/locale/de.yml +0 -11
  52. data/lib/carrierwave/locale/el.yml +0 -11
  53. data/lib/carrierwave/locale/es.yml +0 -11
  54. data/lib/carrierwave/locale/fr.yml +0 -11
  55. data/lib/carrierwave/locale/ja.yml +0 -11
  56. data/lib/carrierwave/locale/nb.yml +0 -11
  57. data/lib/carrierwave/locale/nl.yml +0 -11
  58. data/lib/carrierwave/locale/pl.yml +0 -11
  59. data/lib/carrierwave/locale/pt-BR.yml +0 -11
  60. data/lib/carrierwave/locale/pt-PT.yml +0 -11
  61. data/lib/carrierwave/locale/ru.yml +0 -11
  62. data/lib/carrierwave/locale/sk.yml +0 -11
  63. data/lib/carrierwave/locale/tr.yml +0 -11
  64. data/lib/carrierwave/processing/mime_types.rb +0 -74
  65. data/lib/carrierwave/uploader/content_type_blacklist.rb +0 -48
  66. data/lib/carrierwave/uploader/content_type_whitelist.rb +0 -48
  67. data/lib/carrierwave/uploader/extension_blacklist.rb +0 -47
  68. data/lib/carrierwave/uploader/extension_whitelist.rb +0 -49
  69. data/lib/carrierwave/utilities/deprecation.rb +0 -18
@@ -0,0 +1,257 @@
1
+ module CarrierWave
2
+
3
+ # this is an internal class, used by CarrierWave::Mount so that
4
+ # we don't pollute the model with a lot of methods.
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
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)
39
+ @record = record
40
+ @column = column
41
+ @options = record.class.uploader_options[column]
42
+ @download_errors = []
43
+ @processing_errors = []
44
+ @integrity_errors = []
45
+
46
+ @removed_uploaders = []
47
+ @added_uploaders = []
48
+ end
49
+
50
+ def uploader_class
51
+ record.class.uploaders[column]
52
+ end
53
+
54
+ def blank_uploader
55
+ uploader_class.new(record, column)
56
+ end
57
+
58
+ def identifiers
59
+ uploaders.map(&:identifier)
60
+ end
61
+
62
+ def read_identifiers
63
+ [record.read_uploader(serialization_column)].flatten.reject(&:blank?)
64
+ end
65
+
66
+ def uploaders
67
+ @uploaders ||= read_identifiers.map do |identifier|
68
+ uploader = blank_uploader
69
+ uploader.retrieve_from_store!(identifier)
70
+ uploader
71
+ end
72
+ end
73
+
74
+ def cache(new_files)
75
+ return if !new_files.is_a?(Array) && new_files.blank?
76
+ old_uploaders = uploaders
77
+ @uploaders = new_files.map do |new_file|
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
101
+ end
102
+
103
+ def cache_names
104
+ uploaders.map(&:cache_name).compact
105
+ end
106
+
107
+ def cache_names=(cache_names)
108
+ cache_names = cache_names.reject(&:blank?)
109
+ return if cache_names.blank?
110
+ clear_unstaged
111
+ cache_names.each do |cache_name|
112
+ uploader = blank_uploader
113
+ uploader.retrieve_from_cache!(cache_name)
114
+ @uploaders << uploader
115
+ rescue CarrierWave::InvalidParameter
116
+ # ignore
117
+ end
118
+ write_temporary_identifier
119
+ end
120
+
121
+ def remote_urls=(urls)
122
+ if urls.nil?
123
+ urls = []
124
+ else
125
+ urls = Array.wrap(urls).reject(&:blank?)
126
+ return if urls.blank?
127
+ end
128
+ @download_errors.clear
129
+ @remote_urls = urls
130
+
131
+ clear_unstaged
132
+ @remote_urls.zip(remote_request_headers || []) do |url, header|
133
+ handle_error do
134
+ uploader = blank_uploader
135
+ uploader.download!(url, header || {})
136
+ @uploaders << uploader
137
+ end
138
+ end
139
+ write_temporary_identifier
140
+ end
141
+
142
+ def store!
143
+ uploaders.each(&:store!)
144
+ end
145
+
146
+ def write_identifier
147
+ return if record.frozen?
148
+
149
+ clear! if remove?
150
+
151
+ additions, remains = uploaders.partition(&:cached?)
152
+ existing_identifiers = (@removed_uploaders + remains).map(&:identifier)
153
+ additions.each do |uploader|
154
+ uploader.deduplicate(existing_identifiers)
155
+ existing_identifiers << uploader.identifier
156
+ end
157
+ @added_uploaders += additions
158
+
159
+ record.write_uploader(serialization_column, identifier)
160
+ end
161
+
162
+ def urls(*args)
163
+ uploaders.map { |u| u.url(*args) }
164
+ end
165
+
166
+ def blank?
167
+ uploaders.none?(&:present?)
168
+ end
169
+
170
+ def remove=(value)
171
+ uploaders # Ensure that uploaders are initialized based on the current value
172
+ @remove = value
173
+ write_temporary_identifier
174
+ end
175
+
176
+ def remove?
177
+ remove.present? && (remove.to_s !~ /\A0|false$\z/)
178
+ end
179
+
180
+ def remove!
181
+ uploaders.each(&:remove!)
182
+ clear!
183
+ end
184
+
185
+ def clear!
186
+ @removed_uploaders += uploaders
187
+ @remove = nil
188
+ @uploaders = []
189
+ end
190
+
191
+ def reset_changes!
192
+ @removed_uploaders = []
193
+ @added_uploaders = []
194
+ end
195
+
196
+ def serialization_column
197
+ option(:mount_on) || column
198
+ end
199
+
200
+ def remove_previous
201
+ current_paths = uploaders.map(&:path)
202
+ @removed_uploaders
203
+ .reject {|uploader| current_paths.include?(uploader.path) }
204
+ .each { |uploader| uploader.remove! if uploader.remove_previously_stored_files_after_update }
205
+ reset_changes!
206
+ end
207
+
208
+ def remove_added
209
+ current_paths = (@removed_uploaders + uploaders.select(&:staged)).map(&:path)
210
+ @added_uploaders
211
+ .reject {|uploader| current_paths.include?(uploader.path) }
212
+ .each { |uploader| uploader.remove! }
213
+ reset_changes!
214
+ end
215
+
216
+ private
217
+
218
+ def option(name)
219
+ self.uploader_options ||= {}
220
+ self.uploader_options[name] ||= record.class.uploader_option(column, name)
221
+ end
222
+
223
+ def clear_unstaged
224
+ uploaders # Ensure that uploaders are initialized based on the current value
225
+ staged, unstaged = @uploaders.partition(&:staged)
226
+ @uploaders = staged
227
+ @removed_uploaders += unstaged
228
+ end
229
+
230
+ def handle_error
231
+ yield
232
+ rescue CarrierWave::DownloadError => e
233
+ @download_errors << e
234
+ raise e unless option(:ignore_download_errors)
235
+ rescue CarrierWave::ProcessingError => e
236
+ @processing_errors << e
237
+ raise e unless option(:ignore_processing_errors)
238
+ rescue CarrierWave::IntegrityError => e
239
+ @integrity_errors << e
240
+ raise e unless option(:ignore_integrity_errors)
241
+ end
242
+
243
+ def write_temporary_identifier
244
+ return if record.frozen?
245
+
246
+ record.write_uploader(serialization_column, temporary_identifier)
247
+ end
248
+
249
+ def temporary_identifiers
250
+ if remove?
251
+ []
252
+ else
253
+ uploaders.map { |uploader| uploader.temporary_identifier }
254
+ end
255
+ end
256
+ end # Mounter
257
+ end # CarrierWave
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  require 'active_record'
4
2
  require 'carrierwave/validations/active_model'
5
3
 
@@ -8,10 +6,9 @@ module CarrierWave
8
6
 
9
7
  include CarrierWave::Mount
10
8
 
11
- ##
12
- # See +CarrierWave::Mount#mount_uploader+ for documentation
13
- #
14
- def mount_uploader(column, uploader=nil, options={}, &block)
9
+ private
10
+
11
+ def mount_base(column, uploader=nil, options={}, &block)
15
12
  super
16
13
 
17
14
  alias_method :read_uploader, :read_attribute
@@ -27,45 +24,42 @@ module CarrierWave
27
24
 
28
25
  after_save :"store_#{column}!"
29
26
  before_save :"write_#{column}_identifier"
27
+ if ::ActiveRecord.try(:run_after_transaction_callbacks_in_order_defined)
28
+ after_commit :"remove_previously_stored_#{column}", :on => :update
29
+ after_commit :"reset_previous_changes_for_#{column}"
30
+ after_commit :"mark_remove_#{column}_false", :on => :update
31
+ else
32
+ after_commit :"mark_remove_#{column}_false", :on => :update
33
+ after_commit :"reset_previous_changes_for_#{column}"
34
+ after_commit :"remove_previously_stored_#{column}", :on => :update
35
+ end
30
36
  after_commit :"remove_#{column}!", :on => :destroy
31
- after_commit :"mark_remove_#{column}_false", :on => :update
32
- before_update :"store_previous_model_for_#{column}"
33
- after_save :"remove_previously_stored_#{column}"
34
-
35
- class_eval <<-RUBY, __FILE__, __LINE__+1
36
- def #{column}=(new_file)
37
- column = _mounter(:#{column}).serialization_column
38
- send(:"\#{column}_will_change!")
37
+ after_rollback :"remove_rolled_back_#{column}"
38
+
39
+ mod = Module.new
40
+ prepend mod
41
+ mod.class_eval <<-RUBY, __FILE__, __LINE__+1
42
+ # Reset cached mounter on record reload
43
+ def reload(*)
44
+ @_mounters = nil
39
45
  super
40
46
  end
41
47
 
42
- def remote_#{column}_url=(url)
43
- column = _mounter(:#{column}).serialization_column
44
- send(:"\#{column}_will_change!")
48
+ # Reset cached mounter on record dup
49
+ def initialize_dup(other)
50
+ old_uploaders = _mounter(:"#{column}").uploaders
45
51
  super
52
+ @_mounters[:"#{column}"] = nil
53
+ # The attribute needs to be cleared to prevent it from picked up as identifier
54
+ write_uploader(_mounter(:#{column}).serialization_column, nil)
55
+ _mounter(:"#{column}").cache(old_uploaders)
46
56
  end
47
57
 
48
- def remove_#{column}!
58
+ def write_#{column}_identifier
59
+ return unless has_attribute?(_mounter(:#{column}).serialization_column)
49
60
  super
50
- _mounter(:#{column}).remove = true
51
- _mounter(:#{column}).write_identifier
52
- end
53
-
54
- def serializable_hash(options=nil)
55
- hash = {}
56
-
57
- except = options && options[:except] && Array.wrap(options[:except]).map(&:to_s)
58
- only = options && options[:only] && Array.wrap(options[:only]).map(&:to_s)
59
-
60
- self.class.uploaders.each do |column, uploader|
61
- if (!only && !except) || (only && only.include?(column.to_s)) || (!only && except && !except.include?(column.to_s))
62
- hash[column.to_s] = _mounter(column).uploader.serializable_hash
63
- end
64
- end
65
- super(options).merge(hash)
66
61
  end
67
62
  RUBY
68
-
69
63
  end
70
64
 
71
65
  end # ActiveRecord