From 27a49def634b506c4acad5f5303c1d54757a7da0 Mon Sep 17 00:00:00 2001 From: Matthieu Prat Date: Tue, 12 Nov 2024 12:59:10 +0000 Subject: [PATCH 1/2] Support file extensions in uppercase Since version 1.3.1 (fa64570), the extension of an attachment is validated against its content type. However, when the extension is not in lowercase, validation fails. This commit fixes the issue by downcasing the attachment's extension before checking it against possible extensions for the content type. --- .../content_type_validator.rb | 2 +- .../models/content_type/validator/check.rb | 2 ++ .../validators/content_type_validator_test.rb | 35 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/lib/active_storage_validations/content_type_validator.rb b/lib/active_storage_validations/content_type_validator.rb index 30d1d56..466931c 100644 --- a/lib/active_storage_validations/content_type_validator.rb +++ b/lib/active_storage_validations/content_type_validator.rb @@ -67,7 +67,7 @@ def extension_matches_content_type?(record, attribute, attachable) extension = @attachable_filename.split('.').last possible_extensions = Marcel::TYPE_EXTS[@attachable_content_type] - return true if possible_extensions && extension.in?(possible_extensions) + return true if possible_extensions && extension.downcase.in?(possible_extensions) errors_options = initialize_and_populate_error_options(options, attachable) add_error(record, attribute, ERROR_TYPES.first, **errors_options) diff --git a/test/dummy/app/models/content_type/validator/check.rb b/test/dummy/app/models/content_type/validator/check.rb index 5cd229d..58a7a62 100644 --- a/test/dummy/app/models/content_type/validator/check.rb +++ b/test/dummy/app/models/content_type/validator/check.rb @@ -27,6 +27,8 @@ def self.example_for(type, several: false) validates :extension_two_extensions_docx, content_type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' has_one_attached :extension_two_extensions_pdf validates :extension_two_extensions_pdf, content_type: 'application/pdf' + has_one_attached :pdf_file + validates :pdf_file, content_type: 'application/pdf' %w(symbol string regex).each do |type| has_one_attached :"with_#{type}" diff --git a/test/validators/content_type_validator_test.rb b/test/validators/content_type_validator_test.rb index 9fe757a..5380447 100644 --- a/test/validators/content_type_validator_test.rb +++ b/test/validators/content_type_validator_test.rb @@ -126,6 +126,41 @@ it { is_expected_to_be_valid } end end + + describe "when the extension is in uppercase" do + subject { model.public_send(attribute).attach(pdf_file_with_extension_in_uppercase) and model } + + let(:attribute) { :pdf_file } + let(:pdf_file_with_extension_in_uppercase) do + pdf_file.tap do |file| + file[:filename][".pdf"] = ".PDF" + end + end + + it { is_expected_to_be_valid } + end + + describe "when the extension is missing" do + subject { model.public_send(attribute).attach(pdf_file_without_extension) and model } + + let(:attribute) { :pdf_file } + let(:pdf_file_without_extension) do + pdf_file.tap do |file| + file[:filename][".pdf"] = "" + end + end + let(:error_options) do + { + authorized_types: "PDF", + content_type: pdf_file_without_extension[:content_type], + filename: pdf_file_without_extension[:filename] + } + end + + it { is_expected_not_to_be_valid } + it { is_expected_to_have_error_message("content_type_invalid", error_options: error_options) } + it { is_expected_to_have_error_options(error_options) } + end end describe ":with" do From eb1cff3e02abfcdf60fc6c235b18951a1637b81d Mon Sep 17 00:00:00 2001 From: Matthieu Prat Date: Tue, 12 Nov 2024 14:30:34 +0000 Subject: [PATCH 2/2] Use bespoke attachments for each validation Addresses the following comment: https://github.com/igorkasyanchuk/active_storage_validations/pull/289#discussion_r1838190689 --- test/dummy/app/models/content_type/validator/check.rb | 6 ++++-- test/validators/content_type_validator_test.rb | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/dummy/app/models/content_type/validator/check.rb b/test/dummy/app/models/content_type/validator/check.rb index 58a7a62..b950a51 100644 --- a/test/dummy/app/models/content_type/validator/check.rb +++ b/test/dummy/app/models/content_type/validator/check.rb @@ -27,8 +27,10 @@ def self.example_for(type, several: false) validates :extension_two_extensions_docx, content_type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' has_one_attached :extension_two_extensions_pdf validates :extension_two_extensions_pdf, content_type: 'application/pdf' - has_one_attached :pdf_file - validates :pdf_file, content_type: 'application/pdf' + has_one_attached :extension_upcase_extension + validates :extension_upcase_extension, content_type: 'application/pdf' + has_one_attached :extension_missing_extension + validates :extension_missing_extension, content_type: 'application/pdf' %w(symbol string regex).each do |type| has_one_attached :"with_#{type}" diff --git a/test/validators/content_type_validator_test.rb b/test/validators/content_type_validator_test.rb index 5380447..571f900 100644 --- a/test/validators/content_type_validator_test.rb +++ b/test/validators/content_type_validator_test.rb @@ -130,7 +130,7 @@ describe "when the extension is in uppercase" do subject { model.public_send(attribute).attach(pdf_file_with_extension_in_uppercase) and model } - let(:attribute) { :pdf_file } + let(:attribute) { :extension_upcase_extension } let(:pdf_file_with_extension_in_uppercase) do pdf_file.tap do |file| file[:filename][".pdf"] = ".PDF" @@ -143,7 +143,7 @@ describe "when the extension is missing" do subject { model.public_send(attribute).attach(pdf_file_without_extension) and model } - let(:attribute) { :pdf_file } + let(:attribute) { :extension_missing_extension } let(:pdf_file_without_extension) do pdf_file.tap do |file| file[:filename][".pdf"] = ""