kt-paperclip 5.4.0 → 6.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/issue_template.md +3 -0
- data/.hound.yml +27 -32
- data/.travis.yml +23 -2
- data/Appraisals +17 -0
- data/Gemfile +9 -7
- data/NEWS +21 -0
- data/README.md +27 -37
- data/Rakefile +29 -21
- data/UPGRADING +3 -3
- data/features/basic_integration.feature +4 -0
- data/features/migration.feature +10 -51
- data/features/step_definitions/attachment_steps.rb +12 -12
- data/features/step_definitions/html_steps.rb +5 -5
- data/features/step_definitions/rails_steps.rb +29 -9
- data/features/step_definitions/s3_steps.rb +3 -3
- data/features/step_definitions/web_steps.rb +5 -6
- data/features/support/env.rb +4 -4
- data/features/support/fakeweb.rb +3 -5
- data/features/support/file_helpers.rb +2 -2
- data/features/support/paths.rb +4 -4
- data/features/support/rails.rb +7 -7
- data/features/support/selectors.rb +1 -1
- data/gemfiles/4.2.gemfile +7 -4
- data/gemfiles/5.0.gemfile +7 -4
- data/gemfiles/5.1.gemfile +20 -0
- data/gemfiles/5.2.gemfile +20 -0
- data/gemfiles/6.0.gemfile +20 -0
- data/lib/generators/paperclip/paperclip_generator.rb +6 -8
- data/lib/paperclip/attachment.rb +102 -104
- data/lib/paperclip/attachment_registry.rb +2 -2
- data/lib/paperclip/file_command_content_type_detector.rb +1 -3
- data/lib/paperclip/filename_cleaner.rb +0 -1
- data/lib/paperclip/geometry.rb +18 -19
- data/lib/paperclip/geometry_detector_factory.rb +13 -16
- data/lib/paperclip/geometry_parser_factory.rb +5 -5
- data/lib/paperclip/glue.rb +3 -3
- data/lib/paperclip/has_attached_file.rb +5 -4
- data/lib/paperclip/helpers.rb +3 -3
- data/lib/paperclip/interpolations.rb +42 -38
- data/lib/paperclip/io_adapters/abstract_adapter.rb +16 -14
- data/lib/paperclip/io_adapters/attachment_adapter.rb +12 -6
- data/lib/paperclip/io_adapters/data_uri_adapter.rb +1 -1
- data/lib/paperclip/io_adapters/file_adapter.rb +1 -3
- data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +3 -3
- data/lib/paperclip/io_adapters/identity_adapter.rb +1 -2
- data/lib/paperclip/io_adapters/registry.rb +1 -1
- data/lib/paperclip/io_adapters/stringio_adapter.rb +1 -1
- data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +6 -8
- data/lib/paperclip/io_adapters/uri_adapter.rb +9 -7
- data/lib/paperclip/logger.rb +1 -1
- data/lib/paperclip/matchers/have_attached_file_matcher.rb +4 -4
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +19 -18
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +4 -4
- data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +11 -10
- data/lib/paperclip/matchers.rb +4 -4
- data/lib/paperclip/media_type_spoof_detector.rb +13 -13
- data/lib/paperclip/missing_attachment_styles.rb +11 -6
- data/lib/paperclip/processor.rb +13 -6
- data/lib/paperclip/processor_helpers.rb +3 -1
- data/lib/paperclip/rails_environment.rb +1 -5
- data/lib/paperclip/railtie.rb +5 -5
- data/lib/paperclip/schema.rb +18 -14
- data/lib/paperclip/storage/filesystem.rb +5 -7
- data/lib/paperclip/storage/fog.rb +36 -32
- data/lib/paperclip/storage/s3.rb +67 -75
- data/lib/paperclip/style.rb +3 -6
- data/lib/paperclip/tempfile.rb +4 -5
- data/lib/paperclip/tempfile_factory.rb +0 -1
- data/lib/paperclip/thumbnail.rb +11 -11
- data/lib/paperclip/url_generator.rb +5 -12
- data/lib/paperclip/validators/attachment_content_type_validator.rb +3 -3
- data/lib/paperclip/validators/attachment_file_name_validator.rb +5 -10
- data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +1 -2
- data/lib/paperclip/validators/attachment_presence_validator.rb +3 -5
- data/lib/paperclip/validators/attachment_size_validator.rb +8 -8
- data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +3 -1
- data/lib/paperclip/validators.rb +12 -13
- data/lib/paperclip/version.rb +1 -3
- data/lib/paperclip.rb +49 -48
- data/lib/tasks/paperclip.rake +23 -24
- data/paperclip.gemspec +29 -33
- data/shoulda_macros/paperclip.rb +16 -16
- data/spec/paperclip/attachment_definitions_spec.rb +5 -5
- data/spec/paperclip/attachment_processing_spec.rb +22 -23
- data/spec/paperclip/attachment_registry_spec.rb +15 -15
- data/spec/paperclip/attachment_spec.rb +238 -196
- data/spec/paperclip/content_type_detector_spec.rb +11 -12
- data/spec/paperclip/file_command_content_type_detector_spec.rb +10 -10
- data/spec/paperclip/filename_cleaner_spec.rb +3 -4
- data/spec/paperclip/geometry_detector_spec.rb +7 -8
- data/spec/paperclip/geometry_parser_spec.rb +31 -31
- data/spec/paperclip/geometry_spec.rb +24 -24
- data/spec/paperclip/glue_spec.rb +3 -5
- data/spec/paperclip/has_attached_file_spec.rb +46 -126
- data/spec/paperclip/integration_spec.rb +111 -77
- data/spec/paperclip/interpolations_spec.rb +101 -93
- data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +41 -13
- data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +8 -10
- data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +13 -14
- data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +4 -4
- data/spec/paperclip/io_adapters/file_adapter_spec.rb +12 -12
- data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +42 -26
- data/spec/paperclip/io_adapters/identity_adapter_spec.rb +1 -1
- data/spec/paperclip/io_adapters/nil_adapter_spec.rb +2 -2
- data/spec/paperclip/io_adapters/registry_spec.rb +4 -4
- data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +10 -10
- data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +6 -6
- data/spec/paperclip/io_adapters/uri_adapter_spec.rb +80 -31
- data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +3 -3
- data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +4 -5
- data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +4 -4
- data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +4 -4
- data/spec/paperclip/media_type_spoof_detector_spec.rb +50 -24
- data/spec/paperclip/meta_class_spec.rb +3 -3
- data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +28 -24
- data/spec/paperclip/paperclip_spec.rb +15 -11
- data/spec/paperclip/plural_cache_spec.rb +8 -8
- data/spec/paperclip/processor_helpers_spec.rb +35 -35
- data/spec/paperclip/processor_spec.rb +8 -8
- data/spec/paperclip/rails_environment_spec.rb +7 -10
- data/spec/paperclip/rake_spec.rb +39 -39
- data/spec/paperclip/schema_spec.rb +57 -53
- data/spec/paperclip/storage/filesystem_spec.rb +6 -6
- data/spec/paperclip/storage/fog_spec.rb +76 -82
- data/spec/paperclip/storage/s3_live_spec.rb +22 -22
- data/spec/paperclip/storage/s3_spec.rb +585 -583
- data/spec/paperclip/style_spec.rb +67 -71
- data/spec/paperclip/tempfile_factory_spec.rb +5 -5
- data/spec/paperclip/thumbnail_spec.rb +68 -67
- data/spec/paperclip/url_generator_spec.rb +18 -29
- data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +27 -27
- data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +15 -16
- data/spec/paperclip/validators/attachment_presence_validator_spec.rb +5 -5
- data/spec/paperclip/validators/attachment_size_validator_spec.rb +21 -21
- data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +9 -13
- data/spec/paperclip/validators_spec.rb +40 -40
- data/spec/spec_helper.rb +21 -23
- data/spec/support/assertions.rb +8 -6
- data/spec/support/fake_model.rb +1 -2
- data/spec/support/fake_rails.rb +1 -1
- data/spec/support/matchers/exist.rb +1 -1
- data/spec/support/matchers/have_column.rb +1 -1
- data/spec/support/mock_url_generator_builder.rb +2 -3
- data/spec/support/model_reconstruction.rb +16 -12
- data/spec/support/reporting.rb +1 -1
- data/spec/support/test_data.rb +2 -2
- metadata +49 -105
- data/lib/kt-paperclip.rb +0 -1
- data/spec/support/conditional_filter_helper.rb +0 -5
data/lib/paperclip/storage/s3.rb
CHANGED
@@ -3,8 +3,8 @@ module Paperclip
|
|
3
3
|
# Amazon's S3 file hosting service is a scalable, easy place to store files for
|
4
4
|
# distribution. You can find out more about it at http://aws.amazon.com/s3
|
5
5
|
#
|
6
|
-
# To use Paperclip with S3, include the +aws-sdk+ gem in your Gemfile:
|
7
|
-
# gem 'aws-sdk'
|
6
|
+
# To use Paperclip with S3, include the +aws-sdk-s3+ gem in your Gemfile:
|
7
|
+
# gem 'aws-sdk-s3'
|
8
8
|
# There are a few S3-specific options for has_attached_file:
|
9
9
|
# * +s3_credentials+: Takes a path, a File, a Hash or a Proc. The path (or File) must point
|
10
10
|
# to a YAML file containing the +access_key_id+ and +secret_access_key+ that Amazon
|
@@ -96,7 +96,7 @@ module Paperclip
|
|
96
96
|
# separate parts of your file name.
|
97
97
|
# * +s3_host_name+: If you are using your bucket in Tokyo region
|
98
98
|
# etc, write host_name (e.g., 's3-ap-northeast-1.amazonaws.com').
|
99
|
-
# * +s3_region+: For aws-sdk
|
99
|
+
# * +s3_region+: For aws-sdk-s3, s3_region is required.
|
100
100
|
# * +s3_metadata+: These key/value pairs will be stored with the
|
101
101
|
# object. This option works by prefixing each key with
|
102
102
|
# "x-amz-meta-" before sending it as a header on the object
|
@@ -118,25 +118,21 @@ module Paperclip
|
|
118
118
|
# :s3_storage_class => :REDUCED_REDUNDANCY
|
119
119
|
#
|
120
120
|
# Other storage classes, such as <tt>:STANDARD_IA</tt>, are also available—see the
|
121
|
-
# documentation for the <tt>aws-sdk</tt> gem for the full list.
|
121
|
+
# documentation for the <tt>aws-sdk-s3</tt> gem for the full list.
|
122
122
|
|
123
123
|
module S3
|
124
|
-
def self.extended
|
124
|
+
def self.extended(base)
|
125
125
|
begin
|
126
|
-
require
|
126
|
+
require "aws-sdk-s3"
|
127
127
|
rescue LoadError => e
|
128
|
-
e.message << " (You may need to install the aws-sdk gem)"
|
128
|
+
e.message << " (You may need to install the aws-sdk-s3 gem)"
|
129
129
|
raise e
|
130
130
|
end
|
131
|
-
if Gem::Version.new(Aws::VERSION) >= Gem::Version.new(2) &&
|
132
|
-
Gem::Version.new(Aws::VERSION) <= Gem::Version.new("2.0.33")
|
133
|
-
raise LoadError, "paperclip does not support aws-sdk versions 2.0.0 - 2.0.33. Please upgrade aws-sdk to a newer version."
|
134
|
-
end
|
135
131
|
|
136
132
|
base.instance_eval do
|
137
|
-
@s3_options = @options[:s3_options]
|
133
|
+
@s3_options = @options[:s3_options] || {}
|
138
134
|
@s3_permissions = set_permissions(@options[:s3_permissions])
|
139
|
-
@s3_protocol = @options[:s3_protocol] || ""
|
135
|
+
@s3_protocol = @options[:s3_protocol] || ""
|
140
136
|
@s3_metadata = @options[:s3_metadata] || {}
|
141
137
|
@s3_headers = {}
|
142
138
|
merge_s3_headers(@options[:s3_headers], @s3_headers, @s3_metadata)
|
@@ -144,47 +140,46 @@ module Paperclip
|
|
144
140
|
@s3_storage_class = set_storage_class(@options[:s3_storage_class])
|
145
141
|
|
146
142
|
@s3_server_side_encryption = "AES256"
|
147
|
-
if @options[:s3_server_side_encryption].blank?
|
148
|
-
|
149
|
-
end
|
150
|
-
if @s3_server_side_encryption
|
151
|
-
@s3_server_side_encryption = @options[:s3_server_side_encryption]
|
152
|
-
end
|
143
|
+
@s3_server_side_encryption = false if @options[:s3_server_side_encryption].blank?
|
144
|
+
@s3_server_side_encryption = @options[:s3_server_side_encryption] if @s3_server_side_encryption
|
153
145
|
|
154
|
-
unless @options[:url].to_s.match(/\A:s3.*url\z/) || @options[:url] == ":asset_host"
|
155
|
-
@options[:path] = path_option.gsub(/:url/, @options[:url]).sub(/\A:rails_root\/public\/system/, ""
|
156
|
-
@options[:url] = ":s3_path_url"
|
146
|
+
unless @options[:url].to_s.match(/\A:s3.*url\z/) || @options[:url] == ":asset_host"
|
147
|
+
@options[:path] = path_option.gsub(/:url/, @options[:url]).sub(/\A:rails_root\/public\/system/, "")
|
148
|
+
@options[:url] = ":s3_path_url"
|
157
149
|
end
|
158
150
|
@options[:url] = @options[:url].inspect if @options[:url].is_a?(Symbol)
|
159
151
|
|
160
152
|
@http_proxy = @options[:http_proxy] || nil
|
161
153
|
|
162
|
-
if @options.has_key?(:use_accelerate_endpoint) &&
|
163
|
-
Gem::Version.new(Aws::VERSION) < Gem::Version.new("2.3.0")
|
164
|
-
raise LoadError, ":use_accelerate_endpoint is only available from aws-sdk version 2.3.0. Please upgrade aws-sdk to a newer version."
|
165
|
-
end
|
166
|
-
|
167
154
|
@use_accelerate_endpoint = @options[:use_accelerate_endpoint]
|
168
155
|
end
|
169
156
|
|
170
|
-
Paperclip.
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
157
|
+
unless Paperclip::Interpolations.respond_to? :s3_alias_url
|
158
|
+
Paperclip.interpolates(:s3_alias_url) do |attachment, style|
|
159
|
+
protocol = attachment.s3_protocol(style, true)
|
160
|
+
host = attachment.s3_host_alias
|
161
|
+
path = attachment.path(style).
|
162
|
+
split("/")[attachment.s3_prefixes_in_alias..-1].
|
163
|
+
join("/").
|
164
|
+
sub(%r{\A/}, "")
|
165
|
+
"#{protocol}//#{host}/#{path}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
unless Paperclip::Interpolations.respond_to? :s3_path_url
|
169
|
+
Paperclip.interpolates(:s3_path_url) do |attachment, style|
|
170
|
+
"#{attachment.s3_protocol(style, true)}//#{attachment.s3_host_name}/#{attachment.bucket_name}/#{attachment.path(style).sub(%r{\A/}, '')}"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
unless Paperclip::Interpolations.respond_to? :s3_domain_url
|
174
|
+
Paperclip.interpolates(:s3_domain_url) do |attachment, style|
|
175
|
+
"#{attachment.s3_protocol(style, true)}//#{attachment.bucket_name}.#{attachment.s3_host_name}/#{attachment.path(style).sub(%r{\A/}, '')}"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
unless Paperclip::Interpolations.respond_to? :asset_host
|
179
|
+
Paperclip.interpolates(:asset_host) do |attachment, style|
|
180
|
+
attachment.path(style).sub(%r{\A/}, "").to_s
|
181
|
+
end
|
182
|
+
end
|
188
183
|
end
|
189
184
|
|
190
185
|
def expiring_url(time = 3600, style_name = default_style)
|
@@ -192,7 +187,7 @@ module Paperclip
|
|
192
187
|
base_options = { expires_in: time }
|
193
188
|
s3_object(style_name).presigned_url(
|
194
189
|
:get,
|
195
|
-
base_options.merge(s3_url_options)
|
190
|
+
base_options.merge(s3_url_options)
|
196
191
|
).to_s
|
197
192
|
else
|
198
193
|
url(style_name)
|
@@ -207,7 +202,7 @@ module Paperclip
|
|
207
202
|
host_name = @options[:s3_host_name]
|
208
203
|
host_name = host_name.call(self) if host_name.is_a?(Proc)
|
209
204
|
|
210
|
-
host_name || s3_credentials[:s3_host_name] || "s3.amazonaws.com"
|
205
|
+
host_name || s3_credentials[:s3_host_name] || "s3.amazonaws.com"
|
211
206
|
end
|
212
207
|
|
213
208
|
def s3_region
|
@@ -236,7 +231,7 @@ module Paperclip
|
|
236
231
|
def bucket_name
|
237
232
|
@bucket = @options[:bucket] || s3_credentials[:bucket]
|
238
233
|
@bucket = @bucket.call(self) if @bucket.respond_to?(:call)
|
239
|
-
@bucket
|
234
|
+
@bucket || raise(ArgumentError, "missing required :bucket option")
|
240
235
|
end
|
241
236
|
|
242
237
|
def s3_interface
|
@@ -245,7 +240,7 @@ module Paperclip
|
|
245
240
|
|
246
241
|
if using_http_proxy?
|
247
242
|
|
248
|
-
proxy_opts = { :
|
243
|
+
proxy_opts = { host: http_proxy_host }
|
249
244
|
proxy_opts[:port] = http_proxy_port if http_proxy_port
|
250
245
|
if http_proxy_user
|
251
246
|
userinfo = http_proxy_user.to_s
|
@@ -275,10 +270,10 @@ module Paperclip
|
|
275
270
|
end
|
276
271
|
|
277
272
|
def style_name_as_path(style_name)
|
278
|
-
path(style_name).sub(%r{\A/},
|
273
|
+
path(style_name).sub(%r{\A/}, "")
|
279
274
|
end
|
280
275
|
|
281
|
-
def s3_object
|
276
|
+
def s3_object(style_name = default_style)
|
282
277
|
s3_bucket.object style_name_as_path(style_name)
|
283
278
|
end
|
284
279
|
|
@@ -306,17 +301,17 @@ module Paperclip
|
|
306
301
|
using_http_proxy? ? @http_proxy[:password] : nil
|
307
302
|
end
|
308
303
|
|
309
|
-
def set_permissions
|
310
|
-
permissions = { :
|
311
|
-
permissions.merge :
|
304
|
+
def set_permissions(permissions)
|
305
|
+
permissions = { default: permissions } unless permissions.respond_to?(:merge)
|
306
|
+
permissions.merge default: (permissions[:default] || :"public-read")
|
312
307
|
end
|
313
308
|
|
314
309
|
def set_storage_class(storage_class)
|
315
|
-
storage_class = {:
|
310
|
+
storage_class = { default: storage_class } unless storage_class.respond_to?(:merge)
|
316
311
|
storage_class
|
317
312
|
end
|
318
313
|
|
319
|
-
def parse_credentials
|
314
|
+
def parse_credentials(creds)
|
320
315
|
creds = creds.respond_to?(:call) ? creds.call(self) : creds
|
321
316
|
creds = find_credentials(creds).stringify_keys
|
322
317
|
(creds[RailsEnvironment.get] || creds).symbolize_keys
|
@@ -359,26 +354,26 @@ module Paperclip
|
|
359
354
|
|
360
355
|
def flush_writes #:nodoc:
|
361
356
|
@queued_for_write.each do |style, file|
|
362
|
-
|
357
|
+
retries = 0
|
363
358
|
begin
|
364
359
|
log("saving #{path(style)}")
|
365
360
|
write_options = {
|
366
|
-
:
|
367
|
-
:
|
361
|
+
content_type: file.content_type,
|
362
|
+
acl: s3_permissions(style)
|
368
363
|
}
|
369
364
|
|
370
365
|
# add storage class for this style if defined
|
371
366
|
storage_class = s3_storage_class(style)
|
372
|
-
write_options.merge!(:
|
367
|
+
write_options.merge!(storage_class: storage_class) if storage_class
|
373
368
|
|
374
|
-
if @s3_server_side_encryption
|
375
|
-
write_options[:server_side_encryption] = @s3_server_side_encryption
|
376
|
-
end
|
369
|
+
write_options[:server_side_encryption] = @s3_server_side_encryption if @s3_server_side_encryption
|
377
370
|
|
378
371
|
style_specific_options = styles[style]
|
379
372
|
|
380
373
|
if style_specific_options
|
381
|
-
|
374
|
+
if style_specific_options[:s3_headers]
|
375
|
+
merge_s3_headers(style_specific_options[:s3_headers], @s3_headers, @s3_metadata)
|
376
|
+
end
|
382
377
|
@s3_metadata.merge!(style_specific_options[:s3_metadata]) if style_specific_options[:s3_metadata]
|
383
378
|
end
|
384
379
|
|
@@ -392,7 +387,7 @@ module Paperclip
|
|
392
387
|
rescue ::Aws::S3::Errors::SlowDown
|
393
388
|
retries += 1
|
394
389
|
if retries <= 5
|
395
|
-
sleep((2
|
390
|
+
sleep((2**retries) * 0.5)
|
396
391
|
retry
|
397
392
|
else
|
398
393
|
raise
|
@@ -421,11 +416,7 @@ module Paperclip
|
|
421
416
|
|
422
417
|
def copy_to_local_file(style, local_dest_path)
|
423
418
|
log("copying #{path(style)} to local file #{local_dest_path}")
|
424
|
-
|
425
|
-
s3_object(style).get do |chunk|
|
426
|
-
local_file.write(chunk)
|
427
|
-
end
|
428
|
-
end
|
419
|
+
s3_object(style).download_file(local_dest_path)
|
429
420
|
rescue Aws::Errors::ServiceError => e
|
430
421
|
warn("#{e} - cannot copy #{path(style)} to local file #{local_dest_path}")
|
431
422
|
false
|
@@ -433,12 +424,12 @@ module Paperclip
|
|
433
424
|
|
434
425
|
private
|
435
426
|
|
436
|
-
def find_credentials
|
427
|
+
def find_credentials(creds)
|
437
428
|
case creds
|
438
429
|
when File
|
439
|
-
YAML::
|
430
|
+
YAML::safe_load(ERB.new(File.read(creds.path)).result)
|
440
431
|
when String, Pathname
|
441
|
-
YAML::
|
432
|
+
YAML::safe_load(ERB.new(File.read(creds)).result)
|
442
433
|
when Hash
|
443
434
|
creds
|
444
435
|
when NilClass
|
@@ -454,13 +445,14 @@ module Paperclip
|
|
454
445
|
|
455
446
|
def merge_s3_headers(http_headers, s3_headers, s3_metadata)
|
456
447
|
return if http_headers.nil?
|
448
|
+
|
457
449
|
http_headers = http_headers.call(instance) if http_headers.respond_to?(:call)
|
458
|
-
http_headers.inject({}) do |
|
450
|
+
http_headers.inject({}) do |_headers, (name, value)|
|
459
451
|
case name.to_s
|
460
452
|
when /\Ax-amz-meta-(.*)/i
|
461
453
|
s3_metadata[$1.downcase] = value
|
462
454
|
else
|
463
|
-
s3_headers[name.to_s.downcase.sub(/\Ax-amz-/,
|
455
|
+
s3_headers[name.to_s.downcase.sub(/\Ax-amz-/, "").tr("-", "_").to_sym] = value
|
464
456
|
end
|
465
457
|
end
|
466
458
|
end
|
data/lib/paperclip/style.rb
CHANGED
@@ -1,17 +1,15 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
module Paperclip
|
3
2
|
# The Style class holds the definition of a thumbnail style, applying
|
4
3
|
# whatever processing is required to normalize the definition and delaying
|
5
4
|
# the evaluation of block parameters until useful context is available.
|
6
5
|
|
7
6
|
class Style
|
8
|
-
|
9
7
|
attr_reader :name, :attachment, :format
|
10
8
|
|
11
9
|
# Creates a Style object. +name+ is the name of the attachment,
|
12
10
|
# +definition+ is the style definition from has_attached_file, which
|
13
11
|
# can be string, array or hash
|
14
|
-
def initialize
|
12
|
+
def initialize(name, definition, attachment)
|
15
13
|
@name = name
|
16
14
|
@attachment = attachment
|
17
15
|
if definition.is_a? Hash
|
@@ -71,8 +69,8 @@ module Paperclip
|
|
71
69
|
# Arguments other than the standard geometry, format etc are just passed through from
|
72
70
|
# initialization and any procs are called here, just before post-processing.
|
73
71
|
def processor_options
|
74
|
-
args = {:
|
75
|
-
@other_args.each do |k,v|
|
72
|
+
args = { style: name }
|
73
|
+
@other_args.each do |k, v|
|
76
74
|
args[k] = v.respond_to?(:call) ? v.call(attachment) : v
|
77
75
|
end
|
78
76
|
[:processors, :geometry, :format, :whiny, :convert_options, :source_file_options].each do |k|
|
@@ -104,6 +102,5 @@ module Paperclip
|
|
104
102
|
base = attachment.options[:default_format]
|
105
103
|
base.respond_to?(:call) ? base.call(attachment, name) : base
|
106
104
|
end
|
107
|
-
|
108
105
|
end
|
109
106
|
end
|
data/lib/paperclip/tempfile.rb
CHANGED
@@ -12,7 +12,8 @@ module Paperclip
|
|
12
12
|
if RUBY_PLATFORM =~ /java/
|
13
13
|
case prefix_suffix
|
14
14
|
when String
|
15
|
-
prefix
|
15
|
+
prefix = prefix_suffix
|
16
|
+
suffix = ""
|
16
17
|
when Array
|
17
18
|
prefix, suffix = *prefix_suffix
|
18
19
|
else
|
@@ -32,12 +33,10 @@ module Paperclip
|
|
32
33
|
# for binary mode is ASCII-8BIT. This behavior is what's in CRuby, but not
|
33
34
|
# in JRuby
|
34
35
|
def binmode
|
35
|
-
set_encoding(
|
36
|
+
set_encoding("ASCII-8BIT")
|
36
37
|
super
|
37
38
|
end
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
41
|
-
if RUBY_PLATFORM =~ /java/
|
42
|
-
::Tempfile.send :include, Paperclip::TempfileEncoding
|
43
|
-
end
|
42
|
+
::Tempfile.include Paperclip::TempfileEncoding if RUBY_PLATFORM =~ /java/
|
data/lib/paperclip/thumbnail.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Paperclip
|
2
2
|
# Handles thumbnailing images that are uploaded.
|
3
3
|
class Thumbnail < Processor
|
4
|
-
|
5
4
|
attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options,
|
6
5
|
:source_file_options, :animated, :auto_orient, :frame_index
|
7
6
|
|
8
7
|
# List of formats that we need to preserve animation
|
9
|
-
ANIMATED_FORMATS = %w(gif)
|
10
|
-
MULTI_FRAME_FORMATS = %w(.mkv .avi .mp4 .mov .mpg .mpeg .gif)
|
8
|
+
ANIMATED_FORMATS = %w(gif).freeze
|
9
|
+
MULTI_FRAME_FORMATS = %w(.mkv .avi .mp4 .mov .mpg .mpeg .gif).freeze
|
11
10
|
|
12
11
|
# Creates a Thumbnail object set to work on the +file+ given. It
|
13
12
|
# will attempt to transform the image into one defined by +target_geometry+
|
@@ -31,7 +30,7 @@ module Paperclip
|
|
31
30
|
super
|
32
31
|
|
33
32
|
geometry = options[:geometry].to_s
|
34
|
-
@crop = geometry[-1,1] ==
|
33
|
+
@crop = geometry[-1, 1] == "#"
|
35
34
|
@target_geometry = options.fetch(:string_geometry_parser, Geometry).parse(geometry)
|
36
35
|
@current_geometry = options.fetch(:file_geometry_parser, Geometry).from_file(@file)
|
37
36
|
@source_file_options = options[:source_file_options]
|
@@ -40,9 +39,7 @@ module Paperclip
|
|
40
39
|
@format = options[:format]
|
41
40
|
@animated = options.fetch(:animated, true)
|
42
41
|
@auto_orient = options.fetch(:auto_orient, true)
|
43
|
-
if @auto_orient && @current_geometry.respond_to?(:auto_orient)
|
44
|
-
@current_geometry.auto_orient
|
45
|
-
end
|
42
|
+
@current_geometry.auto_orient if @auto_orient && @current_geometry.respond_to?(:auto_orient)
|
46
43
|
@source_file_options = @source_file_options.split(/\s+/) if @source_file_options.respond_to?(:split)
|
47
44
|
@convert_options = @convert_options.split(/\s+/) if @convert_options.respond_to?(:split)
|
48
45
|
|
@@ -82,10 +79,13 @@ module Paperclip
|
|
82
79
|
convert(
|
83
80
|
parameters,
|
84
81
|
source: "#{File.expand_path(src.path)}#{frame}",
|
85
|
-
dest: File.expand_path(dst.path)
|
82
|
+
dest: File.expand_path(dst.path)
|
86
83
|
)
|
87
84
|
rescue Terrapin::ExitStatusError => e
|
88
|
-
|
85
|
+
if @whiny
|
86
|
+
message = "There was an error processing the thumbnail for #{@basename}:\n" + e.message
|
87
|
+
raise Paperclip::Error, message
|
88
|
+
end
|
89
89
|
rescue Terrapin::CommandNotFoundError => e
|
90
90
|
raise Paperclip::Errors::CommandNotFoundError.new("Could not run the `convert` command. Please install ImageMagick.")
|
91
91
|
end
|
@@ -113,13 +113,13 @@ module Paperclip
|
|
113
113
|
end
|
114
114
|
|
115
115
|
def animated?
|
116
|
-
@animated && (ANIMATED_FORMATS.include?(@format.to_s) || @format.blank?)
|
116
|
+
@animated && (ANIMATED_FORMATS.include?(@format.to_s) || @format.blank?) && identified_as_animated?
|
117
117
|
end
|
118
118
|
|
119
119
|
# Return true if ImageMagick's +identify+ returns an animated format
|
120
120
|
def identified_as_animated?
|
121
121
|
if @identified_as_animated.nil?
|
122
|
-
@identified_as_animated = ANIMATED_FORMATS.include? identify("-format %m :file", :
|
122
|
+
@identified_as_animated = ANIMATED_FORMATS.include? identify("-format %m :file", file: "#{@file.path}[0]").to_s.downcase.strip
|
123
123
|
end
|
124
124
|
@identified_as_animated
|
125
125
|
rescue Terrapin::ExitStatusError => e
|
@@ -1,15 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "uri"
|
2
|
+
require "active_support/core_ext/module/delegation"
|
3
3
|
|
4
4
|
module Paperclip
|
5
5
|
class UrlGenerator
|
6
|
-
class << self
|
7
|
-
def encoder
|
8
|
-
@encoder ||= URI::RFC2396_Parser.new
|
9
|
-
end
|
10
|
-
delegate :escape, :unescape, to: :encoder
|
11
|
-
end
|
12
|
-
|
13
6
|
def initialize(attachment)
|
14
7
|
@attachment = attachment
|
15
8
|
end
|
@@ -49,8 +42,8 @@ module Paperclip
|
|
49
42
|
|
50
43
|
def timestamp_as_needed(url, options)
|
51
44
|
if options[:timestamp] && timestamp_possible?
|
52
|
-
delimiter_char = url.match(/\?.+=/) ?
|
53
|
-
"#{url}#{delimiter_char}#{@attachment.updated_at
|
45
|
+
delimiter_char = url.match(/\?.+=/) ? "&" : "?"
|
46
|
+
"#{url}#{delimiter_char}#{@attachment.updated_at}"
|
54
47
|
else
|
55
48
|
url
|
56
49
|
end
|
@@ -72,7 +65,7 @@ module Paperclip
|
|
72
65
|
if url.respond_to?(:escape)
|
73
66
|
url.escape
|
74
67
|
else
|
75
|
-
|
68
|
+
URI.escape(url).gsub(escape_regex) { |m| "%#{m.ord.to_s(16).upcase}" }
|
76
69
|
end
|
77
70
|
end
|
78
71
|
|
@@ -2,7 +2,7 @@ module Paperclip
|
|
2
2
|
module Validators
|
3
3
|
class AttachmentContentTypeValidator < ActiveModel::EachValidator
|
4
4
|
def initialize(options)
|
5
|
-
options[:allow_nil] = true unless options.
|
5
|
+
options[:allow_nil] = true unless options.key?(:allow_nil)
|
6
6
|
super
|
7
7
|
end
|
8
8
|
|
@@ -40,7 +40,7 @@ module Paperclip
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def mark_invalid(record, attribute, types)
|
43
|
-
record.errors.add attribute, :invalid, options.merge(:
|
43
|
+
record.errors.add attribute, :invalid, options.merge(types: types.join(", "))
|
44
44
|
end
|
45
45
|
|
46
46
|
def allowed_types
|
@@ -52,7 +52,7 @@ module Paperclip
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def check_validity!
|
55
|
-
unless options.
|
55
|
+
unless options.key?(:content_type) || options.key?(:not)
|
56
56
|
raise ArgumentError, "You must pass in either :content_type or :not to the validator"
|
57
57
|
end
|
58
58
|
end
|
@@ -2,7 +2,7 @@ module Paperclip
|
|
2
2
|
module Validators
|
3
3
|
class AttachmentFileNameValidator < ActiveModel::EachValidator
|
4
4
|
def initialize(options)
|
5
|
-
options[:allow_nil] = true unless options.
|
5
|
+
options[:allow_nil] = true unless options.key?(:allow_nil)
|
6
6
|
super
|
7
7
|
end
|
8
8
|
|
@@ -28,19 +28,15 @@ module Paperclip
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def validate_whitelist(record, attribute, value)
|
31
|
-
if allowed.present? && allowed.none? { |type| type === value }
|
32
|
-
mark_invalid record, attribute, allowed
|
33
|
-
end
|
31
|
+
mark_invalid record, attribute, allowed if allowed.present? && allowed.none? { |type| type === value }
|
34
32
|
end
|
35
33
|
|
36
34
|
def validate_blacklist(record, attribute, value)
|
37
|
-
if forbidden.present? && forbidden.any? { |type| type === value }
|
38
|
-
mark_invalid record, attribute, forbidden
|
39
|
-
end
|
35
|
+
mark_invalid record, attribute, forbidden if forbidden.present? && forbidden.any? { |type| type === value }
|
40
36
|
end
|
41
37
|
|
42
38
|
def mark_invalid(record, attribute, patterns)
|
43
|
-
record.errors.add attribute, :invalid, options.merge(:
|
39
|
+
record.errors.add attribute, :invalid, options.merge(names: patterns.join(", "))
|
44
40
|
end
|
45
41
|
|
46
42
|
def allowed
|
@@ -52,7 +48,7 @@ module Paperclip
|
|
52
48
|
end
|
53
49
|
|
54
50
|
def check_validity!
|
55
|
-
unless options.
|
51
|
+
unless options.key?(:matches) || options.key?(:not)
|
56
52
|
raise ArgumentError, "You must pass in either :matches or :not to the validator"
|
57
53
|
end
|
58
54
|
end
|
@@ -77,4 +73,3 @@ module Paperclip
|
|
77
73
|
end
|
78
74
|
end
|
79
75
|
end
|
80
|
-
|
@@ -1,12 +1,10 @@
|
|
1
|
-
require
|
1
|
+
require "active_model/validations/presence"
|
2
2
|
|
3
3
|
module Paperclip
|
4
4
|
module Validators
|
5
5
|
class AttachmentPresenceValidator < ActiveModel::EachValidator
|
6
|
-
def validate_each(record, attribute,
|
7
|
-
if record.send("#{attribute}_file_name").blank?
|
8
|
-
record.errors.add(attribute, :blank, options)
|
9
|
-
end
|
6
|
+
def validate_each(record, attribute, _value)
|
7
|
+
record.errors.add(attribute, :blank, options) if record.send("#{attribute}_file_name").blank?
|
10
8
|
end
|
11
9
|
|
12
10
|
def self.helper_method_name
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require
|
1
|
+
require "active_model/validations/numericality"
|
2
2
|
|
3
3
|
module Paperclip
|
4
4
|
module Validators
|
5
5
|
class AttachmentSizeValidator < ActiveModel::Validations::NumericalityValidator
|
6
|
-
AVAILABLE_CHECKS = [:less_than, :less_than_or_equal_to, :greater_than, :greater_than_or_equal_to]
|
6
|
+
AVAILABLE_CHECKS = [:less_than, :less_than_or_equal_to, :greater_than, :greater_than_or_equal_to].freeze
|
7
7
|
|
8
8
|
def initialize(options)
|
9
9
|
extract_options(options)
|
@@ -26,12 +26,12 @@ module Paperclip
|
|
26
26
|
|
27
27
|
unless value.send(CHECKS[option], option_value)
|
28
28
|
error_message_key = options[:in] ? :in_between : option
|
29
|
-
[
|
29
|
+
[attr_name, base_attr_name].each do |error_attr_name|
|
30
30
|
record.errors.add(error_attr_name, error_message_key, filtered_options(value).merge(
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
min: min_value_in_human_size(record),
|
32
|
+
max: max_value_in_human_size(record),
|
33
|
+
count: human_size(option_value)
|
34
|
+
))
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -39,7 +39,7 @@ module Paperclip
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def check_validity!
|
42
|
-
unless (AVAILABLE_CHECKS + [:in]).any? { |argument| options.
|
42
|
+
unless (AVAILABLE_CHECKS + [:in]).any? { |argument| options.key?(argument) }
|
43
43
|
raise ArgumentError, "You must pass either :less_than, :greater_than, or :in to the validator"
|
44
44
|
end
|
45
45
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_model/validations/presence"
|
2
2
|
|
3
3
|
module Paperclip
|
4
4
|
module Validators
|
@@ -8,6 +8,8 @@ module Paperclip
|
|
8
8
|
if Paperclip::MediaTypeSpoofDetector.using(adapter, value.original_filename, value.content_type).spoofed?
|
9
9
|
record.errors.add(attribute, :spoofed_media_type)
|
10
10
|
end
|
11
|
+
|
12
|
+
adapter.tempfile.close(true) if adapter.tempfile
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|