##// END OF EJS Templates
Fixes that custom values length and attachment size validation error raises an error....
Jean-Philippe Lang -
r2575:1c03b98e5dac
parent child
Show More
@@ -1,151 +1,153
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require "digest/md5"
19 19
20 20 class Attachment < ActiveRecord::Base
21 21 belongs_to :container, :polymorphic => true
22 22 belongs_to :author, :class_name => "User", :foreign_key => "author_id"
23 23
24 24 validates_presence_of :container, :filename, :author
25 25 validates_length_of :filename, :maximum => 255
26 26 validates_length_of :disk_filename, :maximum => 255
27 27
28 28 acts_as_event :title => :filename,
29 29 :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}}
30 30
31 31 acts_as_activity_provider :type => 'files',
32 32 :permission => :view_files,
33 33 :author_key => :author_id,
34 34 :find_options => {:select => "#{Attachment.table_name}.*",
35 35 :joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " +
36 36 "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id OR ( #{Attachment.table_name}.container_type='Project' AND #{Attachment.table_name}.container_id = #{Project.table_name}.id )"}
37 37
38 38 acts_as_activity_provider :type => 'documents',
39 39 :permission => :view_documents,
40 40 :author_key => :author_id,
41 41 :find_options => {:select => "#{Attachment.table_name}.*",
42 42 :joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " +
43 43 "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"}
44 44
45 45 cattr_accessor :storage_path
46 46 @@storage_path = "#{RAILS_ROOT}/files"
47 47
48 48 def validate
49 errors.add_to_base :too_long if self.filesize > Setting.attachment_max_size.to_i.kilobytes
49 if self.filesize > Setting.attachment_max_size.to_i.kilobytes
50 errors.add(:base, :too_long, :count => Setting.attachment_max_size.to_i.kilobytes)
51 end
50 52 end
51 53
52 54 def file=(incoming_file)
53 55 unless incoming_file.nil?
54 56 @temp_file = incoming_file
55 57 if @temp_file.size > 0
56 58 self.filename = sanitize_filename(@temp_file.original_filename)
57 59 self.disk_filename = Attachment.disk_filename(filename)
58 60 self.content_type = @temp_file.content_type.to_s.chomp
59 61 self.filesize = @temp_file.size
60 62 end
61 63 end
62 64 end
63 65
64 66 def file
65 67 nil
66 68 end
67 69
68 70 # Copy temp file to its final location
69 71 def before_save
70 72 if @temp_file && (@temp_file.size > 0)
71 73 logger.debug("saving '#{self.diskfile}'")
72 74 File.open(diskfile, "wb") do |f|
73 75 f.write(@temp_file.read)
74 76 end
75 77 self.digest = self.class.digest(diskfile)
76 78 end
77 79 # Don't save the content type if it's longer than the authorized length
78 80 if self.content_type && self.content_type.length > 255
79 81 self.content_type = nil
80 82 end
81 83 end
82 84
83 85 # Deletes file on the disk
84 86 def after_destroy
85 87 File.delete(diskfile) if !filename.blank? && File.exist?(diskfile)
86 88 end
87 89
88 90 # Returns file's location on disk
89 91 def diskfile
90 92 "#{@@storage_path}/#{self.disk_filename}"
91 93 end
92 94
93 95 def increment_download
94 96 increment!(:downloads)
95 97 end
96 98
97 99 def project
98 100 container.project
99 101 end
100 102
101 103 def visible?(user=User.current)
102 104 container.attachments_visible?(user)
103 105 end
104 106
105 107 def deletable?(user=User.current)
106 108 container.attachments_deletable?(user)
107 109 end
108 110
109 111 def image?
110 112 self.filename =~ /\.(jpe?g|gif|png)$/i
111 113 end
112 114
113 115 def is_text?
114 116 Redmine::MimeType.is_type?('text', filename)
115 117 end
116 118
117 119 def is_diff?
118 120 self.filename =~ /\.(patch|diff)$/i
119 121 end
120 122
121 123 private
122 124 def sanitize_filename(value)
123 125 # get only the filename, not the whole path
124 126 just_filename = value.gsub(/^.*(\\|\/)/, '')
125 127 # NOTE: File.basename doesn't work right with Windows paths on Unix
126 128 # INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/'))
127 129
128 130 # Finally, replace all non alphanumeric, hyphens or periods with underscore
129 131 @filename = just_filename.gsub(/[^\w\.\-]/,'_')
130 132 end
131 133
132 134 # Returns an ASCII or hashed filename
133 135 def self.disk_filename(filename)
134 136 df = DateTime.now.strftime("%y%m%d%H%M%S") + "_"
135 137 if filename =~ %r{^[a-zA-Z0-9_\.\-]*$}
136 138 df << filename
137 139 else
138 140 df << Digest::MD5.hexdigest(filename)
139 141 # keep the extension if any
140 142 df << $1 if filename =~ %r{(\.[a-zA-Z0-9]+)$}
141 143 end
142 144 df
143 145 end
144 146
145 147 # Returns the MD5 digest of the file at given path
146 148 def self.digest(filename)
147 149 File.open(filename, 'rb') do |f|
148 150 Digest::MD5.hexdigest(f.read)
149 151 end
150 152 end
151 153 end
@@ -1,67 +1,67
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class CustomValue < ActiveRecord::Base
19 19 belongs_to :custom_field
20 20 belongs_to :customized, :polymorphic => true
21 21
22 22 def after_initialize
23 23 if custom_field && new_record? && (customized_type.blank? || (customized && customized.new_record?))
24 24 self.value ||= custom_field.default_value
25 25 end
26 26 end
27 27
28 28 # Returns true if the boolean custom value is true
29 29 def true?
30 30 self.value == '1'
31 31 end
32 32
33 33 def editable?
34 34 custom_field.editable?
35 35 end
36 36
37 37 def required?
38 38 custom_field.is_required?
39 39 end
40 40
41 41 def to_s
42 42 value.to_s
43 43 end
44 44
45 45 protected
46 46 def validate
47 47 if value.blank?
48 48 errors.add(:value, :blank) if custom_field.is_required? and value.blank?
49 49 else
50 50 errors.add(:value, :invalid) unless custom_field.regexp.blank? or value =~ Regexp.new(custom_field.regexp)
51 errors.add(:value, :too_short) if custom_field.min_length > 0 and value.length < custom_field.min_length
52 errors.add(:value, :too_long) if custom_field.max_length > 0 and value.length > custom_field.max_length
51 errors.add(:value, :too_short, :count => custom_field.min_length) if custom_field.min_length > 0 and value.length < custom_field.min_length
52 errors.add(:value, :too_long, :count => custom_field.max_length) if custom_field.max_length > 0 and value.length > custom_field.max_length
53 53
54 54 # Format specific validations
55 55 case custom_field.field_format
56 56 when 'int'
57 57 errors.add(:value, :not_a_number) unless value =~ /^[+-]?\d+$/
58 58 when 'float'
59 59 begin; Kernel.Float(value); rescue; errors.add(:value, :invalid) end
60 60 when 'date'
61 61 errors.add(:value, :not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/
62 62 when 'list'
63 63 errors.add(:value, :inclusion) unless custom_field.possible_values.include?(value)
64 64 end
65 65 end
66 66 end
67 67 end
General Comments 0
You need to be logged in to leave comments. Login now