##// END OF EJS Templates
Mail handler: strip tags when receiving a html-only email (#2312)....
Jean-Philippe Lang -
r2134:3bb2fccaf11d
parent child
Show More
@@ -0,0 +1,22
1 x-sender: <jsmith@somenet.foo>
2 x-receiver: <redmine@somenet.foo>
3 Received: from [127.0.0.1] ([127.0.0.1]) by somenet.foo with Quick 'n Easy Mail Server SMTP (1.0.0.0);
4 Sun, 14 Dec 2008 16:18:06 GMT
5 Message-ID: <494531B9.1070709@somenet.foo>
6 Date: Sun, 14 Dec 2008 17:18:01 +0100
7 From: "John Smith" <jsmith@somenet.foo>
8 User-Agent: Thunderbird 2.0.0.18 (Windows/20081105)
9 MIME-Version: 1.0
10 To: redmine@somenet.foo
11 Subject: HTML email
12 Content-Type: text/html; charset=ISO-8859-1
13 Content-Transfer-Encoding: 7bit
14
15 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
16 <html>
17 <head>
18 </head>
19 <body bgcolor="#ffffff" text="#000000">
20 This is a <b>html-only</b> email.<br>
21 </body>
22 </html>
@@ -1,176 +1,186
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class MailHandler < ActionMailer::Base
18 class MailHandler < ActionMailer::Base
19 include ActionView::Helpers::SanitizeHelper
19
20
20 class UnauthorizedAction < StandardError; end
21 class UnauthorizedAction < StandardError; end
21 class MissingInformation < StandardError; end
22 class MissingInformation < StandardError; end
22
23
23 attr_reader :email, :user
24 attr_reader :email, :user
24
25
25 def self.receive(email, options={})
26 def self.receive(email, options={})
26 @@handler_options = options.dup
27 @@handler_options = options.dup
27
28
28 @@handler_options[:issue] ||= {}
29 @@handler_options[:issue] ||= {}
29
30
30 @@handler_options[:allow_override] = @@handler_options[:allow_override].split(',').collect(&:strip) if @@handler_options[:allow_override].is_a?(String)
31 @@handler_options[:allow_override] = @@handler_options[:allow_override].split(',').collect(&:strip) if @@handler_options[:allow_override].is_a?(String)
31 @@handler_options[:allow_override] ||= []
32 @@handler_options[:allow_override] ||= []
32 # Project needs to be overridable if not specified
33 # Project needs to be overridable if not specified
33 @@handler_options[:allow_override] << 'project' unless @@handler_options[:issue].has_key?(:project)
34 @@handler_options[:allow_override] << 'project' unless @@handler_options[:issue].has_key?(:project)
34 # Status overridable by default
35 # Status overridable by default
35 @@handler_options[:allow_override] << 'status' unless @@handler_options[:issue].has_key?(:status)
36 @@handler_options[:allow_override] << 'status' unless @@handler_options[:issue].has_key?(:status)
36 super email
37 super email
37 end
38 end
38
39
39 # Processes incoming emails
40 # Processes incoming emails
40 def receive(email)
41 def receive(email)
41 @email = email
42 @email = email
42 @user = User.active.find_by_mail(email.from.first.to_s.strip)
43 @user = User.active.find_by_mail(email.from.first.to_s.strip)
43 unless @user
44 unless @user
44 # Unknown user => the email is ignored
45 # Unknown user => the email is ignored
45 # TODO: ability to create the user's account
46 # TODO: ability to create the user's account
46 logger.info "MailHandler: email submitted by unknown user [#{email.from.first}]" if logger && logger.info
47 logger.info "MailHandler: email submitted by unknown user [#{email.from.first}]" if logger && logger.info
47 return false
48 return false
48 end
49 end
49 User.current = @user
50 User.current = @user
50 dispatch
51 dispatch
51 end
52 end
52
53
53 private
54 private
54
55
55 ISSUE_REPLY_SUBJECT_RE = %r{\[[^\]]+#(\d+)\]}
56 ISSUE_REPLY_SUBJECT_RE = %r{\[[^\]]+#(\d+)\]}
56
57
57 def dispatch
58 def dispatch
58 if m = email.subject.match(ISSUE_REPLY_SUBJECT_RE)
59 if m = email.subject.match(ISSUE_REPLY_SUBJECT_RE)
59 receive_issue_update(m[1].to_i)
60 receive_issue_update(m[1].to_i)
60 else
61 else
61 receive_issue
62 receive_issue
62 end
63 end
63 rescue ActiveRecord::RecordInvalid => e
64 rescue ActiveRecord::RecordInvalid => e
64 # TODO: send a email to the user
65 # TODO: send a email to the user
65 logger.error e.message if logger
66 logger.error e.message if logger
66 false
67 false
67 rescue MissingInformation => e
68 rescue MissingInformation => e
68 logger.error "MailHandler: missing information from #{user}: #{e.message}" if logger
69 logger.error "MailHandler: missing information from #{user}: #{e.message}" if logger
69 false
70 false
70 rescue UnauthorizedAction => e
71 rescue UnauthorizedAction => e
71 logger.error "MailHandler: unauthorized attempt from #{user}" if logger
72 logger.error "MailHandler: unauthorized attempt from #{user}" if logger
72 false
73 false
73 end
74 end
74
75
75 # Creates a new issue
76 # Creates a new issue
76 def receive_issue
77 def receive_issue
77 project = target_project
78 project = target_project
78 tracker = (get_keyword(:tracker) && project.trackers.find_by_name(get_keyword(:tracker))) || project.trackers.find(:first)
79 tracker = (get_keyword(:tracker) && project.trackers.find_by_name(get_keyword(:tracker))) || project.trackers.find(:first)
79 category = (get_keyword(:category) && project.issue_categories.find_by_name(get_keyword(:category)))
80 category = (get_keyword(:category) && project.issue_categories.find_by_name(get_keyword(:category)))
80 priority = (get_keyword(:priority) && Enumeration.find_by_opt_and_name('IPRI', get_keyword(:priority)))
81 priority = (get_keyword(:priority) && Enumeration.find_by_opt_and_name('IPRI', get_keyword(:priority)))
81 status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))
82 status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))
82
83
83 # check permission
84 # check permission
84 raise UnauthorizedAction unless user.allowed_to?(:add_issues, project)
85 raise UnauthorizedAction unless user.allowed_to?(:add_issues, project)
85 issue = Issue.new(:author => user, :project => project, :tracker => tracker, :category => category, :priority => priority)
86 issue = Issue.new(:author => user, :project => project, :tracker => tracker, :category => category, :priority => priority)
86 # check workflow
87 # check workflow
87 if status && issue.new_statuses_allowed_to(user).include?(status)
88 if status && issue.new_statuses_allowed_to(user).include?(status)
88 issue.status = status
89 issue.status = status
89 end
90 end
90 issue.subject = email.subject.chomp.toutf8
91 issue.subject = email.subject.chomp.toutf8
91 issue.description = email.plain_text_body.chomp
92 issue.description = plain_text_body
92 issue.save!
93 issue.save!
93 add_attachments(issue)
94 add_attachments(issue)
94 logger.info "MailHandler: issue ##{issue.id} created by #{user}" if logger && logger.info
95 logger.info "MailHandler: issue ##{issue.id} created by #{user}" if logger && logger.info
95 # send notification before adding watchers since they were cc'ed
96 # send notification before adding watchers since they were cc'ed
96 Mailer.deliver_issue_add(issue) if Setting.notified_events.include?('issue_added')
97 Mailer.deliver_issue_add(issue) if Setting.notified_events.include?('issue_added')
97 # add To and Cc as watchers
98 # add To and Cc as watchers
98 add_watchers(issue)
99 add_watchers(issue)
99
100
100 issue
101 issue
101 end
102 end
102
103
103 def target_project
104 def target_project
104 # TODO: other ways to specify project:
105 # TODO: other ways to specify project:
105 # * parse the email To field
106 # * parse the email To field
106 # * specific project (eg. Setting.mail_handler_target_project)
107 # * specific project (eg. Setting.mail_handler_target_project)
107 target = Project.find_by_identifier(get_keyword(:project))
108 target = Project.find_by_identifier(get_keyword(:project))
108 raise MissingInformation.new('Unable to determine target project') if target.nil?
109 raise MissingInformation.new('Unable to determine target project') if target.nil?
109 target
110 target
110 end
111 end
111
112
112 # Adds a note to an existing issue
113 # Adds a note to an existing issue
113 def receive_issue_update(issue_id)
114 def receive_issue_update(issue_id)
114 status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))
115 status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))
115
116
116 issue = Issue.find_by_id(issue_id)
117 issue = Issue.find_by_id(issue_id)
117 return unless issue
118 return unless issue
118 # check permission
119 # check permission
119 raise UnauthorizedAction unless user.allowed_to?(:add_issue_notes, issue.project) || user.allowed_to?(:edit_issues, issue.project)
120 raise UnauthorizedAction unless user.allowed_to?(:add_issue_notes, issue.project) || user.allowed_to?(:edit_issues, issue.project)
120 raise UnauthorizedAction unless status.nil? || user.allowed_to?(:edit_issues, issue.project)
121 raise UnauthorizedAction unless status.nil? || user.allowed_to?(:edit_issues, issue.project)
121
122
122 # add the note
123 # add the note
123 journal = issue.init_journal(user, email.plain_text_body.chomp)
124 journal = issue.init_journal(user, plain_text_body)
124 add_attachments(issue)
125 add_attachments(issue)
125 # check workflow
126 # check workflow
126 if status && issue.new_statuses_allowed_to(user).include?(status)
127 if status && issue.new_statuses_allowed_to(user).include?(status)
127 issue.status = status
128 issue.status = status
128 end
129 end
129 issue.save!
130 issue.save!
130 logger.info "MailHandler: issue ##{issue.id} updated by #{user}" if logger && logger.info
131 logger.info "MailHandler: issue ##{issue.id} updated by #{user}" if logger && logger.info
131 Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
132 Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
132 journal
133 journal
133 end
134 end
134
135
135 def add_attachments(obj)
136 def add_attachments(obj)
136 if email.has_attachments?
137 if email.has_attachments?
137 email.attachments.each do |attachment|
138 email.attachments.each do |attachment|
138 Attachment.create(:container => obj,
139 Attachment.create(:container => obj,
139 :file => attachment,
140 :file => attachment,
140 :author => user,
141 :author => user,
141 :content_type => attachment.content_type)
142 :content_type => attachment.content_type)
142 end
143 end
143 end
144 end
144 end
145 end
145
146
146 # Adds To and Cc as watchers of the given object if the sender has the
147 # Adds To and Cc as watchers of the given object if the sender has the
147 # appropriate permission
148 # appropriate permission
148 def add_watchers(obj)
149 def add_watchers(obj)
149 if user.allowed_to?("add_#{obj.class.name.underscore}_watchers".to_sym, obj.project)
150 if user.allowed_to?("add_#{obj.class.name.underscore}_watchers".to_sym, obj.project)
150 addresses = [email.to, email.cc].flatten.compact.uniq.collect {|a| a.strip.downcase}
151 addresses = [email.to, email.cc].flatten.compact.uniq.collect {|a| a.strip.downcase}
151 unless addresses.empty?
152 unless addresses.empty?
152 watchers = User.active.find(:all, :conditions => ['LOWER(mail) IN (?)', addresses])
153 watchers = User.active.find(:all, :conditions => ['LOWER(mail) IN (?)', addresses])
153 watchers.each {|w| obj.add_watcher(w)}
154 watchers.each {|w| obj.add_watcher(w)}
154 end
155 end
155 end
156 end
156 end
157 end
157
158
158 def get_keyword(attr)
159 def get_keyword(attr)
159 if @@handler_options[:allow_override].include?(attr.to_s) && email.plain_text_body =~ /^#{attr}:[ \t]*(.+)$/i
160 if @@handler_options[:allow_override].include?(attr.to_s) && plain_text_body =~ /^#{attr}:[ \t]*(.+)$/i
160 $1.strip
161 $1.strip
161 elsif !@@handler_options[:issue][attr].blank?
162 elsif !@@handler_options[:issue][attr].blank?
162 @@handler_options[:issue][attr]
163 @@handler_options[:issue][attr]
163 end
164 end
164 end
165 end
165 end
166
166
167 # Returns the text/plain part of the email
167 class TMail::Mail
168 # If not found (eg. HTML-only email), returns the body with tags removed
168 # Returns body of the first plain text part found if any
169 def plain_text_body
169 def plain_text_body
170 return @plain_text_body unless @plain_text_body.nil?
170 return @plain_text_body unless @plain_text_body.nil?
171 p = self.parts.collect {|c| (c.respond_to?(:parts) && !c.parts.empty?) ? c.parts : c}.flatten
171 parts = @email.parts.collect {|c| (c.respond_to?(:parts) && !c.parts.empty?) ? c.parts : c}.flatten
172 plain = p.detect {|c| c.content_type == 'text/plain'}
172 if parts.empty?
173 @plain_text_body = plain.nil? ? self.body : plain.body
173 parts << @email
174 end
175 plain_text_part = parts.detect {|p| p.content_type == 'text/plain'}
176 if plain_text_part.nil?
177 # no text/plain part found, assuming html-only email
178 # strip html tags and remove doctype directive
179 @plain_text_body = strip_tags(@email.body.to_s)
180 @plain_text_body.gsub! %r{^<!DOCTYPE .*$}, ''
181 else
182 @plain_text_body = plain_text_part.body.to_s
183 end
184 @plain_text_body.strip!
174 end
185 end
175 end
186 end
176
@@ -1,139 +1,148
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
19
19
20 class MailHandlerTest < Test::Unit::TestCase
20 class MailHandlerTest < Test::Unit::TestCase
21 fixtures :users, :projects,
21 fixtures :users, :projects,
22 :enabled_modules,
22 :enabled_modules,
23 :roles,
23 :roles,
24 :members,
24 :members,
25 :issues,
25 :issues,
26 :issue_statuses,
26 :issue_statuses,
27 :workflows,
27 :workflows,
28 :trackers,
28 :trackers,
29 :projects_trackers,
29 :projects_trackers,
30 :enumerations,
30 :enumerations,
31 :issue_categories
31 :issue_categories
32
32
33 FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
33 FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
34
34
35 def setup
35 def setup
36 ActionMailer::Base.deliveries.clear
36 ActionMailer::Base.deliveries.clear
37 end
37 end
38
38
39 def test_add_issue
39 def test_add_issue
40 # This email contains: 'Project: onlinestore'
40 # This email contains: 'Project: onlinestore'
41 issue = submit_email('ticket_on_given_project.eml')
41 issue = submit_email('ticket_on_given_project.eml')
42 assert issue.is_a?(Issue)
42 assert issue.is_a?(Issue)
43 assert !issue.new_record?
43 assert !issue.new_record?
44 issue.reload
44 issue.reload
45 assert_equal 'New ticket on a given project', issue.subject
45 assert_equal 'New ticket on a given project', issue.subject
46 assert_equal User.find_by_login('jsmith'), issue.author
46 assert_equal User.find_by_login('jsmith'), issue.author
47 assert_equal Project.find(2), issue.project
47 assert_equal Project.find(2), issue.project
48 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
48 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
49 end
49 end
50
50
51 def test_add_issue_with_status
51 def test_add_issue_with_status
52 # This email contains: 'Project: onlinestore' and 'Status: Resolved'
52 # This email contains: 'Project: onlinestore' and 'Status: Resolved'
53 issue = submit_email('ticket_on_given_project.eml')
53 issue = submit_email('ticket_on_given_project.eml')
54 assert issue.is_a?(Issue)
54 assert issue.is_a?(Issue)
55 assert !issue.new_record?
55 assert !issue.new_record?
56 issue.reload
56 issue.reload
57 assert_equal Project.find(2), issue.project
57 assert_equal Project.find(2), issue.project
58 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
58 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
59 end
59 end
60
60
61 def test_add_issue_with_attributes_override
61 def test_add_issue_with_attributes_override
62 issue = submit_email('ticket_with_attributes.eml', :allow_override => 'tracker,category,priority')
62 issue = submit_email('ticket_with_attributes.eml', :allow_override => 'tracker,category,priority')
63 assert issue.is_a?(Issue)
63 assert issue.is_a?(Issue)
64 assert !issue.new_record?
64 assert !issue.new_record?
65 issue.reload
65 issue.reload
66 assert_equal 'New ticket on a given project', issue.subject
66 assert_equal 'New ticket on a given project', issue.subject
67 assert_equal User.find_by_login('jsmith'), issue.author
67 assert_equal User.find_by_login('jsmith'), issue.author
68 assert_equal Project.find(2), issue.project
68 assert_equal Project.find(2), issue.project
69 assert_equal 'Feature request', issue.tracker.to_s
69 assert_equal 'Feature request', issue.tracker.to_s
70 assert_equal 'Stock management', issue.category.to_s
70 assert_equal 'Stock management', issue.category.to_s
71 assert_equal 'Urgent', issue.priority.to_s
71 assert_equal 'Urgent', issue.priority.to_s
72 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
72 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
73 end
73 end
74
74
75 def test_add_issue_with_partial_attributes_override
75 def test_add_issue_with_partial_attributes_override
76 issue = submit_email('ticket_with_attributes.eml', :issue => {:priority => 'High'}, :allow_override => ['tracker'])
76 issue = submit_email('ticket_with_attributes.eml', :issue => {:priority => 'High'}, :allow_override => ['tracker'])
77 assert issue.is_a?(Issue)
77 assert issue.is_a?(Issue)
78 assert !issue.new_record?
78 assert !issue.new_record?
79 issue.reload
79 issue.reload
80 assert_equal 'New ticket on a given project', issue.subject
80 assert_equal 'New ticket on a given project', issue.subject
81 assert_equal User.find_by_login('jsmith'), issue.author
81 assert_equal User.find_by_login('jsmith'), issue.author
82 assert_equal Project.find(2), issue.project
82 assert_equal Project.find(2), issue.project
83 assert_equal 'Feature request', issue.tracker.to_s
83 assert_equal 'Feature request', issue.tracker.to_s
84 assert_nil issue.category
84 assert_nil issue.category
85 assert_equal 'High', issue.priority.to_s
85 assert_equal 'High', issue.priority.to_s
86 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
86 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
87 end
87 end
88
88
89 def test_add_issue_with_attachment_to_specific_project
89 def test_add_issue_with_attachment_to_specific_project
90 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
90 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
91 assert issue.is_a?(Issue)
91 assert issue.is_a?(Issue)
92 assert !issue.new_record?
92 assert !issue.new_record?
93 issue.reload
93 issue.reload
94 assert_equal 'Ticket created by email with attachment', issue.subject
94 assert_equal 'Ticket created by email with attachment', issue.subject
95 assert_equal User.find_by_login('jsmith'), issue.author
95 assert_equal User.find_by_login('jsmith'), issue.author
96 assert_equal Project.find(2), issue.project
96 assert_equal Project.find(2), issue.project
97 assert_equal 'This is a new ticket with attachments', issue.description
97 assert_equal 'This is a new ticket with attachments', issue.description
98 # Attachment properties
98 # Attachment properties
99 assert_equal 1, issue.attachments.size
99 assert_equal 1, issue.attachments.size
100 assert_equal 'Paella.jpg', issue.attachments.first.filename
100 assert_equal 'Paella.jpg', issue.attachments.first.filename
101 assert_equal 'image/jpeg', issue.attachments.first.content_type
101 assert_equal 'image/jpeg', issue.attachments.first.content_type
102 assert_equal 10790, issue.attachments.first.filesize
102 assert_equal 10790, issue.attachments.first.filesize
103 end
103 end
104
104
105 def test_add_issue_with_cc
105 def test_add_issue_with_cc
106 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
106 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
107 assert issue.is_a?(Issue)
107 assert issue.is_a?(Issue)
108 assert !issue.new_record?
108 assert !issue.new_record?
109 issue.reload
109 issue.reload
110 assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
110 assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
111 assert_equal 1, issue.watchers.size
111 assert_equal 1, issue.watchers.size
112 end
112 end
113
113
114 def test_add_issue_note
114 def test_add_issue_note
115 journal = submit_email('ticket_reply.eml')
115 journal = submit_email('ticket_reply.eml')
116 assert journal.is_a?(Journal)
116 assert journal.is_a?(Journal)
117 assert_equal User.find_by_login('jsmith'), journal.user
117 assert_equal User.find_by_login('jsmith'), journal.user
118 assert_equal Issue.find(2), journal.journalized
118 assert_equal Issue.find(2), journal.journalized
119 assert_match /This is reply/, journal.notes
119 assert_match /This is reply/, journal.notes
120 end
120 end
121
121
122 def test_add_issue_note_with_status_change
122 def test_add_issue_note_with_status_change
123 # This email contains: 'Status: Resolved'
123 # This email contains: 'Status: Resolved'
124 journal = submit_email('ticket_reply_with_status.eml')
124 journal = submit_email('ticket_reply_with_status.eml')
125 assert journal.is_a?(Journal)
125 assert journal.is_a?(Journal)
126 issue = Issue.find(journal.issue.id)
126 issue = Issue.find(journal.issue.id)
127 assert_equal User.find_by_login('jsmith'), journal.user
127 assert_equal User.find_by_login('jsmith'), journal.user
128 assert_equal Issue.find(2), journal.journalized
128 assert_equal Issue.find(2), journal.journalized
129 assert_match /This is reply/, journal.notes
129 assert_match /This is reply/, journal.notes
130 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
130 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
131 end
131 end
132
133 def test_should_strip_tags_of_html_only_emails
134 issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
135 assert issue.is_a?(Issue)
136 assert !issue.new_record?
137 issue.reload
138 assert_equal 'HTML email', issue.subject
139 assert_equal 'This is a html-only email.', issue.description
140 end
132
141
133 private
142 private
134
143
135 def submit_email(filename, options={})
144 def submit_email(filename, options={})
136 raw = IO.read(File.join(FIXTURES_PATH, filename))
145 raw = IO.read(File.join(FIXTURES_PATH, filename))
137 MailHandler.receive(raw, options)
146 MailHandler.receive(raw, options)
138 end
147 end
139 end
148 end
General Comments 0
You need to be logged in to leave comments. Login now