diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb
index 4686811d..e1b10991 100644
--- a/app/models/mail_handler.rb
+++ b/app/models/mail_handler.rb
@@ -69,6 +69,7 @@ class MailHandler < ActionMailer::Base
else
# Default behaviour, emails from unknown users are ignored
logger.info "MailHandler: ignoring email from unknown user [#{sender_email}]" if logger && logger.info
+ Mailer.deliver_mail_handler_unauthorized_action(user, email.subject.to_s, :to => sender_email) if Setting.mail_handler_confirmation_on_failure
return false
end
end
@@ -102,12 +103,15 @@ class MailHandler < ActionMailer::Base
rescue ActiveRecord::RecordInvalid => e
# TODO: send a email to the user
logger.error e.message if logger
+ Mailer.deliver_mail_handler_missing_information(user, email.subject.to_s, e.message) if Setting.mail_handler_confirmation_on_failure
false
rescue MissingInformation => e
logger.error "MailHandler: missing information from #{user}: #{e.message}" if logger
+ Mailer.deliver_mail_handler_missing_information(user, email.subject.to_s, e.message) if Setting.mail_handler_confirmation_on_failure
false
rescue UnauthorizedAction => e
logger.error "MailHandler: unauthorized attempt from #{user}" if logger
+ Mailer.deliver_mail_handler_unauthorized_action(user, email.subject.to_s) if Setting.mail_handler_confirmation_on_failure
false
end
@@ -141,6 +145,7 @@ class MailHandler < ActionMailer::Base
issue.save!
add_attachments(issue)
logger.info "MailHandler: issue ##{issue.id} created by #{user}" if logger && logger.info
+ Mailer.deliver_mail_handler_confirmation(issue, user, issue.subject) if Setting.mail_handler_confirmation_on_success
issue
end
@@ -162,6 +167,7 @@ class MailHandler < ActionMailer::Base
add_attachments(issue)
issue.save!
logger.info "MailHandler: issue ##{issue.id} updated by #{user}" if logger && logger.info
+ Mailer.deliver_mail_handler_confirmation(issue.last_journal, user, email.subject) if Setting.mail_handler_confirmation_on_success
issue.last_journal
end
@@ -190,6 +196,7 @@ class MailHandler < ActionMailer::Base
reply.board = message.board
message.children << reply
add_attachments(reply)
+ Mailer.deliver_mail_handler_confirmation(message, user, reply.subject) if Setting.mail_handler_confirmation_on_success
reply
else
logger.info "MailHandler: ignoring reply from [#{sender_email}] to a locked topic" if logger && logger.info
diff --git a/app/models/mailer.rb b/app/models/mailer.rb
index b99e211d..962fd870 100644
--- a/app/models/mailer.rb
+++ b/app/models/mailer.rb
@@ -285,6 +285,44 @@ class Mailer < ActionMailer::Base
render_multipart('register', body)
end
+ def mail_handler_confirmation(object, user, email_subject)
+ recipients user.mail
+
+ case
+ when object.is_a?(Issue)
+ project = object.project.name
+ url = url_for(:controller => 'issues', :action => 'show', :id => object.id)
+ when object.is_a?(Journal)
+ project = object.project.name
+ url = url_for(:controller => 'issues', :action => 'show', :id => object.issue.id)
+ when object.class == Message
+ project = object.project.name
+ url = url_for(object.event_url)
+ else
+ project = ''
+ url = ''
+ end
+
+ subject "[#{project}] #{l(:label_mail_handler_confirmation, :subject => email_subject)}"
+ body(:object => object,
+ :url => url)
+ render_multipart('mail_handler_confirmation', body)
+ end
+
+ def mail_handler_unauthorized_action(user, email_subject, options={})
+ recipients options[:to] || user.mail
+ subject l(:label_mail_handler_failure, :subject => email_subject)
+ body({})
+ render_multipart('mail_handler_unauthorized_action', body)
+ end
+
+ def mail_handler_missing_information(user, email_subject, error_message)
+ recipients user.mail
+ subject l(:label_mail_handler_failure, :subject => email_subject)
+ body({:errors => error_message.to_s})
+ render_multipart('mail_handler_missing_information', body)
+ end
+
def test(user)
redmine_headers 'Type' => "Test"
set_language_if_valid(user.language)
diff --git a/app/views/mailer/mail_handler_confirmation.text.html.rhtml b/app/views/mailer/mail_handler_confirmation.text.html.rhtml
new file mode 100644
index 00000000..5e115e2b
--- /dev/null
+++ b/app/views/mailer/mail_handler_confirmation.text.html.rhtml
@@ -0,0 +1,2 @@
+
<%= l(:text_mail_handler_confirmation_successful) %>
+<%= auto_link(@url) %>
diff --git a/app/views/mailer/mail_handler_confirmation.text.plain.rhtml b/app/views/mailer/mail_handler_confirmation.text.plain.rhtml
new file mode 100644
index 00000000..0b8348e4
--- /dev/null
+++ b/app/views/mailer/mail_handler_confirmation.text.plain.rhtml
@@ -0,0 +1,2 @@
+<%= l(:text_mail_handler_confirmation_successful) %>
+<%= @url %>
diff --git a/app/views/mailer/mail_handler_missing_information.text.html.rhtml b/app/views/mailer/mail_handler_missing_information.text.html.rhtml
new file mode 100644
index 00000000..639e2aa6
--- /dev/null
+++ b/app/views/mailer/mail_handler_missing_information.text.html.rhtml
@@ -0,0 +1,3 @@
+<%= l(:label_mail_handler_errors_with_submission) %>
+
+<%= h(@errors) %>
diff --git a/app/views/mailer/mail_handler_missing_information.text.plain.rhtml b/app/views/mailer/mail_handler_missing_information.text.plain.rhtml
new file mode 100644
index 00000000..458f515d
--- /dev/null
+++ b/app/views/mailer/mail_handler_missing_information.text.plain.rhtml
@@ -0,0 +1,3 @@
+<%= l(:label_mail_handler_errors_with_submission) %>
+
+<%= h(@errors) %>
diff --git a/app/views/mailer/mail_handler_unauthorized_action.text.html.rhtml b/app/views/mailer/mail_handler_unauthorized_action.text.html.rhtml
new file mode 100644
index 00000000..e1f58ad4
--- /dev/null
+++ b/app/views/mailer/mail_handler_unauthorized_action.text.html.rhtml
@@ -0,0 +1 @@
+<%= l(:notice_not_authorized_action) %>
diff --git a/app/views/mailer/mail_handler_unauthorized_action.text.plain.rhtml b/app/views/mailer/mail_handler_unauthorized_action.text.plain.rhtml
new file mode 100644
index 00000000..e1f58ad4
--- /dev/null
+++ b/app/views/mailer/mail_handler_unauthorized_action.text.plain.rhtml
@@ -0,0 +1 @@
+<%= l(:notice_not_authorized_action) %>
diff --git a/app/views/settings/_mail_handler.rhtml b/app/views/settings/_mail_handler.rhtml
index b5ed14ea..722ba617 100644
--- a/app/views/settings/_mail_handler.rhtml
+++ b/app/views/settings/_mail_handler.rhtml
@@ -5,6 +5,9 @@
<%= setting_text_area :mail_handler_body_delimiters, :rows => 5 %>
<%= l(:text_line_separated) %>
+
+ <%= setting_check_box :mail_handler_confirmation_on_success %>
+ <%= setting_check_box :mail_handler_confirmation_on_failure %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 7fe8846b..2f2752d6 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -157,6 +157,7 @@ en:
notice_file_not_found: The page you were trying to access doesn't exist or has been removed.
notice_locking_conflict: Data has been updated by another user.
notice_not_authorized: You are not authorized to access this page.
+ notice_not_authorized_action: You are not authorized to perform this action.
notice_not_authorized_archived_project: The project you're trying to access has been archived.
notice_email_sent: "An email was sent to %{value}"
notice_email_error: "An error occurred while sending mail (%{value})"
@@ -368,6 +369,8 @@ en:
setting_commit_logtime_activity_id: Activity for logged time
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
setting_issue_startdate_is_adddate: Use current date as start date for new issues
+ setting_mail_handler_confirmation_on_success: "Send confirmation email on successful incoming email"
+ setting_mail_handler_confirmation_on_failure: "Send confirmation email on failed incoming email"
permission_add_project: Create project
permission_add_subprojects: Create subprojects
@@ -818,6 +821,9 @@ en:
label_path_encoding: Path encoding
label_deleted_custom_field: '(deleted custom field)'
label_toc: "Contents"
+ label_mail_handler_confirmation: "Confirmation of email submission: %{subject}"
+ label_mail_handler_failure: "Failed email submission: %{subject}"
+ label_mail_handler_errors_with_submission: "There were errors with your email submission:"
button_login: Login
button_submit: Submit
@@ -943,7 +949,8 @@ en:
text_git_repo_example: "a bare and local repository (e.g. /gitrepo, c:\\gitrepo)"
text_display_subprojects: Display subprojects
text_current_project: Current project
-
+ text_mail_handler_confirmation_successful: "Your email has been successful added at the following url"
+
default_role_manager: Manager
default_role_developer: Developer
default_role_reporter: Reporter
diff --git a/config/settings.yml b/config/settings.yml
index 5f708e2d..91139c14 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -178,5 +178,9 @@ default_notification_option:
default: 'only_my_events'
emails_header:
default: ''
+mail_handler_confirmation_on_success:
+ default: 1
+mail_handler_confirmation_on_failure:
+ default: 1
issue_startdate_is_adddate:
- default: 1
\ No newline at end of file
+ default: 1
diff --git a/test/fixtures/mail_handler/ticket_on_project_with_missing_information.eml b/test/fixtures/mail_handler/ticket_on_project_with_missing_information.eml
new file mode 100644
index 00000000..798bb03a
--- /dev/null
+++ b/test/fixtures/mail_handler/ticket_on_project_with_missing_information.eml
@@ -0,0 +1,23 @@
+Return-Path:
+Received: from osiris ([127.0.0.1])
+ by OSIRIS
+ with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200
+Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris>
+From: "John Smith"
+To:
+Subject: New ticket on a given project
+Date: Sun, 22 Jun 2008 12:28:07 +0200
+MIME-Version: 1.0
+Content-Type: text/plain;
+ format=flowed;
+ charset="iso-8859-1";
+ reply-type=original
+Content-Transfer-Encoding: 7bit
+X-Priority: 3
+X-MSMail-Priority: Normal
+X-Mailer: Microsoft Outlook Express 6.00.2900.2869
+X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869
+
+Test with missing information
+
+Project: onlinestore
diff --git a/test/unit/mail_handler_test.rb b/test/unit/mail_handler_test.rb
index a4e68542..0386da11 100644
--- a/test/unit/mail_handler_test.rb
+++ b/test/unit/mail_handler_test.rb
@@ -1,4 +1,4 @@
-#-- encoding: UTF-8
+#-- encoding: utf-8 -8
#-- copyright
# ChiliProject is a project management system.
#
@@ -39,6 +39,8 @@ class MailHandlerTest < ActiveSupport::TestCase
def setup
ActionMailer::Base.deliveries.clear
Setting.notified_events = Redmine::Notifiable.all.collect(&:name)
+ Setting.mail_handler_confirmation_on_success = true
+ Setting.mail_handler_confirmation_on_failure = true
end
def test_add_issue
@@ -67,6 +69,7 @@ class MailHandlerTest < ActiveSupport::TestCase
assert !issue.description.match(/^Status:/i)
assert !issue.description.match(/^Start Date:/i)
# Email notification should be sent
+ assert_equal 2, ActionMailer::Base.deliveries.size
mail = ActionMailer::Base.deliveries.last
assert_not_nil mail
assert mail.subject.include?('New ticket on a given project')
@@ -289,7 +292,7 @@ class MailHandlerTest < ActiveSupport::TestCase
# This email contains: 'Project: onlinestore'
issue = submit_email('ticket_on_given_project.eml')
assert issue.is_a?(Issue)
- assert_equal 1, ActionMailer::Base.deliveries.size
+ assert_equal 2, ActionMailer::Base.deliveries.size
end
def test_add_issue_note
@@ -301,15 +304,6 @@ class MailHandlerTest < ActiveSupport::TestCase
assert_equal 'Feature request', journal.issue.tracker.name
end
- test "reply to issue update (Journal) by message_id" do
- journal = submit_email('ticket_reply_by_message_id.eml')
- assert journal.is_a?(IssueJournal), "Email was a #{journal.class}"
- assert_equal User.find_by_login('jsmith'), journal.user
- assert_equal Issue.find(2), journal.journaled
- assert_match /This is reply/, journal.notes
- assert_equal 'Feature request', journal.issue.tracker.name
- end
-
def test_add_issue_note_with_attribute_changes
# This email contains: 'Status: Resolved'
journal = submit_email('ticket_reply_with_status.eml')
@@ -333,7 +327,7 @@ class MailHandlerTest < ActiveSupport::TestCase
ActionMailer::Base.deliveries.clear
journal = submit_email('ticket_reply.eml')
assert journal.is_a?(Journal)
- assert_equal 3, ActionMailer::Base.deliveries.size
+ assert_equal 1, ActionMailer::Base.deliveries.size
end
def test_add_issue_note_should_not_set_defaults
@@ -456,6 +450,116 @@ class MailHandlerTest < ActiveSupport::TestCase
assert_equal issue.subject, 'New ticket on a given project with a very long subject line which exceeds 255 chars and should not be ignored but chopped off. And if the subject line is still not long enough, we just add more text. And more text. Wow, this is really annoying. Especially, if you have nothing to say...'[0,255]
end
+ context "with an email that performs an unauthorized action" do
+ should "deliver an email error confirmation for an unknown user" do
+ ActionMailer::Base.deliveries.clear
+ issue = submit_email('ticket_by_unknown_user.eml')
+ assert_equal false, issue
+
+ assert_equal 1, ActionMailer::Base.deliveries.size
+ mail = ActionMailer::Base.deliveries.last
+ assert_not_nil mail
+ assert mail.to.include?('john.doe@somenet.foo')
+ assert mail.subject.include?('Failed email submission: Ticket by unknown user')
+ assert mail.body.include?('You are not authorized to perform this action')
+ end
+
+ should "deliver an email error confirmation for a user without permission" do
+ ActionMailer::Base.deliveries.clear
+ # Clear memberships for the sending user so they fail permission checks
+ Project.find(1).update_attributes(:is_public => false)
+ Member.all(:conditions => {:user_id => 2}).collect(&:destroy)
+ assert_no_difference('Journal.count') do
+ assert_equal false, submit_email('ticket_reply.eml')
+ end
+
+ assert_equal 1, ActionMailer::Base.deliveries.size
+ mail = ActionMailer::Base.deliveries.last
+ assert_not_nil mail
+ assert mail.to.include?('jsmith@somenet.foo')
+ assert mail.subject.include?('Failed email submission: Re: Add ingredients categories')
+ assert mail.body.include?('You are not authorized to perform this action')
+ end
+ end
+
+ context "with an email that is missing required information" do
+ should "deliver an email error confirmation to the sender for a missing project" do
+ ActionMailer::Base.deliveries.clear
+ issue = submit_email('ticket_with_attachment.eml') # No project set
+ assert_equal false, issue
+
+ assert_equal 1, ActionMailer::Base.deliveries.size
+ mail = ActionMailer::Base.deliveries.last
+ assert_not_nil mail
+ assert mail.to.include?('jsmith@somenet.foo')
+ assert mail.subject.include?('Failed email submission: Ticket created by email with attachment')
+ assert mail.body.include?('There were errors with your email submission')
+ assert mail.body.include?('Unable to determine target project')
+
+ end
+
+ should "deliver an email error confirmation to the sender for a missing other attributes" do
+ # Add a required custom field to simulate the error
+ project = Project.find('onlinestore')
+ project.issue_custom_fields << IssueCustomField.generate(:name => 'Required Custom Field0', :is_required => true, :trackers => project.trackers)
+ project.save
+
+ ActionMailer::Base.deliveries.clear
+ issue = submit_email('ticket_on_project_with_missing_information.eml')
+ assert_equal false, issue
+
+ assert_equal 1, ActionMailer::Base.deliveries.size
+ mail = ActionMailer::Base.deliveries.last
+ assert_not_nil mail
+ assert mail.bcc.include?('jsmith@somenet.foo')
+ assert mail.subject.include?('Failed email submission: New ticket on a given project')
+ assert mail.body.include?('There were errors with your email submission')
+ assert mail.body.include?('Required Custom Field0 can\'t be blank')
+ end
+ end
+
+ context "#receive_issue" do
+ should "deliver an email confirmation when configured" do
+ ActionMailer::Base.deliveries.clear
+ issue = submit_email('ticket_on_given_project.eml')
+
+ assert_equal 2, ActionMailer::Base.deliveries.size
+ mail = ActionMailer::Base.deliveries.last
+ assert_not_nil mail
+ assert mail.subject.include?('[OnlineStore]'), "Project name missing"
+ assert mail.subject.include?('Confirmation of email submission: New ticket on a given project'), "Main subject missing"
+ assert mail.body.include?("/issues/#{issue.reload.id}"), "Link to issue missing"
+ end
+ end
+
+ context "#receive_issue_reply" do
+ should "deliver an email confirmation when configured" do
+ journal = submit_email('ticket_reply.eml')
+
+ assert_equal 1, ActionMailer::Base.deliveries.size
+ mail = ActionMailer::Base.deliveries.last
+ assert_not_nil mail
+ assert mail.subject.include?('[eCookbook]'), "Project name missing"
+ assert mail.subject.include?('Confirmation of email submission: Re: Add ingredients categories'), "Main subject missing"
+ assert mail.body.include?("/issues/2"), "Link to issue missing"
+ end
+
+ end
+
+ context "#receive_message_reply" do
+ should "deliver an email confirmation when configured" do
+ ActionMailer::Base.deliveries.clear
+ m = submit_email('message_reply.eml')
+
+ assert_equal 3, ActionMailer::Base.deliveries.size
+ mail = ActionMailer::Base.deliveries.last
+ assert_not_nil mail
+ assert mail.subject.include?('[eCookbook]'), "Project name missing"
+ assert mail.subject.include?('Confirmation of email submission: Reply via email'), "Main subject missing"
+ assert mail.body.include?("/boards/1/topics/1"), "Link to message missing"
+ end
+ end
+
private
def submit_email(filename, options={})