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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -8
  3. data/config/locales/da.yml +0 -1
  4. data/config/locales/de.yml +0 -1
  5. data/config/locales/en.yml +0 -1
  6. data/config/locales/es.yml +0 -1
  7. data/config/locales/fr.yml +0 -1
  8. data/config/locales/it.yml +0 -1
  9. data/config/locales/ja.yml +0 -1
  10. data/config/locales/nl.yml +0 -1
  11. data/config/locales/pl.yml +0 -1
  12. data/config/locales/pt-BR.yml +0 -1
  13. data/config/locales/ru.yml +0 -1
  14. data/config/locales/sv.yml +0 -1
  15. data/config/locales/tr.yml +0 -1
  16. data/config/locales/uk.yml +0 -1
  17. data/config/locales/vi.yml +0 -1
  18. data/config/locales/zh-CN.yml +0 -1
  19. data/lib/active_storage_validations/aspect_ratio_validator.rb +58 -43
  20. data/lib/active_storage_validations/attached_validator.rb +3 -3
  21. data/lib/active_storage_validations/base_size_validator.rb +5 -4
  22. data/lib/active_storage_validations/content_type_spoof_detector.rb +12 -48
  23. data/lib/active_storage_validations/content_type_validator.rb +97 -49
  24. data/lib/active_storage_validations/dimension_validator.rb +8 -7
  25. data/lib/active_storage_validations/limit_validator.rb +6 -5
  26. data/lib/active_storage_validations/matchers/aspect_ratio_validator_matcher.rb +7 -7
  27. data/lib/active_storage_validations/matchers/attached_validator_matcher.rb +6 -6
  28. data/lib/active_storage_validations/matchers/base_size_validator_matcher.rb +7 -7
  29. data/lib/active_storage_validations/matchers/content_type_validator_matcher.rb +33 -33
  30. data/lib/active_storage_validations/matchers/dimension_validator_matcher.rb +7 -7
  31. data/lib/active_storage_validations/matchers/limit_validator_matcher.rb +7 -7
  32. data/lib/active_storage_validations/matchers/processable_image_validator_matcher.rb +7 -7
  33. data/lib/active_storage_validations/metadata.rb +17 -18
  34. data/lib/active_storage_validations/processable_image_validator.rb +5 -5
  35. data/lib/active_storage_validations/shared/attachable.rb +134 -0
  36. data/lib/active_storage_validations/{concerns → shared}/errorable.rb +2 -1
  37. data/lib/active_storage_validations/shared/optionable.rb +27 -0
  38. data/lib/active_storage_validations/size_validator.rb +2 -2
  39. data/lib/active_storage_validations/total_size_validator.rb +2 -2
  40. data/lib/active_storage_validations/version.rb +1 -1
  41. data/lib/active_storage_validations.rb +0 -1
  42. metadata +65 -25
  43. data/lib/active_storage_validations/concerns/metadatable.rb +0 -31
  44. data/lib/active_storage_validations/option_proc_unfolding.rb +0 -16
  45. /data/lib/active_storage_validations/matchers/{concerns → shared}/active_storageable.rb +0 -0
  46. /data/lib/active_storage_validations/matchers/{concerns → shared}/allow_blankable.rb +0 -0
  47. /data/lib/active_storage_validations/matchers/{concerns → shared}/attachable.rb +0 -0
  48. /data/lib/active_storage_validations/matchers/{concerns → shared}/contextable.rb +0 -0
  49. /data/lib/active_storage_validations/matchers/{concerns → shared}/messageable.rb +0 -0
  50. /data/lib/active_storage_validations/matchers/{concerns → shared}/rspecable.rb +0 -0
  51. /data/lib/active_storage_validations/matchers/{concerns → shared}/validatable.rb +0 -0
  52. /data/lib/active_storage_validations/{concerns → shared}/active_storageable.rb +0 -0
  53. /data/lib/active_storage_validations/{concerns → shared}/loggable.rb +0 -0
  54. /data/lib/active_storage_validations/{concerns → shared}/symbolizable.rb +0 -0
@@ -0,0 +1,134 @@
1
+ require_relative "../metadata"
2
+
3
+ module ActiveStorageValidations
4
+ # ActiveStorageValidations::Attachable
5
+ #
6
+ # Validator methods for analyzing attachable.
7
+ #
8
+ # An attachable is a file representation such as ActiveStorage::Blob,
9
+ # ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile, Hash, String,
10
+ # File or Pathname
11
+ module Attachable
12
+ extend ActiveSupport::Concern
13
+
14
+ private
15
+
16
+ # Loop through the newly submitted attachables to validate them. Using
17
+ # attachables is the only way to get the attached file io that is necessary
18
+ # to perform file analyses.
19
+ def validate_changed_files_from_metadata(record, attribute)
20
+ attachables_from_changes(record, attribute).each do |attachable|
21
+ is_valid?(record, attribute, attachable, Metadata.new(attachable).metadata)
22
+ end
23
+ end
24
+
25
+ # Retrieve an array of newly submitted attachables. Some file could be passed
26
+ # several times, we just need to perform the analysis once on the file,
27
+ # therefore the use of #uniq.
28
+ def attachables_from_changes(record, attribute)
29
+ changes = record.attachment_changes[attribute.to_s]
30
+ return [] if changes.blank?
31
+
32
+ Array.wrap(
33
+ changes.is_a?(ActiveStorage::Attached::Changes::CreateMany) ? changes.attachables : changes.attachable
34
+ ).uniq
35
+ end
36
+
37
+ # Retrieve the full declared content_type from attachable.
38
+ def full_attachable_content_type(attachable)
39
+ case attachable
40
+ when ActiveStorage::Blob
41
+ attachable.content_type
42
+ when ActionDispatch::Http::UploadedFile
43
+ attachable.content_type
44
+ when Rack::Test::UploadedFile
45
+ attachable.content_type
46
+ when String
47
+ blob = ActiveStorage::Blob.find_signed!(attachable)
48
+ blob.content_type
49
+ when Hash
50
+ attachable[:content_type]
51
+ when File
52
+ supports_file_attachment? ? marcel_content_type_from_filename(attachable) : raise_rails_like_error(attachable)
53
+ when Pathname
54
+ supports_pathname_attachment? ? marcel_content_type_from_filename(attachable) : raise_rails_like_error(attachable)
55
+ else
56
+ raise_rails_like_error(attachable)
57
+ end
58
+ end
59
+
60
+ # Retrieve the declared content_type from attachable without potential mime
61
+ # type parameters (e.g. 'application/x-rar-compressed;version=5')
62
+ def attachable_content_type(attachable)
63
+ full_attachable_content_type(attachable) && full_attachable_content_type(attachable).downcase.split(/[;,\s]/, 2).first
64
+ end
65
+
66
+ # Retrieve the io from attachable.
67
+ def attachable_io(attachable)
68
+ case attachable
69
+ when ActiveStorage::Blob
70
+ attachable.download
71
+ when ActionDispatch::Http::UploadedFile
72
+ attachable.read
73
+ when Rack::Test::UploadedFile
74
+ attachable.read
75
+ when String
76
+ blob = ActiveStorage::Blob.find_signed!(attachable)
77
+ blob.download
78
+ when Hash
79
+ attachable[:io].read
80
+ when File
81
+ supports_file_attachment? ? attachable : raise_rails_like_error(attachable)
82
+ when Pathname
83
+ supports_pathname_attachment? ? attachable.read : raise_rails_like_error(attachable)
84
+ else
85
+ raise_rails_like_error(attachable)
86
+ end
87
+ end
88
+
89
+ # Retrieve the declared filename from attachable.
90
+ def attachable_filename(attachable)
91
+ case attachable
92
+ when ActiveStorage::Blob
93
+ attachable.filename
94
+ when ActionDispatch::Http::UploadedFile
95
+ attachable.original_filename
96
+ when Rack::Test::UploadedFile
97
+ attachable.original_filename
98
+ when String
99
+ blob = ActiveStorage::Blob.find_signed!(attachable)
100
+ blob.filename
101
+ when Hash
102
+ attachable[:filename]
103
+ when File
104
+ supports_file_attachment? ? File.basename(attachable) : raise_rails_like_error(attachable)
105
+ when Pathname
106
+ supports_pathname_attachment? ? File.basename(attachable) : raise_rails_like_error(attachable)
107
+ else
108
+ raise_rails_like_error(attachable)
109
+ end
110
+ end
111
+
112
+ # Raise the same Rails error for not-implemented file representations.
113
+ def raise_rails_like_error(attachable)
114
+ raise(
115
+ ArgumentError,
116
+ "Could not find or build blob: expected attachable, " \
117
+ "got #{attachable.inspect}"
118
+ )
119
+ end
120
+
121
+ # Check if the current Rails version supports File or Pathname attachment
122
+ #
123
+ # https://github.com/rails/rails/blob/7-1-stable/activestorage/CHANGELOG.md#rails-710rc1-september-27-2023
124
+ def supports_file_attachment?
125
+ Rails.gem_version >= Gem::Version.new('7.1.0.rc1')
126
+ end
127
+ alias :supports_pathname_attachment? :supports_file_attachment?
128
+
129
+ # Retrieve the content_type from the file name only
130
+ def marcel_content_type_from_filename(attachable)
131
+ Marcel::MimeType.for(name: attachable_filename(attachable).to_s)
132
+ end
133
+ end
134
+ end
@@ -30,8 +30,9 @@ module ActiveStorageValidations
30
30
 
31
31
  case file
32
32
  when ActiveStorage::Attached, ActiveStorage::Attachment then file.blob&.filename&.to_s
33
+ when ActiveStorage::Blob then file.filename
33
34
  when Hash then file[:filename]
34
- end
35
+ end.to_s
35
36
  end
36
37
  end
37
38
  end
@@ -0,0 +1,27 @@
1
+ module ActiveStorageValidations
2
+ # ActiveStorageValidations::Optionable
3
+ #
4
+ # Helper method to flatten the validator options.
5
+ module Optionable
6
+ extend ActiveSupport::Concern
7
+
8
+ private
9
+
10
+ def set_flat_options(record)
11
+ flatten_options(record, self.options)
12
+ end
13
+
14
+ def flatten_options(record, options, available_checks = self.class::AVAILABLE_CHECKS)
15
+ case options
16
+ when Hash
17
+ options.merge(options) do |key, value|
18
+ available_checks&.exclude?(key) ? {} : flatten_options(record, value, nil)
19
+ end
20
+ when Array
21
+ options.map { |option| flatten_options(record, option, available_checks) }
22
+ else
23
+ options.is_a?(Proc) ? options.call(record) : options
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base_size_validator.rb'
3
+ require_relative 'base_size_validator'
4
4
 
5
5
  module ActiveStorageValidations
6
6
  class SizeValidator < BaseSizeValidator
@@ -15,7 +15,7 @@ module ActiveStorageValidations
15
15
  def validate_each(record, attribute, _value)
16
16
  return if no_attachments?(record, attribute)
17
17
 
18
- flat_options = unfold_procs(record, self.options, AVAILABLE_CHECKS)
18
+ flat_options = set_flat_options(record)
19
19
 
20
20
  attached_files(record, attribute).each do |file|
21
21
  next if is_valid?(file.blob.byte_size, flat_options)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base_size_validator.rb'
3
+ require_relative 'base_size_validator'
4
4
 
5
5
  module ActiveStorageValidations
6
6
  class TotalSizeValidator < BaseSizeValidator
@@ -18,7 +18,7 @@ module ActiveStorageValidations
18
18
  return if no_attachments?(record, attribute)
19
19
 
20
20
  total_file_size = attached_files(record, attribute).sum { |file| file.blob.byte_size }
21
- flat_options = unfold_procs(record, self.options, AVAILABLE_CHECKS)
21
+ flat_options = set_flat_options(record)
22
22
 
23
23
  return if is_valid?(total_file_size, flat_options)
24
24
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveStorageValidations
4
- VERSION = '1.3.0'
4
+ VERSION = '1.3.2'
5
5
  end
@@ -5,7 +5,6 @@ require 'active_support/concern'
5
5
 
6
6
  require 'active_storage_validations/railtie'
7
7
  require 'active_storage_validations/engine'
8
- require 'active_storage_validations/option_proc_unfolding'
9
8
  require 'active_storage_validations/attached_validator'
10
9
  require 'active_storage_validations/content_type_validator'
11
10
  require 'active_storage_validations/limit_validator'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_storage_validations
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Kasyanchuk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-20 00:00:00.000000000 Z
11
+ date: 2024-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: 6.1.4
69
+ - !ruby/object:Gem::Dependency
70
+ name: marcel
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 1.0.3
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 1.0.3
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: combustion
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -81,47 +95,73 @@ dependencies:
81
95
  - !ruby/object:Gem::Version
82
96
  version: '1.3'
83
97
  - !ruby/object:Gem::Dependency
84
- name: marcel
98
+ name: mini_magick
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
101
  - - ">="
88
102
  - !ruby/object:Gem::Version
89
- version: 1.0.3
103
+ version: 4.9.5
90
104
  type: :development
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
108
  - - ">="
95
109
  - !ruby/object:Gem::Version
96
- version: 1.0.3
110
+ version: 4.9.5
97
111
  - !ruby/object:Gem::Dependency
98
- name: mini_magick
112
+ name: minitest-focus
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.4'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.4'
125
+ - !ruby/object:Gem::Dependency
126
+ name: minitest-mock_expectations
99
127
  requirement: !ruby/object:Gem::Requirement
100
128
  requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.2'
101
132
  - - ">="
102
133
  - !ruby/object:Gem::Version
103
- version: 4.9.5
134
+ version: 1.2.0
104
135
  type: :development
105
136
  prerelease: false
106
137
  version_requirements: !ruby/object:Gem::Requirement
107
138
  requirements:
139
+ - - "~>"
140
+ - !ruby/object:Gem::Version
141
+ version: '1.2'
108
142
  - - ">="
109
143
  - !ruby/object:Gem::Version
110
- version: 4.9.5
144
+ version: 1.2.0
111
145
  - !ruby/object:Gem::Dependency
112
- name: minitest-focus
146
+ name: minitest-stub_any_instance
113
147
  requirement: !ruby/object:Gem::Requirement
114
148
  requirements:
115
149
  - - "~>"
116
150
  - !ruby/object:Gem::Version
117
- version: '1.4'
151
+ version: '1.0'
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: 1.0.3
118
155
  type: :development
119
156
  prerelease: false
120
157
  version_requirements: !ruby/object:Gem::Requirement
121
158
  requirements:
122
159
  - - "~>"
123
160
  - !ruby/object:Gem::Version
124
- version: '1.4'
161
+ version: '1.0'
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: 1.0.3
125
165
  - !ruby/object:Gem::Dependency
126
166
  name: pry
127
167
  requirement: !ruby/object:Gem::Requirement
@@ -222,11 +262,6 @@ files:
222
262
  - lib/active_storage_validations/aspect_ratio_validator.rb
223
263
  - lib/active_storage_validations/attached_validator.rb
224
264
  - lib/active_storage_validations/base_size_validator.rb
225
- - lib/active_storage_validations/concerns/active_storageable.rb
226
- - lib/active_storage_validations/concerns/errorable.rb
227
- - lib/active_storage_validations/concerns/loggable.rb
228
- - lib/active_storage_validations/concerns/metadatable.rb
229
- - lib/active_storage_validations/concerns/symbolizable.rb
230
265
  - lib/active_storage_validations/content_type_spoof_detector.rb
231
266
  - lib/active_storage_validations/content_type_validator.rb
232
267
  - lib/active_storage_validations/dimension_validator.rb
@@ -237,23 +272,28 @@ files:
237
272
  - lib/active_storage_validations/matchers/aspect_ratio_validator_matcher.rb
238
273
  - lib/active_storage_validations/matchers/attached_validator_matcher.rb
239
274
  - lib/active_storage_validations/matchers/base_size_validator_matcher.rb
240
- - lib/active_storage_validations/matchers/concerns/active_storageable.rb
241
- - lib/active_storage_validations/matchers/concerns/allow_blankable.rb
242
- - lib/active_storage_validations/matchers/concerns/attachable.rb
243
- - lib/active_storage_validations/matchers/concerns/contextable.rb
244
- - lib/active_storage_validations/matchers/concerns/messageable.rb
245
- - lib/active_storage_validations/matchers/concerns/rspecable.rb
246
- - lib/active_storage_validations/matchers/concerns/validatable.rb
247
275
  - lib/active_storage_validations/matchers/content_type_validator_matcher.rb
248
276
  - lib/active_storage_validations/matchers/dimension_validator_matcher.rb
249
277
  - lib/active_storage_validations/matchers/limit_validator_matcher.rb
250
278
  - lib/active_storage_validations/matchers/processable_image_validator_matcher.rb
279
+ - lib/active_storage_validations/matchers/shared/active_storageable.rb
280
+ - lib/active_storage_validations/matchers/shared/allow_blankable.rb
281
+ - lib/active_storage_validations/matchers/shared/attachable.rb
282
+ - lib/active_storage_validations/matchers/shared/contextable.rb
283
+ - lib/active_storage_validations/matchers/shared/messageable.rb
284
+ - lib/active_storage_validations/matchers/shared/rspecable.rb
285
+ - lib/active_storage_validations/matchers/shared/validatable.rb
251
286
  - lib/active_storage_validations/matchers/size_validator_matcher.rb
252
287
  - lib/active_storage_validations/matchers/total_size_validator_matcher.rb
253
288
  - lib/active_storage_validations/metadata.rb
254
- - lib/active_storage_validations/option_proc_unfolding.rb
255
289
  - lib/active_storage_validations/processable_image_validator.rb
256
290
  - lib/active_storage_validations/railtie.rb
291
+ - lib/active_storage_validations/shared/active_storageable.rb
292
+ - lib/active_storage_validations/shared/attachable.rb
293
+ - lib/active_storage_validations/shared/errorable.rb
294
+ - lib/active_storage_validations/shared/loggable.rb
295
+ - lib/active_storage_validations/shared/optionable.rb
296
+ - lib/active_storage_validations/shared/symbolizable.rb
257
297
  - lib/active_storage_validations/size_validator.rb
258
298
  - lib/active_storage_validations/total_size_validator.rb
259
299
  - lib/active_storage_validations/version.rb
@@ -278,7 +318,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
278
318
  - !ruby/object:Gem::Version
279
319
  version: '0'
280
320
  requirements: []
281
- rubygems_version: 3.5.11
321
+ rubygems_version: 3.5.16
282
322
  signing_key:
283
323
  specification_version: 4
284
324
  summary: Validations for Active Storage
@@ -1,31 +0,0 @@
1
- require_relative '../metadata'
2
-
3
- module ActiveStorageValidations
4
- # ActiveStorageValidations::Metadatable
5
- #
6
- # Validator methods for analyzing the attachment metadata.
7
- module Metadatable
8
- extend ActiveSupport::Concern
9
-
10
- private
11
-
12
- # Loop through the newly submitted attachables to validate them
13
- def validate_changed_files_from_metadata(record, attribute)
14
- attachables_from_changes(record, attribute).each do |attachable|
15
- is_valid?(record, attribute, attachable, Metadata.new(attachable).metadata)
16
- end
17
- end
18
-
19
- # Retrieve an array of newly submitted attachables which are file
20
- # representations such as ActiveStorage::Blob, ActionDispatch::Http::UploadedFile,
21
- # Rack::Test::UploadedFile, Hash, String, File or Pathname
22
- def attachables_from_changes(record, attribute)
23
- changes = record.attachment_changes[attribute.to_s]
24
- return [] if changes.blank?
25
-
26
- Array.wrap(
27
- changes.is_a?(ActiveStorage::Attached::Changes::CreateMany) ? changes.attachables : changes.attachable
28
- )
29
- end
30
- end
31
- end
@@ -1,16 +0,0 @@
1
- module ActiveStorageValidations
2
- module OptionProcUnfolding
3
-
4
- def unfold_procs(record, object, only_keys)
5
- case object
6
- when Hash
7
- object.merge(object) { |key, value| only_keys&.exclude?(key) ? {} : unfold_procs(record, value, nil) }
8
- when Array
9
- object.map { |o| unfold_procs(record, o, only_keys) }
10
- else
11
- object.is_a?(Proc) ? object.call(record) : object
12
- end
13
- end
14
-
15
- end
16
- end