From 19e89cce3d8faa1180ce433d6856495f86f2259a Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 7 Sep 2016 15:44:11 +0200 Subject: [PATCH] [feature] validate project attachement by mime type --- app/models/project_cao.rb | 9 +++ app/uploaders/project_cao_uploader.rb | 2 +- app/validators/file_mime_type_validator.rb | 81 ++++++++++++++++++++++ config/locales/rails.en.yml | 1 + config/locales/rails.fr.yml | 1 + 5 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 app/validators/file_mime_type_validator.rb diff --git a/app/models/project_cao.rb b/app/models/project_cao.rb index a4b0ecf49..b6154bf48 100644 --- a/app/models/project_cao.rb +++ b/app/models/project_cao.rb @@ -2,4 +2,13 @@ class ProjectCao < Asset mount_uploader :attachment, ProjectCaoUploader validates :attachment, file_size: { maximum: 20.megabytes.to_i } + validates :attachment, :file_mime_type => { + :content_type => %w(application/pdf application/postscript application/illustrator application/postscript + image/x-eps image/svg+xml application/sla application/dxf application/acad application/dwg + application/octet-stream application/step application/iges model/iges x-world/x-3dmf + application/ application/vnd.openxmlformats-officedocument.wordprocessingml.document + image/png text/x-arduino text/plain application/scad application/vnd.sketchup.skp + application/x-koan application/vnd-koan koan/x-skm application/vnd.koan application/x-tex + application/x-latex) + } end diff --git a/app/uploaders/project_cao_uploader.rb b/app/uploaders/project_cao_uploader.rb index 6b2187c54..11777d649 100644 --- a/app/uploaders/project_cao_uploader.rb +++ b/app/uploaders/project_cao_uploader.rb @@ -39,7 +39,7 @@ class ProjectCaoUploader < CarrierWave::Uploader::Base # Add a white list of extensions which are allowed to be uploaded. # For images you might use something like this: def extension_white_list - %w(pdf ai eps cad math svg stl dxf dwg obj step iges 3dm doc docx png ino scad fcad skp sldprt sldasm slddrw slddrt tex latex ps) + %w(pdf ai eps cad math svg stl dxf dwg obj step iges igs 3dm 3dmf doc docx png ino scad fcad skp sldprt sldasm slddrw slddrt tex latex ps) end # Override the filename of the uploaded files: diff --git a/app/validators/file_mime_type_validator.rb b/app/validators/file_mime_type_validator.rb new file mode 100644 index 000000000..43c384521 --- /dev/null +++ b/app/validators/file_mime_type_validator.rb @@ -0,0 +1,81 @@ +# Based on: https://gist.github.com/1298417 + +class FileMimeTypeValidator < ActiveModel::EachValidator + MESSAGES = { :content_type => :wrong_content_type }.freeze + CHECKS = [ :content_type ].freeze + + DEFAULT_TOKENIZER = lambda { |value| value.split(//) } + RESERVED_OPTIONS = [:content_type, :tokenizer] + + def initialize(options) + super + + end + + def check_validity! + keys = CHECKS & options.keys + + if keys.empty? + raise ArgumentError, 'Patterns unspecified. Specify the :content_type option.' + end + + keys.each do |key| + value = options[key] + + unless valid_content_type_option?(value) + raise ArgumentError, ":#{key} must be a String or a Regexp or an Array" + end + + if key.is_a?(Array) && key == :content_type + options[key].each do |val| + raise ArgumentError, "#{val} must be a String or a Regexp" unless val.is_a?(String) || val.is_a?(Regexp) + end + end + end + end + + def validate_each(record, attribute, value) + raise(ArgumentError, 'A CarrierWave::Uploader::Base object was expected') unless value.kind_of? CarrierWave::Uploader::Base + value = (options[:tokenizer] || DEFAULT_TOKENIZER).call(value) if value.kind_of?(String) + return if value.length == 0 + + CHECKS.each do |key| + next unless check_value = options[key] + do_validation(value, check_value, key, record, attribute) if key == :content_type + end + end + + def help + Helper.instance + end + + class Helper + include Singleton + include ActionView::Helpers::NumberHelper + end + + private + + def valid_content_type_option?(content_type) + return true if %w{Array String Regexp}.include?(content_type.class.to_s) + false + end + + def do_validation(value, pattern, key, record, attribute) + if pattern.is_a?(String) || pattern.is_a?(Regexp) + return if value.file.content_type.send((pattern.is_a?(String) ? '==' : '=~' ), pattern) + else + valid_list = pattern.map do |p| + value.file.content_type.send((p.is_a?(String) ? '==' : '=~' ), p) + end + return if valid_list.include?(true) + end + + errors_options = options.except(*RESERVED_OPTIONS) + + default_message = options[MESSAGES[key]] + errors_options[:message] ||= default_message if default_message + + record.errors.add(attribute, MESSAGES[key], errors_options) + end +end \ No newline at end of file diff --git a/config/locales/rails.en.yml b/config/locales/rails.en.yml index 43dd86e3c..f74f5d29d 100644 --- a/config/locales/rails.en.yml +++ b/config/locales/rails.en.yml @@ -130,6 +130,7 @@ en: one: is the wrong length (should be 1 character) other: is the wrong length (should be %{count} characters) other_than: must be other than %{count} + wrong_content_type: "is the wrong content type" template: body: 'There were problems with the following fields:' header: diff --git a/config/locales/rails.fr.yml b/config/locales/rails.fr.yml index 26d2eb66f..42601f161 100644 --- a/config/locales/rails.fr.yml +++ b/config/locales/rails.fr.yml @@ -132,6 +132,7 @@ fr: one: ne fait pas la bonne longueur (doit comporter un seul caractère) other: ne fait pas la bonne longueur (doit comporter %{count} caractères) other_than: doit être différent de %{count} + wrong_content_type: "n'est pas le bon type de contenu" template: body: 'Veuillez vérifier les champs suivants : ' header: