##// END OF EJS Templates
Option to specify allowed extensions for a file custom field (#6719)....
Jean-Philippe Lang -
r15539:f94711ea8c99
parent child
Show More
@@ -354,22 +354,37 class Attachment < ActiveRecord::Base
354 end
354 end
355 end
355 end
356
356
357 # Returns true if the extension is allowed, otherwise false
357 # Returns true if the extension is allowed regarding allowed/denied
358 # extensions defined in application settings, otherwise false
358 def self.valid_extension?(extension)
359 def self.valid_extension?(extension)
359 extension = extension.downcase.sub(/\A\.+/, '')
360
361 denied, allowed = [:attachment_extensions_denied, :attachment_extensions_allowed].map do |setting|
360 denied, allowed = [:attachment_extensions_denied, :attachment_extensions_allowed].map do |setting|
362 Setting.send(setting).to_s.split(",").map {|s| s.strip.downcase.sub(/\A\.+/, '')}.reject(&:blank?)
361 Setting.send(setting)
363 end
362 end
364 if denied.present? && denied.include?(extension)
363 if denied.present? && extension_in?(extension, denied)
365 return false
364 return false
366 end
365 end
367 unless allowed.blank? || allowed.include?(extension)
366 if allowed.present? && !extension_in?(extension, allowed)
368 return false
367 return false
369 end
368 end
370 true
369 true
371 end
370 end
372
371
372 # Returns true if extension belongs to extensions list.
373 def self.extension_in?(extension, extensions)
374 extension = extension.downcase.sub(/\A\.+/, '')
375
376 unless extensions.is_a?(Array)
377 extensions = extensions.to_s.split(",").map(&:strip)
378 end
379 extensions = extensions.map {|s| s.downcase.sub(/\A\.+/, '')}.reject(&:blank?)
380 extensions.include?(extension)
381 end
382
383 # Returns true if attachment's extension belongs to extensions list.
384 def extension_in?(extensions)
385 self.class.extension_in?(File.extname(filename), extensions)
386 end
387
373 private
388 private
374
389
375 # Physically deletes the file from the file system
390 # Physically deletes the file from the file system
@@ -87,7 +87,8 class CustomField < ActiveRecord::Base
87 'text_formatting',
87 'text_formatting',
88 'edit_tag_style',
88 'edit_tag_style',
89 'user_role',
89 'user_role',
90 'version_status'
90 'version_status',
91 'extensions_allowed'
91
92
92 def format
93 def format
93 @format ||= Redmine::FieldFormat.find(field_format)
94 @format ||= Redmine::FieldFormat.find(field_format)
@@ -0,0 +1,4
1 <p>
2 <%= f.text_field :extensions_allowed, :size => 50, :label => :setting_attachment_extensions_allowed %>
3 <em class="info"><%= l(:text_comma_separated) %> <%= l(:label_example) %>: txt, png</em>
4 </p>
@@ -861,6 +861,7 module Redmine
861 self.form_partial = 'custom_fields/formats/attachment'
861 self.form_partial = 'custom_fields/formats/attachment'
862 self.is_filter_supported = false
862 self.is_filter_supported = false
863 self.change_no_details = true
863 self.change_no_details = true
864 field_attributes :extensions_allowed
864
865
865 def set_custom_field_value(custom_field, custom_field_value, value)
866 def set_custom_field_value(custom_field, custom_field_value, value)
866 attachment_present = false
867 attachment_present = false
@@ -917,9 +918,19 module Redmine
917 def validate_custom_value(custom_value)
918 def validate_custom_value(custom_value)
918 errors = []
919 errors = []
919
920
920 if custom_value.instance_variable_get("@attachment_present") && custom_value.value.blank?
921 if custom_value.value.blank?
922 if custom_value.instance_variable_get("@attachment_present")
921 errors << ::I18n.t('activerecord.errors.messages.invalid')
923 errors << ::I18n.t('activerecord.errors.messages.invalid')
922 end
924 end
925 else
926 if custom_value.value.present?
927 attachment = Attachment.where(:id => custom_value.value.to_s).first
928 extensions = custom_value.custom_field.extensions_allowed
929 if attachment && extensions.present? && !attachment.extension_in?(extensions)
930 errors << "#{::I18n.t('activerecord.errors.messages.invalid')} (#{l(:setting_attachment_extensions_allowed)}: #{extensions})"
931 end
932 end
933 end
923
934
924 errors.uniq
935 errors.uniq
925 end
936 end
@@ -153,4 +153,42 class AttachmentFieldFormatTest < Redmine::IntegrationTest
153 assert_equal attachment.id.to_s, custom_value.value
153 assert_equal attachment.id.to_s, custom_value.value
154 assert_equal custom_value, attachment.reload.container
154 assert_equal custom_value, attachment.reload.container
155 end
155 end
156
157 def test_create_with_valid_extension
158 @field.extensions_allowed = "txt, log"
159 @field.save!
160
161 attachment = new_record(Attachment) do
162 assert_difference 'Issue.count' do
163 post '/projects/ecookbook/issues', {
164 :issue => {
165 :subject => "Blank",
166 :custom_field_values => {
167 @field.id => {:file => uploaded_test_file("testfile.txt", "text/plain")}
168 }
169 }
170 }
171 assert_response 302
172 end
173 end
174 end
175
176 def test_create_with_invalid_extension_should_fail
177 @field.extensions_allowed = "png, jpeg"
178 @field.save!
179
180 attachment = new_record(Attachment) do
181 assert_no_difference 'Issue.count' do
182 post '/projects/ecookbook/issues', {
183 :issue => {
184 :subject => "Blank",
185 :custom_field_values => {
186 @field.id => {:file => uploaded_test_file("testfile.txt", "text/plain")}
187 }
188 }
189 }
190 assert_response :success
191 end
192 end
193 end
156 end
194 end
General Comments 0
You need to be logged in to leave comments. Login now