Mercurial > hg > soundsoftware-site
diff app/models/mail_handler.rb @ 37:94944d00e43c
* Update to SVN trunk rev 4411
author | Chris Cannam <chris.cannam@soundsoftware.ac.uk> |
---|---|
date | Fri, 19 Nov 2010 13:24:41 +0000 |
parents | 513646585e45 |
children | af80e5618e9b 8661b858af72 |
line wrap: on
line diff
--- a/app/models/mail_handler.rb Fri Sep 24 14:06:04 2010 +0100 +++ b/app/models/mail_handler.rb Fri Nov 19 13:24:41 2010 +0000 @@ -17,6 +17,7 @@ class MailHandler < ActionMailer::Base include ActionView::Helpers::SanitizeHelper + include Redmine::I18n class UnauthorizedAction < StandardError; end class MissingInformation < StandardError; end @@ -116,36 +117,20 @@ # Creates a new issue def receive_issue project = target_project - tracker = (get_keyword(:tracker) && project.trackers.find_by_name(get_keyword(:tracker))) || project.trackers.find(:first) - category = (get_keyword(:category) && project.issue_categories.find_by_name(get_keyword(:category))) - priority = (get_keyword(:priority) && IssuePriority.find_by_name(get_keyword(:priority))) - status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status))) - assigned_to = (get_keyword(:assigned_to, :override => true) && find_user_from_keyword(get_keyword(:assigned_to, :override => true))) - due_date = get_keyword(:due_date, :override => true) - start_date = get_keyword(:start_date, :override => true) - # check permission unless @@handler_options[:no_permission_check] raise UnauthorizedAction unless user.allowed_to?(:add_issues, project) end - 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) - # check workflow - if status && issue.new_statuses_allowed_to(user).include?(status) - issue.status = status - end - issue.subject = email.subject.chomp[0,255] + issue = Issue.new(:author => user, :project => project) + issue.safe_attributes = issue_attributes_from_keywords(issue) + issue.safe_attributes = {'custom_field_values' => custom_field_values_from_keywords(issue)} + issue.subject = email.subject.to_s.chomp[0,255] if issue.subject.blank? issue.subject = '(no subject)' end - # custom fields - issue.custom_field_values = issue.available_custom_fields.inject({}) do |h, c| - if value = get_keyword(c.name, :override => true) - h[c.id] = value - end - h - end issue.description = cleaned_up_text_body + # add To and Cc as watchers before saving so the watchers can reply to Redmine add_watchers(issue) issue.save! @@ -154,41 +139,19 @@ issue end - def target_project - # TODO: other ways to specify project: - # * parse the email To field - # * specific project (eg. Setting.mail_handler_target_project) - target = Project.find_by_identifier(get_keyword(:project)) - raise MissingInformation.new('Unable to determine target project') if target.nil? - target - end - # Adds a note to an existing issue def receive_issue_reply(issue_id) - status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status))) - due_date = get_keyword(:due_date, :override => true) - start_date = get_keyword(:start_date, :override => true) - assigned_to = (get_keyword(:assigned_to, :override => true) && find_user_from_keyword(get_keyword(:assigned_to, :override => true))) - issue = Issue.find_by_id(issue_id) return unless issue # check permission unless @@handler_options[:no_permission_check] raise UnauthorizedAction unless user.allowed_to?(:add_issue_notes, issue.project) || user.allowed_to?(:edit_issues, issue.project) - raise UnauthorizedAction unless status.nil? || user.allowed_to?(:edit_issues, issue.project) end - - # add the note + journal = issue.init_journal(user, cleaned_up_text_body) + issue.safe_attributes = issue_attributes_from_keywords(issue) + issue.safe_attributes = {'custom_field_values' => custom_field_values_from_keywords(issue)} add_attachments(issue) - # check workflow - if status && issue.new_statuses_allowed_to(user).include?(status) - issue.status = status - end - issue.start_date = start_date if start_date - issue.due_date = due_date if due_date - issue.assigned_to = assigned_to if assigned_to - issue.save! logger.info "MailHandler: issue ##{issue.id} updated by #{user}" if logger && logger.info journal @@ -255,8 +218,8 @@ @keywords[attr] else @keywords[attr] = begin - if (options[:override] || @@handler_options[:allow_override].include?(attr.to_s)) && plain_text_body.gsub!(/^#{attr.to_s.humanize}[ \t]*:[ \t]*(.+)\s*$/i, '') - $1.strip + if (options[:override] || @@handler_options[:allow_override].include?(attr.to_s)) && (v = extract_keyword!(plain_text_body, attr, options[:format])) + v elsif !@@handler_options[:issue][attr].blank? @@handler_options[:issue][attr] end @@ -264,6 +227,59 @@ end end + # Destructively extracts the value for +attr+ in +text+ + # Returns nil if no matching keyword found + def extract_keyword!(text, attr, format=nil) + keys = [attr.to_s.humanize] + if attr.is_a?(Symbol) + keys << l("field_#{attr}", :default => '', :locale => user.language) if user + keys << l("field_#{attr}", :default => '', :locale => Setting.default_language) + end + keys.reject! {|k| k.blank?} + keys.collect! {|k| Regexp.escape(k)} + format ||= '.+' + text.gsub!(/^(#{keys.join('|')})[ \t]*:[ \t]*(#{format})\s*$/i, '') + $2 && $2.strip + end + + def target_project + # TODO: other ways to specify project: + # * parse the email To field + # * specific project (eg. Setting.mail_handler_target_project) + target = Project.find_by_identifier(get_keyword(:project)) + raise MissingInformation.new('Unable to determine target project') if target.nil? + target + end + + # Returns a Hash of issue attributes extracted from keywords in the email body + def issue_attributes_from_keywords(issue) + assigned_to = (k = get_keyword(:assigned_to, :override => true)) && find_user_from_keyword(k) + assigned_to = nil if assigned_to && !issue.assignable_users.include?(assigned_to) + + { + 'tracker_id' => ((k = get_keyword(:tracker)) && issue.project.trackers.find_by_name(k).try(:id)) || issue.project.trackers.find(:first).try(:id), + 'status_id' => (k = get_keyword(:status)) && IssueStatus.find_by_name(k).try(:id), + 'priority_id' => (k = get_keyword(:priority)) && IssuePriority.find_by_name(k).try(:id), + 'category_id' => (k = get_keyword(:category)) && issue.project.issue_categories.find_by_name(k).try(:id), + 'assigned_to_id' => assigned_to.try(:id), + 'fixed_version_id' => (k = get_keyword(:fixed_version, :override => true)) && issue.project.shared_versions.find_by_name(k).try(:id), + 'start_date' => get_keyword(:start_date, :override => true, :format => '\d{4}-\d{2}-\d{2}'), + 'due_date' => get_keyword(:due_date, :override => true, :format => '\d{4}-\d{2}-\d{2}'), + 'estimated_hours' => get_keyword(:estimated_hours, :override => true), + 'done_ratio' => get_keyword(:done_ratio, :override => true, :format => '(\d|10)?0') + }.delete_if {|k, v| v.blank? } + end + + # Returns a Hash of issue custom field values extracted from keywords in the email body + def custom_field_values_from_keywords(customized) + customized.custom_field_values.inject({}) do |h, v| + if value = get_keyword(v.custom_field.name, :override => true) + h[v.custom_field.id.to_s] = value + end + h + end + end + # Returns the text/plain part of the email # If not found (eg. HTML-only email), returns the body with tags removed def plain_text_body @@ -318,7 +334,7 @@ def cleanup_body(body) delimiters = Setting.mail_handler_body_delimiters.to_s.split(/[\r\n]+/).reject(&:blank?).map {|s| Regexp.escape(s)} unless delimiters.empty? - regex = Regexp.new("^(#{ delimiters.join('|') })\s*[\r\n].*", Regexp::MULTILINE) + regex = Regexp.new("^[> ]*(#{ delimiters.join('|') })\s*[\r\n].*", Regexp::MULTILINE) body = body.gsub(regex, '') end body.strip