##// END OF EJS Templates
Makes MailHandler accept all issue attributes and custom fields that can be set/updated (#4071, #4807, #5622, #6110)....
Jean-Philippe Lang -
r4280:e0e8c14c2aef
parent child
Show More
@@ -248,19 +248,22 class Issue < ActiveRecord::Base
248 248 def safe_attributes=(attrs, user=User.current)
249 249 return unless attrs.is_a?(Hash)
250 250
251 new_statuses_allowed = new_statuses_allowed_to(user)
252
253 251 # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed
254 252 if new_record? || user.allowed_to?(:edit_issues, project)
255 253 attrs = attrs.reject {|k,v| !SAFE_ATTRIBUTES.include?(k)}
256 elsif new_statuses_allowed.any?
254 elsif new_statuses_allowed_to(user).any?
257 255 attrs = attrs.reject {|k,v| !SAFE_ATTRIBUTES_ON_TRANSITION.include?(k)}
258 256 else
259 257 return
260 258 end
261 259
260 # Tracker must be set before since new_statuses_allowed_to depends on it.
261 if t = attrs.delete('tracker_id')
262 self.tracker_id = t
263 end
264
262 265 if attrs['status_id']
263 unless new_statuses_allowed.collect(&:id).include?(attrs['status_id'].to_i)
266 unless new_statuses_allowed_to(user).collect(&:id).include?(attrs['status_id'].to_i)
264 267 attrs.delete('status_id')
265 268 end
266 269 end
@@ -116,36 +116,20 class MailHandler < ActionMailer::Base
116 116 # Creates a new issue
117 117 def receive_issue
118 118 project = target_project
119 tracker = (get_keyword(:tracker) && project.trackers.find_by_name(get_keyword(:tracker))) || project.trackers.find(:first)
120 category = (get_keyword(:category) && project.issue_categories.find_by_name(get_keyword(:category)))
121 priority = (get_keyword(:priority) && IssuePriority.find_by_name(get_keyword(:priority)))
122 status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))
123 assigned_to = (get_keyword(:assigned_to, :override => true) && find_user_from_keyword(get_keyword(:assigned_to, :override => true)))
124 due_date = get_keyword(:due_date, :override => true)
125 start_date = get_keyword(:start_date, :override => true)
126
127 119 # check permission
128 120 unless @@handler_options[:no_permission_check]
129 121 raise UnauthorizedAction unless user.allowed_to?(:add_issues, project)
130 122 end
131 123
132 issue = Issue.new(:author => user, :project => project, :tracker => tracker, :category => category, :priority => priority, :due_date => due_date, :start_date => start_date, :assigned_to => assigned_to)
133 # check workflow
134 if status && issue.new_statuses_allowed_to(user).include?(status)
135 issue.status = status
136 end
137 issue.subject = email.subject.chomp[0,255]
124 issue = Issue.new(:author => user, :project => project)
125 issue.safe_attributes = issue_attributes_from_keywords(issue)
126 issue.safe_attributes = {'custom_field_values' => custom_field_values_from_keywords(issue)}
127 issue.subject = email.subject.to_s.chomp[0,255]
138 128 if issue.subject.blank?
139 129 issue.subject = '(no subject)'
140 130 end
141 # custom fields
142 issue.custom_field_values = issue.available_custom_fields.inject({}) do |h, c|
143 if value = get_keyword(c.name, :override => true)
144 h[c.id] = value
145 end
146 h
147 end
148 131 issue.description = cleaned_up_text_body
132
149 133 # add To and Cc as watchers before saving so the watchers can reply to Redmine
150 134 add_watchers(issue)
151 135 issue.save!
@@ -154,41 +138,19 class MailHandler < ActionMailer::Base
154 138 issue
155 139 end
156 140
157 def target_project
158 # TODO: other ways to specify project:
159 # * parse the email To field
160 # * specific project (eg. Setting.mail_handler_target_project)
161 target = Project.find_by_identifier(get_keyword(:project))
162 raise MissingInformation.new('Unable to determine target project') if target.nil?
163 target
164 end
165
166 141 # Adds a note to an existing issue
167 142 def receive_issue_reply(issue_id)
168 status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))
169 due_date = get_keyword(:due_date, :override => true)
170 start_date = get_keyword(:start_date, :override => true)
171 assigned_to = (get_keyword(:assigned_to, :override => true) && find_user_from_keyword(get_keyword(:assigned_to, :override => true)))
172
173 143 issue = Issue.find_by_id(issue_id)
174 144 return unless issue
175 145 # check permission
176 146 unless @@handler_options[:no_permission_check]
177 147 raise UnauthorizedAction unless user.allowed_to?(:add_issue_notes, issue.project) || user.allowed_to?(:edit_issues, issue.project)
178 raise UnauthorizedAction unless status.nil? || user.allowed_to?(:edit_issues, issue.project)
179 148 end
180
181 # add the note
149
182 150 journal = issue.init_journal(user, cleaned_up_text_body)
151 issue.safe_attributes = issue_attributes_from_keywords(issue)
152 issue.safe_attributes = {'custom_field_values' => custom_field_values_from_keywords(issue)}
183 153 add_attachments(issue)
184 # check workflow
185 if status && issue.new_statuses_allowed_to(user).include?(status)
186 issue.status = status
187 end
188 issue.start_date = start_date if start_date
189 issue.due_date = due_date if due_date
190 issue.assigned_to = assigned_to if assigned_to
191
192 154 issue.save!
193 155 logger.info "MailHandler: issue ##{issue.id} updated by #{user}" if logger && logger.info
194 156 journal
@@ -263,6 +225,41 class MailHandler < ActionMailer::Base
263 225 end
264 226 end
265 227 end
228
229 def target_project
230 # TODO: other ways to specify project:
231 # * parse the email To field
232 # * specific project (eg. Setting.mail_handler_target_project)
233 target = Project.find_by_identifier(get_keyword(:project))
234 raise MissingInformation.new('Unable to determine target project') if target.nil?
235 target
236 end
237
238 # Returns a Hash of issue attributes extracted from keywords in the email body
239 def issue_attributes_from_keywords(issue)
240 {
241 'tracker_id' => ((k = get_keyword(:tracker)) && issue.project.trackers.find_by_name(k).try(:id)) || issue.project.trackers.find(:first).try(:id),
242 'status_id' => (k = get_keyword(:status)) && IssueStatus.find_by_name(k).try(:id),
243 'priority_id' => (k = get_keyword(:priority)) && IssuePriority.find_by_name(k).try(:id),
244 'category_id' => (k = get_keyword(:category)) && issue.project.issue_categories.find_by_name(k).try(:id),
245 'assigned_to_id' => (k = get_keyword(:assigned_to, :override => true)) && find_user_from_keyword(k).try(:id),
246 'fixed_version_id' => (k = get_keyword(:fixed_version, :override => true)) && issue.project.shared_versions.find_by_name(k).try(:id),
247 'start_date' => get_keyword(:start_date, :override => true),
248 'due_date' => get_keyword(:due_date, :override => true),
249 'estimated_hours' => get_keyword(:estimated_hours, :override => true),
250 'done_ratio' => get_keyword(:done_ratio, :override => true),
251 }.delete_if {|k, v| v.blank? }
252 end
253
254 # Returns a Hash of issue custom field values extracted from keywords in the email body
255 def custom_field_values_from_keywords(customized)
256 customized.custom_field_values.inject({}) do |h, v|
257 if value = get_keyword(v.custom_field.name, :override => true)
258 h[v.custom_field.id.to_s] = value
259 end
260 h
261 end
262 end
266 263
267 264 # Returns the text/plain part of the email
268 265 # If not found (eg. HTML-only email), returns the body with tags removed
@@ -54,4 +54,7 Status: Resolved
54 54 due date: 2010-12-31
55 55 Start Date:2010-01-01
56 56 Assigned to: John Smith
57 fixed version: alpha
58 estimated hours: 2.5
59 done ratio: 30
57 60
@@ -29,6 +29,7 Status: Resolved
29 29 due date: 2010-12-31
30 30 Start Date:2010-01-01
31 31 Assigned to: jsmith@somenet.foo
32 searchable field: Updated custom value
32 33
33 34 ------=_NextPart_000_0067_01C8D3CE.711F9CC0
34 35 Content-Type: text/html;
@@ -30,6 +30,7 class MailHandlerTest < ActiveSupport::TestCase
30 30 :workflows,
31 31 :trackers,
32 32 :projects_trackers,
33 :versions,
33 34 :enumerations,
34 35 :issue_categories,
35 36 :custom_fields,
@@ -59,6 +60,9 class MailHandlerTest < ActiveSupport::TestCase
59 60 assert_equal '2010-01-01', issue.start_date.to_s
60 61 assert_equal '2010-12-31', issue.due_date.to_s
61 62 assert_equal User.find_by_login('jsmith'), issue.assigned_to
63 assert_equal Version.find_by_name('alpha'), issue.fixed_version
64 assert_equal 2.5, issue.estimated_hours
65 assert_equal 30, issue.done_ratio
62 66 # keywords should be removed from the email body
63 67 assert !issue.description.match(/^Project:/i)
64 68 assert !issue.description.match(/^Status:/i)
@@ -269,6 +273,7 class MailHandlerTest < ActiveSupport::TestCase
269 273 assert_equal '2010-01-01', issue.start_date.to_s
270 274 assert_equal '2010-12-31', issue.due_date.to_s
271 275 assert_equal User.find_by_login('jsmith'), issue.assigned_to
276 assert_equal 'Updated custom value', issue.custom_value_for(CustomField.find_by_name('Searchable field')).value
272 277 end
273 278
274 279 def test_add_issue_note_should_send_email_notification
General Comments 0
You need to be logged in to leave comments. Login now