@@ -354,22 +354,37 class Attachment < ActiveRecord::Base | |||
|
354 | 354 | end |
|
355 | 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 | 359 | def self.valid_extension?(extension) |
|
359 | extension = extension.downcase.sub(/\A\.+/, '') | |
|
360 | ||
|
361 | 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 | 362 | end |
|
364 |
if denied.present? && |
|
|
363 | if denied.present? && extension_in?(extension, denied) | |
|
365 | 364 | return false |
|
366 | 365 | end |
|
367 | unless allowed.blank? || allowed.include?(extension) | |
|
366 | if allowed.present? && !extension_in?(extension, allowed) | |
|
368 | 367 | return false |
|
369 | 368 | end |
|
370 | 369 | true |
|
371 | 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 | 388 | private |
|
374 | 389 | |
|
375 | 390 | # Physically deletes the file from the file system |
@@ -87,7 +87,8 class CustomField < ActiveRecord::Base | |||
|
87 | 87 | 'text_formatting', |
|
88 | 88 | 'edit_tag_style', |
|
89 | 89 | 'user_role', |
|
90 | 'version_status' | |
|
90 | 'version_status', | |
|
91 | 'extensions_allowed' | |
|
91 | 92 | |
|
92 | 93 | def format |
|
93 | 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 | 861 | self.form_partial = 'custom_fields/formats/attachment' |
|
862 | 862 | self.is_filter_supported = false |
|
863 | 863 | self.change_no_details = true |
|
864 | field_attributes :extensions_allowed | |
|
864 | 865 | |
|
865 | 866 | def set_custom_field_value(custom_field, custom_field_value, value) |
|
866 | 867 | attachment_present = false |
@@ -917,8 +918,18 module Redmine | |||
|
917 | 918 | def validate_custom_value(custom_value) |
|
918 | 919 | errors = [] |
|
919 | 920 | |
|
920 | if custom_value.instance_variable_get("@attachment_present") && custom_value.value.blank? | |
|
921 | errors << ::I18n.t('activerecord.errors.messages.invalid') | |
|
921 | if custom_value.value.blank? | |
|
922 | if custom_value.instance_variable_get("@attachment_present") | |
|
923 | errors << ::I18n.t('activerecord.errors.messages.invalid') | |
|
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 | |
|
922 | 933 | end |
|
923 | 934 | |
|
924 | 935 | errors.uniq |
@@ -153,4 +153,42 class AttachmentFieldFormatTest < Redmine::IntegrationTest | |||
|
153 | 153 | assert_equal attachment.id.to_s, custom_value.value |
|
154 | 154 | assert_equal custom_value, attachment.reload.container |
|
155 | 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 | 194 | end |
General Comments 0
You need to be logged in to leave comments.
Login now