@@ -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 |
|
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? && |
|
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