##// END OF EJS Templates
Backported r2429, r2430, r248 to r2491 and r2522 from trunk (request and controller objects added to the hooks by default.)....
Backported r2429, r2430, r248 to r2491 and r2522 from trunk (request and controller objects added to the hooks by default.). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2558 e93f8b46-1217-0410-a6f0-8f06a7374b81

File last commit:

r2489:b366375e7ee1
r2490:36b5d4f6af04
Show More
mail_handler.rb
200 lines | 7.4 KiB | text/x-ruby | RubyLexer
Jean-Philippe Lang
Added a simple mail handler....
r520 # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class MailHandler < ActionMailer::Base
Jean-Philippe Lang
Merged r2109, r2118, r2130, r2131, r2134, r2135, r2136 and r2139 to r2145 from trunk....
r2144 include ActionView::Helpers::SanitizeHelper
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554
class UnauthorizedAction < StandardError; end
class MissingInformation < StandardError; end
attr_reader :email, :user
def self.receive(email, options={})
Jean-Philippe Lang
Mail handler: more control over issue attributes (#1110)....
r1629 @@handler_options = options.dup
@@handler_options[:issue] ||= {}
@@handler_options[:allow_override] = @@handler_options[:allow_override].split(',').collect(&:strip) if @@handler_options[:allow_override].is_a?(String)
@@handler_options[:allow_override] ||= []
# Project needs to be overridable if not specified
@@handler_options[:allow_override] << 'project' unless @@handler_options[:issue].has_key?(:project)
Jean-Philippe Lang
Mail handler: check workflow for status set/change....
r2072 # Status overridable by default
Eric Davis
Added the "Status:" keyword to the MailHandler for setting and changing an Issue status via email....
r1750 @@handler_options[:allow_override] << 'status' unless @@handler_options[:issue].has_key?(:status)
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554 super email
end
Jean-Philippe Lang
Added a simple mail handler....
r520
# Processes incoming emails
def receive(email)
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554 @email = email
Jean-Philippe Lang
Merged r2553 from trunk....
r2489 @user = User.active.find(:first, :conditions => ["LOWER(mail) = ?", email.from.to_a.first.to_s.strip.downcase])
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554 unless @user
# Unknown user => the email is ignored
# TODO: ability to create the user's account
logger.info "MailHandler: email submitted by unknown user [#{email.from.first}]" if logger && logger.info
return false
end
User.current = @user
dispatch
end
private
ISSUE_REPLY_SUBJECT_RE = %r{\[[^\]]+#(\d+)\]}
def dispatch
if m = email.subject.match(ISSUE_REPLY_SUBJECT_RE)
receive_issue_update(m[1].to_i)
else
receive_issue
end
rescue ActiveRecord::RecordInvalid => e
# TODO: send a email to the user
logger.error e.message if logger
false
rescue MissingInformation => e
logger.error "MailHandler: missing information from #{user}: #{e.message}" if logger
false
rescue UnauthorizedAction => e
logger.error "MailHandler: unauthorized attempt from #{user}" if logger
false
end
# Creates a new issue
def receive_issue
project = target_project
Jean-Philippe Lang
Mail handler: more control over issue attributes (#1110)....
r1629 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) && Enumeration.find_by_opt_and_name('IPRI', get_keyword(:priority)))
Jean-Philippe Lang
Mail handler: check workflow for status set/change....
r2072 status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))
Jean-Philippe Lang
Mail handler: more control over issue attributes (#1110)....
r1629
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554 # check permission
raise UnauthorizedAction unless user.allowed_to?(:add_issues, project)
Jean-Philippe Lang
Mail handler: check workflow for status set/change....
r2072 issue = Issue.new(:author => user, :project => project, :tracker => tracker, :category => category, :priority => priority)
# check workflow
if status && issue.new_statuses_allowed_to(user).include?(status)
issue.status = status
end
Jean-Philippe Lang
Fixed: broken subject when submitting issue via email written in japanese (Patch #2059 by Go MAEDA)....
r1988 issue.subject = email.subject.chomp.toutf8
Jean-Philippe Lang
Merged r2109, r2118, r2130, r2131, r2134, r2135, r2136 and r2139 to r2145 from trunk....
r2144 issue.description = plain_text_body
Jean-Philippe Lang
Merged r2209 to r2211 from trunk....
r2227 # 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
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554 issue.save!
add_attachments(issue)
logger.info "MailHandler: issue ##{issue.id} created by #{user}" if logger && logger.info
Jean-Philippe Lang
Adds To and Cc as watchers when submitting an issue by email (#2245)....
r2075 # add To and Cc as watchers
add_watchers(issue)
Jean-Philippe Lang
Merged r2195 from trunk....
r2195 # send notification after adding watchers so that they can reply to Redmine
Mailer.deliver_issue_add(issue) if Setting.notified_events.include?('issue_added')
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554 issue
end
def target_project
# TODO: other ways to specify project:
# * parse the email To field
# * specific project (eg. Setting.mail_handler_target_project)
Jean-Philippe Lang
Mail handler: more control over issue attributes (#1110)....
r1629 target = Project.find_by_identifier(get_keyword(:project))
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554 raise MissingInformation.new('Unable to determine target project') if target.nil?
target
end
# Adds a note to an existing issue
def receive_issue_update(issue_id)
Eric Davis
Added the "Status:" keyword to the MailHandler for setting and changing an Issue status via email....
r1750 status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554 issue = Issue.find_by_id(issue_id)
Jean-Philippe Lang
Added a simple mail handler....
r520 return unless issue
# check permission
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554 raise UnauthorizedAction unless user.allowed_to?(:add_issue_notes, issue.project) || user.allowed_to?(:edit_issues, issue.project)
Eric Davis
Added the "Status:" keyword to the MailHandler for setting and changing an Issue status via email....
r1750 raise UnauthorizedAction unless status.nil? || user.allowed_to?(:edit_issues, issue.project)
Jean-Philippe Lang
Added a test for the mail handler....
r521 # add the note
Jean-Philippe Lang
Merged r2109, r2118, r2130, r2131, r2134, r2135, r2136 and r2139 to r2145 from trunk....
r2144 journal = issue.init_journal(user, plain_text_body)
Jean-Philippe Lang
Fixes reply attachments handling....
r1556 add_attachments(issue)
Jean-Philippe Lang
Mail handler: check workflow for status set/change....
r2072 # check workflow
if status && issue.new_statuses_allowed_to(user).include?(status)
issue.status = status
end
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554 issue.save!
logger.info "MailHandler: issue ##{issue.id} updated by #{user}" if logger && logger.info
Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
journal
end
def add_attachments(obj)
if email.has_attachments?
email.attachments.each do |attachment|
Attachment.create(:container => obj,
:file => attachment,
:author => user,
:content_type => attachment.content_type)
end
end
Jean-Philippe Lang
Added a simple mail handler....
r520 end
Jean-Philippe Lang
Mail handler: more control over issue attributes (#1110)....
r1629
Jean-Philippe Lang
Adds To and Cc as watchers when submitting an issue by email (#2245)....
r2075 # Adds To and Cc as watchers of the given object if the sender has the
# appropriate permission
def add_watchers(obj)
if user.allowed_to?("add_#{obj.class.name.underscore}_watchers".to_sym, obj.project)
addresses = [email.to, email.cc].flatten.compact.uniq.collect {|a| a.strip.downcase}
unless addresses.empty?
Jean-Philippe Lang
Replaces User.find_active with a named scope....
r2077 watchers = User.active.find(:all, :conditions => ['LOWER(mail) IN (?)', addresses])
Jean-Philippe Lang
Adds To and Cc as watchers when submitting an issue by email (#2245)....
r2075 watchers.each {|w| obj.add_watcher(w)}
end
end
end
Jean-Philippe Lang
Merged r2209 to r2211 from trunk....
r2227 def get_keyword(attr, options={})
Jean-Philippe Lang
Merged r2426 and r2484 from trunk....
r2449 @keywords ||= {}
if @keywords.has_key?(attr)
@keywords[attr]
else
@keywords[attr] = begin
if (options[:override] || @@handler_options[:allow_override].include?(attr.to_s)) && plain_text_body.gsub!(/^#{attr}:[ \t]*(.+)\s*$/i, '')
$1.strip
elsif !@@handler_options[:issue][attr].blank?
@@handler_options[:issue][attr]
end
end
Jean-Philippe Lang
Mail handler: more control over issue attributes (#1110)....
r1629 end
end
Jean-Philippe Lang
Merged r2109, r2118, r2130, r2131, r2134, r2135, r2136 and r2139 to r2145 from trunk....
r2144
# Returns the text/plain part of the email
# If not found (eg. HTML-only email), returns the body with tags removed
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554 def plain_text_body
return @plain_text_body unless @plain_text_body.nil?
Jean-Philippe Lang
Merged r2109, r2118, r2130, r2131, r2134, r2135, r2136 and r2139 to r2145 from trunk....
r2144 parts = @email.parts.collect {|c| (c.respond_to?(:parts) && !c.parts.empty?) ? c.parts : c}.flatten
if parts.empty?
parts << @email
end
plain_text_part = parts.detect {|p| p.content_type == 'text/plain'}
if plain_text_part.nil?
# no text/plain part found, assuming html-only email
# strip html tags and remove doctype directive
@plain_text_body = strip_tags(@email.body.to_s)
@plain_text_body.gsub! %r{^<!DOCTYPE .*$}, ''
else
@plain_text_body = plain_text_part.body.to_s
end
@plain_text_body.strip!
Jean-Philippe Lang
Merged r2520 from trunk....
r2457 @plain_text_body
Jean-Philippe Lang
Adds basic support for issue creation via email (#1110)....
r1554 end
end