git-svn-id: http://svn.redmine.org/redmine/trunk@15921 e93f8b46-1217-0410-a6f0-8f06a7374b81tags/3.4.0
@@ -354,22 +354,37 @@ class Attachment < ActiveRecord::Base | |||
end | |||
end | |||
# Returns true if the extension is allowed, otherwise false | |||
# Returns true if the extension is allowed regarding allowed/denied | |||
# extensions defined in application settings, otherwise false | |||
def self.valid_extension?(extension) | |||
extension = extension.downcase.sub(/\A\.+/, '') | |||
denied, allowed = [:attachment_extensions_denied, :attachment_extensions_allowed].map do |setting| | |||
Setting.send(setting).to_s.split(",").map {|s| s.strip.downcase.sub(/\A\.+/, '')}.reject(&:blank?) | |||
Setting.send(setting) | |||
end | |||
if denied.present? && denied.include?(extension) | |||
if denied.present? && extension_in?(extension, denied) | |||
return false | |||
end | |||
unless allowed.blank? || allowed.include?(extension) | |||
if allowed.present? && !extension_in?(extension, allowed) | |||
return false | |||
end | |||
true | |||
end | |||
# Returns true if extension belongs to extensions list. | |||
def self.extension_in?(extension, extensions) | |||
extension = extension.downcase.sub(/\A\.+/, '') | |||
unless extensions.is_a?(Array) | |||
extensions = extensions.to_s.split(",").map(&:strip) | |||
end | |||
extensions = extensions.map {|s| s.downcase.sub(/\A\.+/, '')}.reject(&:blank?) | |||
extensions.include?(extension) | |||
end | |||
# Returns true if attachment's extension belongs to extensions list. | |||
def extension_in?(extensions) | |||
self.class.extension_in?(File.extname(filename), extensions) | |||
end | |||
private | |||
# Physically deletes the file from the file system |
@@ -87,7 +87,8 @@ class CustomField < ActiveRecord::Base | |||
'text_formatting', | |||
'edit_tag_style', | |||
'user_role', | |||
'version_status' | |||
'version_status', | |||
'extensions_allowed' | |||
def format | |||
@format ||= Redmine::FieldFormat.find(field_format) |
@@ -0,0 +1,4 @@ | |||
<p> | |||
<%= f.text_field :extensions_allowed, :size => 50, :label => :setting_attachment_extensions_allowed %> | |||
<em class="info"><%= l(:text_comma_separated) %> <%= l(:label_example) %>: txt, png</em> | |||
</p> |
@@ -861,6 +861,7 @@ module Redmine | |||
self.form_partial = 'custom_fields/formats/attachment' | |||
self.is_filter_supported = false | |||
self.change_no_details = true | |||
field_attributes :extensions_allowed | |||
def set_custom_field_value(custom_field, custom_field_value, value) | |||
attachment_present = false | |||
@@ -917,8 +918,18 @@ module Redmine | |||
def validate_custom_value(custom_value) | |||
errors = [] | |||
if custom_value.instance_variable_get("@attachment_present") && custom_value.value.blank? | |||
errors << ::I18n.t('activerecord.errors.messages.invalid') | |||
if custom_value.value.blank? | |||
if custom_value.instance_variable_get("@attachment_present") | |||
errors << ::I18n.t('activerecord.errors.messages.invalid') | |||
end | |||
else | |||
if custom_value.value.present? | |||
attachment = Attachment.where(:id => custom_value.value.to_s).first | |||
extensions = custom_value.custom_field.extensions_allowed | |||
if attachment && extensions.present? && !attachment.extension_in?(extensions) | |||
errors << "#{::I18n.t('activerecord.errors.messages.invalid')} (#{l(:setting_attachment_extensions_allowed)}: #{extensions})" | |||
end | |||
end | |||
end | |||
errors.uniq |
@@ -153,4 +153,42 @@ class AttachmentFieldFormatTest < Redmine::IntegrationTest | |||
assert_equal attachment.id.to_s, custom_value.value | |||
assert_equal custom_value, attachment.reload.container | |||
end | |||
def test_create_with_valid_extension | |||
@field.extensions_allowed = "txt, log" | |||
@field.save! | |||
attachment = new_record(Attachment) do | |||
assert_difference 'Issue.count' do | |||
post '/projects/ecookbook/issues', { | |||
:issue => { | |||
:subject => "Blank", | |||
:custom_field_values => { | |||
@field.id => {:file => uploaded_test_file("testfile.txt", "text/plain")} | |||
} | |||
} | |||
} | |||
assert_response 302 | |||
end | |||
end | |||
end | |||
def test_create_with_invalid_extension_should_fail | |||
@field.extensions_allowed = "png, jpeg" | |||
@field.save! | |||
attachment = new_record(Attachment) do | |||
assert_no_difference 'Issue.count' do | |||
post '/projects/ecookbook/issues', { | |||
:issue => { | |||
:subject => "Blank", | |||
:custom_field_values => { | |||
@field.id => {:file => uploaded_test_file("testfile.txt", "text/plain")} | |||
} | |||
} | |||
} | |||
assert_response :success | |||
end | |||
end | |||
end | |||
end |