active_storage_validations 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +12 -8
- data/config/locales/da.yml +0 -1
- data/config/locales/de.yml +0 -1
- data/config/locales/en.yml +0 -1
- data/config/locales/es.yml +0 -1
- data/config/locales/fr.yml +0 -1
- data/config/locales/it.yml +0 -1
- data/config/locales/ja.yml +0 -1
- data/config/locales/nl.yml +0 -1
- data/config/locales/pl.yml +0 -1
- data/config/locales/pt-BR.yml +0 -1
- data/config/locales/ru.yml +0 -1
- data/config/locales/sv.yml +0 -1
- data/config/locales/tr.yml +0 -1
- data/config/locales/uk.yml +0 -1
- data/config/locales/vi.yml +0 -1
- data/config/locales/zh-CN.yml +0 -1
- data/lib/active_storage_validations/aspect_ratio_validator.rb +58 -43
- data/lib/active_storage_validations/attached_validator.rb +3 -3
- data/lib/active_storage_validations/base_size_validator.rb +5 -4
- data/lib/active_storage_validations/content_type_spoof_detector.rb +12 -48
- data/lib/active_storage_validations/content_type_validator.rb +97 -49
- data/lib/active_storage_validations/dimension_validator.rb +8 -7
- data/lib/active_storage_validations/limit_validator.rb +6 -5
- data/lib/active_storage_validations/matchers/aspect_ratio_validator_matcher.rb +7 -7
- data/lib/active_storage_validations/matchers/attached_validator_matcher.rb +6 -6
- data/lib/active_storage_validations/matchers/base_size_validator_matcher.rb +7 -7
- data/lib/active_storage_validations/matchers/content_type_validator_matcher.rb +33 -33
- data/lib/active_storage_validations/matchers/dimension_validator_matcher.rb +7 -7
- data/lib/active_storage_validations/matchers/limit_validator_matcher.rb +7 -7
- data/lib/active_storage_validations/matchers/processable_image_validator_matcher.rb +7 -7
- data/lib/active_storage_validations/metadata.rb +17 -18
- data/lib/active_storage_validations/processable_image_validator.rb +5 -5
- data/lib/active_storage_validations/shared/attachable.rb +134 -0
- data/lib/active_storage_validations/{concerns → shared}/errorable.rb +2 -1
- data/lib/active_storage_validations/shared/optionable.rb +27 -0
- data/lib/active_storage_validations/size_validator.rb +2 -2
- data/lib/active_storage_validations/total_size_validator.rb +2 -2
- data/lib/active_storage_validations/version.rb +1 -1
- data/lib/active_storage_validations.rb +0 -1
- metadata +65 -25
- data/lib/active_storage_validations/concerns/metadatable.rb +0 -31
- data/lib/active_storage_validations/option_proc_unfolding.rb +0 -16
- /data/lib/active_storage_validations/matchers/{concerns → shared}/active_storageable.rb +0 -0
- /data/lib/active_storage_validations/matchers/{concerns → shared}/allow_blankable.rb +0 -0
- /data/lib/active_storage_validations/matchers/{concerns → shared}/attachable.rb +0 -0
- /data/lib/active_storage_validations/matchers/{concerns → shared}/contextable.rb +0 -0
- /data/lib/active_storage_validations/matchers/{concerns → shared}/messageable.rb +0 -0
- /data/lib/active_storage_validations/matchers/{concerns → shared}/rspecable.rb +0 -0
- /data/lib/active_storage_validations/matchers/{concerns → shared}/validatable.rb +0 -0
- /data/lib/active_storage_validations/{concerns → shared}/active_storageable.rb +0 -0
- /data/lib/active_storage_validations/{concerns → shared}/loggable.rb +0 -0
- /data/lib/active_storage_validations/{concerns → shared}/symbolizable.rb +0 -0
@@ -1,15 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
3
|
+
require_relative 'shared/active_storageable'
|
4
|
+
require_relative 'shared/attachable'
|
5
|
+
require_relative 'shared/errorable'
|
6
|
+
require_relative 'shared/optionable'
|
7
|
+
require_relative 'shared/symbolizable'
|
8
|
+
require_relative 'content_type_spoof_detector'
|
7
9
|
|
8
10
|
module ActiveStorageValidations
|
9
11
|
class ContentTypeValidator < ActiveModel::EachValidator # :nodoc:
|
10
12
|
include ActiveStorageable
|
11
|
-
include
|
13
|
+
include Attachable
|
12
14
|
include Errorable
|
15
|
+
include Optionable
|
13
16
|
include Symbolizable
|
14
17
|
|
15
18
|
AVAILABLE_CHECKS = %i[with in].freeze
|
@@ -26,18 +29,20 @@ module ActiveStorageValidations
|
|
26
29
|
def validate_each(record, attribute, _value)
|
27
30
|
return if no_attachments?(record, attribute)
|
28
31
|
|
29
|
-
|
30
|
-
return if
|
32
|
+
@authorized_content_types = authorized_content_types_from_options(record)
|
33
|
+
return if @authorized_content_types.empty?
|
31
34
|
|
32
|
-
|
33
|
-
|
35
|
+
attachables_from_changes(record, attribute).each do |attachable|
|
36
|
+
set_attachable_cached_values(attachable)
|
37
|
+
is_valid?(record, attribute, attachable)
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
37
41
|
private
|
38
42
|
|
39
|
-
def
|
40
|
-
flat_options =
|
43
|
+
def authorized_content_types_from_options(record)
|
44
|
+
flat_options = set_flat_options(record)
|
45
|
+
|
41
46
|
(Array.wrap(flat_options[:with]) + Array.wrap(flat_options[:in])).compact.map do |type|
|
42
47
|
case type
|
43
48
|
when String, Symbol then Marcel::MimeType.for(declared_type: type.to_s, extension: type.to_s)
|
@@ -46,47 +51,48 @@ module ActiveStorageValidations
|
|
46
51
|
end
|
47
52
|
end
|
48
53
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
.join(', ')
|
54
|
+
def set_attachable_cached_values(attachable)
|
55
|
+
@attachable_content_type = attachable_content_type(attachable)
|
56
|
+
@attachable_filename = attachable_filename(attachable).to_s
|
53
57
|
end
|
54
58
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
59
|
+
def is_valid?(record, attribute, attachable)
|
60
|
+
extension_matches_content_type?(record, attribute, attachable) &&
|
61
|
+
authorized_content_type?(record, attribute, attachable) &&
|
62
|
+
not_spoofing_content_type?(record, attribute, attachable)
|
58
63
|
end
|
59
64
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
65
|
+
def extension_matches_content_type?(record, attribute, attachable)
|
66
|
+
extension = @attachable_filename.split('.').last
|
67
|
+
|
68
|
+
possible_extensions = Marcel::TYPE_EXTS[@attachable_content_type]
|
69
|
+
return true if possible_extensions && extension.in?(possible_extensions)
|
70
|
+
|
71
|
+
errors_options = initialize_and_populate_error_options(options, attachable)
|
72
|
+
add_error(record, attribute, ERROR_TYPES.first, **errors_options)
|
73
|
+
false
|
63
74
|
end
|
64
75
|
|
65
|
-
def
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
when
|
70
|
-
when Regexp then type.match?(file_type.to_s)
|
76
|
+
def authorized_content_type?(record, attribute, attachable)
|
77
|
+
attachable_content_type_is_authorized = @authorized_content_types.any? do |authorized_content_type|
|
78
|
+
case authorized_content_type
|
79
|
+
when String then authorized_content_type == marcel_attachable_content_type(attachable)
|
80
|
+
when Regexp then authorized_content_type.match?(marcel_attachable_content_type(attachable).to_s)
|
71
81
|
end
|
72
82
|
end
|
73
83
|
|
74
|
-
if
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
errors_options[:content_type] = content_type(file)
|
80
|
-
add_error(record, attribute, ERROR_TYPES.first, **errors_options)
|
81
|
-
false
|
82
|
-
end
|
84
|
+
return true if attachable_content_type_is_authorized
|
85
|
+
|
86
|
+
errors_options = initialize_and_populate_error_options(options, attachable)
|
87
|
+
add_error(record, attribute, ERROR_TYPES.first, **errors_options)
|
88
|
+
false
|
83
89
|
end
|
84
90
|
|
85
|
-
def not_spoofing_content_type?(record, attribute,
|
91
|
+
def not_spoofing_content_type?(record, attribute, attachable)
|
86
92
|
return true unless enable_spoofing_protection?
|
87
93
|
|
88
|
-
if ContentTypeSpoofDetector.new(record, attribute,
|
89
|
-
errors_options = initialize_error_options(options,
|
94
|
+
if ContentTypeSpoofDetector.new(record, attribute, attachable).spoofed?
|
95
|
+
errors_options = initialize_error_options(options, attachable)
|
90
96
|
add_error(record, attribute, ERROR_TYPES.second, **errors_options)
|
91
97
|
false
|
92
98
|
else
|
@@ -94,6 +100,37 @@ module ActiveStorageValidations
|
|
94
100
|
end
|
95
101
|
end
|
96
102
|
|
103
|
+
def marcel_attachable_content_type(attachable)
|
104
|
+
Marcel::MimeType.for(declared_type: @attachable_content_type, name: @attachable_filename)
|
105
|
+
end
|
106
|
+
|
107
|
+
def enable_spoofing_protection?
|
108
|
+
options[:spoofing_protection] == true
|
109
|
+
end
|
110
|
+
|
111
|
+
def initialize_and_populate_error_options(options, attachable)
|
112
|
+
errors_options = initialize_error_options(options, attachable)
|
113
|
+
errors_options[:content_type] = @attachable_content_type
|
114
|
+
errors_options[:human_content_type] = content_type_to_human_format(@attachable_content_type)
|
115
|
+
errors_options[:authorized_types] = content_type_to_human_format(@authorized_content_types)
|
116
|
+
errors_options
|
117
|
+
end
|
118
|
+
|
119
|
+
def content_type_to_human_format(content_type)
|
120
|
+
Array(content_type)
|
121
|
+
.map do |content_type|
|
122
|
+
case content_type
|
123
|
+
when String, Symbol
|
124
|
+
content_type.to_s.match?(/\//) ? Marcel::TYPE_EXTS[content_type.to_s]&.first&.upcase : content_type.upcase
|
125
|
+
when Regexp
|
126
|
+
content_type.source
|
127
|
+
end
|
128
|
+
end
|
129
|
+
.flatten
|
130
|
+
.compact
|
131
|
+
.join(', ')
|
132
|
+
end
|
133
|
+
|
97
134
|
def ensure_exactly_one_validator_option
|
98
135
|
unless AVAILABLE_CHECKS.one? { |argument| options.key?(argument) }
|
99
136
|
raise ArgumentError, 'You must pass either :with or :in to the validator'
|
@@ -104,28 +141,39 @@ module ActiveStorageValidations
|
|
104
141
|
return true if options[:with]&.is_a?(Proc) || options[:in]&.is_a?(Proc)
|
105
142
|
|
106
143
|
([options[:with]] || options[:in]).each do |content_type|
|
107
|
-
raise ArgumentError,
|
144
|
+
raise ArgumentError, invalid_content_type_option_message(content_type) if invalid_option?(content_type)
|
108
145
|
end
|
109
146
|
end
|
110
147
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
148
|
+
def invalid_content_type_option_message(content_type)
|
149
|
+
if content_type.to_s.match?(/\//)
|
150
|
+
<<~ERROR_MESSAGE
|
151
|
+
You must pass valid content types to the validator
|
152
|
+
'#{content_type}' is not found in Marcel::TYPE_EXTS
|
153
|
+
ERROR_MESSAGE
|
154
|
+
else
|
155
|
+
<<~ERROR_MESSAGE
|
156
|
+
You must pass valid content types extensions to the validator
|
157
|
+
'#{content_type}' is not found in Marcel::EXTENSIONS
|
158
|
+
ERROR_MESSAGE
|
159
|
+
end
|
116
160
|
end
|
117
161
|
|
118
|
-
def
|
162
|
+
def invalid_option?(content_type)
|
119
163
|
case content_type
|
120
164
|
when String, Symbol
|
121
|
-
|
165
|
+
content_type.to_s.match?(/\//) ? invalid_content_type?(content_type) : invalid_extension?(content_type)
|
122
166
|
when Regexp
|
123
167
|
false # We always validate regexes
|
124
168
|
end
|
125
169
|
end
|
126
170
|
|
127
|
-
def
|
128
|
-
|
171
|
+
def invalid_content_type?(content_type)
|
172
|
+
Marcel::TYPE_EXTS[content_type.to_s] == nil
|
173
|
+
end
|
174
|
+
|
175
|
+
def invalid_extension?(content_type)
|
176
|
+
Marcel::MimeType.for(extension: content_type.to_s) == 'application/octet-stream'
|
129
177
|
end
|
130
178
|
end
|
131
179
|
end
|
@@ -1,16 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
3
|
+
require_relative 'shared/active_storageable'
|
4
|
+
require_relative 'shared/attachable'
|
5
|
+
require_relative 'shared/errorable'
|
6
|
+
require_relative 'shared/optionable'
|
7
|
+
require_relative 'shared/symbolizable'
|
7
8
|
|
8
9
|
module ActiveStorageValidations
|
9
10
|
class DimensionValidator < ActiveModel::EachValidator # :nodoc
|
10
11
|
include ActiveStorageable
|
12
|
+
include Attachable
|
11
13
|
include Errorable
|
12
|
-
include
|
13
|
-
include Metadatable
|
14
|
+
include Optionable
|
14
15
|
include Symbolizable
|
15
16
|
|
16
17
|
AVAILABLE_CHECKS = %i[width height min max].freeze
|
@@ -122,7 +123,7 @@ module ActiveStorageValidations
|
|
122
123
|
end
|
123
124
|
|
124
125
|
def process_options(record)
|
125
|
-
flat_options =
|
126
|
+
flat_options = set_flat_options(record)
|
126
127
|
|
127
128
|
[:width, :height].each do |length|
|
128
129
|
if flat_options[length] and flat_options[length].is_a?(Hash)
|
@@ -1,14 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
3
|
+
require_relative 'shared/active_storageable'
|
4
|
+
require_relative 'shared/errorable'
|
5
|
+
require_relative 'shared/optionable'
|
6
|
+
require_relative 'shared/symbolizable'
|
6
7
|
|
7
8
|
module ActiveStorageValidations
|
8
9
|
class LimitValidator < ActiveModel::EachValidator # :nodoc:
|
9
10
|
include ActiveStorageable
|
10
|
-
include OptionProcUnfolding
|
11
11
|
include Errorable
|
12
|
+
include Optionable
|
12
13
|
include Symbolizable
|
13
14
|
|
14
15
|
AVAILABLE_CHECKS = %i[max min].freeze
|
@@ -23,7 +24,7 @@ module ActiveStorageValidations
|
|
23
24
|
|
24
25
|
def validate_each(record, attribute, _value)
|
25
26
|
files = attached_files(record, attribute).reject(&:blank?)
|
26
|
-
flat_options =
|
27
|
+
flat_options = set_flat_options(record)
|
27
28
|
|
28
29
|
return if files_count_valid?(files.count, flat_options)
|
29
30
|
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
7
|
-
require_relative '
|
8
|
-
require_relative '
|
9
|
-
require_relative '
|
3
|
+
require_relative 'shared/active_storageable'
|
4
|
+
require_relative 'shared/allow_blankable'
|
5
|
+
require_relative 'shared/attachable'
|
6
|
+
require_relative 'shared/contextable'
|
7
|
+
require_relative 'shared/messageable'
|
8
|
+
require_relative 'shared/rspecable'
|
9
|
+
require_relative 'shared/validatable'
|
10
10
|
|
11
11
|
module ActiveStorageValidations
|
12
12
|
module Matchers
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
7
|
-
require_relative '
|
8
|
-
require_relative '
|
3
|
+
require_relative 'shared/active_storageable'
|
4
|
+
require_relative 'shared/attachable'
|
5
|
+
require_relative 'shared/contextable'
|
6
|
+
require_relative 'shared/messageable'
|
7
|
+
require_relative 'shared/rspecable'
|
8
|
+
require_relative 'shared/validatable'
|
9
9
|
|
10
10
|
module ActiveStorageValidations
|
11
11
|
module Matchers
|
@@ -3,13 +3,13 @@
|
|
3
3
|
# Big thank you to the paperclip validation matchers:
|
4
4
|
# https://github.com/thoughtbot/paperclip/blob/v6.1.0/lib/paperclip/matchers/validate_attachment_size_matcher.rb
|
5
5
|
|
6
|
-
require_relative '
|
7
|
-
require_relative '
|
8
|
-
require_relative '
|
9
|
-
require_relative '
|
10
|
-
require_relative '
|
11
|
-
require_relative '
|
12
|
-
require_relative '
|
6
|
+
require_relative 'shared/active_storageable'
|
7
|
+
require_relative 'shared/allow_blankable'
|
8
|
+
require_relative 'shared/attachable'
|
9
|
+
require_relative 'shared/contextable'
|
10
|
+
require_relative 'shared/messageable'
|
11
|
+
require_relative 'shared/rspecable'
|
12
|
+
require_relative 'shared/validatable'
|
13
13
|
|
14
14
|
module ActiveStorageValidations
|
15
15
|
module Matchers
|
@@ -3,13 +3,13 @@
|
|
3
3
|
# Big thank you to the paperclip validation matchers:
|
4
4
|
# https://github.com/thoughtbot/paperclip/blob/v6.1.0/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb
|
5
5
|
|
6
|
-
require_relative '
|
7
|
-
require_relative '
|
8
|
-
require_relative '
|
9
|
-
require_relative '
|
10
|
-
require_relative '
|
11
|
-
require_relative '
|
12
|
-
require_relative '
|
6
|
+
require_relative 'shared/active_storageable'
|
7
|
+
require_relative 'shared/allow_blankable'
|
8
|
+
require_relative 'shared/attachable'
|
9
|
+
require_relative 'shared/contextable'
|
10
|
+
require_relative 'shared/messageable'
|
11
|
+
require_relative 'shared/rspecable'
|
12
|
+
require_relative 'shared/validatable'
|
13
13
|
|
14
14
|
module ActiveStorageValidations
|
15
15
|
module Matchers
|
@@ -32,7 +32,7 @@ module ActiveStorageValidations
|
|
32
32
|
initialize_messageable
|
33
33
|
initialize_rspecable
|
34
34
|
@attribute_name = attribute_name
|
35
|
-
@
|
35
|
+
@allowed_content_types = @rejected_content_types = []
|
36
36
|
end
|
37
37
|
|
38
38
|
def description
|
@@ -45,13 +45,13 @@ module ActiveStorageValidations
|
|
45
45
|
message.join("\n")
|
46
46
|
end
|
47
47
|
|
48
|
-
def allowing(*
|
49
|
-
@
|
48
|
+
def allowing(*content_types)
|
49
|
+
@allowed_content_types = content_types.flatten
|
50
50
|
self
|
51
51
|
end
|
52
52
|
|
53
|
-
def rejecting(*
|
54
|
-
@
|
53
|
+
def rejecting(*content_types)
|
54
|
+
@rejected_content_types = content_types.flatten
|
55
55
|
self
|
56
56
|
end
|
57
57
|
|
@@ -62,21 +62,21 @@ module ActiveStorageValidations
|
|
62
62
|
is_context_valid? &&
|
63
63
|
is_allowing_blank? &&
|
64
64
|
is_custom_message_valid? &&
|
65
|
-
|
66
|
-
|
65
|
+
all_allowed_content_types_allowed? &&
|
66
|
+
all_rejected_content_types_rejected?
|
67
67
|
end
|
68
68
|
|
69
69
|
protected
|
70
70
|
|
71
71
|
def build_failure_message(message)
|
72
|
-
if @
|
73
|
-
message << " the following content type#{'s' if @
|
74
|
-
message << " but #{pluralize(@
|
72
|
+
if @allowed_content_types_not_allowed.present?
|
73
|
+
message << " the following content type#{'s' if @allowed_content_types.count > 1} should be allowed: :#{@allowed_content_types.join(", :")}"
|
74
|
+
message << " but #{pluralize(@allowed_content_types_not_allowed)} rejected"
|
75
75
|
end
|
76
76
|
|
77
|
-
if @
|
78
|
-
message << " the following content type#{'s' if @
|
79
|
-
message << " but #{pluralize(@
|
77
|
+
if @rejected_content_types_not_rejected.present?
|
78
|
+
message << " the following content type#{'s' if @rejected_content_types.count > 1} should be rejected: :#{@rejected_content_types.join(", :")}"
|
79
|
+
message << " but #{pluralize(@rejected_content_types_not_rejected)} accepted"
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
@@ -88,25 +88,25 @@ module ActiveStorageValidations
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
|
-
def
|
92
|
-
@
|
93
|
-
@
|
91
|
+
def all_allowed_content_types_allowed?
|
92
|
+
@allowed_content_types_not_allowed ||= @allowed_content_types.reject { |type| type_allowed?(type) }
|
93
|
+
@allowed_content_types_not_allowed.empty?
|
94
94
|
end
|
95
95
|
|
96
|
-
def
|
97
|
-
@
|
98
|
-
@
|
96
|
+
def all_rejected_content_types_rejected?
|
97
|
+
@rejected_content_types_not_rejected ||= @rejected_content_types.select { |type| type_allowed?(type) }
|
98
|
+
@rejected_content_types_not_rejected.empty?
|
99
99
|
end
|
100
100
|
|
101
|
-
def type_allowed?(
|
102
|
-
|
101
|
+
def type_allowed?(content_type)
|
102
|
+
attach_file_with_content_type(content_type)
|
103
103
|
validate
|
104
104
|
detach_file
|
105
105
|
is_valid?
|
106
106
|
end
|
107
107
|
|
108
|
-
def
|
109
|
-
@subject.public_send(@attribute_name).attach(attachment_for(
|
108
|
+
def attach_file_with_content_type(content_type)
|
109
|
+
@subject.public_send(@attribute_name).attach(attachment_for(content_type))
|
110
110
|
end
|
111
111
|
|
112
112
|
def is_custom_message_valid?
|
@@ -121,13 +121,13 @@ module ActiveStorageValidations
|
|
121
121
|
@subject.public_send(@attribute_name).attach(attachment_for('fake/fake'))
|
122
122
|
end
|
123
123
|
|
124
|
-
def attachment_for(
|
125
|
-
suffix =
|
124
|
+
def attachment_for(content_type)
|
125
|
+
suffix = Marcel::TYPE_EXTS[content_type.to_s]&.first || 'fake'
|
126
126
|
|
127
127
|
{
|
128
128
|
io: Tempfile.new('.'),
|
129
129
|
filename: "test.#{suffix}",
|
130
|
-
content_type:
|
130
|
+
content_type: content_type
|
131
131
|
}
|
132
132
|
end
|
133
133
|
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
7
|
-
require_relative '
|
8
|
-
require_relative '
|
9
|
-
require_relative '
|
3
|
+
require_relative 'shared/active_storageable'
|
4
|
+
require_relative 'shared/allow_blankable'
|
5
|
+
require_relative 'shared/attachable'
|
6
|
+
require_relative 'shared/contextable'
|
7
|
+
require_relative 'shared/messageable'
|
8
|
+
require_relative 'shared/rspecable'
|
9
|
+
require_relative 'shared/validatable'
|
10
10
|
|
11
11
|
module ActiveStorageValidations
|
12
12
|
module Matchers
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
7
|
-
require_relative '
|
8
|
-
require_relative '
|
9
|
-
require_relative '
|
3
|
+
require_relative 'shared/active_storageable'
|
4
|
+
require_relative 'shared/allow_blankable'
|
5
|
+
require_relative 'shared/attachable'
|
6
|
+
require_relative 'shared/contextable'
|
7
|
+
require_relative 'shared/messageable'
|
8
|
+
require_relative 'shared/rspecable'
|
9
|
+
require_relative 'shared/validatable'
|
10
10
|
|
11
11
|
module ActiveStorageValidations
|
12
12
|
module Matchers
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
7
|
-
require_relative '
|
8
|
-
require_relative '
|
9
|
-
require_relative '
|
3
|
+
require_relative 'shared/active_storageable'
|
4
|
+
require_relative 'shared/allow_blankable'
|
5
|
+
require_relative 'shared/attachable'
|
6
|
+
require_relative 'shared/contextable'
|
7
|
+
require_relative 'shared/messageable'
|
8
|
+
require_relative 'shared/rspecable'
|
9
|
+
require_relative 'shared/validatable'
|
10
10
|
|
11
11
|
module ActiveStorageValidations
|
12
12
|
module Matchers
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'shared/loggable'
|
4
4
|
|
5
5
|
module ActiveStorageValidations
|
6
6
|
class Metadata
|
@@ -8,13 +8,13 @@ module ActiveStorageValidations
|
|
8
8
|
|
9
9
|
class InvalidImageError < StandardError; end
|
10
10
|
|
11
|
-
attr_reader :
|
11
|
+
attr_reader :attachable
|
12
12
|
|
13
13
|
DEFAULT_IMAGE_PROCESSOR = :mini_magick.freeze
|
14
14
|
|
15
|
-
def initialize(
|
15
|
+
def initialize(attachable)
|
16
16
|
require_image_processor
|
17
|
-
@
|
17
|
+
@attachable = attachable
|
18
18
|
end
|
19
19
|
|
20
20
|
def valid?
|
@@ -64,14 +64,9 @@ module ActiveStorageValidations
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def read_image
|
67
|
-
is_string =
|
68
|
-
if is_string ||
|
69
|
-
blob =
|
70
|
-
if is_string
|
71
|
-
ActiveStorage::Blob.find_signed!(file)
|
72
|
-
else
|
73
|
-
file
|
74
|
-
end
|
67
|
+
is_string = attachable.is_a?(String)
|
68
|
+
if is_string || attachable.is_a?(ActiveStorage::Blob)
|
69
|
+
blob = is_string ? ActiveStorage::Blob.find_signed!(attachable) : attachable
|
75
70
|
|
76
71
|
tempfile = Tempfile.new(["ActiveStorage-#{blob.id}-", blob.filename.extension_with_delimiter])
|
77
72
|
tempfile.binmode
|
@@ -107,9 +102,9 @@ module ActiveStorageValidations
|
|
107
102
|
begin
|
108
103
|
Vips::Image.new_from_file(path)
|
109
104
|
rescue exception_class
|
110
|
-
# We handle cases where an error is raised when reading the
|
105
|
+
# We handle cases where an error is raised when reading the attachable
|
111
106
|
# because Vips can throw errors rather than returning false
|
112
|
-
# We stumble upon this issue while reading 0 byte size
|
107
|
+
# We stumble upon this issue while reading 0 byte size attachable
|
113
108
|
# https://github.com/janko/image_processing/issues/97
|
114
109
|
false
|
115
110
|
end
|
@@ -156,13 +151,13 @@ module ActiveStorageValidations
|
|
156
151
|
end
|
157
152
|
|
158
153
|
def read_file_path
|
159
|
-
case
|
154
|
+
case attachable
|
160
155
|
when ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile
|
161
|
-
|
156
|
+
attachable.path
|
162
157
|
when Hash
|
163
|
-
io =
|
158
|
+
io = attachable.fetch(:io)
|
164
159
|
if io.is_a?(StringIO)
|
165
|
-
tempfile = Tempfile.new([File.basename(
|
160
|
+
tempfile = Tempfile.new([File.basename(attachable[:filename], '.*'), File.extname(attachable[:filename])])
|
166
161
|
tempfile.binmode
|
167
162
|
IO.copy_stream(io, tempfile)
|
168
163
|
io.rewind
|
@@ -172,6 +167,10 @@ module ActiveStorageValidations
|
|
172
167
|
else
|
173
168
|
File.open(io).path
|
174
169
|
end
|
170
|
+
when File
|
171
|
+
attachable.path
|
172
|
+
when Pathname
|
173
|
+
attachable.to_s
|
175
174
|
else
|
176
175
|
raise "Something wrong with params."
|
177
176
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
3
|
+
require_relative 'shared/active_storageable'
|
4
|
+
require_relative 'shared/attachable'
|
5
|
+
require_relative 'shared/errorable'
|
6
|
+
require_relative 'shared/symbolizable'
|
7
7
|
|
8
8
|
module ActiveStorageValidations
|
9
9
|
class ProcessableImageValidator < ActiveModel::EachValidator # :nodoc
|
10
10
|
include ActiveStorageable
|
11
|
+
include Attachable
|
11
12
|
include Errorable
|
12
|
-
include Metadatable
|
13
13
|
include Symbolizable
|
14
14
|
|
15
15
|
ERROR_TYPES = %i[
|