active_storage_validations 3.0.5 → 4.1.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/MIT-LICENSE +1 -1
- data/README.md +227 -116
- data/Rakefile +13 -15
- data/config/locales/da.yml +2 -0
- data/config/locales/de.yml +2 -0
- data/config/locales/en-GB.yml +2 -0
- data/config/locales/en.yml +2 -0
- data/config/locales/es.yml +2 -0
- data/config/locales/fr.yml +2 -0
- data/config/locales/it.yml +2 -0
- data/config/locales/ja.yml +2 -0
- data/config/locales/nl.yml +2 -0
- data/config/locales/pl.yml +2 -0
- data/config/locales/pt-BR.yml +2 -0
- data/config/locales/ru.yml +2 -0
- data/config/locales/sv.yml +2 -0
- data/config/locales/tr.yml +2 -0
- data/config/locales/uk.yml +2 -0
- data/config/locales/vi.yml +2 -0
- data/config/locales/zh-CN.yml +2 -0
- data/lib/active_storage_validations/analyzer/audio_analyzer.rb +0 -1
- data/lib/active_storage_validations/analyzer/content_type_analyzer/file.rb +31 -0
- data/lib/active_storage_validations/analyzer/content_type_analyzer/magika.rb +44 -0
- data/lib/active_storage_validations/analyzer/content_type_analyzer.rb +15 -24
- data/lib/active_storage_validations/analyzer/image_analyzer/image_magick.rb +41 -7
- data/lib/active_storage_validations/analyzer/image_analyzer/vips.rb +36 -10
- data/lib/active_storage_validations/analyzer/pdf_analyzer.rb +3 -9
- data/lib/active_storage_validations/analyzer/shared/asv_ff_probable.rb +5 -4
- data/lib/active_storage_validations/analyzer/video_analyzer.rb +0 -1
- data/lib/active_storage_validations/analyzer.rb +35 -3
- data/lib/active_storage_validations/content_type_validator.rb +24 -6
- data/lib/active_storage_validations/dimension_validator.rb +4 -2
- data/lib/active_storage_validations/form_builder.rb +43 -0
- data/lib/active_storage_validations/matchers/aspect_ratio_validator_matcher.rb +8 -0
- data/lib/active_storage_validations/matchers/attached_validator_matcher.rb +4 -0
- data/lib/active_storage_validations/matchers/base_comparison_validator_matcher.rb +11 -1
- data/lib/active_storage_validations/matchers/content_type_validator_matcher.rb +12 -0
- data/lib/active_storage_validations/matchers/dimension_validator_matcher.rb +8 -0
- data/lib/active_storage_validations/matchers/duration_validator_matcher.rb +8 -0
- data/lib/active_storage_validations/matchers/limit_validator_matcher.rb +4 -0
- data/lib/active_storage_validations/matchers/pages_validator_matcher.rb +8 -0
- data/lib/active_storage_validations/matchers/processable_file_validator_matcher.rb +8 -0
- data/lib/active_storage_validations/matchers/shared/asv_except_onable.rb +57 -0
- data/lib/active_storage_validations/matchers/shared/asv_spoofing_protectable.rb +44 -0
- data/lib/active_storage_validations/matchers/shared/asv_timeoutable.rb +32 -0
- data/lib/active_storage_validations/matchers/with_audio_validator_matcher.rb +114 -0
- data/lib/active_storage_validations/matchers.rb +10 -1
- data/lib/active_storage_validations/processable_file_validator.rb +60 -1
- data/lib/active_storage_validations/railtie.rb +6 -0
- data/lib/active_storage_validations/shared/asv_analyzable.rb +66 -8
- data/lib/active_storage_validations/shared/asv_attachable.rb +9 -10
- data/lib/active_storage_validations/shared/asv_commandable.rb +95 -0
- data/lib/active_storage_validations/shared/asv_optionable.rb +5 -1
- data/lib/active_storage_validations/version.rb +1 -1
- data/lib/active_storage_validations/with_audio_validator.rb +37 -0
- data/lib/active_storage_validations.rb +23 -0
- metadata +27 -58
|
@@ -6,7 +6,6 @@ require_relative "shared/asv_attachable"
|
|
|
6
6
|
require_relative "shared/asv_errorable"
|
|
7
7
|
require_relative "shared/asv_optionable"
|
|
8
8
|
require_relative "shared/asv_symbolizable"
|
|
9
|
-
require_relative "analyzer/content_type_analyzer"
|
|
10
9
|
|
|
11
10
|
module ActiveStorageValidations
|
|
12
11
|
class ContentTypeValidator < ActiveModel::EachValidator # :nodoc:
|
|
@@ -18,6 +17,7 @@ module ActiveStorageValidations
|
|
|
18
17
|
include ASVSymbolizable
|
|
19
18
|
|
|
20
19
|
AVAILABLE_CHECKS = %i[with in].freeze
|
|
20
|
+
AVAILABLE_SPOOFING_PROTECTION_VALUES = [ true, false, :file, :magika ].freeze
|
|
21
21
|
ERROR_TYPES = %i[
|
|
22
22
|
content_type_invalid
|
|
23
23
|
content_type_spoofed
|
|
@@ -27,6 +27,7 @@ module ActiveStorageValidations
|
|
|
27
27
|
def check_validity!
|
|
28
28
|
ensure_exactly_one_validator_option
|
|
29
29
|
ensure_content_types_validity
|
|
30
|
+
ensure_spoofing_protection_validity
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
def validate_each(record, attribute, _value)
|
|
@@ -125,7 +126,25 @@ module ActiveStorageValidations
|
|
|
125
126
|
end
|
|
126
127
|
|
|
127
128
|
def enable_spoofing_protection?
|
|
128
|
-
|
|
129
|
+
spoofing_protection_backend.present?
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# +true+ and +:file+ both select the UNIX +file+ CLI; +:magika+ selects Magika.
|
|
133
|
+
def spoofing_protection_backend
|
|
134
|
+
case options[:spoofing_protection]
|
|
135
|
+
when true, :file then :file
|
|
136
|
+
when :magika then :magika
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def ensure_spoofing_protection_validity
|
|
141
|
+
return unless options.key?(:spoofing_protection)
|
|
142
|
+
return if AVAILABLE_SPOOFING_PROTECTION_VALUES.include?(options[:spoofing_protection])
|
|
143
|
+
|
|
144
|
+
raise ArgumentError, <<~ERROR_MESSAGE
|
|
145
|
+
Unknown spoofing_protection option: #{options[:spoofing_protection].inspect}.
|
|
146
|
+
Allowed values: #{AVAILABLE_SPOOFING_PROTECTION_VALUES.map(&:inspect).join(", ")}
|
|
147
|
+
ERROR_MESSAGE
|
|
129
148
|
end
|
|
130
149
|
|
|
131
150
|
def attachable_content_type_vs_detected_content_type_mismatch?
|
|
@@ -134,10 +153,9 @@ module ActiveStorageValidations
|
|
|
134
153
|
end
|
|
135
154
|
|
|
136
155
|
def attachable_content_type_intersects_detected_content_type?
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
end
|
|
156
|
+
enlarged_content_type(content_type_without_parameters(@attachable_content_type)).intersect?(
|
|
157
|
+
enlarged_content_type(content_type_without_parameters(@detected_content_type))
|
|
158
|
+
)
|
|
141
159
|
end
|
|
142
160
|
|
|
143
161
|
def enlarged_content_type(content_type)
|
|
@@ -215,8 +215,10 @@ module ActiveStorageValidations
|
|
|
215
215
|
|
|
216
216
|
%i[min max].each do |bound|
|
|
217
217
|
if (range = flat_options[bound])
|
|
218
|
-
flat_options[:width]
|
|
219
|
-
flat_options[:height]
|
|
218
|
+
flat_options[:width] ||= {}
|
|
219
|
+
flat_options[:height] ||= {}
|
|
220
|
+
flat_options[:width][bound] = range.first
|
|
221
|
+
flat_options[:height][bound] = range.last
|
|
220
222
|
end
|
|
221
223
|
end
|
|
222
224
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveStorageValidations
|
|
4
|
+
module FormBuilder
|
|
5
|
+
def file_field(method, options = {})
|
|
6
|
+
options = options.symbolize_keys
|
|
7
|
+
infer_accept = options.delete(:infer_accept)
|
|
8
|
+
infer_accept = ActiveStorageValidations.infer_file_field_accept if infer_accept.nil?
|
|
9
|
+
|
|
10
|
+
if infer_accept && !options.key?(:accept)
|
|
11
|
+
accept = inferred_accept_types(method)
|
|
12
|
+
options[:accept] = accept.join(",") if accept.any?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
super(method, options)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def inferred_accept_types(method)
|
|
21
|
+
return [] unless @object.class.respond_to?(:validators_on)
|
|
22
|
+
|
|
23
|
+
content_type_validators = @object.class.validators_on(method).select do |v|
|
|
24
|
+
v.is_a?(ActiveStorageValidations::ContentTypeValidator)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
content_type_validators.flat_map do |validator|
|
|
28
|
+
types = Array(validator.options[:with]) + Array(validator.options[:in])
|
|
29
|
+
types.filter_map do |type|
|
|
30
|
+
case type
|
|
31
|
+
when String
|
|
32
|
+
type.include?("/") ? type : Marcel::MimeType.for(declared_type: type, extension: type)
|
|
33
|
+
when Symbol
|
|
34
|
+
Marcel::MimeType.for(declared_type: type.to_s, extension: type.to_s)
|
|
35
|
+
when Regexp
|
|
36
|
+
match = type.source.match(%r{\A\\A([a-z]+)/\.\*\\z\z})
|
|
37
|
+
"#{match[1]}/*" if match
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end.uniq
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -4,8 +4,10 @@ require_relative "shared/asv_active_storageable"
|
|
|
4
4
|
require_relative "shared/asv_allow_blankable"
|
|
5
5
|
require_relative "shared/asv_attachable"
|
|
6
6
|
require_relative "shared/asv_contextable"
|
|
7
|
+
require_relative "shared/asv_except_onable"
|
|
7
8
|
require_relative "shared/asv_messageable"
|
|
8
9
|
require_relative "shared/asv_rspecable"
|
|
10
|
+
require_relative "shared/asv_timeoutable"
|
|
9
11
|
require_relative "shared/asv_validatable"
|
|
10
12
|
|
|
11
13
|
module ActiveStorageValidations
|
|
@@ -19,15 +21,19 @@ module ActiveStorageValidations
|
|
|
19
21
|
include ASVAllowBlankable
|
|
20
22
|
include ASVAttachable
|
|
21
23
|
include ASVContextable
|
|
24
|
+
include ASVExceptOnable
|
|
22
25
|
include ASVMessageable
|
|
23
26
|
include ASVRspecable
|
|
27
|
+
include ASVTimeoutable
|
|
24
28
|
include ASVValidatable
|
|
25
29
|
|
|
26
30
|
def initialize(attribute_name)
|
|
27
31
|
initialize_allow_blankable
|
|
28
32
|
initialize_contextable
|
|
33
|
+
initialize_except_onable
|
|
29
34
|
initialize_messageable
|
|
30
35
|
initialize_rspecable
|
|
36
|
+
initialize_timeoutable
|
|
31
37
|
@attribute_name = attribute_name
|
|
32
38
|
@allowed_aspect_ratios = @rejected_aspect_ratios = []
|
|
33
39
|
end
|
|
@@ -55,7 +61,9 @@ module ActiveStorageValidations
|
|
|
55
61
|
|
|
56
62
|
is_a_valid_active_storage_attribute? &&
|
|
57
63
|
is_context_valid? &&
|
|
64
|
+
is_except_on_valid? &&
|
|
58
65
|
is_allowing_blank? &&
|
|
66
|
+
is_timeout_valid? &&
|
|
59
67
|
is_custom_message_valid? &&
|
|
60
68
|
all_allowed_aspect_ratios_allowed? &&
|
|
61
69
|
all_rejected_aspect_ratios_rejected?
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "shared/asv_active_storageable"
|
|
4
4
|
require_relative "shared/asv_attachable"
|
|
5
5
|
require_relative "shared/asv_contextable"
|
|
6
|
+
require_relative "shared/asv_except_onable"
|
|
6
7
|
require_relative "shared/asv_messageable"
|
|
7
8
|
require_relative "shared/asv_rspecable"
|
|
8
9
|
require_relative "shared/asv_validatable"
|
|
@@ -17,12 +18,14 @@ module ActiveStorageValidations
|
|
|
17
18
|
include ASVActiveStorageable
|
|
18
19
|
include ASVAttachable
|
|
19
20
|
include ASVContextable
|
|
21
|
+
include ASVExceptOnable
|
|
20
22
|
include ASVMessageable
|
|
21
23
|
include ASVRspecable
|
|
22
24
|
include ASVValidatable
|
|
23
25
|
|
|
24
26
|
def initialize(attribute_name)
|
|
25
27
|
initialize_contextable
|
|
28
|
+
initialize_except_onable
|
|
26
29
|
initialize_messageable
|
|
27
30
|
initialize_rspecable
|
|
28
31
|
@attribute_name = attribute_name
|
|
@@ -41,6 +44,7 @@ module ActiveStorageValidations
|
|
|
41
44
|
|
|
42
45
|
is_a_valid_active_storage_attribute? &&
|
|
43
46
|
is_context_valid? &&
|
|
47
|
+
is_except_on_valid? &&
|
|
44
48
|
is_custom_message_valid? &&
|
|
45
49
|
is_valid_when_file_attached? &&
|
|
46
50
|
is_invalid_when_file_not_attached?
|
|
@@ -7,6 +7,7 @@ require_relative "shared/asv_active_storageable"
|
|
|
7
7
|
require_relative "shared/asv_allow_blankable"
|
|
8
8
|
require_relative "shared/asv_attachable"
|
|
9
9
|
require_relative "shared/asv_contextable"
|
|
10
|
+
require_relative "shared/asv_except_onable"
|
|
10
11
|
require_relative "shared/asv_messageable"
|
|
11
12
|
require_relative "shared/asv_rspecable"
|
|
12
13
|
require_relative "shared/asv_validatable"
|
|
@@ -20,6 +21,7 @@ module ActiveStorageValidations
|
|
|
20
21
|
include ASVAllowBlankable
|
|
21
22
|
include ASVAttachable
|
|
22
23
|
include ASVContextable
|
|
24
|
+
include ASVExceptOnable
|
|
23
25
|
include ASVMessageable
|
|
24
26
|
include ASVRspecable
|
|
25
27
|
include ASVValidatable
|
|
@@ -27,6 +29,7 @@ module ActiveStorageValidations
|
|
|
27
29
|
def initialize(attribute_name)
|
|
28
30
|
initialize_allow_blankable
|
|
29
31
|
initialize_contextable
|
|
32
|
+
initialize_except_onable
|
|
30
33
|
initialize_messageable
|
|
31
34
|
initialize_rspecable
|
|
32
35
|
@attribute_name = attribute_name
|
|
@@ -68,17 +71,24 @@ module ActiveStorageValidations
|
|
|
68
71
|
|
|
69
72
|
is_a_valid_active_storage_attribute? &&
|
|
70
73
|
is_context_valid? &&
|
|
74
|
+
is_except_on_valid? &&
|
|
71
75
|
is_allowing_blank? &&
|
|
72
76
|
is_custom_message_valid? &&
|
|
73
77
|
not_lower_than_min? &&
|
|
74
78
|
higher_than_min? &&
|
|
75
79
|
lower_than_max? &&
|
|
76
80
|
not_higher_than_max? &&
|
|
77
|
-
equal_to_exact?
|
|
81
|
+
equal_to_exact? &&
|
|
82
|
+
is_timeout_valid?
|
|
78
83
|
end
|
|
79
84
|
|
|
80
85
|
protected
|
|
81
86
|
|
|
87
|
+
# Hook for ASVTimeoutable (Duration / Pages). Size / TotalSize leave this as-is.
|
|
88
|
+
def is_timeout_valid?
|
|
89
|
+
true
|
|
90
|
+
end
|
|
91
|
+
|
|
82
92
|
def build_failure_message(message)
|
|
83
93
|
return unless @failure_message_artefacts.present?
|
|
84
94
|
|
|
@@ -7,8 +7,11 @@ require_relative "shared/asv_active_storageable"
|
|
|
7
7
|
require_relative "shared/asv_allow_blankable"
|
|
8
8
|
require_relative "shared/asv_attachable"
|
|
9
9
|
require_relative "shared/asv_contextable"
|
|
10
|
+
require_relative "shared/asv_except_onable"
|
|
10
11
|
require_relative "shared/asv_messageable"
|
|
11
12
|
require_relative "shared/asv_rspecable"
|
|
13
|
+
require_relative "shared/asv_spoofing_protectable"
|
|
14
|
+
require_relative "shared/asv_timeoutable"
|
|
12
15
|
require_relative "shared/asv_validatable"
|
|
13
16
|
|
|
14
17
|
module ActiveStorageValidations
|
|
@@ -22,15 +25,21 @@ module ActiveStorageValidations
|
|
|
22
25
|
include ASVAllowBlankable
|
|
23
26
|
include ASVAttachable
|
|
24
27
|
include ASVContextable
|
|
28
|
+
include ASVExceptOnable
|
|
25
29
|
include ASVMessageable
|
|
26
30
|
include ASVRspecable
|
|
31
|
+
include ASVSpoofingProtectable
|
|
32
|
+
include ASVTimeoutable
|
|
27
33
|
include ASVValidatable
|
|
28
34
|
|
|
29
35
|
def initialize(attribute_name)
|
|
30
36
|
initialize_allow_blankable
|
|
31
37
|
initialize_contextable
|
|
38
|
+
initialize_except_onable
|
|
32
39
|
initialize_messageable
|
|
33
40
|
initialize_rspecable
|
|
41
|
+
initialize_spoofing_protectable
|
|
42
|
+
initialize_timeoutable
|
|
34
43
|
@attribute_name = attribute_name
|
|
35
44
|
@allowed_content_types = @rejected_content_types = []
|
|
36
45
|
end
|
|
@@ -62,7 +71,10 @@ module ActiveStorageValidations
|
|
|
62
71
|
|
|
63
72
|
is_a_valid_active_storage_attribute? &&
|
|
64
73
|
is_context_valid? &&
|
|
74
|
+
is_except_on_valid? &&
|
|
65
75
|
is_allowing_blank? &&
|
|
76
|
+
is_timeout_valid? &&
|
|
77
|
+
is_spoofing_protection_valid? &&
|
|
66
78
|
is_custom_message_valid? &&
|
|
67
79
|
all_allowed_content_types_allowed? &&
|
|
68
80
|
all_rejected_content_types_rejected?
|
|
@@ -4,8 +4,10 @@ require_relative "shared/asv_active_storageable"
|
|
|
4
4
|
require_relative "shared/asv_allow_blankable"
|
|
5
5
|
require_relative "shared/asv_attachable"
|
|
6
6
|
require_relative "shared/asv_contextable"
|
|
7
|
+
require_relative "shared/asv_except_onable"
|
|
7
8
|
require_relative "shared/asv_messageable"
|
|
8
9
|
require_relative "shared/asv_rspecable"
|
|
10
|
+
require_relative "shared/asv_timeoutable"
|
|
9
11
|
require_relative "shared/asv_validatable"
|
|
10
12
|
|
|
11
13
|
module ActiveStorageValidations
|
|
@@ -19,15 +21,19 @@ module ActiveStorageValidations
|
|
|
19
21
|
include ASVAllowBlankable
|
|
20
22
|
include ASVAttachable
|
|
21
23
|
include ASVContextable
|
|
24
|
+
include ASVExceptOnable
|
|
22
25
|
include ASVMessageable
|
|
23
26
|
include ASVRspecable
|
|
27
|
+
include ASVTimeoutable
|
|
24
28
|
include ASVValidatable
|
|
25
29
|
|
|
26
30
|
def initialize(attribute_name)
|
|
27
31
|
initialize_allow_blankable
|
|
28
32
|
initialize_contextable
|
|
33
|
+
initialize_except_onable
|
|
29
34
|
initialize_messageable
|
|
30
35
|
initialize_rspecable
|
|
36
|
+
initialize_timeoutable
|
|
31
37
|
@attribute_name = attribute_name
|
|
32
38
|
@width_min = @width_max = @height_min = @height_max = nil
|
|
33
39
|
end
|
|
@@ -87,7 +93,9 @@ module ActiveStorageValidations
|
|
|
87
93
|
|
|
88
94
|
is_a_valid_active_storage_attribute? &&
|
|
89
95
|
is_context_valid? &&
|
|
96
|
+
is_except_on_valid? &&
|
|
90
97
|
is_allowing_blank? &&
|
|
98
|
+
is_timeout_valid? &&
|
|
91
99
|
is_custom_message_valid? &&
|
|
92
100
|
width_not_smaller_than_min? &&
|
|
93
101
|
width_larger_than_min? &&
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "base_comparison_validator_matcher"
|
|
4
|
+
require_relative "shared/asv_timeoutable"
|
|
4
5
|
|
|
5
6
|
module ActiveStorageValidations
|
|
6
7
|
module Matchers
|
|
@@ -9,6 +10,13 @@ module ActiveStorageValidations
|
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
class DurationValidatorMatcher < BaseComparisonValidatorMatcher
|
|
13
|
+
include ASVTimeoutable
|
|
14
|
+
|
|
15
|
+
def initialize(attribute_name)
|
|
16
|
+
super
|
|
17
|
+
initialize_timeoutable
|
|
18
|
+
end
|
|
19
|
+
|
|
12
20
|
def description
|
|
13
21
|
"validate file duration of :#{@attribute_name}"
|
|
14
22
|
end
|
|
@@ -4,6 +4,7 @@ require_relative "shared/asv_active_storageable"
|
|
|
4
4
|
require_relative "shared/asv_allow_blankable"
|
|
5
5
|
require_relative "shared/asv_attachable"
|
|
6
6
|
require_relative "shared/asv_contextable"
|
|
7
|
+
require_relative "shared/asv_except_onable"
|
|
7
8
|
require_relative "shared/asv_messageable"
|
|
8
9
|
require_relative "shared/asv_rspecable"
|
|
9
10
|
require_relative "shared/asv_validatable"
|
|
@@ -19,6 +20,7 @@ module ActiveStorageValidations
|
|
|
19
20
|
include ASVAllowBlankable
|
|
20
21
|
include ASVAttachable
|
|
21
22
|
include ASVContextable
|
|
23
|
+
include ASVExceptOnable
|
|
22
24
|
include ASVMessageable
|
|
23
25
|
include ASVRspecable
|
|
24
26
|
include ASVValidatable
|
|
@@ -26,6 +28,7 @@ module ActiveStorageValidations
|
|
|
26
28
|
def initialize(attribute_name)
|
|
27
29
|
initialize_allow_blankable
|
|
28
30
|
initialize_contextable
|
|
31
|
+
initialize_except_onable
|
|
29
32
|
initialize_messageable
|
|
30
33
|
initialize_rspecable
|
|
31
34
|
@attribute_name = attribute_name
|
|
@@ -57,6 +60,7 @@ module ActiveStorageValidations
|
|
|
57
60
|
|
|
58
61
|
is_a_valid_active_storage_attribute? &&
|
|
59
62
|
is_context_valid? &&
|
|
63
|
+
is_except_on_valid? &&
|
|
60
64
|
is_custom_message_valid? &&
|
|
61
65
|
file_count_not_smaller_than_min? &&
|
|
62
66
|
file_count_equal_min? &&
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "base_comparison_validator_matcher"
|
|
4
|
+
require_relative "shared/asv_timeoutable"
|
|
4
5
|
|
|
5
6
|
module ActiveStorageValidations
|
|
6
7
|
module Matchers
|
|
@@ -9,6 +10,13 @@ module ActiveStorageValidations
|
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
class PagesValidatorMatcher < BaseComparisonValidatorMatcher
|
|
13
|
+
include ASVTimeoutable
|
|
14
|
+
|
|
15
|
+
def initialize(attribute_name)
|
|
16
|
+
super
|
|
17
|
+
initialize_timeoutable
|
|
18
|
+
end
|
|
19
|
+
|
|
12
20
|
def description
|
|
13
21
|
"validate file number of pages of :#{@attribute_name}"
|
|
14
22
|
end
|
|
@@ -4,8 +4,10 @@ require_relative "shared/asv_active_storageable"
|
|
|
4
4
|
require_relative "shared/asv_allow_blankable"
|
|
5
5
|
require_relative "shared/asv_attachable"
|
|
6
6
|
require_relative "shared/asv_contextable"
|
|
7
|
+
require_relative "shared/asv_except_onable"
|
|
7
8
|
require_relative "shared/asv_messageable"
|
|
8
9
|
require_relative "shared/asv_rspecable"
|
|
10
|
+
require_relative "shared/asv_timeoutable"
|
|
9
11
|
require_relative "shared/asv_validatable"
|
|
10
12
|
|
|
11
13
|
module ActiveStorageValidations
|
|
@@ -19,15 +21,19 @@ module ActiveStorageValidations
|
|
|
19
21
|
include ASVAllowBlankable
|
|
20
22
|
include ASVAttachable
|
|
21
23
|
include ASVContextable
|
|
24
|
+
include ASVExceptOnable
|
|
22
25
|
include ASVMessageable
|
|
23
26
|
include ASVRspecable
|
|
27
|
+
include ASVTimeoutable
|
|
24
28
|
include ASVValidatable
|
|
25
29
|
|
|
26
30
|
def initialize(attribute_name)
|
|
27
31
|
initialize_allow_blankable
|
|
28
32
|
initialize_contextable
|
|
33
|
+
initialize_except_onable
|
|
29
34
|
initialize_messageable
|
|
30
35
|
initialize_rspecable
|
|
36
|
+
initialize_timeoutable
|
|
31
37
|
@attribute_name = attribute_name
|
|
32
38
|
end
|
|
33
39
|
|
|
@@ -44,6 +50,8 @@ module ActiveStorageValidations
|
|
|
44
50
|
|
|
45
51
|
is_a_valid_active_storage_attribute? &&
|
|
46
52
|
is_context_valid? &&
|
|
53
|
+
is_except_on_valid? &&
|
|
54
|
+
is_timeout_valid? &&
|
|
47
55
|
is_custom_message_valid? &&
|
|
48
56
|
is_valid_when_image_processable? &&
|
|
49
57
|
is_invalid_when_file_not_processable?
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
|
|
5
|
+
module ActiveStorageValidations
|
|
6
|
+
module Matchers
|
|
7
|
+
module ASVExceptOnable
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
def initialize_except_onable
|
|
11
|
+
@except_on = nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def except_on(context)
|
|
15
|
+
@except_on = context
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def is_except_on_valid?
|
|
22
|
+
return true if !@except_on && attribute_validators.none? { |validator| validator.options[:except_on] }
|
|
23
|
+
|
|
24
|
+
ensure_except_on_present!
|
|
25
|
+
ensure_except_on_valid!
|
|
26
|
+
|
|
27
|
+
if @except_on.is_a?(Array)
|
|
28
|
+
(validator_except_on_contexts & @except_on.map(&:to_s)) == validator_except_on_contexts || raise_except_on_not_listed_error
|
|
29
|
+
elsif @except_on.is_a?(Symbol)
|
|
30
|
+
validator_except_on_contexts.include?(@except_on.to_s) || raise_except_on_not_listed_error
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def ensure_except_on_present!
|
|
35
|
+
raise ArgumentError, "This validator matcher needs the #except_on option to work since its validator has one" if !@except_on && attribute_validators.all? { |validator| validator.options[:except_on] }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def ensure_except_on_valid!
|
|
39
|
+
raise ArgumentError, "This validator matcher option only allows a symbol or an array" if !(@except_on.is_a?(Symbol) || @except_on.is_a?(Array))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def validator_except_on_contexts
|
|
43
|
+
attribute_validators.map do |validator|
|
|
44
|
+
case validator.options[:except_on]
|
|
45
|
+
when Array then validator.options[:except_on].map { |context| context.to_s }
|
|
46
|
+
when NilClass then nil
|
|
47
|
+
else validator.options[:except_on].to_s
|
|
48
|
+
end
|
|
49
|
+
end.flatten.compact
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def raise_except_on_not_listed_error
|
|
53
|
+
raise ArgumentError, "One of the provided contexts to the #except_on method is not found in any of the listed contexts for this attribute"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
|
|
5
|
+
module ActiveStorageValidations
|
|
6
|
+
module Matchers
|
|
7
|
+
module ASVSpoofingProtectable
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
UNSET = Object.new.freeze
|
|
11
|
+
|
|
12
|
+
def initialize_spoofing_protectable
|
|
13
|
+
@spoofing_protection = UNSET
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def spoofing_protection(value = true)
|
|
17
|
+
@spoofing_protection = value
|
|
18
|
+
self
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def is_spoofing_protection_valid?
|
|
24
|
+
return true if @spoofing_protection.equal?(UNSET)
|
|
25
|
+
|
|
26
|
+
expected = normalize_spoofing_protection(@spoofing_protection)
|
|
27
|
+
attribute_validators.any? do |validator|
|
|
28
|
+
next false unless validator.options.key?(:spoofing_protection)
|
|
29
|
+
|
|
30
|
+
normalize_spoofing_protection(validator.options[:spoofing_protection]) == expected
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def normalize_spoofing_protection(value)
|
|
35
|
+
case value
|
|
36
|
+
when true, :file then :file
|
|
37
|
+
when :magika then :magika
|
|
38
|
+
when false then false
|
|
39
|
+
else value
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
|
|
5
|
+
module ActiveStorageValidations
|
|
6
|
+
module Matchers
|
|
7
|
+
module ASVTimeoutable
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
UNSET = Object.new.freeze
|
|
11
|
+
|
|
12
|
+
def initialize_timeoutable
|
|
13
|
+
@timeout = UNSET
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def timeout(value)
|
|
17
|
+
@timeout = value
|
|
18
|
+
self
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def is_timeout_valid?
|
|
24
|
+
return true if @timeout.equal?(UNSET)
|
|
25
|
+
|
|
26
|
+
attribute_validators.any? do |validator|
|
|
27
|
+
validator.options.key?(:timeout) && validator.options[:timeout] == @timeout
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|