paperclip 4.2.2 → 5.2.1
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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +17 -0
- data/.hound.yml +1055 -0
- data/.rubocop.yml +1 -0
- data/.travis.yml +17 -15
- data/Appraisals +4 -16
- data/CONTRIBUTING.md +19 -8
- data/Gemfile +5 -9
- data/LICENSE +1 -1
- data/NEWS +148 -31
- data/README.md +327 -191
- data/RELEASING.md +17 -0
- data/Rakefile +2 -2
- data/UPGRADING +12 -9
- data/features/basic_integration.feature +10 -6
- data/features/migration.feature +0 -24
- data/features/step_definitions/attachment_steps.rb +33 -27
- data/features/step_definitions/html_steps.rb +2 -2
- data/features/step_definitions/rails_steps.rb +39 -38
- data/features/step_definitions/s3_steps.rb +2 -2
- data/features/step_definitions/web_steps.rb +1 -103
- data/features/support/env.rb +1 -0
- data/features/support/file_helpers.rb +2 -2
- data/features/support/paths.rb +1 -1
- data/features/support/rails.rb +0 -24
- data/gemfiles/4.2.gemfile +6 -8
- data/gemfiles/5.0.gemfile +17 -0
- data/lib/paperclip/attachment.rb +32 -20
- data/lib/paperclip/attachment_registry.rb +3 -2
- data/lib/paperclip/callbacks.rb +8 -6
- data/lib/paperclip/content_type_detector.rb +27 -11
- data/lib/paperclip/errors.rb +3 -1
- data/lib/paperclip/file_command_content_type_detector.rb +6 -8
- data/lib/paperclip/geometry_parser_factory.rb +1 -1
- data/lib/paperclip/glue.rb +1 -1
- data/lib/paperclip/has_attached_file.rb +9 -2
- data/lib/paperclip/helpers.rb +14 -10
- data/lib/paperclip/interpolations/plural_cache.rb +6 -5
- data/lib/paperclip/interpolations.rb +19 -14
- data/lib/paperclip/io_adapters/abstract_adapter.rb +26 -3
- data/lib/paperclip/io_adapters/attachment_adapter.rb +10 -5
- data/lib/paperclip/io_adapters/data_uri_adapter.rb +8 -8
- data/lib/paperclip/io_adapters/empty_string_adapter.rb +5 -4
- data/lib/paperclip/io_adapters/file_adapter.rb +12 -6
- data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +7 -7
- data/lib/paperclip/io_adapters/identity_adapter.rb +12 -6
- data/lib/paperclip/io_adapters/nil_adapter.rb +8 -5
- data/lib/paperclip/io_adapters/registry.rb +6 -2
- data/lib/paperclip/io_adapters/stringio_adapter.rb +9 -6
- data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +10 -6
- data/lib/paperclip/io_adapters/uri_adapter.rb +41 -19
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +4 -4
- data/lib/paperclip/media_type_spoof_detector.rb +2 -2
- data/lib/paperclip/processor.rb +5 -4
- data/lib/paperclip/rails_environment.rb +25 -0
- data/lib/paperclip/schema.rb +3 -9
- data/lib/paperclip/storage/filesystem.rb +13 -2
- data/lib/paperclip/storage/fog.rb +30 -18
- data/lib/paperclip/storage/s3.rb +92 -65
- data/lib/paperclip/thumbnail.rb +16 -7
- data/lib/paperclip/url_generator.rb +16 -13
- data/lib/paperclip/validators/attachment_size_validator.rb +1 -7
- data/lib/paperclip/validators.rb +1 -1
- data/lib/paperclip/version.rb +3 -1
- data/lib/paperclip.rb +25 -12
- data/lib/tasks/paperclip.rake +33 -3
- data/paperclip.gemspec +18 -15
- data/spec/paperclip/attachment_definitions_spec.rb +1 -1
- data/spec/paperclip/attachment_processing_spec.rb +2 -4
- data/spec/paperclip/attachment_registry_spec.rb +84 -13
- data/spec/paperclip/attachment_spec.rb +130 -39
- data/spec/paperclip/content_type_detector_spec.rb +8 -1
- data/spec/paperclip/file_command_content_type_detector_spec.rb +0 -1
- data/spec/paperclip/geometry_spec.rb +1 -1
- data/spec/paperclip/glue_spec.rb +44 -0
- data/spec/paperclip/has_attached_file_spec.rb +24 -8
- data/spec/paperclip/integration_spec.rb +4 -3
- data/spec/paperclip/interpolations_spec.rb +16 -13
- data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +47 -23
- data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +6 -3
- data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +7 -1
- data/spec/paperclip/io_adapters/file_adapter_spec.rb +6 -3
- data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +26 -6
- data/spec/paperclip/io_adapters/identity_adapter_spec.rb +1 -1
- data/spec/paperclip/io_adapters/registry_spec.rb +2 -2
- data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +5 -1
- data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +5 -5
- data/spec/paperclip/io_adapters/uri_adapter_spec.rb +77 -7
- data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +10 -0
- data/spec/paperclip/media_type_spoof_detector_spec.rb +34 -11
- data/spec/paperclip/paperclip_spec.rb +4 -29
- data/spec/paperclip/plural_cache_spec.rb +17 -16
- data/spec/paperclip/rails_environment_spec.rb +33 -0
- data/spec/paperclip/storage/fog_spec.rb +58 -3
- data/spec/paperclip/storage/s3_live_spec.rb +20 -14
- data/spec/paperclip/storage/s3_spec.rb +398 -213
- data/spec/paperclip/tempfile_factory_spec.rb +4 -0
- data/spec/paperclip/tempfile_spec.rb +35 -0
- data/spec/paperclip/thumbnail_spec.rb +51 -32
- data/spec/paperclip/url_generator_spec.rb +55 -44
- data/spec/paperclip/validators/attachment_size_validator_spec.rb +26 -20
- data/spec/paperclip/validators_spec.rb +5 -5
- data/spec/spec_helper.rb +8 -1
- data/spec/support/assertions.rb +12 -1
- data/spec/support/conditional_filter_helper.rb +5 -0
- data/spec/support/fake_model.rb +4 -0
- data/spec/support/fixtures/empty.xlsx +0 -0
- data/spec/support/matchers/have_column.rb +11 -2
- data/spec/support/mock_attachment.rb +2 -0
- data/spec/support/mock_url_generator_builder.rb +2 -2
- data/spec/support/model_reconstruction.rb +9 -1
- data/spec/support/reporting.rb +11 -0
- metadata +109 -162
- data/RUNNING_TESTS.md +0 -4
- data/cucumber/paperclip_steps.rb +0 -6
- data/gemfiles/3.2.gemfile +0 -19
- data/gemfiles/4.0.gemfile +0 -19
- data/gemfiles/4.1.gemfile +0 -19
- data/lib/paperclip/locales/de.yml +0 -18
- data/lib/paperclip/locales/es.yml +0 -18
- data/lib/paperclip/locales/ja.yml +0 -18
- data/lib/paperclip/locales/pt-BR.yml +0 -18
- data/lib/paperclip/locales/zh-CN.yml +0 -18
- data/lib/paperclip/locales/zh-HK.yml +0 -18
- data/lib/paperclip/locales/zh-TW.yml +0 -18
- data/spec/support/mock_model.rb +0 -2
- data/spec/support/rails_helpers.rb +0 -7
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
module Paperclip
|
|
2
2
|
class AttachmentAdapter < AbstractAdapter
|
|
3
|
-
def
|
|
3
|
+
def self.register
|
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
|
5
|
+
Paperclip::Attachment === target || Paperclip::Style === target
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize(target, options = {})
|
|
10
|
+
super
|
|
4
11
|
@target, @style = case target
|
|
5
12
|
when Paperclip::Attachment
|
|
6
13
|
[target, :original]
|
|
@@ -22,7 +29,7 @@ module Paperclip
|
|
|
22
29
|
|
|
23
30
|
def copy_to_tempfile(source)
|
|
24
31
|
if source.staged?
|
|
25
|
-
|
|
32
|
+
link_or_copy_file(source.staged_path(@style), destination.path)
|
|
26
33
|
else
|
|
27
34
|
source.copy_to_local_file(@style, destination.path)
|
|
28
35
|
end
|
|
@@ -31,6 +38,4 @@ module Paperclip
|
|
|
31
38
|
end
|
|
32
39
|
end
|
|
33
40
|
|
|
34
|
-
Paperclip.
|
|
35
|
-
Paperclip::Attachment === target || Paperclip::Style === target
|
|
36
|
-
end
|
|
41
|
+
Paperclip::AttachmentAdapter.register
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
module Paperclip
|
|
2
2
|
class DataUriAdapter < StringioAdapter
|
|
3
|
+
def self.register
|
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
|
5
|
+
String === target && target =~ REGEXP
|
|
6
|
+
end
|
|
7
|
+
end
|
|
3
8
|
|
|
4
9
|
REGEXP = /\Adata:([-\w]+\/[-\w\+\.]+)?;base64,(.*)/m
|
|
5
10
|
|
|
6
|
-
def initialize(target_uri)
|
|
7
|
-
super(extract_target(target_uri))
|
|
11
|
+
def initialize(target_uri, options = {})
|
|
12
|
+
super(extract_target(target_uri), options)
|
|
8
13
|
end
|
|
9
14
|
|
|
10
15
|
private
|
|
11
16
|
|
|
12
17
|
def extract_target(uri)
|
|
13
18
|
data_uri_parts = uri.match(REGEXP) || []
|
|
14
|
-
StringIO.new(Base64.decode64(data_uri_parts[2] ||
|
|
19
|
+
StringIO.new(Base64.decode64(data_uri_parts[2] || ""))
|
|
15
20
|
end
|
|
16
|
-
|
|
17
21
|
end
|
|
18
22
|
end
|
|
19
|
-
|
|
20
|
-
Paperclip.io_adapters.register Paperclip::DataUriAdapter do |target|
|
|
21
|
-
String === target && target =~ Paperclip::DataUriAdapter::REGEXP
|
|
22
|
-
end
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
module Paperclip
|
|
2
2
|
class EmptyStringAdapter < AbstractAdapter
|
|
3
|
-
def
|
|
3
|
+
def self.register
|
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
|
5
|
+
target.is_a?(String) && target.empty?
|
|
6
|
+
end
|
|
4
7
|
end
|
|
5
8
|
|
|
6
9
|
def nil?
|
|
@@ -13,6 +16,4 @@ module Paperclip
|
|
|
13
16
|
end
|
|
14
17
|
end
|
|
15
18
|
|
|
16
|
-
Paperclip.
|
|
17
|
-
target.is_a?(String) && target.empty?
|
|
18
|
-
end
|
|
19
|
+
Paperclip::EmptyStringAdapter.register
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
module Paperclip
|
|
2
2
|
class FileAdapter < AbstractAdapter
|
|
3
|
-
def
|
|
4
|
-
|
|
3
|
+
def self.register
|
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
|
5
|
+
File === target || ::Tempfile === target
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize(target, options = {})
|
|
10
|
+
super
|
|
5
11
|
cache_current_values
|
|
6
12
|
end
|
|
7
13
|
|
|
8
14
|
private
|
|
9
15
|
|
|
10
16
|
def cache_current_values
|
|
11
|
-
|
|
17
|
+
if @target.respond_to?(:original_filename)
|
|
18
|
+
self.original_filename = @target.original_filename
|
|
19
|
+
end
|
|
12
20
|
self.original_filename ||= File.basename(@target.path)
|
|
13
21
|
@tempfile = copy_to_tempfile(@target)
|
|
14
22
|
@content_type = ContentTypeDetector.new(@target.path).detect
|
|
@@ -17,6 +25,4 @@ module Paperclip
|
|
|
17
25
|
end
|
|
18
26
|
end
|
|
19
27
|
|
|
20
|
-
Paperclip.
|
|
21
|
-
File === target || Tempfile === target
|
|
22
|
-
end
|
|
28
|
+
Paperclip::FileAdapter.register
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
module Paperclip
|
|
2
2
|
class HttpUrlProxyAdapter < UriAdapter
|
|
3
|
+
def self.register
|
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
|
5
|
+
String === target && target =~ REGEXP
|
|
6
|
+
end
|
|
7
|
+
end
|
|
3
8
|
|
|
4
9
|
REGEXP = /\Ahttps?:\/\//
|
|
5
10
|
|
|
6
|
-
def initialize(target)
|
|
7
|
-
super(URI(target))
|
|
11
|
+
def initialize(target, options = {})
|
|
12
|
+
super(URI(URI.escape(target)), options)
|
|
8
13
|
end
|
|
9
|
-
|
|
10
14
|
end
|
|
11
15
|
end
|
|
12
|
-
|
|
13
|
-
Paperclip.io_adapters.register Paperclip::HttpUrlProxyAdapter do |target|
|
|
14
|
-
String === target && target =~ Paperclip::HttpUrlProxyAdapter::REGEXP
|
|
15
|
-
end
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
module Paperclip
|
|
2
2
|
class IdentityAdapter < AbstractAdapter
|
|
3
|
-
def
|
|
4
|
-
|
|
3
|
+
def self.register
|
|
4
|
+
Paperclip.io_adapters.register Paperclip::IdentityAdapter.new do |target|
|
|
5
|
+
Paperclip.io_adapters.registered?(target)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
5
10
|
end
|
|
6
|
-
end
|
|
7
|
-
end
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
def new(target, _)
|
|
13
|
+
target
|
|
14
|
+
end
|
|
15
|
+
end
|
|
11
16
|
end
|
|
12
17
|
|
|
18
|
+
Paperclip::IdentityAdapter.register
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
module Paperclip
|
|
2
2
|
class NilAdapter < AbstractAdapter
|
|
3
|
-
def
|
|
3
|
+
def self.register
|
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
|
5
|
+
target.nil? || ((Paperclip::Attachment === target) && !target.present?)
|
|
6
|
+
end
|
|
4
7
|
end
|
|
5
8
|
|
|
9
|
+
def initialize(_target, _options = {}); end
|
|
10
|
+
|
|
6
11
|
def original_filename
|
|
7
12
|
""
|
|
8
13
|
end
|
|
@@ -19,7 +24,7 @@ module Paperclip
|
|
|
19
24
|
true
|
|
20
25
|
end
|
|
21
26
|
|
|
22
|
-
def read(*
|
|
27
|
+
def read(*_args)
|
|
23
28
|
nil
|
|
24
29
|
end
|
|
25
30
|
|
|
@@ -29,6 +34,4 @@ module Paperclip
|
|
|
29
34
|
end
|
|
30
35
|
end
|
|
31
36
|
|
|
32
|
-
Paperclip.
|
|
33
|
-
target.nil? || ( (Paperclip::Attachment === target) && !target.present? )
|
|
34
|
-
end
|
|
37
|
+
Paperclip::NilAdapter.register
|
|
@@ -12,6 +12,10 @@ module Paperclip
|
|
|
12
12
|
@registered_handlers << [block, handler_class]
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
def unregister(handler_class)
|
|
16
|
+
@registered_handlers.reject! { |_, klass| klass == handler_class }
|
|
17
|
+
end
|
|
18
|
+
|
|
15
19
|
def handler_for(target)
|
|
16
20
|
@registered_handlers.each do |tester, handler|
|
|
17
21
|
return handler if tester.call(target)
|
|
@@ -25,8 +29,8 @@ module Paperclip
|
|
|
25
29
|
end
|
|
26
30
|
end
|
|
27
31
|
|
|
28
|
-
def for(target)
|
|
29
|
-
handler_for(target).new(target)
|
|
32
|
+
def for(target, options = {})
|
|
33
|
+
handler_for(target).new(target, options)
|
|
30
34
|
end
|
|
31
35
|
end
|
|
32
36
|
end
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
module Paperclip
|
|
2
2
|
class StringioAdapter < AbstractAdapter
|
|
3
|
-
def
|
|
4
|
-
|
|
3
|
+
def self.register
|
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
|
5
|
+
StringIO === target
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize(target, options = {})
|
|
10
|
+
super
|
|
5
11
|
cache_current_values
|
|
6
12
|
end
|
|
7
13
|
|
|
@@ -24,10 +30,7 @@ module Paperclip
|
|
|
24
30
|
destination.rewind
|
|
25
31
|
destination
|
|
26
32
|
end
|
|
27
|
-
|
|
28
33
|
end
|
|
29
34
|
end
|
|
30
35
|
|
|
31
|
-
Paperclip.
|
|
32
|
-
StringIO === target
|
|
33
|
-
end
|
|
36
|
+
Paperclip::StringioAdapter.register
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
module Paperclip
|
|
2
2
|
class UploadedFileAdapter < AbstractAdapter
|
|
3
|
-
def
|
|
4
|
-
|
|
3
|
+
def self.register
|
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
|
5
|
+
target.class.name.include?("UploadedFile")
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize(target, options = {})
|
|
10
|
+
super
|
|
5
11
|
cache_current_values
|
|
6
12
|
|
|
7
13
|
if @target.respond_to?(:tempfile)
|
|
@@ -24,7 +30,7 @@ module Paperclip
|
|
|
24
30
|
end
|
|
25
31
|
|
|
26
32
|
def content_type_detector
|
|
27
|
-
self.class.content_type_detector
|
|
33
|
+
self.class.content_type_detector || Paperclip::ContentTypeDetector
|
|
28
34
|
end
|
|
29
35
|
|
|
30
36
|
def determine_content_type
|
|
@@ -37,6 +43,4 @@ module Paperclip
|
|
|
37
43
|
end
|
|
38
44
|
end
|
|
39
45
|
|
|
40
|
-
Paperclip.
|
|
41
|
-
target.class.name.include?("UploadedFile")
|
|
42
|
-
end
|
|
46
|
+
Paperclip::UploadedFileAdapter.register
|
|
@@ -1,35 +1,61 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "open-uri"
|
|
2
2
|
|
|
3
3
|
module Paperclip
|
|
4
4
|
class UriAdapter < AbstractAdapter
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
attr_writer :content_type
|
|
6
|
+
|
|
7
|
+
def self.register
|
|
8
|
+
Paperclip.io_adapters.register self do |target|
|
|
9
|
+
target.is_a?(URI)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def initialize(target, options = {})
|
|
14
|
+
super
|
|
7
15
|
@content = download_content
|
|
8
16
|
cache_current_values
|
|
9
17
|
@tempfile = copy_to_tempfile(@content)
|
|
10
18
|
end
|
|
11
19
|
|
|
12
|
-
attr_writer :content_type
|
|
13
|
-
|
|
14
20
|
private
|
|
15
21
|
|
|
16
|
-
def
|
|
17
|
-
|
|
22
|
+
def cache_current_values
|
|
23
|
+
self.content_type = content_type_from_content || "text/html"
|
|
24
|
+
|
|
25
|
+
self.original_filename = filename_from_content_disposition ||
|
|
26
|
+
filename_from_path || default_filename
|
|
27
|
+
@size = @content.size
|
|
18
28
|
end
|
|
19
29
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
30
|
+
def content_type_from_content
|
|
31
|
+
if @content.respond_to?(:content_type)
|
|
32
|
+
@content.content_type
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def filename_from_content_disposition
|
|
37
|
+
if @content.meta.key?("content-disposition")
|
|
38
|
+
matches = @content.meta["content-disposition"].match(/filename="([^"]*)"/)
|
|
39
|
+
matches[1] if matches
|
|
40
|
+
end
|
|
41
|
+
end
|
|
24
42
|
|
|
25
|
-
|
|
26
|
-
@
|
|
43
|
+
def filename_from_path
|
|
44
|
+
@target.path.split("/").last
|
|
45
|
+
end
|
|
27
46
|
|
|
28
|
-
|
|
47
|
+
def default_filename
|
|
48
|
+
"index.html"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def download_content
|
|
52
|
+
options = { read_timeout: Paperclip.options[:read_timeout] }.compact
|
|
53
|
+
|
|
54
|
+
open(@target, **options)
|
|
29
55
|
end
|
|
30
56
|
|
|
31
57
|
def copy_to_tempfile(src)
|
|
32
|
-
while data = src.read(16*1024)
|
|
58
|
+
while data = src.read(16 * 1024)
|
|
33
59
|
destination.write(data)
|
|
34
60
|
end
|
|
35
61
|
src.close
|
|
@@ -38,7 +64,3 @@ module Paperclip
|
|
|
38
64
|
end
|
|
39
65
|
end
|
|
40
66
|
end
|
|
41
|
-
|
|
42
|
-
Paperclip.io_adapters.register Paperclip::UriAdapter do |target|
|
|
43
|
-
target.kind_of?(URI)
|
|
44
|
-
end
|
|
@@ -40,9 +40,9 @@ module Paperclip
|
|
|
40
40
|
|
|
41
41
|
def failure_message
|
|
42
42
|
"#{expected_attachment}\n".tap do |message|
|
|
43
|
-
message << accepted_types_and_failures
|
|
43
|
+
message << accepted_types_and_failures.to_s
|
|
44
44
|
message << "\n\n" if @allowed_types.present? && @rejected_types.present?
|
|
45
|
-
message << rejected_types_and_failures
|
|
45
|
+
message << rejected_types_and_failures.to_s
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
@@ -55,7 +55,7 @@ module Paperclip
|
|
|
55
55
|
def accepted_types_and_failures
|
|
56
56
|
if @allowed_types.present?
|
|
57
57
|
"Accept content types: #{@allowed_types.join(", ")}\n".tap do |message|
|
|
58
|
-
if @missing_allowed_types.
|
|
58
|
+
if @missing_allowed_types.present?
|
|
59
59
|
message << " #{@missing_allowed_types.join(", ")} were rejected."
|
|
60
60
|
else
|
|
61
61
|
message << " All were accepted successfully."
|
|
@@ -66,7 +66,7 @@ module Paperclip
|
|
|
66
66
|
def rejected_types_and_failures
|
|
67
67
|
if @rejected_types.present?
|
|
68
68
|
"Reject content types: #{@rejected_types.join(", ")}\n".tap do |message|
|
|
69
|
-
if @missing_rejected_types.
|
|
69
|
+
if @missing_rejected_types.present?
|
|
70
70
|
message << " #{@missing_rejected_types.join(", ")} were accepted."
|
|
71
71
|
else
|
|
72
72
|
message << " All were rejected successfully."
|
|
@@ -12,7 +12,7 @@ module Paperclip
|
|
|
12
12
|
|
|
13
13
|
def spoofed?
|
|
14
14
|
if has_name? && has_extension? && media_type_mismatch? && mapping_override_mismatch?
|
|
15
|
-
Paperclip.log("Content Type Spoof: Filename #{File.basename(@name)} (#{supplied_content_type} from Headers, #{content_types_from_name} from Extension), content type discovered from file command: #{calculated_content_type}. See documentation to allow this combination.")
|
|
15
|
+
Paperclip.log("Content Type Spoof: Filename #{File.basename(@name)} (#{supplied_content_type} from Headers, #{content_types_from_name.map(&:to_s)} from Extension), content type discovered from file command: #{calculated_content_type}. See documentation to allow this combination.")
|
|
16
16
|
true
|
|
17
17
|
else
|
|
18
18
|
false
|
|
@@ -42,7 +42,7 @@ module Paperclip
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def mapping_override_mismatch?
|
|
45
|
-
mapped_content_type
|
|
45
|
+
!Array(mapped_content_type).include?(calculated_content_type)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
|
data/lib/paperclip/processor.rb
CHANGED
|
@@ -7,13 +7,14 @@ module Paperclip
|
|
|
7
7
|
# Processors are required to be defined inside the Paperclip module and
|
|
8
8
|
# are also required to be a subclass of Paperclip::Processor. There is
|
|
9
9
|
# only one method you *must* implement to properly be a subclass:
|
|
10
|
-
# #make, but #initialize may also be of use.
|
|
10
|
+
# #make, but #initialize may also be of use. #initialize accepts 3
|
|
11
11
|
# arguments: the file that will be operated on (which is an instance of
|
|
12
12
|
# File), a hash of options that were defined in has_attached_file's
|
|
13
|
-
# style hash, and the Paperclip::Attachment itself.
|
|
13
|
+
# style hash, and the Paperclip::Attachment itself. These are set as
|
|
14
|
+
# instance variables that can be used within `#make`.
|
|
14
15
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
16
|
+
# #make must return an instance of File (Tempfile is acceptable) which
|
|
17
|
+
# contains the results of the processing.
|
|
17
18
|
#
|
|
18
19
|
# See Paperclip.run for more information about using command-line
|
|
19
20
|
# utilities from within Processors.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Paperclip
|
|
2
|
+
class RailsEnvironment
|
|
3
|
+
def self.get
|
|
4
|
+
new.get
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def get
|
|
8
|
+
if rails_exists? && rails_environment_exists?
|
|
9
|
+
Rails.env
|
|
10
|
+
else
|
|
11
|
+
nil
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def rails_exists?
|
|
18
|
+
Object.const_defined?(:Rails)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def rails_environment_exists?
|
|
22
|
+
Rails.respond_to?(:env)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/paperclip/schema.rb
CHANGED
|
@@ -12,10 +12,7 @@ module Paperclip
|
|
|
12
12
|
ActiveRecord::ConnectionAdapters::Table.send :include, TableDefinition
|
|
13
13
|
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, TableDefinition
|
|
14
14
|
ActiveRecord::ConnectionAdapters::AbstractAdapter.send :include, Statements
|
|
15
|
-
|
|
16
|
-
if defined?(ActiveRecord::Migration::CommandRecorder) # Rails 3.1+
|
|
17
|
-
ActiveRecord::Migration::CommandRecorder.send :include, CommandRecorder
|
|
18
|
-
end
|
|
15
|
+
ActiveRecord::Migration::CommandRecorder.send :include, CommandRecorder
|
|
19
16
|
end
|
|
20
17
|
|
|
21
18
|
module Statements
|
|
@@ -35,12 +32,9 @@ module Paperclip
|
|
|
35
32
|
def remove_attachment(table_name, *attachment_names)
|
|
36
33
|
raise ArgumentError, "Please specify attachment name in your remove_attachment call in your migration." if attachment_names.empty?
|
|
37
34
|
|
|
38
|
-
options = attachment_names.extract_options!
|
|
39
|
-
|
|
40
35
|
attachment_names.each do |attachment_name|
|
|
41
|
-
COLUMNS.
|
|
42
|
-
|
|
43
|
-
remove_column(table_name, "#{attachment_name}_#{column_name}", column_type, column_options)
|
|
36
|
+
COLUMNS.keys.each do |column_name|
|
|
37
|
+
remove_column(table_name, "#{attachment_name}_#{column_name}")
|
|
44
38
|
end
|
|
45
39
|
end
|
|
46
40
|
end
|
|
@@ -37,7 +37,7 @@ module Paperclip
|
|
|
37
37
|
@queued_for_write.each do |style_name, file|
|
|
38
38
|
FileUtils.mkdir_p(File.dirname(path(style_name)))
|
|
39
39
|
begin
|
|
40
|
-
|
|
40
|
+
move_file(file.path, path(style_name))
|
|
41
41
|
rescue SystemCallError
|
|
42
42
|
File.open(path(style_name), "wb") do |new_file|
|
|
43
43
|
while chunk = file.read(16 * 1024)
|
|
@@ -46,7 +46,7 @@ module Paperclip
|
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
unless @options[:override_file_permissions] == false
|
|
49
|
-
resolved_chmod = (@options[:override_file_permissions]
|
|
49
|
+
resolved_chmod = (@options[:override_file_permissions] & ~0111) || (0666 & ~File.umask)
|
|
50
50
|
FileUtils.chmod( resolved_chmod, path(style_name) )
|
|
51
51
|
end
|
|
52
52
|
file.rewind
|
|
@@ -84,6 +84,17 @@ module Paperclip
|
|
|
84
84
|
def copy_to_local_file(style, local_dest_path)
|
|
85
85
|
FileUtils.cp(path(style), local_dest_path)
|
|
86
86
|
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def move_file(src, dest)
|
|
91
|
+
# Support hardlinked files
|
|
92
|
+
if File.identical?(src, dest)
|
|
93
|
+
File.unlink(src)
|
|
94
|
+
else
|
|
95
|
+
FileUtils.mv(src, dest)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
87
98
|
end
|
|
88
99
|
|
|
89
100
|
end
|
|
@@ -33,6 +33,10 @@ module Paperclip
|
|
|
33
33
|
# that is the alias to the S3 domain of your bucket, e.g.
|
|
34
34
|
# 'http://images.example.com'. This can also be used in
|
|
35
35
|
# conjunction with Cloudfront (http://aws.amazon.com/cloudfront)
|
|
36
|
+
# * +fog_options+: (optional) A hash of options that are passed
|
|
37
|
+
# to fog when the file is created. For example, you could set
|
|
38
|
+
# the multipart-chunk size to 100MB with a hash:
|
|
39
|
+
# { :multipart_chunk_size => 104857600 }
|
|
36
40
|
|
|
37
41
|
module Fog
|
|
38
42
|
def self.extended base
|
|
@@ -44,7 +48,7 @@ module Paperclip
|
|
|
44
48
|
end unless defined?(Fog)
|
|
45
49
|
|
|
46
50
|
base.instance_eval do
|
|
47
|
-
unless @options[:url].to_s.match(/\A:fog.*url\
|
|
51
|
+
unless @options[:url].to_s.match(/\A:fog.*url\z/)
|
|
48
52
|
@options[:path] = @options[:path].gsub(/:url/, @options[:url]).gsub(/\A:rails_root\/public\/system\//, '')
|
|
49
53
|
@options[:url] = ':fog_public_url'
|
|
50
54
|
end
|
|
@@ -54,7 +58,7 @@ module Paperclip
|
|
|
54
58
|
end
|
|
55
59
|
end
|
|
56
60
|
|
|
57
|
-
AWS_BUCKET_SUBDOMAIN_RESTRICTON_REGEX = /\A(?:[a-z]|\d(?!\d{0,2}(?:\.\d{1,3}){3}\
|
|
61
|
+
AWS_BUCKET_SUBDOMAIN_RESTRICTON_REGEX = /\A(?:[a-z]|\d(?!\d{0,2}(?:\.\d{1,3}){3}\z))(?:[a-z0-9]|\.(?![\.\-])|\-(?![\.])){1,61}[a-z0-9]\z/
|
|
58
62
|
|
|
59
63
|
def exists?(style = default_style)
|
|
60
64
|
if original_filename
|
|
@@ -82,11 +86,14 @@ module Paperclip
|
|
|
82
86
|
end
|
|
83
87
|
|
|
84
88
|
def fog_public(style = default_style)
|
|
85
|
-
if @options.
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
if @options.key?(:fog_public)
|
|
90
|
+
value = @options[:fog_public]
|
|
91
|
+
if value.respond_to?(:key?) && value.key?(style)
|
|
92
|
+
value[style]
|
|
93
|
+
elsif value.respond_to?(:call)
|
|
94
|
+
value.call(self)
|
|
88
95
|
else
|
|
89
|
-
|
|
96
|
+
value
|
|
90
97
|
end
|
|
91
98
|
else
|
|
92
99
|
true
|
|
@@ -98,12 +105,14 @@ module Paperclip
|
|
|
98
105
|
log("saving #{path(style)}")
|
|
99
106
|
retried = false
|
|
100
107
|
begin
|
|
101
|
-
|
|
108
|
+
attributes = fog_file.merge(
|
|
102
109
|
:body => file,
|
|
103
110
|
:key => path(style),
|
|
104
111
|
:public => fog_public(style),
|
|
105
112
|
:content_type => file.content_type
|
|
106
|
-
)
|
|
113
|
+
)
|
|
114
|
+
attributes.merge!(@options[:fog_options]) if @options[:fog_options]
|
|
115
|
+
directory.files.create(attributes)
|
|
107
116
|
rescue Excon::Errors::NotFound
|
|
108
117
|
raise if retried
|
|
109
118
|
retried = true
|
|
@@ -141,8 +150,9 @@ module Paperclip
|
|
|
141
150
|
|
|
142
151
|
def expiring_url(time = (Time.now + 3600), style_name = default_style)
|
|
143
152
|
time = convert_time(time)
|
|
144
|
-
|
|
145
|
-
|
|
153
|
+
http_url_method = "get_#{scheme}_url"
|
|
154
|
+
if path(style_name) && directory.files.respond_to?(http_url_method)
|
|
155
|
+
expiring_url = directory.files.public_send(http_url_method, path(style_name), time)
|
|
146
156
|
|
|
147
157
|
if @options[:fog_host]
|
|
148
158
|
expiring_url.gsub!(/#{host_name_for_directory}/, dynamic_fog_host_for_style(style_name))
|
|
@@ -156,14 +166,14 @@ module Paperclip
|
|
|
156
166
|
|
|
157
167
|
def parse_credentials(creds)
|
|
158
168
|
creds = find_credentials(creds).stringify_keys
|
|
159
|
-
|
|
160
|
-
(creds[env] || creds).symbolize_keys
|
|
169
|
+
(creds[RailsEnvironment.get] || creds).symbolize_keys
|
|
161
170
|
end
|
|
162
171
|
|
|
163
172
|
def copy_to_local_file(style, local_dest_path)
|
|
164
173
|
log("copying #{path(style)} to local file #{local_dest_path}")
|
|
165
174
|
::File.open(local_dest_path, 'wb') do |local_file|
|
|
166
175
|
file = directory.files.get(path(style))
|
|
176
|
+
return false unless file
|
|
167
177
|
local_file.write(file.body)
|
|
168
178
|
end
|
|
169
179
|
rescue ::Fog::Errors::Error => e
|
|
@@ -189,10 +199,10 @@ module Paperclip
|
|
|
189
199
|
end
|
|
190
200
|
|
|
191
201
|
def host_name_for_directory
|
|
192
|
-
if
|
|
193
|
-
"#{
|
|
202
|
+
if directory_name.to_s =~ Fog::AWS_BUCKET_SUBDOMAIN_RESTRICTON_REGEX
|
|
203
|
+
"#{directory_name}.s3.amazonaws.com"
|
|
194
204
|
else
|
|
195
|
-
"s3.amazonaws.com/#{
|
|
205
|
+
"s3.amazonaws.com/#{directory_name}"
|
|
196
206
|
end
|
|
197
207
|
end
|
|
198
208
|
|
|
@@ -218,13 +228,15 @@ module Paperclip
|
|
|
218
228
|
end
|
|
219
229
|
|
|
220
230
|
def directory
|
|
221
|
-
|
|
231
|
+
@directory ||= connection.directories.new(key: directory_name)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def directory_name
|
|
235
|
+
if @options[:fog_directory].respond_to?(:call)
|
|
222
236
|
@options[:fog_directory].call(self)
|
|
223
237
|
else
|
|
224
238
|
@options[:fog_directory]
|
|
225
239
|
end
|
|
226
|
-
|
|
227
|
-
@directory ||= connection.directories.new(:key => dir)
|
|
228
240
|
end
|
|
229
241
|
|
|
230
242
|
def scheme
|