kt-paperclip 4.4.0 → 5.4.0
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 +5 -16
- data/.travis.yml +15 -12
- data/Appraisals +4 -8
- data/CONTRIBUTING.md +16 -5
- data/Gemfile +3 -8
- data/LICENSE +1 -1
- data/NEWS +105 -31
- data/README.md +239 -153
- data/Rakefile +1 -1
- data/UPGRADING +12 -9
- data/features/basic_integration.feature +3 -2
- data/features/migration.feature +0 -24
- data/features/step_definitions/attachment_steps.rb +6 -6
- data/features/step_definitions/rails_steps.rb +29 -28
- data/features/step_definitions/s3_steps.rb +2 -2
- data/features/support/env.rb +1 -0
- data/features/support/paths.rb +1 -1
- data/features/support/rails.rb +0 -24
- data/gemfiles/4.2.gemfile +3 -5
- data/gemfiles/{3.2.gemfile → 5.0.gemfile} +4 -6
- data/lib/generators/paperclip/paperclip_generator.rb +9 -1
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +1 -1
- data/lib/paperclip/attachment.rb +25 -14
- data/lib/paperclip/attachment_registry.rb +2 -1
- data/lib/paperclip/callbacks.rb +8 -6
- data/lib/paperclip/content_type_detector.rb +3 -2
- data/lib/paperclip/errors.rb +3 -1
- data/lib/paperclip/file_command_content_type_detector.rb +1 -1
- data/lib/paperclip/geometry_detector_factory.rb +2 -2
- data/lib/paperclip/glue.rb +1 -1
- data/lib/paperclip/has_attached_file.rb +7 -1
- data/lib/paperclip/helpers.rb +15 -11
- data/lib/paperclip/interpolations.rb +1 -1
- data/lib/paperclip/io_adapters/abstract_adapter.rb +29 -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 +17 -14
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +4 -4
- data/lib/paperclip/media_type_spoof_detector.rb +3 -2
- data/lib/paperclip/processor.rb +5 -4
- data/lib/paperclip/schema.rb +4 -10
- data/lib/paperclip/storage/filesystem.rb +13 -2
- data/lib/paperclip/storage/fog.rb +19 -13
- data/lib/paperclip/storage/s3.rb +87 -58
- data/lib/paperclip/thumbnail.rb +18 -8
- data/lib/paperclip/url_generator.rb +18 -14
- 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 +13 -12
- data/lib/tasks/paperclip.rake +18 -4
- data/paperclip.gemspec +13 -11
- data/spec/paperclip/attachment_processing_spec.rb +2 -4
- data/spec/paperclip/attachment_registry_spec.rb +28 -0
- data/spec/paperclip/attachment_spec.rb +72 -18
- data/spec/paperclip/content_type_detector_spec.rb +1 -1
- data/spec/paperclip/file_command_content_type_detector_spec.rb +15 -1
- data/spec/paperclip/has_attached_file_spec.rb +24 -8
- data/spec/paperclip/integration_spec.rb +4 -3
- data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +76 -22
- 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 +2 -2
- data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +18 -1
- 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 +1 -1
- data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +5 -5
- data/spec/paperclip/io_adapters/uri_adapter_spec.rb +48 -3
- data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +10 -0
- data/spec/paperclip/media_type_spoof_detector_spec.rb +15 -0
- data/spec/paperclip/paperclip_spec.rb +15 -45
- data/spec/paperclip/processor_spec.rb +4 -4
- data/spec/paperclip/storage/fog_spec.rb +26 -0
- data/spec/paperclip/storage/s3_live_spec.rb +20 -14
- data/spec/paperclip/storage/s3_spec.rb +357 -190
- data/spec/paperclip/tempfile_spec.rb +35 -0
- data/spec/paperclip/thumbnail_spec.rb +38 -35
- data/spec/paperclip/url_generator_spec.rb +53 -42
- data/spec/paperclip/validators/attachment_size_validator_spec.rb +26 -20
- data/spec/paperclip/validators_spec.rb +5 -5
- data/spec/spec_helper.rb +6 -2
- data/spec/support/assertions.rb +12 -1
- data/spec/support/conditional_filter_helper.rb +5 -0
- data/spec/support/mock_attachment.rb +2 -0
- data/spec/support/mock_url_generator_builder.rb +2 -2
- data/spec/support/model_reconstruction.rb +10 -2
- data/spec/support/reporting.rb +11 -0
- metadata +69 -75
- data/cucumber/paperclip_steps.rb +0 -6
- data/gemfiles/4.1.gemfile +0 -19
- data/lib/paperclip/deprecations.rb +0 -42
- 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/paperclip/deprecations_spec.rb +0 -65
- data/spec/support/deprecations.rb +0 -9
- data/spec/support/rails_helpers.rb +0 -7
data/lib/paperclip/helpers.rb
CHANGED
|
@@ -8,27 +8,31 @@ module Paperclip
|
|
|
8
8
|
Paperclip::Interpolations[key] = block
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
# The run method takes the name of a binary to run, the arguments
|
|
12
|
-
# and some options
|
|
11
|
+
# The run method takes the name of a binary to run, the arguments
|
|
12
|
+
# to that binary, the values to interpolate and some local options.
|
|
13
13
|
#
|
|
14
|
-
#
|
|
15
|
-
# on the filesystem. Colon-separated, just like $PATH.
|
|
14
|
+
# :cmd -> The name of a binary to run.
|
|
16
15
|
#
|
|
17
|
-
#
|
|
18
|
-
# of the binary. Defaults to [0].
|
|
16
|
+
# :arguments -> The command line arguments to that binary.
|
|
19
17
|
#
|
|
20
|
-
#
|
|
21
|
-
# This will only log if logging in general is set to true as well.
|
|
18
|
+
# :interpolation_values -> Values to be interpolated into the arguments.
|
|
22
19
|
#
|
|
23
|
-
#
|
|
20
|
+
# :local_options -> The options to be used by Cocain::CommandLine.
|
|
21
|
+
# These could be: runner
|
|
22
|
+
# logger
|
|
23
|
+
# swallow_stderr
|
|
24
|
+
# expected_outcodes
|
|
25
|
+
# environment
|
|
26
|
+
# runner_options
|
|
24
27
|
#
|
|
25
28
|
def run(cmd, arguments = "", interpolation_values = {}, local_options = {})
|
|
26
29
|
command_path = options[:command_path]
|
|
27
|
-
|
|
30
|
+
terrapin_path_array = Terrapin::CommandLine.path.try(:split, Terrapin::OS.path_separator)
|
|
31
|
+
Terrapin::CommandLine.path = [terrapin_path_array, command_path].flatten.compact.uniq
|
|
28
32
|
if logging? && (options[:log_command] || local_options[:log_command])
|
|
29
33
|
local_options = local_options.merge(:logger => logger)
|
|
30
34
|
end
|
|
31
|
-
|
|
35
|
+
Terrapin::CommandLine.new(cmd, arguments, local_options).run(interpolation_values)
|
|
32
36
|
end
|
|
33
37
|
|
|
34
38
|
# Find all instances of the given Active Record model +klass+ with attachment +name+.
|
|
@@ -141,7 +141,7 @@ module Paperclip
|
|
|
141
141
|
# It's possible, though unlikely, that the mime type is not in the
|
|
142
142
|
# database, so just use the part after the '/' in the mime type as the
|
|
143
143
|
# extension.
|
|
144
|
-
%r{/([^/]*)\
|
|
144
|
+
%r{/([^/]*)\z}.match(attachment.content_type)[1]
|
|
145
145
|
end
|
|
146
146
|
end
|
|
147
147
|
|
|
@@ -5,11 +5,23 @@ module Paperclip
|
|
|
5
5
|
OS_RESTRICTED_CHARACTERS = %r{[/:]}
|
|
6
6
|
|
|
7
7
|
attr_reader :content_type, :original_filename, :size
|
|
8
|
-
delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :rewind, :unlink, :to => :@tempfile
|
|
8
|
+
delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :readbyte, :rewind, :unlink, :to => :@tempfile
|
|
9
9
|
alias :length :size
|
|
10
10
|
|
|
11
|
+
def initialize(target, options = {})
|
|
12
|
+
@target = target
|
|
13
|
+
@options = options
|
|
14
|
+
end
|
|
15
|
+
|
|
11
16
|
def fingerprint
|
|
12
|
-
@fingerprint ||=
|
|
17
|
+
@fingerprint ||= begin
|
|
18
|
+
digest = @options.fetch(:hash_digest).new
|
|
19
|
+
File.open(path, "rb") do |f|
|
|
20
|
+
buf = ""
|
|
21
|
+
digest.update(buf) while f.read(16384, buf)
|
|
22
|
+
end
|
|
23
|
+
digest.hexdigest
|
|
24
|
+
end
|
|
13
25
|
end
|
|
14
26
|
|
|
15
27
|
def read(length = nil, buffer = nil)
|
|
@@ -40,8 +52,22 @@ module Paperclip
|
|
|
40
52
|
end
|
|
41
53
|
|
|
42
54
|
def copy_to_tempfile(src)
|
|
43
|
-
|
|
55
|
+
link_or_copy_file(src.path, destination.path)
|
|
44
56
|
destination
|
|
45
57
|
end
|
|
58
|
+
|
|
59
|
+
def link_or_copy_file(src, dest)
|
|
60
|
+
Paperclip.log("Trying to link #{src} to #{dest}")
|
|
61
|
+
FileUtils.ln(src, dest, force: true) # overwrite existing
|
|
62
|
+
@destination.close
|
|
63
|
+
@destination.open.binmode
|
|
64
|
+
rescue Errno::EXDEV, Errno::EPERM, Errno::ENOENT, Errno::EEXIST => e
|
|
65
|
+
Paperclip.log(
|
|
66
|
+
"Link failed with #{e.message}; copying link #{src} to #{dest}"
|
|
67
|
+
)
|
|
68
|
+
FileUtils.cp(src, dest)
|
|
69
|
+
@destination.close
|
|
70
|
+
@destination.open.binmode
|
|
71
|
+
end
|
|
46
72
|
end
|
|
47
73
|
end
|
|
@@ -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,16 +1,16 @@
|
|
|
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)
|
|
11
|
+
def initialize(target, options = {})
|
|
7
12
|
escaped = Paperclip::UrlGenerator.escape(target)
|
|
8
|
-
super(URI(target == Paperclip::UrlGenerator.unescape(target) ? escaped : target))
|
|
13
|
+
super(URI(target == Paperclip::UrlGenerator.unescape(target) ? escaped : target), options)
|
|
9
14
|
end
|
|
10
|
-
|
|
11
15
|
end
|
|
12
16
|
end
|
|
13
|
-
|
|
14
|
-
Paperclip.io_adapters.register Paperclip::HttpUrlProxyAdapter do |target|
|
|
15
|
-
String === target && target =~ Paperclip::HttpUrlProxyAdapter::REGEXP
|
|
16
|
-
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,11 +1,17 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "open-uri"
|
|
2
2
|
|
|
3
3
|
module Paperclip
|
|
4
4
|
class UriAdapter < AbstractAdapter
|
|
5
5
|
attr_writer :content_type
|
|
6
6
|
|
|
7
|
-
def
|
|
8
|
-
|
|
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
|
|
9
15
|
@content = download_content
|
|
10
16
|
cache_current_values
|
|
11
17
|
@tempfile = copy_to_tempfile(@content)
|
|
@@ -17,8 +23,7 @@ module Paperclip
|
|
|
17
23
|
self.content_type = content_type_from_content || "text/html"
|
|
18
24
|
|
|
19
25
|
self.original_filename = filename_from_content_disposition ||
|
|
20
|
-
filename_from_path ||
|
|
21
|
-
default_filename
|
|
26
|
+
filename_from_path || default_filename
|
|
22
27
|
@size = @content.size
|
|
23
28
|
end
|
|
24
29
|
|
|
@@ -29,9 +34,9 @@ module Paperclip
|
|
|
29
34
|
end
|
|
30
35
|
|
|
31
36
|
def filename_from_content_disposition
|
|
32
|
-
if @content.meta.
|
|
33
|
-
@content.meta["content-disposition"].
|
|
34
|
-
|
|
37
|
+
if @content.meta.key?("content-disposition")
|
|
38
|
+
matches = @content.meta["content-disposition"].match(/filename="([^"]*)"/)
|
|
39
|
+
matches[1] if matches
|
|
35
40
|
end
|
|
36
41
|
end
|
|
37
42
|
|
|
@@ -44,11 +49,13 @@ module Paperclip
|
|
|
44
49
|
end
|
|
45
50
|
|
|
46
51
|
def download_content
|
|
47
|
-
|
|
52
|
+
options = { read_timeout: Paperclip.options[:read_timeout] }.compact
|
|
53
|
+
|
|
54
|
+
self.open(@target, options)
|
|
48
55
|
end
|
|
49
56
|
|
|
50
57
|
def copy_to_tempfile(src)
|
|
51
|
-
while data = src.read(16*1024)
|
|
58
|
+
while data = src.read(16 * 1024)
|
|
52
59
|
destination.write(data)
|
|
53
60
|
end
|
|
54
61
|
src.close
|
|
@@ -57,7 +64,3 @@ module Paperclip
|
|
|
57
64
|
end
|
|
58
65
|
end
|
|
59
66
|
end
|
|
60
|
-
|
|
61
|
-
Paperclip.io_adapters.register Paperclip::UriAdapter do |target|
|
|
62
|
-
target.kind_of?(URI)
|
|
63
|
-
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."
|
|
@@ -72,8 +72,9 @@ module Paperclip
|
|
|
72
72
|
|
|
73
73
|
def type_from_file_command
|
|
74
74
|
begin
|
|
75
|
-
Paperclip.run("file", "-b --mime :file", :
|
|
76
|
-
|
|
75
|
+
Paperclip.run("file", "-b --mime :file", file: @file.path).
|
|
76
|
+
split(/[:;\s]+/).first
|
|
77
|
+
rescue Terrapin::CommandLineError
|
|
77
78
|
""
|
|
78
79
|
end
|
|
79
80
|
end
|
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.
|
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
|
|
@@ -27,7 +24,7 @@ module Paperclip
|
|
|
27
24
|
attachment_names.each do |attachment_name|
|
|
28
25
|
COLUMNS.each_pair do |column_name, column_type|
|
|
29
26
|
column_options = options.merge(options[column_name.to_sym] || {})
|
|
30
|
-
add_column(table_name, "#{attachment_name}_#{column_name}", column_type, column_options)
|
|
27
|
+
add_column(table_name, "#{attachment_name}_#{column_name}", column_type, **column_options)
|
|
31
28
|
end
|
|
32
29
|
end
|
|
33
30
|
end
|
|
@@ -35,11 +32,8 @@ 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
|
-
column_options = options.merge(options[column_name.to_sym] || {})
|
|
36
|
+
COLUMNS.keys.each do |column_name|
|
|
43
37
|
remove_column(table_name, "#{attachment_name}_#{column_name}")
|
|
44
38
|
end
|
|
45
39
|
end
|
|
@@ -57,7 +51,7 @@ module Paperclip
|
|
|
57
51
|
attachment_names.each do |attachment_name|
|
|
58
52
|
COLUMNS.each_pair do |column_name, column_type|
|
|
59
53
|
column_options = options.merge(options[column_name.to_sym] || {})
|
|
60
|
-
column("#{attachment_name}_#{column_name}", column_type, column_options)
|
|
54
|
+
column("#{attachment_name}_#{column_name}", column_type, **column_options)
|
|
61
55
|
end
|
|
62
56
|
end
|
|
63
57
|
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
|