kt-paperclip 6.2.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 +7 -0
- data/.codeclimate.yml +17 -0
- data/.github/issue_template.md +3 -0
- data/.gitignore +19 -0
- data/.hound.yml +1050 -0
- data/.rubocop.yml +1 -0
- data/.travis.yml +47 -0
- data/Appraisals +24 -0
- data/CONTRIBUTING.md +86 -0
- data/Gemfile +18 -0
- data/LICENSE +24 -0
- data/NEWS +515 -0
- data/README.md +1053 -0
- data/RELEASING.md +17 -0
- data/Rakefile +52 -0
- data/UPGRADING +17 -0
- data/features/basic_integration.feature +85 -0
- data/features/migration.feature +29 -0
- data/features/rake_tasks.feature +62 -0
- data/features/step_definitions/attachment_steps.rb +110 -0
- data/features/step_definitions/html_steps.rb +15 -0
- data/features/step_definitions/rails_steps.rb +257 -0
- data/features/step_definitions/s3_steps.rb +14 -0
- data/features/step_definitions/web_steps.rb +106 -0
- data/features/support/env.rb +12 -0
- data/features/support/fakeweb.rb +11 -0
- data/features/support/file_helpers.rb +34 -0
- data/features/support/fixtures/boot_config.txt +15 -0
- data/features/support/fixtures/gemfile.txt +5 -0
- data/features/support/fixtures/preinitializer.txt +20 -0
- data/features/support/paths.rb +28 -0
- data/features/support/rails.rb +39 -0
- data/features/support/selectors.rb +19 -0
- data/gemfiles/4.2.gemfile +20 -0
- data/gemfiles/5.0.gemfile +20 -0
- 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/USAGE +8 -0
- data/lib/generators/paperclip/paperclip_generator.rb +36 -0
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +15 -0
- data/lib/paperclip.rb +215 -0
- data/lib/paperclip/attachment.rb +617 -0
- data/lib/paperclip/attachment_registry.rb +60 -0
- data/lib/paperclip/callbacks.rb +42 -0
- data/lib/paperclip/content_type_detector.rb +80 -0
- data/lib/paperclip/errors.rb +34 -0
- data/lib/paperclip/file_command_content_type_detector.rb +28 -0
- data/lib/paperclip/filename_cleaner.rb +15 -0
- data/lib/paperclip/geometry.rb +157 -0
- data/lib/paperclip/geometry_detector_factory.rb +45 -0
- data/lib/paperclip/geometry_parser_factory.rb +31 -0
- data/lib/paperclip/glue.rb +17 -0
- data/lib/paperclip/has_attached_file.rb +116 -0
- data/lib/paperclip/helpers.rb +60 -0
- data/lib/paperclip/interpolations.rb +201 -0
- data/lib/paperclip/interpolations/plural_cache.rb +18 -0
- data/lib/paperclip/io_adapters/abstract_adapter.rb +75 -0
- data/lib/paperclip/io_adapters/attachment_adapter.rb +47 -0
- data/lib/paperclip/io_adapters/data_uri_adapter.rb +22 -0
- data/lib/paperclip/io_adapters/empty_string_adapter.rb +19 -0
- data/lib/paperclip/io_adapters/file_adapter.rb +26 -0
- data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +16 -0
- data/lib/paperclip/io_adapters/identity_adapter.rb +17 -0
- data/lib/paperclip/io_adapters/nil_adapter.rb +37 -0
- data/lib/paperclip/io_adapters/registry.rb +36 -0
- data/lib/paperclip/io_adapters/stringio_adapter.rb +36 -0
- data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +44 -0
- data/lib/paperclip/io_adapters/uri_adapter.rb +68 -0
- data/lib/paperclip/locales/en.yml +18 -0
- data/lib/paperclip/logger.rb +21 -0
- data/lib/paperclip/matchers.rb +64 -0
- data/lib/paperclip/matchers/have_attached_file_matcher.rb +54 -0
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +101 -0
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +59 -0
- data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +97 -0
- data/lib/paperclip/media_type_spoof_detector.rb +90 -0
- data/lib/paperclip/missing_attachment_styles.rb +84 -0
- data/lib/paperclip/processor.rb +56 -0
- data/lib/paperclip/processor_helpers.rb +52 -0
- data/lib/paperclip/rails_environment.rb +21 -0
- data/lib/paperclip/railtie.rb +31 -0
- data/lib/paperclip/schema.rb +81 -0
- data/lib/paperclip/storage.rb +3 -0
- data/lib/paperclip/storage/filesystem.rb +99 -0
- data/lib/paperclip/storage/fog.rb +252 -0
- data/lib/paperclip/storage/s3.rb +461 -0
- data/lib/paperclip/style.rb +106 -0
- data/lib/paperclip/tempfile.rb +42 -0
- data/lib/paperclip/tempfile_factory.rb +22 -0
- data/lib/paperclip/thumbnail.rb +131 -0
- data/lib/paperclip/url_generator.rb +76 -0
- data/lib/paperclip/validators.rb +73 -0
- data/lib/paperclip/validators/attachment_content_type_validator.rb +88 -0
- data/lib/paperclip/validators/attachment_file_name_validator.rb +75 -0
- data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +28 -0
- data/lib/paperclip/validators/attachment_presence_validator.rb +28 -0
- data/lib/paperclip/validators/attachment_size_validator.rb +109 -0
- data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +29 -0
- data/lib/paperclip/version.rb +3 -0
- data/lib/tasks/paperclip.rake +140 -0
- data/paperclip.gemspec +50 -0
- data/shoulda_macros/paperclip.rb +134 -0
- data/spec/database.yml +4 -0
- data/spec/paperclip/attachment_definitions_spec.rb +13 -0
- data/spec/paperclip/attachment_processing_spec.rb +79 -0
- data/spec/paperclip/attachment_registry_spec.rb +158 -0
- data/spec/paperclip/attachment_spec.rb +1590 -0
- data/spec/paperclip/content_type_detector_spec.rb +47 -0
- data/spec/paperclip/file_command_content_type_detector_spec.rb +40 -0
- data/spec/paperclip/filename_cleaner_spec.rb +13 -0
- data/spec/paperclip/geometry_detector_spec.rb +38 -0
- data/spec/paperclip/geometry_parser_spec.rb +73 -0
- data/spec/paperclip/geometry_spec.rb +255 -0
- data/spec/paperclip/glue_spec.rb +42 -0
- data/spec/paperclip/has_attached_file_spec.rb +78 -0
- data/spec/paperclip/integration_spec.rb +702 -0
- data/spec/paperclip/interpolations_spec.rb +270 -0
- data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +160 -0
- data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +140 -0
- data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +88 -0
- data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
- data/spec/paperclip/io_adapters/file_adapter_spec.rb +131 -0
- data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +137 -0
- data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
- data/spec/paperclip/io_adapters/nil_adapter_spec.rb +25 -0
- data/spec/paperclip/io_adapters/registry_spec.rb +35 -0
- data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +64 -0
- data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +146 -0
- data/spec/paperclip/io_adapters/uri_adapter_spec.rb +221 -0
- data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
- data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +108 -0
- data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
- data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
- data/spec/paperclip/media_type_spoof_detector_spec.rb +120 -0
- data/spec/paperclip/meta_class_spec.rb +30 -0
- data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +88 -0
- data/spec/paperclip/paperclip_spec.rb +196 -0
- data/spec/paperclip/plural_cache_spec.rb +37 -0
- data/spec/paperclip/processor_helpers_spec.rb +57 -0
- data/spec/paperclip/processor_spec.rb +26 -0
- data/spec/paperclip/rails_environment_spec.rb +30 -0
- data/spec/paperclip/rake_spec.rb +103 -0
- data/spec/paperclip/schema_spec.rb +252 -0
- data/spec/paperclip/storage/filesystem_spec.rb +79 -0
- data/spec/paperclip/storage/fog_spec.rb +560 -0
- data/spec/paperclip/storage/s3_live_spec.rb +188 -0
- data/spec/paperclip/storage/s3_spec.rb +1695 -0
- data/spec/paperclip/style_spec.rb +251 -0
- data/spec/paperclip/tempfile_factory_spec.rb +33 -0
- data/spec/paperclip/tempfile_spec.rb +35 -0
- data/spec/paperclip/thumbnail_spec.rb +504 -0
- data/spec/paperclip/url_generator_spec.rb +221 -0
- data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +322 -0
- data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +159 -0
- data/spec/paperclip/validators/attachment_presence_validator_spec.rb +85 -0
- data/spec/paperclip/validators/attachment_size_validator_spec.rb +235 -0
- data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +48 -0
- data/spec/paperclip/validators_spec.rb +164 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/support/assertions.rb +84 -0
- data/spec/support/fake_model.rb +24 -0
- data/spec/support/fake_rails.rb +12 -0
- data/spec/support/fixtures/12k.png +0 -0
- data/spec/support/fixtures/50x50.png +0 -0
- data/spec/support/fixtures/5k.png +0 -0
- data/spec/support/fixtures/animated +0 -0
- data/spec/support/fixtures/animated.gif +0 -0
- data/spec/support/fixtures/animated.unknown +0 -0
- data/spec/support/fixtures/bad.png +1 -0
- data/spec/support/fixtures/empty.html +1 -0
- data/spec/support/fixtures/empty.xlsx +0 -0
- data/spec/support/fixtures/fog.yml +8 -0
- data/spec/support/fixtures/rotated.jpg +0 -0
- data/spec/support/fixtures/s3.yml +8 -0
- data/spec/support/fixtures/spaced file.jpg +0 -0
- data/spec/support/fixtures/spaced file.png +0 -0
- data/spec/support/fixtures/text.txt +1 -0
- data/spec/support/fixtures/twopage.pdf +0 -0
- data/spec/support/fixtures/uppercase.PNG +0 -0
- data/spec/support/matchers/accept.rb +5 -0
- data/spec/support/matchers/exist.rb +5 -0
- data/spec/support/matchers/have_column.rb +23 -0
- data/spec/support/mock_attachment.rb +24 -0
- data/spec/support/mock_interpolator.rb +24 -0
- data/spec/support/mock_url_generator_builder.rb +26 -0
- data/spec/support/model_reconstruction.rb +72 -0
- data/spec/support/reporting.rb +11 -0
- data/spec/support/test_data.rb +13 -0
- data/spec/support/version_helper.rb +9 -0
- metadata +586 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
module Paperclip
|
2
|
+
module Validators
|
3
|
+
class AttachmentContentTypeValidator < ActiveModel::EachValidator
|
4
|
+
def initialize(options)
|
5
|
+
options[:allow_nil] = true unless options.key?(:allow_nil)
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.helper_method_name
|
10
|
+
:validates_attachment_content_type
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate_each(record, attribute, value)
|
14
|
+
base_attribute = attribute.to_sym
|
15
|
+
attribute = "#{attribute}_content_type".to_sym
|
16
|
+
value = record.send :read_attribute_for_validation, attribute
|
17
|
+
|
18
|
+
return if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
|
19
|
+
|
20
|
+
validate_whitelist(record, attribute, value)
|
21
|
+
validate_blacklist(record, attribute, value)
|
22
|
+
|
23
|
+
if record.errors.include? attribute
|
24
|
+
record.errors[attribute].each do |error|
|
25
|
+
record.errors.add base_attribute, error
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate_whitelist(record, attribute, value)
|
31
|
+
if allowed_types.present? && allowed_types.none? { |type| type === value }
|
32
|
+
mark_invalid record, attribute, allowed_types
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate_blacklist(record, attribute, value)
|
37
|
+
if forbidden_types.present? && forbidden_types.any? { |type| type === value }
|
38
|
+
mark_invalid record, attribute, forbidden_types
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def mark_invalid(record, attribute, types)
|
43
|
+
record.errors.add attribute, :invalid, options.merge(types: types.join(", "))
|
44
|
+
end
|
45
|
+
|
46
|
+
def allowed_types
|
47
|
+
[options[:content_type]].flatten.compact
|
48
|
+
end
|
49
|
+
|
50
|
+
def forbidden_types
|
51
|
+
[options[:not]].flatten.compact
|
52
|
+
end
|
53
|
+
|
54
|
+
def check_validity!
|
55
|
+
unless options.key?(:content_type) || options.key?(:not)
|
56
|
+
raise ArgumentError, "You must pass in either :content_type or :not to the validator"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
module HelperMethods
|
62
|
+
# Places ActiveModel validations on the content type of the file
|
63
|
+
# assigned. The possible options are:
|
64
|
+
# * +content_type+: Allowed content types. Can be a single content type
|
65
|
+
# or an array. Each type can be a String or a Regexp. It should be
|
66
|
+
# noted that Internet Explorer uploads files with content_types that you
|
67
|
+
# may not expect. For example, JPEG images are given image/pjpeg and
|
68
|
+
# PNGs are image/x-png, so keep that in mind when determining how you
|
69
|
+
# match. Allows all by default.
|
70
|
+
# * +not+: Forbidden content types.
|
71
|
+
# * +message+: The message to display when the uploaded file has an invalid
|
72
|
+
# content type.
|
73
|
+
# * +if+: A lambda or name of an instance method. Validation will only
|
74
|
+
# be run is this lambda or method returns true.
|
75
|
+
# * +unless+: Same as +if+ but validates if lambda or method returns false.
|
76
|
+
# NOTE: If you do not specify an [attachment]_content_type field on your
|
77
|
+
# model, content_type validation will work _ONLY upon assignment_ and
|
78
|
+
# re-validation after the instance has been reloaded will always succeed.
|
79
|
+
# You'll still need to have a virtual attribute (created by +attr_accessor+)
|
80
|
+
# name +[attachment]_content_type+ to be able to use this validator.
|
81
|
+
def validates_attachment_content_type(*attr_names)
|
82
|
+
options = _merge_attributes(attr_names)
|
83
|
+
validates_with AttachmentContentTypeValidator, options.dup
|
84
|
+
validate_before_processing AttachmentContentTypeValidator, options.dup
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Paperclip
|
2
|
+
module Validators
|
3
|
+
class AttachmentFileNameValidator < ActiveModel::EachValidator
|
4
|
+
def initialize(options)
|
5
|
+
options[:allow_nil] = true unless options.key?(:allow_nil)
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.helper_method_name
|
10
|
+
:validates_attachment_file_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate_each(record, attribute, value)
|
14
|
+
base_attribute = attribute.to_sym
|
15
|
+
attribute = "#{attribute}_file_name".to_sym
|
16
|
+
value = record.send :read_attribute_for_validation, attribute
|
17
|
+
|
18
|
+
return if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
|
19
|
+
|
20
|
+
validate_whitelist(record, attribute, value)
|
21
|
+
validate_blacklist(record, attribute, value)
|
22
|
+
|
23
|
+
if record.errors.include? attribute
|
24
|
+
record.errors[attribute].each do |error|
|
25
|
+
record.errors.add base_attribute, error
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate_whitelist(record, attribute, value)
|
31
|
+
mark_invalid record, attribute, allowed if allowed.present? && allowed.none? { |type| type === value }
|
32
|
+
end
|
33
|
+
|
34
|
+
def validate_blacklist(record, attribute, value)
|
35
|
+
mark_invalid record, attribute, forbidden if forbidden.present? && forbidden.any? { |type| type === value }
|
36
|
+
end
|
37
|
+
|
38
|
+
def mark_invalid(record, attribute, patterns)
|
39
|
+
record.errors.add attribute, :invalid, options.merge(names: patterns.join(", "))
|
40
|
+
end
|
41
|
+
|
42
|
+
def allowed
|
43
|
+
[options[:matches]].flatten.compact
|
44
|
+
end
|
45
|
+
|
46
|
+
def forbidden
|
47
|
+
[options[:not]].flatten.compact
|
48
|
+
end
|
49
|
+
|
50
|
+
def check_validity!
|
51
|
+
unless options.key?(:matches) || options.key?(:not)
|
52
|
+
raise ArgumentError, "You must pass in either :matches or :not to the validator"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
module HelperMethods
|
58
|
+
# Places ActiveModel validations on the name of the file
|
59
|
+
# assigned. The possible options are:
|
60
|
+
# * +matches+: Allowed filename patterns as Regexps. Can be a single one
|
61
|
+
# or an array.
|
62
|
+
# * +not+: Forbidden file name patterns, specified the same was as +matches+.
|
63
|
+
# * +message+: The message to display when the uploaded file has an invalid
|
64
|
+
# name.
|
65
|
+
# * +if+: A lambda or name of an instance method. Validation will only
|
66
|
+
# be run is this lambda or method returns true.
|
67
|
+
# * +unless+: Same as +if+ but validates if lambda or method returns false.
|
68
|
+
def validates_attachment_file_name(*attr_names)
|
69
|
+
options = _merge_attributes(attr_names)
|
70
|
+
validates_with AttachmentFileNameValidator, options.dup
|
71
|
+
validate_before_processing AttachmentFileNameValidator, options.dup
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "active_model/validations/presence"
|
2
|
+
|
3
|
+
module Paperclip
|
4
|
+
module Validators
|
5
|
+
class AttachmentFileTypeIgnoranceValidator < ActiveModel::EachValidator
|
6
|
+
def validate_each(record, attribute, value)
|
7
|
+
# This doesn't do anything. It's just to mark that you don't care about
|
8
|
+
# the file_names or content_types of your incoming attachments.
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.helper_method_name
|
12
|
+
:do_not_validate_attachment_file_type
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module HelperMethods
|
17
|
+
# Places ActiveModel validations on the presence of a file.
|
18
|
+
# Options:
|
19
|
+
# * +if+: A lambda or name of an instance method. Validation will only
|
20
|
+
# be run if this lambda or method returns true.
|
21
|
+
# * +unless+: Same as +if+ but validates if lambda or method returns false.
|
22
|
+
def do_not_validate_attachment_file_type(*attr_names)
|
23
|
+
options = _merge_attributes(attr_names)
|
24
|
+
validates_with AttachmentFileTypeIgnoranceValidator, options.dup
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "active_model/validations/presence"
|
2
|
+
|
3
|
+
module Paperclip
|
4
|
+
module Validators
|
5
|
+
class AttachmentPresenceValidator < ActiveModel::EachValidator
|
6
|
+
def validate_each(record, attribute, _value)
|
7
|
+
record.errors.add(attribute, :blank, options) if record.send("#{attribute}_file_name").blank?
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.helper_method_name
|
11
|
+
:validates_attachment_presence
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module HelperMethods
|
16
|
+
# Places ActiveModel validations on the presence of a file.
|
17
|
+
# Options:
|
18
|
+
# * +if+: A lambda or name of an instance method. Validation will only
|
19
|
+
# be run if this lambda or method returns true.
|
20
|
+
# * +unless+: Same as +if+ but validates if lambda or method returns false.
|
21
|
+
def validates_attachment_presence(*attr_names)
|
22
|
+
options = _merge_attributes(attr_names)
|
23
|
+
validates_with AttachmentPresenceValidator, options.dup
|
24
|
+
validate_before_processing AttachmentPresenceValidator, options.dup
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require "active_model/validations/numericality"
|
2
|
+
|
3
|
+
module Paperclip
|
4
|
+
module Validators
|
5
|
+
class AttachmentSizeValidator < ActiveModel::Validations::NumericalityValidator
|
6
|
+
AVAILABLE_CHECKS = [:less_than, :less_than_or_equal_to, :greater_than, :greater_than_or_equal_to].freeze
|
7
|
+
|
8
|
+
def initialize(options)
|
9
|
+
extract_options(options)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.helper_method_name
|
14
|
+
:validates_attachment_size
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate_each(record, attr_name, value)
|
18
|
+
base_attr_name = attr_name
|
19
|
+
attr_name = "#{attr_name}_file_size".to_sym
|
20
|
+
value = record.send(:read_attribute_for_validation, attr_name)
|
21
|
+
|
22
|
+
unless value.blank?
|
23
|
+
options.slice(*AVAILABLE_CHECKS).each do |option, option_value|
|
24
|
+
option_value = option_value.call(record) if option_value.is_a?(Proc)
|
25
|
+
option_value = extract_option_value(option, option_value)
|
26
|
+
|
27
|
+
unless value.send(CHECKS[option], option_value)
|
28
|
+
error_message_key = options[:in] ? :in_between : option
|
29
|
+
[attr_name, base_attr_name].each do |error_attr_name|
|
30
|
+
record.errors.add(error_attr_name, error_message_key, filtered_options(value).merge(
|
31
|
+
min: min_value_in_human_size(record),
|
32
|
+
max: max_value_in_human_size(record),
|
33
|
+
count: human_size(option_value)
|
34
|
+
))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def check_validity!
|
42
|
+
unless (AVAILABLE_CHECKS + [:in]).any? { |argument| options.key?(argument) }
|
43
|
+
raise ArgumentError, "You must pass either :less_than, :greater_than, or :in to the validator"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def extract_options(options)
|
50
|
+
if range = options[:in]
|
51
|
+
if !options[:in].respond_to?(:call)
|
52
|
+
options[:less_than_or_equal_to] = range.max
|
53
|
+
options[:greater_than_or_equal_to] = range.min
|
54
|
+
else
|
55
|
+
options[:less_than_or_equal_to] = range
|
56
|
+
options[:greater_than_or_equal_to] = range
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def extract_option_value(option, option_value)
|
62
|
+
if option_value.is_a?(Range)
|
63
|
+
if [:less_than, :less_than_or_equal_to].include?(option)
|
64
|
+
option_value.max
|
65
|
+
else
|
66
|
+
option_value.min
|
67
|
+
end
|
68
|
+
else
|
69
|
+
option_value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def human_size(size)
|
74
|
+
ActiveSupport::NumberHelper.number_to_human_size(size)
|
75
|
+
end
|
76
|
+
|
77
|
+
def min_value_in_human_size(record)
|
78
|
+
value = options[:greater_than_or_equal_to] || options[:greater_than]
|
79
|
+
value = value.call(record) if value.respond_to?(:call)
|
80
|
+
value = value.min if value.respond_to?(:min)
|
81
|
+
human_size(value)
|
82
|
+
end
|
83
|
+
|
84
|
+
def max_value_in_human_size(record)
|
85
|
+
value = options[:less_than_or_equal_to] || options[:less_than]
|
86
|
+
value = value.call(record) if value.respond_to?(:call)
|
87
|
+
value = value.max if value.respond_to?(:max)
|
88
|
+
human_size(value)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
module HelperMethods
|
93
|
+
# Places ActiveModel validations on the size of the file assigned. The
|
94
|
+
# possible options are:
|
95
|
+
# * +in+: a Range of bytes (i.e. +1..1.megabyte+),
|
96
|
+
# * +less_than+: equivalent to :in => 0..options[:less_than]
|
97
|
+
# * +greater_than+: equivalent to :in => options[:greater_than]..Infinity
|
98
|
+
# * +message+: error message to display, use :min and :max as replacements
|
99
|
+
# * +if+: A lambda or name of an instance method. Validation will only
|
100
|
+
# be run if this lambda or method returns true.
|
101
|
+
# * +unless+: Same as +if+ but validates if lambda or method returns false.
|
102
|
+
def validates_attachment_size(*attr_names)
|
103
|
+
options = _merge_attributes(attr_names)
|
104
|
+
validates_with AttachmentSizeValidator, options.dup
|
105
|
+
validate_before_processing AttachmentSizeValidator, options.dup
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "active_model/validations/presence"
|
2
|
+
|
3
|
+
module Paperclip
|
4
|
+
module Validators
|
5
|
+
class MediaTypeSpoofDetectionValidator < ActiveModel::EachValidator
|
6
|
+
def validate_each(record, attribute, value)
|
7
|
+
adapter = Paperclip.io_adapters.for(value)
|
8
|
+
if Paperclip::MediaTypeSpoofDetector.using(adapter, value.original_filename, value.content_type).spoofed?
|
9
|
+
record.errors.add(attribute, :spoofed_media_type)
|
10
|
+
end
|
11
|
+
|
12
|
+
adapter.tempfile.close(true) if adapter.tempfile
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module HelperMethods
|
17
|
+
# Places ActiveModel validations on the presence of a file.
|
18
|
+
# Options:
|
19
|
+
# * +if+: A lambda or name of an instance method. Validation will only
|
20
|
+
# be run if this lambda or method returns true.
|
21
|
+
# * +unless+: Same as +if+ but validates if lambda or method returns false.
|
22
|
+
def validates_media_type_spoof_detection(*attr_names)
|
23
|
+
options = _merge_attributes(attr_names)
|
24
|
+
validates_with MediaTypeSpoofDetectionValidator, options.dup
|
25
|
+
validate_before_processing MediaTypeSpoofDetectionValidator, options.dup
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require "paperclip/attachment_registry"
|
2
|
+
|
3
|
+
module Paperclip
|
4
|
+
module Task
|
5
|
+
def self.obtain_class
|
6
|
+
class_name = ENV["CLASS"] || ENV["class"]
|
7
|
+
raise "Must specify CLASS" unless class_name
|
8
|
+
|
9
|
+
class_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.obtain_attachments(klass)
|
13
|
+
klass = Paperclip.class_for(klass.to_s)
|
14
|
+
name = ENV["ATTACHMENT"] || ENV["attachment"]
|
15
|
+
|
16
|
+
attachment_names = Paperclip::AttachmentRegistry.names_for(klass)
|
17
|
+
|
18
|
+
raise "Class #{klass.name} has no attachments specified" if attachment_names.empty?
|
19
|
+
|
20
|
+
if name.present? && attachment_names.map(&:to_s).include?(name.to_s)
|
21
|
+
[name]
|
22
|
+
else
|
23
|
+
attachment_names
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.log_error(error)
|
28
|
+
$stderr.puts error
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
namespace :paperclip do
|
34
|
+
desc "Refreshes both metadata and thumbnails."
|
35
|
+
task refresh: ["paperclip:refresh:metadata", "paperclip:refresh:thumbnails"]
|
36
|
+
|
37
|
+
namespace :refresh do
|
38
|
+
desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT and STYLES splitted by comma)."
|
39
|
+
task thumbnails: :environment do
|
40
|
+
klass = Paperclip::Task.obtain_class
|
41
|
+
names = Paperclip::Task.obtain_attachments(klass)
|
42
|
+
styles = (ENV["STYLES"] || ENV["styles"] || "").split(",").map(&:to_sym)
|
43
|
+
names.each do |name|
|
44
|
+
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
45
|
+
attachment = instance.send(name)
|
46
|
+
begin
|
47
|
+
attachment.reprocess!(*styles)
|
48
|
+
rescue StandardError => e
|
49
|
+
Paperclip::Task.log_error("exception while processing #{klass} ID #{instance.id}:")
|
50
|
+
Paperclip::Task.log_error(" " + e.message + "\n")
|
51
|
+
end
|
52
|
+
unless instance.errors.blank?
|
53
|
+
Paperclip::Task.log_error("errors while processing #{klass} ID #{instance.id}:")
|
54
|
+
Paperclip::Task.log_error(" " + instance.errors.full_messages.join("\n ") + "\n")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
desc "Regenerates content_type/size metadata for a given CLASS (and optional ATTACHMENT)."
|
61
|
+
task metadata: :environment do
|
62
|
+
klass = Paperclip::Task.obtain_class
|
63
|
+
names = Paperclip::Task.obtain_attachments(klass)
|
64
|
+
names.each do |name|
|
65
|
+
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
66
|
+
attachment = instance.send(name)
|
67
|
+
if file = Paperclip.io_adapters.for(attachment, attachment.options[:adapter_options])
|
68
|
+
instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
|
69
|
+
instance.send("#{name}_content_type=", file.content_type.to_s.strip)
|
70
|
+
instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
|
71
|
+
instance.save(validate: false)
|
72
|
+
else
|
73
|
+
true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "Regenerates missing thumbnail styles for all classes using Paperclip."
|
80
|
+
task missing_styles: :environment do
|
81
|
+
Rails.application.eager_load!
|
82
|
+
Paperclip.missing_attachments_styles.each do |klass, attachment_definitions|
|
83
|
+
attachment_definitions.each do |attachment_name, missing_styles|
|
84
|
+
puts "Regenerating #{klass} -> #{attachment_name} -> #{missing_styles.inspect}"
|
85
|
+
ENV["CLASS"] = klass.to_s
|
86
|
+
ENV["ATTACHMENT"] = attachment_name.to_s
|
87
|
+
ENV["STYLES"] = missing_styles.join(",")
|
88
|
+
Rake::Task["paperclip:refresh:thumbnails"].execute
|
89
|
+
end
|
90
|
+
end
|
91
|
+
Paperclip.save_current_attachments_styles!
|
92
|
+
end
|
93
|
+
|
94
|
+
desc "Regenerates fingerprints for a given CLASS (and optional ATTACHMENT). Useful when changing digest."
|
95
|
+
task fingerprints: :environment do
|
96
|
+
klass = Paperclip::Task.obtain_class
|
97
|
+
names = Paperclip::Task.obtain_attachments(klass)
|
98
|
+
names.each do |name|
|
99
|
+
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
100
|
+
attachment = instance.send(name)
|
101
|
+
attachment.assign(attachment)
|
102
|
+
instance.save(validate: false)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
desc "Cleans out invalid attachments. Useful after you've added new validations."
|
109
|
+
task clean: :environment do
|
110
|
+
klass = Paperclip::Task.obtain_class
|
111
|
+
names = Paperclip::Task.obtain_attachments(klass)
|
112
|
+
names.each do |name|
|
113
|
+
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
114
|
+
unless instance.valid?
|
115
|
+
attributes = %w(file_size file_name content_type).map { |suffix| "#{name}_#{suffix}".to_sym }
|
116
|
+
if attributes.any? { |attribute| instance.errors[attribute].present? }
|
117
|
+
instance.send("#{name}=", nil)
|
118
|
+
instance.save(validate: false)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
desc "find missing attachments. Useful to know which attachments are broken"
|
126
|
+
task find_broken_attachments: :environment do
|
127
|
+
klass = Paperclip::Task.obtain_class
|
128
|
+
names = Paperclip::Task.obtain_attachments(klass)
|
129
|
+
names.each do |name|
|
130
|
+
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
131
|
+
attachment = instance.send(name)
|
132
|
+
if attachment.exists?
|
133
|
+
print "."
|
134
|
+
else
|
135
|
+
Paperclip::Task.log_error("#{instance.class}##{attachment.name}, #{instance.id}, #{attachment.url}")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|