active_storage_validations 1.3.0 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
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