##// END OF EJS Templates
Makes the link in an issue update notification point to the change (#9690)....
Jean-Philippe Lang -
r7910:040cfa4ad5df
parent child
Show More
@@ -1,475 +1,475
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 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 'ar_condition'
18 require 'ar_condition'
19
19
20 class Mailer < ActionMailer::Base
20 class Mailer < ActionMailer::Base
21 layout 'mailer'
21 layout 'mailer'
22 helper :application
22 helper :application
23 helper :issues
23 helper :issues
24 helper :custom_fields
24 helper :custom_fields
25
25
26 include ActionController::UrlWriter
26 include ActionController::UrlWriter
27 include Redmine::I18n
27 include Redmine::I18n
28
28
29 def self.default_url_options
29 def self.default_url_options
30 h = Setting.host_name
30 h = Setting.host_name
31 h = h.to_s.gsub(%r{\/.*$}, '') unless Redmine::Utils.relative_url_root.blank?
31 h = h.to_s.gsub(%r{\/.*$}, '') unless Redmine::Utils.relative_url_root.blank?
32 { :host => h, :protocol => Setting.protocol }
32 { :host => h, :protocol => Setting.protocol }
33 end
33 end
34
34
35 # Builds a tmail object used to email recipients of the added issue.
35 # Builds a tmail object used to email recipients of the added issue.
36 #
36 #
37 # Example:
37 # Example:
38 # issue_add(issue) => tmail object
38 # issue_add(issue) => tmail object
39 # Mailer.deliver_issue_add(issue) => sends an email to issue recipients
39 # Mailer.deliver_issue_add(issue) => sends an email to issue recipients
40 def issue_add(issue)
40 def issue_add(issue)
41 redmine_headers 'Project' => issue.project.identifier,
41 redmine_headers 'Project' => issue.project.identifier,
42 'Issue-Id' => issue.id,
42 'Issue-Id' => issue.id,
43 'Issue-Author' => issue.author.login
43 'Issue-Author' => issue.author.login
44 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
44 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
45 message_id issue
45 message_id issue
46 recipients issue.recipients
46 recipients issue.recipients
47 cc(issue.watcher_recipients - @recipients)
47 cc(issue.watcher_recipients - @recipients)
48 subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
48 subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
49 body :issue => issue,
49 body :issue => issue,
50 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
50 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
51 render_multipart('issue_add', body)
51 render_multipart('issue_add', body)
52 end
52 end
53
53
54 # Builds a tmail object used to email recipients of the edited issue.
54 # Builds a tmail object used to email recipients of the edited issue.
55 #
55 #
56 # Example:
56 # Example:
57 # issue_edit(journal) => tmail object
57 # issue_edit(journal) => tmail object
58 # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients
58 # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients
59 def issue_edit(journal)
59 def issue_edit(journal)
60 issue = journal.journalized.reload
60 issue = journal.journalized.reload
61 redmine_headers 'Project' => issue.project.identifier,
61 redmine_headers 'Project' => issue.project.identifier,
62 'Issue-Id' => issue.id,
62 'Issue-Id' => issue.id,
63 'Issue-Author' => issue.author.login
63 'Issue-Author' => issue.author.login
64 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
64 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
65 message_id journal
65 message_id journal
66 references issue
66 references issue
67 @author = journal.user
67 @author = journal.user
68 recipients issue.recipients
68 recipients issue.recipients
69 # Watchers in cc
69 # Watchers in cc
70 cc(issue.watcher_recipients - @recipients)
70 cc(issue.watcher_recipients - @recipients)
71 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
71 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
72 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
72 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
73 s << issue.subject
73 s << issue.subject
74 subject s
74 subject s
75 body :issue => issue,
75 body :issue => issue,
76 :journal => journal,
76 :journal => journal,
77 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
77 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
78
78
79 render_multipart('issue_edit', body)
79 render_multipart('issue_edit', body)
80 end
80 end
81
81
82 def reminder(user, issues, days)
82 def reminder(user, issues, days)
83 set_language_if_valid user.language
83 set_language_if_valid user.language
84 recipients user.mail
84 recipients user.mail
85 subject l(:mail_subject_reminder, :count => issues.size, :days => days)
85 subject l(:mail_subject_reminder, :count => issues.size, :days => days)
86 body :issues => issues,
86 body :issues => issues,
87 :days => days,
87 :days => days,
88 :issues_url => url_for(:controller => 'issues', :action => 'index',
88 :issues_url => url_for(:controller => 'issues', :action => 'index',
89 :set_filter => 1, :assigned_to_id => user.id,
89 :set_filter => 1, :assigned_to_id => user.id,
90 :sort => 'due_date:asc')
90 :sort => 'due_date:asc')
91 render_multipart('reminder', body)
91 render_multipart('reminder', body)
92 end
92 end
93
93
94 # Builds a tmail object used to email users belonging to the added document's project.
94 # Builds a tmail object used to email users belonging to the added document's project.
95 #
95 #
96 # Example:
96 # Example:
97 # document_added(document) => tmail object
97 # document_added(document) => tmail object
98 # Mailer.deliver_document_added(document) => sends an email to the document's project recipients
98 # Mailer.deliver_document_added(document) => sends an email to the document's project recipients
99 def document_added(document)
99 def document_added(document)
100 redmine_headers 'Project' => document.project.identifier
100 redmine_headers 'Project' => document.project.identifier
101 recipients document.recipients
101 recipients document.recipients
102 subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
102 subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
103 body :document => document,
103 body :document => document,
104 :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
104 :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
105 render_multipart('document_added', body)
105 render_multipart('document_added', body)
106 end
106 end
107
107
108 # Builds a tmail object used to email recipients of a project when an attachements are added.
108 # Builds a tmail object used to email recipients of a project when an attachements are added.
109 #
109 #
110 # Example:
110 # Example:
111 # attachments_added(attachments) => tmail object
111 # attachments_added(attachments) => tmail object
112 # Mailer.deliver_attachments_added(attachments) => sends an email to the project's recipients
112 # Mailer.deliver_attachments_added(attachments) => sends an email to the project's recipients
113 def attachments_added(attachments)
113 def attachments_added(attachments)
114 container = attachments.first.container
114 container = attachments.first.container
115 added_to = ''
115 added_to = ''
116 added_to_url = ''
116 added_to_url = ''
117 case container.class.name
117 case container.class.name
118 when 'Project'
118 when 'Project'
119 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
119 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
120 added_to = "#{l(:label_project)}: #{container}"
120 added_to = "#{l(:label_project)}: #{container}"
121 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
121 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
122 when 'Version'
122 when 'Version'
123 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
123 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
124 added_to = "#{l(:label_version)}: #{container.name}"
124 added_to = "#{l(:label_version)}: #{container.name}"
125 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
125 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
126 when 'Document'
126 when 'Document'
127 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
127 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
128 added_to = "#{l(:label_document)}: #{container.title}"
128 added_to = "#{l(:label_document)}: #{container.title}"
129 recipients container.recipients
129 recipients container.recipients
130 end
130 end
131 redmine_headers 'Project' => container.project.identifier
131 redmine_headers 'Project' => container.project.identifier
132 subject "[#{container.project.name}] #{l(:label_attachment_new)}"
132 subject "[#{container.project.name}] #{l(:label_attachment_new)}"
133 body :attachments => attachments,
133 body :attachments => attachments,
134 :added_to => added_to,
134 :added_to => added_to,
135 :added_to_url => added_to_url
135 :added_to_url => added_to_url
136 render_multipart('attachments_added', body)
136 render_multipart('attachments_added', body)
137 end
137 end
138
138
139 # Builds a tmail object used to email recipients of a news' project when a news item is added.
139 # Builds a tmail object used to email recipients of a news' project when a news item is added.
140 #
140 #
141 # Example:
141 # Example:
142 # news_added(news) => tmail object
142 # news_added(news) => tmail object
143 # Mailer.deliver_news_added(news) => sends an email to the news' project recipients
143 # Mailer.deliver_news_added(news) => sends an email to the news' project recipients
144 def news_added(news)
144 def news_added(news)
145 redmine_headers 'Project' => news.project.identifier
145 redmine_headers 'Project' => news.project.identifier
146 message_id news
146 message_id news
147 recipients news.recipients
147 recipients news.recipients
148 subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
148 subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
149 body :news => news,
149 body :news => news,
150 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
150 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
151 render_multipart('news_added', body)
151 render_multipart('news_added', body)
152 end
152 end
153
153
154 # Builds a tmail object used to email recipients of a news' project when a news comment is added.
154 # Builds a tmail object used to email recipients of a news' project when a news comment is added.
155 #
155 #
156 # Example:
156 # Example:
157 # news_comment_added(comment) => tmail object
157 # news_comment_added(comment) => tmail object
158 # Mailer.news_comment_added(comment) => sends an email to the news' project recipients
158 # Mailer.news_comment_added(comment) => sends an email to the news' project recipients
159 def news_comment_added(comment)
159 def news_comment_added(comment)
160 news = comment.commented
160 news = comment.commented
161 redmine_headers 'Project' => news.project.identifier
161 redmine_headers 'Project' => news.project.identifier
162 message_id comment
162 message_id comment
163 recipients news.recipients
163 recipients news.recipients
164 cc news.watcher_recipients
164 cc news.watcher_recipients
165 subject "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
165 subject "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
166 body :news => news,
166 body :news => news,
167 :comment => comment,
167 :comment => comment,
168 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
168 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
169 render_multipart('news_comment_added', body)
169 render_multipart('news_comment_added', body)
170 end
170 end
171
171
172 # Builds a tmail object used to email the recipients of the specified message that was posted.
172 # Builds a tmail object used to email the recipients of the specified message that was posted.
173 #
173 #
174 # Example:
174 # Example:
175 # message_posted(message) => tmail object
175 # message_posted(message) => tmail object
176 # Mailer.deliver_message_posted(message) => sends an email to the recipients
176 # Mailer.deliver_message_posted(message) => sends an email to the recipients
177 def message_posted(message)
177 def message_posted(message)
178 redmine_headers 'Project' => message.project.identifier,
178 redmine_headers 'Project' => message.project.identifier,
179 'Topic-Id' => (message.parent_id || message.id)
179 'Topic-Id' => (message.parent_id || message.id)
180 message_id message
180 message_id message
181 references message.parent unless message.parent.nil?
181 references message.parent unless message.parent.nil?
182 recipients(message.recipients)
182 recipients(message.recipients)
183 cc((message.root.watcher_recipients + message.board.watcher_recipients).uniq - @recipients)
183 cc((message.root.watcher_recipients + message.board.watcher_recipients).uniq - @recipients)
184 subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
184 subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
185 body :message => message,
185 body :message => message,
186 :message_url => url_for(message.event_url)
186 :message_url => url_for(message.event_url)
187 render_multipart('message_posted', body)
187 render_multipart('message_posted', body)
188 end
188 end
189
189
190 # Builds a tmail object used to email the recipients of a project of the specified wiki content was added.
190 # Builds a tmail object used to email the recipients of a project of the specified wiki content was added.
191 #
191 #
192 # Example:
192 # Example:
193 # wiki_content_added(wiki_content) => tmail object
193 # wiki_content_added(wiki_content) => tmail object
194 # Mailer.deliver_wiki_content_added(wiki_content) => sends an email to the project's recipients
194 # Mailer.deliver_wiki_content_added(wiki_content) => sends an email to the project's recipients
195 def wiki_content_added(wiki_content)
195 def wiki_content_added(wiki_content)
196 redmine_headers 'Project' => wiki_content.project.identifier,
196 redmine_headers 'Project' => wiki_content.project.identifier,
197 'Wiki-Page-Id' => wiki_content.page.id
197 'Wiki-Page-Id' => wiki_content.page.id
198 message_id wiki_content
198 message_id wiki_content
199 recipients wiki_content.recipients
199 recipients wiki_content.recipients
200 cc(wiki_content.page.wiki.watcher_recipients - recipients)
200 cc(wiki_content.page.wiki.watcher_recipients - recipients)
201 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
201 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
202 body :wiki_content => wiki_content,
202 body :wiki_content => wiki_content,
203 :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
203 :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
204 :project_id => wiki_content.project,
204 :project_id => wiki_content.project,
205 :id => wiki_content.page.title)
205 :id => wiki_content.page.title)
206 render_multipart('wiki_content_added', body)
206 render_multipart('wiki_content_added', body)
207 end
207 end
208
208
209 # Builds a tmail object used to email the recipients of a project of the specified wiki content was updated.
209 # Builds a tmail object used to email the recipients of a project of the specified wiki content was updated.
210 #
210 #
211 # Example:
211 # Example:
212 # wiki_content_updated(wiki_content) => tmail object
212 # wiki_content_updated(wiki_content) => tmail object
213 # Mailer.deliver_wiki_content_updated(wiki_content) => sends an email to the project's recipients
213 # Mailer.deliver_wiki_content_updated(wiki_content) => sends an email to the project's recipients
214 def wiki_content_updated(wiki_content)
214 def wiki_content_updated(wiki_content)
215 redmine_headers 'Project' => wiki_content.project.identifier,
215 redmine_headers 'Project' => wiki_content.project.identifier,
216 'Wiki-Page-Id' => wiki_content.page.id
216 'Wiki-Page-Id' => wiki_content.page.id
217 message_id wiki_content
217 message_id wiki_content
218 recipients wiki_content.recipients
218 recipients wiki_content.recipients
219 cc(wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients)
219 cc(wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients)
220 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
220 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
221 body :wiki_content => wiki_content,
221 body :wiki_content => wiki_content,
222 :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
222 :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
223 :project_id => wiki_content.project,
223 :project_id => wiki_content.project,
224 :id => wiki_content.page.title),
224 :id => wiki_content.page.title),
225 :wiki_diff_url => url_for(:controller => 'wiki', :action => 'diff',
225 :wiki_diff_url => url_for(:controller => 'wiki', :action => 'diff',
226 :project_id => wiki_content.project, :id => wiki_content.page.title,
226 :project_id => wiki_content.project, :id => wiki_content.page.title,
227 :version => wiki_content.version)
227 :version => wiki_content.version)
228 render_multipart('wiki_content_updated', body)
228 render_multipart('wiki_content_updated', body)
229 end
229 end
230
230
231 # Builds a tmail object used to email the specified user their account information.
231 # Builds a tmail object used to email the specified user their account information.
232 #
232 #
233 # Example:
233 # Example:
234 # account_information(user, password) => tmail object
234 # account_information(user, password) => tmail object
235 # Mailer.deliver_account_information(user, password) => sends account information to the user
235 # Mailer.deliver_account_information(user, password) => sends account information to the user
236 def account_information(user, password)
236 def account_information(user, password)
237 set_language_if_valid user.language
237 set_language_if_valid user.language
238 recipients user.mail
238 recipients user.mail
239 subject l(:mail_subject_register, Setting.app_title)
239 subject l(:mail_subject_register, Setting.app_title)
240 body :user => user,
240 body :user => user,
241 :password => password,
241 :password => password,
242 :login_url => url_for(:controller => 'account', :action => 'login')
242 :login_url => url_for(:controller => 'account', :action => 'login')
243 render_multipart('account_information', body)
243 render_multipart('account_information', body)
244 end
244 end
245
245
246 # Builds a tmail object used to email all active administrators of an account activation request.
246 # Builds a tmail object used to email all active administrators of an account activation request.
247 #
247 #
248 # Example:
248 # Example:
249 # account_activation_request(user) => tmail object
249 # account_activation_request(user) => tmail object
250 # Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators
250 # Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators
251 def account_activation_request(user)
251 def account_activation_request(user)
252 # Send the email to all active administrators
252 # Send the email to all active administrators
253 recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
253 recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
254 subject l(:mail_subject_account_activation_request, Setting.app_title)
254 subject l(:mail_subject_account_activation_request, Setting.app_title)
255 body :user => user,
255 body :user => user,
256 :url => url_for(:controller => 'users', :action => 'index',
256 :url => url_for(:controller => 'users', :action => 'index',
257 :status => User::STATUS_REGISTERED,
257 :status => User::STATUS_REGISTERED,
258 :sort_key => 'created_on', :sort_order => 'desc')
258 :sort_key => 'created_on', :sort_order => 'desc')
259 render_multipart('account_activation_request', body)
259 render_multipart('account_activation_request', body)
260 end
260 end
261
261
262 # Builds a tmail object used to email the specified user that their account was activated by an administrator.
262 # Builds a tmail object used to email the specified user that their account was activated by an administrator.
263 #
263 #
264 # Example:
264 # Example:
265 # account_activated(user) => tmail object
265 # account_activated(user) => tmail object
266 # Mailer.deliver_account_activated(user) => sends an email to the registered user
266 # Mailer.deliver_account_activated(user) => sends an email to the registered user
267 def account_activated(user)
267 def account_activated(user)
268 set_language_if_valid user.language
268 set_language_if_valid user.language
269 recipients user.mail
269 recipients user.mail
270 subject l(:mail_subject_register, Setting.app_title)
270 subject l(:mail_subject_register, Setting.app_title)
271 body :user => user,
271 body :user => user,
272 :login_url => url_for(:controller => 'account', :action => 'login')
272 :login_url => url_for(:controller => 'account', :action => 'login')
273 render_multipart('account_activated', body)
273 render_multipart('account_activated', body)
274 end
274 end
275
275
276 def lost_password(token)
276 def lost_password(token)
277 set_language_if_valid(token.user.language)
277 set_language_if_valid(token.user.language)
278 recipients token.user.mail
278 recipients token.user.mail
279 subject l(:mail_subject_lost_password, Setting.app_title)
279 subject l(:mail_subject_lost_password, Setting.app_title)
280 body :token => token,
280 body :token => token,
281 :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
281 :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
282 render_multipart('lost_password', body)
282 render_multipart('lost_password', body)
283 end
283 end
284
284
285 def register(token)
285 def register(token)
286 set_language_if_valid(token.user.language)
286 set_language_if_valid(token.user.language)
287 recipients token.user.mail
287 recipients token.user.mail
288 subject l(:mail_subject_register, Setting.app_title)
288 subject l(:mail_subject_register, Setting.app_title)
289 body :token => token,
289 body :token => token,
290 :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
290 :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
291 render_multipart('register', body)
291 render_multipart('register', body)
292 end
292 end
293
293
294 def test(user)
294 def test(user)
295 set_language_if_valid(user.language)
295 set_language_if_valid(user.language)
296 recipients user.mail
296 recipients user.mail
297 subject 'Redmine test'
297 subject 'Redmine test'
298 body :url => url_for(:controller => 'welcome')
298 body :url => url_for(:controller => 'welcome')
299 render_multipart('test', body)
299 render_multipart('test', body)
300 end
300 end
301
301
302 # Overrides default deliver! method to prevent from sending an email
302 # Overrides default deliver! method to prevent from sending an email
303 # with no recipient, cc or bcc
303 # with no recipient, cc or bcc
304 def deliver!(mail = @mail)
304 def deliver!(mail = @mail)
305 set_language_if_valid @initial_language
305 set_language_if_valid @initial_language
306 return false if (recipients.nil? || recipients.empty?) &&
306 return false if (recipients.nil? || recipients.empty?) &&
307 (cc.nil? || cc.empty?) &&
307 (cc.nil? || cc.empty?) &&
308 (bcc.nil? || bcc.empty?)
308 (bcc.nil? || bcc.empty?)
309
309
310 # Set Message-Id and References
310 # Set Message-Id and References
311 if @message_id_object
311 if @message_id_object
312 mail.message_id = self.class.message_id_for(@message_id_object)
312 mail.message_id = self.class.message_id_for(@message_id_object)
313 end
313 end
314 if @references_objects
314 if @references_objects
315 mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}
315 mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}
316 end
316 end
317
317
318 # Log errors when raise_delivery_errors is set to false, Rails does not
318 # Log errors when raise_delivery_errors is set to false, Rails does not
319 raise_errors = self.class.raise_delivery_errors
319 raise_errors = self.class.raise_delivery_errors
320 self.class.raise_delivery_errors = true
320 self.class.raise_delivery_errors = true
321 begin
321 begin
322 return super(mail)
322 return super(mail)
323 rescue Exception => e
323 rescue Exception => e
324 if raise_errors
324 if raise_errors
325 raise e
325 raise e
326 elsif mylogger
326 elsif mylogger
327 mylogger.error "The following error occured while sending email notification: \"#{e.message}\". Check your configuration in config/configuration.yml."
327 mylogger.error "The following error occured while sending email notification: \"#{e.message}\". Check your configuration in config/configuration.yml."
328 end
328 end
329 ensure
329 ensure
330 self.class.raise_delivery_errors = raise_errors
330 self.class.raise_delivery_errors = raise_errors
331 end
331 end
332 end
332 end
333
333
334 # Sends reminders to issue assignees
334 # Sends reminders to issue assignees
335 # Available options:
335 # Available options:
336 # * :days => how many days in the future to remind about (defaults to 7)
336 # * :days => how many days in the future to remind about (defaults to 7)
337 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
337 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
338 # * :project => id or identifier of project to process (defaults to all projects)
338 # * :project => id or identifier of project to process (defaults to all projects)
339 # * :users => array of user ids who should be reminded
339 # * :users => array of user ids who should be reminded
340 def self.reminders(options={})
340 def self.reminders(options={})
341 days = options[:days] || 7
341 days = options[:days] || 7
342 project = options[:project] ? Project.find(options[:project]) : nil
342 project = options[:project] ? Project.find(options[:project]) : nil
343 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
343 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
344 user_ids = options[:users]
344 user_ids = options[:users]
345
345
346 s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?", false, days.day.from_now.to_date]
346 s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?", false, days.day.from_now.to_date]
347 s << "#{Issue.table_name}.assigned_to_id IS NOT NULL"
347 s << "#{Issue.table_name}.assigned_to_id IS NOT NULL"
348 s << ["#{Issue.table_name}.assigned_to_id IN (?)", user_ids] if user_ids.present?
348 s << ["#{Issue.table_name}.assigned_to_id IN (?)", user_ids] if user_ids.present?
349 s << "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}"
349 s << "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}"
350 s << "#{Issue.table_name}.project_id = #{project.id}" if project
350 s << "#{Issue.table_name}.project_id = #{project.id}" if project
351 s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker
351 s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker
352
352
353 issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker],
353 issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker],
354 :conditions => s.conditions
354 :conditions => s.conditions
355 ).group_by(&:assigned_to)
355 ).group_by(&:assigned_to)
356 issues_by_assignee.each do |assignee, issues|
356 issues_by_assignee.each do |assignee, issues|
357 deliver_reminder(assignee, issues, days) if assignee && assignee.active?
357 deliver_reminder(assignee, issues, days) if assignee && assignee.active?
358 end
358 end
359 end
359 end
360
360
361 # Activates/desactivates email deliveries during +block+
361 # Activates/desactivates email deliveries during +block+
362 def self.with_deliveries(enabled = true, &block)
362 def self.with_deliveries(enabled = true, &block)
363 was_enabled = ActionMailer::Base.perform_deliveries
363 was_enabled = ActionMailer::Base.perform_deliveries
364 ActionMailer::Base.perform_deliveries = !!enabled
364 ActionMailer::Base.perform_deliveries = !!enabled
365 yield
365 yield
366 ensure
366 ensure
367 ActionMailer::Base.perform_deliveries = was_enabled
367 ActionMailer::Base.perform_deliveries = was_enabled
368 end
368 end
369
369
370 private
370 private
371 def initialize_defaults(method_name)
371 def initialize_defaults(method_name)
372 super
372 super
373 @initial_language = current_language
373 @initial_language = current_language
374 set_language_if_valid Setting.default_language
374 set_language_if_valid Setting.default_language
375 from Setting.mail_from
375 from Setting.mail_from
376
376
377 # Common headers
377 # Common headers
378 headers 'X-Mailer' => 'Redmine',
378 headers 'X-Mailer' => 'Redmine',
379 'X-Redmine-Host' => Setting.host_name,
379 'X-Redmine-Host' => Setting.host_name,
380 'X-Redmine-Site' => Setting.app_title,
380 'X-Redmine-Site' => Setting.app_title,
381 'X-Auto-Response-Suppress' => 'OOF',
381 'X-Auto-Response-Suppress' => 'OOF',
382 'Auto-Submitted' => 'auto-generated'
382 'Auto-Submitted' => 'auto-generated'
383 end
383 end
384
384
385 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
385 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
386 def redmine_headers(h)
386 def redmine_headers(h)
387 h.each { |k,v| headers["X-Redmine-#{k}"] = v }
387 h.each { |k,v| headers["X-Redmine-#{k}"] = v }
388 end
388 end
389
389
390 # Overrides the create_mail method
390 # Overrides the create_mail method
391 def create_mail
391 def create_mail
392 # Removes the current user from the recipients and cc
392 # Removes the current user from the recipients and cc
393 # if he doesn't want to receive notifications about what he does
393 # if he doesn't want to receive notifications about what he does
394 @author ||= User.current
394 @author ||= User.current
395 if @author.pref[:no_self_notified]
395 if @author.pref[:no_self_notified]
396 recipients.delete(@author.mail) if recipients
396 recipients.delete(@author.mail) if recipients
397 cc.delete(@author.mail) if cc
397 cc.delete(@author.mail) if cc
398 end
398 end
399
399
400 notified_users = [recipients, cc].flatten.compact.uniq
400 notified_users = [recipients, cc].flatten.compact.uniq
401 # Rails would log recipients only, not cc and bcc
401 # Rails would log recipients only, not cc and bcc
402 mylogger.info "Sending email notification to: #{notified_users.join(', ')}" if mylogger
402 mylogger.info "Sending email notification to: #{notified_users.join(', ')}" if mylogger
403
403
404 # Blind carbon copy recipients
404 # Blind carbon copy recipients
405 if Setting.bcc_recipients?
405 if Setting.bcc_recipients?
406 bcc(notified_users)
406 bcc(notified_users)
407 recipients []
407 recipients []
408 cc []
408 cc []
409 end
409 end
410 super
410 super
411 end
411 end
412
412
413 # Rails 2.3 has problems rendering implicit multipart messages with
413 # Rails 2.3 has problems rendering implicit multipart messages with
414 # layouts so this method will wrap an multipart messages with
414 # layouts so this method will wrap an multipart messages with
415 # explicit parts.
415 # explicit parts.
416 #
416 #
417 # https://rails.lighthouseapp.com/projects/8994/tickets/2338-actionmailer-mailer-views-and-content-type
417 # https://rails.lighthouseapp.com/projects/8994/tickets/2338-actionmailer-mailer-views-and-content-type
418 # https://rails.lighthouseapp.com/projects/8994/tickets/1799-actionmailer-doesnt-set-template_format-when-rendering-layouts
418 # https://rails.lighthouseapp.com/projects/8994/tickets/1799-actionmailer-doesnt-set-template_format-when-rendering-layouts
419
419
420 def render_multipart(method_name, body)
420 def render_multipart(method_name, body)
421 if Setting.plain_text_mail?
421 if Setting.plain_text_mail?
422 content_type "text/plain"
422 content_type "text/plain"
423 body render(:file => "#{method_name}.text.erb",
423 body render(:file => "#{method_name}.text.erb",
424 :body => body,
424 :body => body,
425 :layout => 'mailer.text.erb')
425 :layout => 'mailer.text.erb')
426 else
426 else
427 content_type "multipart/alternative"
427 content_type "multipart/alternative"
428 part :content_type => "text/plain",
428 part :content_type => "text/plain",
429 :body => render(:file => "#{method_name}.text.erb",
429 :body => render(:file => "#{method_name}.text.erb",
430 :body => body, :layout => 'mailer.text.erb')
430 :body => body, :layout => 'mailer.text.erb')
431 part :content_type => "text/html",
431 part :content_type => "text/html",
432 :body => render_message("#{method_name}.html.erb", body)
432 :body => render_message("#{method_name}.html.erb", body)
433 end
433 end
434 end
434 end
435
435
436 # Makes partial rendering work with Rails 1.2 (retro-compatibility)
436 # Makes partial rendering work with Rails 1.2 (retro-compatibility)
437 def self.controller_path
437 def self.controller_path
438 ''
438 ''
439 end unless respond_to?('controller_path')
439 end unless respond_to?('controller_path')
440
440
441 # Returns a predictable Message-Id for the given object
441 # Returns a predictable Message-Id for the given object
442 def self.message_id_for(object)
442 def self.message_id_for(object)
443 # id + timestamp should reduce the odds of a collision
443 # id + timestamp should reduce the odds of a collision
444 # as far as we don't send multiple emails for the same object
444 # as far as we don't send multiple emails for the same object
445 timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
445 timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
446 hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{timestamp.strftime("%Y%m%d%H%M%S")}"
446 hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{timestamp.strftime("%Y%m%d%H%M%S")}"
447 host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
447 host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
448 host = "#{::Socket.gethostname}.redmine" if host.empty?
448 host = "#{::Socket.gethostname}.redmine" if host.empty?
449 "<#{hash}@#{host}>"
449 "<#{hash}@#{host}>"
450 end
450 end
451
451
452 private
452 private
453
453
454 def message_id(object)
454 def message_id(object)
455 @message_id_object = object
455 @message_id_object = object
456 end
456 end
457
457
458 def references(object)
458 def references(object)
459 @references_objects ||= []
459 @references_objects ||= []
460 @references_objects << object
460 @references_objects << object
461 end
461 end
462
462
463 def mylogger
463 def mylogger
464 Rails.logger
464 Rails.logger
465 end
465 end
466 end
466 end
467
467
468 # Patch TMail so that message_id is not overwritten
468 # Patch TMail so that message_id is not overwritten
469 module TMail
469 module TMail
470 class Mail
470 class Mail
471 def add_message_id( fqdn = nil )
471 def add_message_id( fqdn = nil )
472 self.message_id ||= ::TMail::new_message_id(fqdn)
472 self.message_id ||= ::TMail::new_message_id(fqdn)
473 end
473 end
474 end
474 end
475 end
475 end
@@ -1,497 +1,502
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class MailerTest < ActiveSupport::TestCase
20 class MailerTest < ActiveSupport::TestCase
21 include Redmine::I18n
21 include Redmine::I18n
22 include ActionController::Assertions::SelectorAssertions
22 include ActionController::Assertions::SelectorAssertions
23 fixtures :projects, :enabled_modules, :issues, :users, :members,
23 fixtures :projects, :enabled_modules, :issues, :users, :members,
24 :member_roles, :roles, :documents, :attachments, :news,
24 :member_roles, :roles, :documents, :attachments, :news,
25 :tokens, :journals, :journal_details, :changesets, :trackers,
25 :tokens, :journals, :journal_details, :changesets, :trackers,
26 :issue_statuses, :enumerations, :messages, :boards, :repositories,
26 :issue_statuses, :enumerations, :messages, :boards, :repositories,
27 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions,
27 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions,
28 :versions,
28 :versions,
29 :comments
29 :comments
30
30
31 def setup
31 def setup
32 ActionMailer::Base.deliveries.clear
32 ActionMailer::Base.deliveries.clear
33 Setting.host_name = 'mydomain.foo'
33 Setting.host_name = 'mydomain.foo'
34 Setting.protocol = 'http'
34 Setting.protocol = 'http'
35 Setting.plain_text_mail = '0'
35 Setting.plain_text_mail = '0'
36 end
36 end
37
37
38 def test_generated_links_in_emails
38 def test_generated_links_in_emails
39 Setting.host_name = 'mydomain.foo'
39 Setting.host_name = 'mydomain.foo'
40 Setting.protocol = 'https'
40 Setting.protocol = 'https'
41
41
42 journal = Journal.find(2)
42 journal = Journal.find(2)
43 assert Mailer.deliver_issue_edit(journal)
43 assert Mailer.deliver_issue_edit(journal)
44
44
45 mail = ActionMailer::Base.deliveries.last
45 mail = ActionMailer::Base.deliveries.last
46 assert_kind_of TMail::Mail, mail
46 assert_kind_of TMail::Mail, mail
47
47
48 assert_select_email do
48 assert_select_email do
49 # link to the main ticket
49 # link to the main ticket
50 assert_select "a[href=?]",
50 assert_select "a[href=?]",
51 "https://mydomain.foo/issues/1",
51 "https://mydomain.foo/issues/1#change-2",
52 :text => "Bug #1: Can't print recipes"
52 :text => "Bug #1: Can't print recipes"
53 # link to a referenced ticket
53 # link to a referenced ticket
54 assert_select "a[href=?][title=?]",
54 assert_select "a[href=?][title=?]",
55 "https://mydomain.foo/issues/2",
55 "https://mydomain.foo/issues/2",
56 "Add ingredients categories (Assigned)",
56 "Add ingredients categories (Assigned)",
57 :text => "#2"
57 :text => "#2"
58 # link to a changeset
58 # link to a changeset
59 assert_select "a[href=?][title=?]",
59 assert_select "a[href=?][title=?]",
60 "https://mydomain.foo/projects/ecookbook/repository/revisions/2",
60 "https://mydomain.foo/projects/ecookbook/repository/revisions/2",
61 "This commit fixes #1, #2 and references #1 &amp; #3",
61 "This commit fixes #1, #2 and references #1 &amp; #3",
62 :text => "r2"
62 :text => "r2"
63 end
63 end
64 end
64 end
65
65
66 def test_generated_links_with_prefix
66 def test_generated_links_with_prefix
67 relative_url_root = Redmine::Utils.relative_url_root
67 relative_url_root = Redmine::Utils.relative_url_root
68 Setting.host_name = 'mydomain.foo/rdm'
68 Setting.host_name = 'mydomain.foo/rdm'
69 Setting.protocol = 'http'
69 Setting.protocol = 'http'
70 Redmine::Utils.relative_url_root = '/rdm'
70 Redmine::Utils.relative_url_root = '/rdm'
71
71
72 journal = Journal.find(2)
72 journal = Journal.find(2)
73 assert Mailer.deliver_issue_edit(journal)
73 assert Mailer.deliver_issue_edit(journal)
74
74
75 mail = ActionMailer::Base.deliveries.last
75 mail = ActionMailer::Base.deliveries.last
76 assert_kind_of TMail::Mail, mail
76 assert_kind_of TMail::Mail, mail
77
77
78 assert_select_email do
78 assert_select_email do
79 # link to the main ticket
79 # link to the main ticket
80 assert_select "a[href=?]",
80 assert_select "a[href=?]",
81 "http://mydomain.foo/rdm/issues/1",
81 "http://mydomain.foo/rdm/issues/1#change-2",
82 :text => "Bug #1: Can't print recipes"
82 :text => "Bug #1: Can't print recipes"
83 # link to a referenced ticket
83 # link to a referenced ticket
84 assert_select "a[href=?][title=?]",
84 assert_select "a[href=?][title=?]",
85 "http://mydomain.foo/rdm/issues/2",
85 "http://mydomain.foo/rdm/issues/2",
86 "Add ingredients categories (Assigned)",
86 "Add ingredients categories (Assigned)",
87 :text => "#2"
87 :text => "#2"
88 # link to a changeset
88 # link to a changeset
89 assert_select "a[href=?][title=?]",
89 assert_select "a[href=?][title=?]",
90 "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2",
90 "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2",
91 "This commit fixes #1, #2 and references #1 &amp; #3",
91 "This commit fixes #1, #2 and references #1 &amp; #3",
92 :text => "r2"
92 :text => "r2"
93 end
93 end
94 ensure
94 ensure
95 # restore it
95 # restore it
96 Redmine::Utils.relative_url_root = relative_url_root
96 Redmine::Utils.relative_url_root = relative_url_root
97 end
97 end
98
98
99 def test_generated_links_with_prefix_and_no_relative_url_root
99 def test_generated_links_with_prefix_and_no_relative_url_root
100 relative_url_root = Redmine::Utils.relative_url_root
100 relative_url_root = Redmine::Utils.relative_url_root
101 Setting.host_name = 'mydomain.foo/rdm'
101 Setting.host_name = 'mydomain.foo/rdm'
102 Setting.protocol = 'http'
102 Setting.protocol = 'http'
103 Redmine::Utils.relative_url_root = nil
103 Redmine::Utils.relative_url_root = nil
104
104
105 journal = Journal.find(2)
105 journal = Journal.find(2)
106 assert Mailer.deliver_issue_edit(journal)
106 assert Mailer.deliver_issue_edit(journal)
107
107
108 mail = ActionMailer::Base.deliveries.last
108 mail = ActionMailer::Base.deliveries.last
109 assert_kind_of TMail::Mail, mail
109 assert_kind_of TMail::Mail, mail
110
110
111 assert_select_email do
111 assert_select_email do
112 # link to the main ticket
112 # link to the main ticket
113 assert_select "a[href=?]",
113 assert_select "a[href=?]",
114 "http://mydomain.foo/rdm/issues/1",
114 "http://mydomain.foo/rdm/issues/1#change-2",
115 :text => "Bug #1: Can't print recipes"
115 :text => "Bug #1: Can't print recipes"
116 # link to a referenced ticket
116 # link to a referenced ticket
117 assert_select "a[href=?][title=?]",
117 assert_select "a[href=?][title=?]",
118 "http://mydomain.foo/rdm/issues/2",
118 "http://mydomain.foo/rdm/issues/2",
119 "Add ingredients categories (Assigned)",
119 "Add ingredients categories (Assigned)",
120 :text => "#2"
120 :text => "#2"
121 # link to a changeset
121 # link to a changeset
122 assert_select "a[href=?][title=?]",
122 assert_select "a[href=?][title=?]",
123 "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2",
123 "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2",
124 "This commit fixes #1, #2 and references #1 &amp; #3",
124 "This commit fixes #1, #2 and references #1 &amp; #3",
125 :text => "r2"
125 :text => "r2"
126 end
126 end
127 ensure
127 ensure
128 # restore it
128 # restore it
129 Redmine::Utils.relative_url_root = relative_url_root
129 Redmine::Utils.relative_url_root = relative_url_root
130 end
130 end
131
131
132 def test_email_headers
132 def test_email_headers
133 issue = Issue.find(1)
133 issue = Issue.find(1)
134 Mailer.deliver_issue_add(issue)
134 Mailer.deliver_issue_add(issue)
135 mail = ActionMailer::Base.deliveries.last
135 mail = ActionMailer::Base.deliveries.last
136 assert_not_nil mail
136 assert_not_nil mail
137 assert_equal 'OOF', mail.header_string('X-Auto-Response-Suppress')
137 assert_equal 'OOF', mail.header_string('X-Auto-Response-Suppress')
138 assert_equal 'auto-generated', mail.header_string('Auto-Submitted')
138 assert_equal 'auto-generated', mail.header_string('Auto-Submitted')
139 end
139 end
140
140
141 def test_plain_text_mail
141 def test_plain_text_mail
142 Setting.plain_text_mail = 1
142 Setting.plain_text_mail = 1
143 journal = Journal.find(2)
143 journal = Journal.find(2)
144 Mailer.deliver_issue_edit(journal)
144 Mailer.deliver_issue_edit(journal)
145 mail = ActionMailer::Base.deliveries.last
145 mail = ActionMailer::Base.deliveries.last
146 assert_equal "text/plain", mail.content_type
146 assert_equal "text/plain", mail.content_type
147 assert_equal 0, mail.parts.size
147 assert_equal 0, mail.parts.size
148 assert !mail.encoded.include?('href')
148 assert !mail.encoded.include?('href')
149 end
149 end
150
150
151 def test_html_mail
151 def test_html_mail
152 Setting.plain_text_mail = 0
152 Setting.plain_text_mail = 0
153 journal = Journal.find(2)
153 journal = Journal.find(2)
154 Mailer.deliver_issue_edit(journal)
154 Mailer.deliver_issue_edit(journal)
155 mail = ActionMailer::Base.deliveries.last
155 mail = ActionMailer::Base.deliveries.last
156 assert_equal 2, mail.parts.size
156 assert_equal 2, mail.parts.size
157 assert mail.encoded.include?('href')
157 assert mail.encoded.include?('href')
158 end
158 end
159
159
160 def test_from_header
160 def test_from_header
161 with_settings :mail_from => 'redmine@example.net' do
161 with_settings :mail_from => 'redmine@example.net' do
162 Mailer.deliver_test(User.find(1))
162 Mailer.deliver_test(User.find(1))
163 end
163 end
164 mail = ActionMailer::Base.deliveries.last
164 mail = ActionMailer::Base.deliveries.last
165 assert_not_nil mail
165 assert_not_nil mail
166 assert_equal 'redmine@example.net', mail.from_addrs.first.address
166 assert_equal 'redmine@example.net', mail.from_addrs.first.address
167 end
167 end
168
168
169 def test_from_header_with_phrase
169 def test_from_header_with_phrase
170 with_settings :mail_from => 'Redmine app <redmine@example.net>' do
170 with_settings :mail_from => 'Redmine app <redmine@example.net>' do
171 Mailer.deliver_test(User.find(1))
171 Mailer.deliver_test(User.find(1))
172 end
172 end
173 mail = ActionMailer::Base.deliveries.last
173 mail = ActionMailer::Base.deliveries.last
174 assert_not_nil mail
174 assert_not_nil mail
175 assert_equal 'redmine@example.net', mail.from_addrs.first.address
175 assert_equal 'redmine@example.net', mail.from_addrs.first.address
176 assert_equal 'Redmine app', mail.from_addrs.first.name
176 assert_equal 'Redmine app', mail.from_addrs.first.name
177 end
177 end
178
178
179 def test_should_not_send_email_without_recipient
179 def test_should_not_send_email_without_recipient
180 news = News.find(:first)
180 news = News.find(:first)
181 user = news.author
181 user = news.author
182 # Remove members except news author
182 # Remove members except news author
183 news.project.memberships.each {|m| m.destroy unless m.user == user}
183 news.project.memberships.each {|m| m.destroy unless m.user == user}
184
184
185 user.pref[:no_self_notified] = false
185 user.pref[:no_self_notified] = false
186 user.pref.save
186 user.pref.save
187 User.current = user
187 User.current = user
188 Mailer.deliver_news_added(news.reload)
188 Mailer.deliver_news_added(news.reload)
189 assert_equal 1, last_email.bcc.size
189 assert_equal 1, last_email.bcc.size
190
190
191 # nobody to notify
191 # nobody to notify
192 user.pref[:no_self_notified] = true
192 user.pref[:no_self_notified] = true
193 user.pref.save
193 user.pref.save
194 User.current = user
194 User.current = user
195 ActionMailer::Base.deliveries.clear
195 ActionMailer::Base.deliveries.clear
196 Mailer.deliver_news_added(news.reload)
196 Mailer.deliver_news_added(news.reload)
197 assert ActionMailer::Base.deliveries.empty?
197 assert ActionMailer::Base.deliveries.empty?
198 end
198 end
199
199
200 def test_issue_add_message_id
200 def test_issue_add_message_id
201 issue = Issue.find(1)
201 issue = Issue.find(1)
202 Mailer.deliver_issue_add(issue)
202 Mailer.deliver_issue_add(issue)
203 mail = ActionMailer::Base.deliveries.last
203 mail = ActionMailer::Base.deliveries.last
204 assert_not_nil mail
204 assert_not_nil mail
205 assert_equal Mailer.message_id_for(issue), mail.message_id
205 assert_equal Mailer.message_id_for(issue), mail.message_id
206 assert_nil mail.references
206 assert_nil mail.references
207 end
207 end
208
208
209 def test_issue_edit_message_id
209 def test_issue_edit_message_id
210 journal = Journal.find(1)
210 journal = Journal.find(1)
211 Mailer.deliver_issue_edit(journal)
211 Mailer.deliver_issue_edit(journal)
212 mail = ActionMailer::Base.deliveries.last
212 mail = ActionMailer::Base.deliveries.last
213 assert_not_nil mail
213 assert_not_nil mail
214 assert_equal Mailer.message_id_for(journal), mail.message_id
214 assert_equal Mailer.message_id_for(journal), mail.message_id
215 assert_equal Mailer.message_id_for(journal.issue), mail.references.first.to_s
215 assert_equal Mailer.message_id_for(journal.issue), mail.references.first.to_s
216 assert_select_email do
217 # link to the update
218 assert_select "a[href=?]",
219 "http://mydomain.foo/issues/#{journal.journalized_id}#change-#{journal.id}"
220 end
216 end
221 end
217
222
218 def test_message_posted_message_id
223 def test_message_posted_message_id
219 message = Message.find(1)
224 message = Message.find(1)
220 Mailer.deliver_message_posted(message)
225 Mailer.deliver_message_posted(message)
221 mail = ActionMailer::Base.deliveries.last
226 mail = ActionMailer::Base.deliveries.last
222 assert_not_nil mail
227 assert_not_nil mail
223 assert_equal Mailer.message_id_for(message), mail.message_id
228 assert_equal Mailer.message_id_for(message), mail.message_id
224 assert_nil mail.references
229 assert_nil mail.references
225 assert_select_email do
230 assert_select_email do
226 # link to the message
231 # link to the message
227 assert_select "a[href=?]",
232 assert_select "a[href=?]",
228 "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.id}",
233 "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.id}",
229 :text => message.subject
234 :text => message.subject
230 end
235 end
231 end
236 end
232
237
233 def test_reply_posted_message_id
238 def test_reply_posted_message_id
234 message = Message.find(3)
239 message = Message.find(3)
235 Mailer.deliver_message_posted(message)
240 Mailer.deliver_message_posted(message)
236 mail = ActionMailer::Base.deliveries.last
241 mail = ActionMailer::Base.deliveries.last
237 assert_not_nil mail
242 assert_not_nil mail
238 assert_equal Mailer.message_id_for(message), mail.message_id
243 assert_equal Mailer.message_id_for(message), mail.message_id
239 assert_equal Mailer.message_id_for(message.parent), mail.references.first.to_s
244 assert_equal Mailer.message_id_for(message.parent), mail.references.first.to_s
240 assert_select_email do
245 assert_select_email do
241 # link to the reply
246 # link to the reply
242 assert_select "a[href=?]",
247 assert_select "a[href=?]",
243 "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.root.id}?r=#{message.id}#message-#{message.id}",
248 "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.root.id}?r=#{message.id}#message-#{message.id}",
244 :text => message.subject
249 :text => message.subject
245 end
250 end
246 end
251 end
247
252
248 context("#issue_add") do
253 context("#issue_add") do
249 setup do
254 setup do
250 ActionMailer::Base.deliveries.clear
255 ActionMailer::Base.deliveries.clear
251 Setting.bcc_recipients = '1'
256 Setting.bcc_recipients = '1'
252 @issue = Issue.find(1)
257 @issue = Issue.find(1)
253 end
258 end
254
259
255 should "notify project members" do
260 should "notify project members" do
256 assert Mailer.deliver_issue_add(@issue)
261 assert Mailer.deliver_issue_add(@issue)
257 assert last_email.bcc.include?('dlopper@somenet.foo')
262 assert last_email.bcc.include?('dlopper@somenet.foo')
258 end
263 end
259
264
260 should "not notify project members that are not allow to view the issue" do
265 should "not notify project members that are not allow to view the issue" do
261 Role.find(2).remove_permission!(:view_issues)
266 Role.find(2).remove_permission!(:view_issues)
262 assert Mailer.deliver_issue_add(@issue)
267 assert Mailer.deliver_issue_add(@issue)
263 assert !last_email.bcc.include?('dlopper@somenet.foo')
268 assert !last_email.bcc.include?('dlopper@somenet.foo')
264 end
269 end
265
270
266 should "notify issue watchers" do
271 should "notify issue watchers" do
267 user = User.find(9)
272 user = User.find(9)
268 # minimal email notification options
273 # minimal email notification options
269 user.pref[:no_self_notified] = '1'
274 user.pref[:no_self_notified] = '1'
270 user.pref.save
275 user.pref.save
271 user.mail_notification = false
276 user.mail_notification = false
272 user.save
277 user.save
273
278
274 Watcher.create!(:watchable => @issue, :user => user)
279 Watcher.create!(:watchable => @issue, :user => user)
275 assert Mailer.deliver_issue_add(@issue)
280 assert Mailer.deliver_issue_add(@issue)
276 assert last_email.bcc.include?(user.mail)
281 assert last_email.bcc.include?(user.mail)
277 end
282 end
278
283
279 should "not notify watchers not allowed to view the issue" do
284 should "not notify watchers not allowed to view the issue" do
280 user = User.find(9)
285 user = User.find(9)
281 Watcher.create!(:watchable => @issue, :user => user)
286 Watcher.create!(:watchable => @issue, :user => user)
282 Role.non_member.remove_permission!(:view_issues)
287 Role.non_member.remove_permission!(:view_issues)
283 assert Mailer.deliver_issue_add(@issue)
288 assert Mailer.deliver_issue_add(@issue)
284 assert !last_email.bcc.include?(user.mail)
289 assert !last_email.bcc.include?(user.mail)
285 end
290 end
286 end
291 end
287
292
288 # test mailer methods for each language
293 # test mailer methods for each language
289 def test_issue_add
294 def test_issue_add
290 issue = Issue.find(1)
295 issue = Issue.find(1)
291 valid_languages.each do |lang|
296 valid_languages.each do |lang|
292 Setting.default_language = lang.to_s
297 Setting.default_language = lang.to_s
293 assert Mailer.deliver_issue_add(issue)
298 assert Mailer.deliver_issue_add(issue)
294 end
299 end
295 end
300 end
296
301
297 def test_issue_edit
302 def test_issue_edit
298 journal = Journal.find(1)
303 journal = Journal.find(1)
299 valid_languages.each do |lang|
304 valid_languages.each do |lang|
300 Setting.default_language = lang.to_s
305 Setting.default_language = lang.to_s
301 assert Mailer.deliver_issue_edit(journal)
306 assert Mailer.deliver_issue_edit(journal)
302 end
307 end
303 end
308 end
304
309
305 def test_document_added
310 def test_document_added
306 document = Document.find(1)
311 document = Document.find(1)
307 valid_languages.each do |lang|
312 valid_languages.each do |lang|
308 Setting.default_language = lang.to_s
313 Setting.default_language = lang.to_s
309 assert Mailer.deliver_document_added(document)
314 assert Mailer.deliver_document_added(document)
310 end
315 end
311 end
316 end
312
317
313 def test_attachments_added
318 def test_attachments_added
314 attachements = [ Attachment.find_by_container_type('Document') ]
319 attachements = [ Attachment.find_by_container_type('Document') ]
315 valid_languages.each do |lang|
320 valid_languages.each do |lang|
316 Setting.default_language = lang.to_s
321 Setting.default_language = lang.to_s
317 assert Mailer.deliver_attachments_added(attachements)
322 assert Mailer.deliver_attachments_added(attachements)
318 end
323 end
319 end
324 end
320
325
321 def test_version_file_added
326 def test_version_file_added
322 attachements = [ Attachment.find_by_container_type('Version') ]
327 attachements = [ Attachment.find_by_container_type('Version') ]
323 assert Mailer.deliver_attachments_added(attachements)
328 assert Mailer.deliver_attachments_added(attachements)
324 assert_not_nil last_email.bcc
329 assert_not_nil last_email.bcc
325 assert last_email.bcc.any?
330 assert last_email.bcc.any?
326 assert_select_email do
331 assert_select_email do
327 assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files"
332 assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files"
328 end
333 end
329 end
334 end
330
335
331 def test_project_file_added
336 def test_project_file_added
332 attachements = [ Attachment.find_by_container_type('Project') ]
337 attachements = [ Attachment.find_by_container_type('Project') ]
333 assert Mailer.deliver_attachments_added(attachements)
338 assert Mailer.deliver_attachments_added(attachements)
334 assert_not_nil last_email.bcc
339 assert_not_nil last_email.bcc
335 assert last_email.bcc.any?
340 assert last_email.bcc.any?
336 assert_select_email do
341 assert_select_email do
337 assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files"
342 assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files"
338 end
343 end
339 end
344 end
340
345
341 def test_news_added
346 def test_news_added
342 news = News.find(:first)
347 news = News.find(:first)
343 valid_languages.each do |lang|
348 valid_languages.each do |lang|
344 Setting.default_language = lang.to_s
349 Setting.default_language = lang.to_s
345 assert Mailer.deliver_news_added(news)
350 assert Mailer.deliver_news_added(news)
346 end
351 end
347 end
352 end
348
353
349 def test_news_comment_added
354 def test_news_comment_added
350 comment = Comment.find(2)
355 comment = Comment.find(2)
351 valid_languages.each do |lang|
356 valid_languages.each do |lang|
352 Setting.default_language = lang.to_s
357 Setting.default_language = lang.to_s
353 assert Mailer.deliver_news_comment_added(comment)
358 assert Mailer.deliver_news_comment_added(comment)
354 end
359 end
355 end
360 end
356
361
357 def test_message_posted
362 def test_message_posted
358 message = Message.find(:first)
363 message = Message.find(:first)
359 recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author}
364 recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author}
360 recipients = recipients.compact.uniq
365 recipients = recipients.compact.uniq
361 valid_languages.each do |lang|
366 valid_languages.each do |lang|
362 Setting.default_language = lang.to_s
367 Setting.default_language = lang.to_s
363 assert Mailer.deliver_message_posted(message)
368 assert Mailer.deliver_message_posted(message)
364 end
369 end
365 end
370 end
366
371
367 def test_wiki_content_added
372 def test_wiki_content_added
368 content = WikiContent.find(:first)
373 content = WikiContent.find(:first)
369 valid_languages.each do |lang|
374 valid_languages.each do |lang|
370 Setting.default_language = lang.to_s
375 Setting.default_language = lang.to_s
371 assert_difference 'ActionMailer::Base.deliveries.size' do
376 assert_difference 'ActionMailer::Base.deliveries.size' do
372 assert Mailer.deliver_wiki_content_added(content)
377 assert Mailer.deliver_wiki_content_added(content)
373 end
378 end
374 end
379 end
375 end
380 end
376
381
377 def test_wiki_content_updated
382 def test_wiki_content_updated
378 content = WikiContent.find(:first)
383 content = WikiContent.find(:first)
379 valid_languages.each do |lang|
384 valid_languages.each do |lang|
380 Setting.default_language = lang.to_s
385 Setting.default_language = lang.to_s
381 assert_difference 'ActionMailer::Base.deliveries.size' do
386 assert_difference 'ActionMailer::Base.deliveries.size' do
382 assert Mailer.deliver_wiki_content_updated(content)
387 assert Mailer.deliver_wiki_content_updated(content)
383 end
388 end
384 end
389 end
385 end
390 end
386
391
387 def test_account_information
392 def test_account_information
388 user = User.find(2)
393 user = User.find(2)
389 valid_languages.each do |lang|
394 valid_languages.each do |lang|
390 user.update_attribute :language, lang.to_s
395 user.update_attribute :language, lang.to_s
391 user.reload
396 user.reload
392 assert Mailer.deliver_account_information(user, 'pAsswORd')
397 assert Mailer.deliver_account_information(user, 'pAsswORd')
393 end
398 end
394 end
399 end
395
400
396 def test_lost_password
401 def test_lost_password
397 token = Token.find(2)
402 token = Token.find(2)
398 valid_languages.each do |lang|
403 valid_languages.each do |lang|
399 token.user.update_attribute :language, lang.to_s
404 token.user.update_attribute :language, lang.to_s
400 token.reload
405 token.reload
401 assert Mailer.deliver_lost_password(token)
406 assert Mailer.deliver_lost_password(token)
402 end
407 end
403 end
408 end
404
409
405 def test_register
410 def test_register
406 token = Token.find(1)
411 token = Token.find(1)
407 Setting.host_name = 'redmine.foo'
412 Setting.host_name = 'redmine.foo'
408 Setting.protocol = 'https'
413 Setting.protocol = 'https'
409
414
410 valid_languages.each do |lang|
415 valid_languages.each do |lang|
411 token.user.update_attribute :language, lang.to_s
416 token.user.update_attribute :language, lang.to_s
412 token.reload
417 token.reload
413 ActionMailer::Base.deliveries.clear
418 ActionMailer::Base.deliveries.clear
414 assert Mailer.deliver_register(token)
419 assert Mailer.deliver_register(token)
415 mail = ActionMailer::Base.deliveries.last
420 mail = ActionMailer::Base.deliveries.last
416 assert mail.body.include?("https://redmine.foo/account/activate?token=#{token.value}")
421 assert mail.body.include?("https://redmine.foo/account/activate?token=#{token.value}")
417 end
422 end
418 end
423 end
419
424
420 def test_test
425 def test_test
421 user = User.find(1)
426 user = User.find(1)
422 valid_languages.each do |lang|
427 valid_languages.each do |lang|
423 user.update_attribute :language, lang.to_s
428 user.update_attribute :language, lang.to_s
424 assert Mailer.deliver_test(user)
429 assert Mailer.deliver_test(user)
425 end
430 end
426 end
431 end
427
432
428 def test_reminders
433 def test_reminders
429 Mailer.reminders(:days => 42)
434 Mailer.reminders(:days => 42)
430 assert_equal 1, ActionMailer::Base.deliveries.size
435 assert_equal 1, ActionMailer::Base.deliveries.size
431 mail = ActionMailer::Base.deliveries.last
436 mail = ActionMailer::Base.deliveries.last
432 assert mail.bcc.include?('dlopper@somenet.foo')
437 assert mail.bcc.include?('dlopper@somenet.foo')
433 assert mail.body.include?('Bug #3: Error 281 when updating a recipe')
438 assert mail.body.include?('Bug #3: Error 281 when updating a recipe')
434 assert_equal '1 issue(s) due in the next 42 days', mail.subject
439 assert_equal '1 issue(s) due in the next 42 days', mail.subject
435 end
440 end
436
441
437 def test_reminders_for_users
442 def test_reminders_for_users
438 Mailer.reminders(:days => 42, :users => ['5'])
443 Mailer.reminders(:days => 42, :users => ['5'])
439 assert_equal 0, ActionMailer::Base.deliveries.size # No mail for dlopper
444 assert_equal 0, ActionMailer::Base.deliveries.size # No mail for dlopper
440 Mailer.reminders(:days => 42, :users => ['3'])
445 Mailer.reminders(:days => 42, :users => ['3'])
441 assert_equal 1, ActionMailer::Base.deliveries.size # No mail for dlopper
446 assert_equal 1, ActionMailer::Base.deliveries.size # No mail for dlopper
442 mail = ActionMailer::Base.deliveries.last
447 mail = ActionMailer::Base.deliveries.last
443 assert mail.bcc.include?('dlopper@somenet.foo')
448 assert mail.bcc.include?('dlopper@somenet.foo')
444 assert mail.body.include?('Bug #3: Error 281 when updating a recipe')
449 assert mail.body.include?('Bug #3: Error 281 when updating a recipe')
445 end
450 end
446
451
447 def last_email
452 def last_email
448 mail = ActionMailer::Base.deliveries.last
453 mail = ActionMailer::Base.deliveries.last
449 assert_not_nil mail
454 assert_not_nil mail
450 mail
455 mail
451 end
456 end
452
457
453 def test_mailer_should_not_change_locale
458 def test_mailer_should_not_change_locale
454 Setting.default_language = 'en'
459 Setting.default_language = 'en'
455 # Set current language to italian
460 # Set current language to italian
456 set_language_if_valid 'it'
461 set_language_if_valid 'it'
457 # Send an email to a french user
462 # Send an email to a french user
458 user = User.find(1)
463 user = User.find(1)
459 user.language = 'fr'
464 user.language = 'fr'
460 Mailer.deliver_account_activated(user)
465 Mailer.deliver_account_activated(user)
461 mail = ActionMailer::Base.deliveries.last
466 mail = ActionMailer::Base.deliveries.last
462 assert mail.body.include?('Votre compte')
467 assert mail.body.include?('Votre compte')
463
468
464 assert_equal :it, current_language
469 assert_equal :it, current_language
465 end
470 end
466
471
467 def test_with_deliveries_off
472 def test_with_deliveries_off
468 Mailer.with_deliveries false do
473 Mailer.with_deliveries false do
469 Mailer.deliver_test(User.find(1))
474 Mailer.deliver_test(User.find(1))
470 end
475 end
471 assert ActionMailer::Base.deliveries.empty?
476 assert ActionMailer::Base.deliveries.empty?
472 # should restore perform_deliveries
477 # should restore perform_deliveries
473 assert ActionMailer::Base.perform_deliveries
478 assert ActionMailer::Base.perform_deliveries
474 end
479 end
475
480
476 def test_tmail_to_header_field_should_not_include_blank_lines
481 def test_tmail_to_header_field_should_not_include_blank_lines
477 mail = TMail::Mail.new
482 mail = TMail::Mail.new
478 mail.to = ["a.user@example.com", "v.user2@example.com", "e.smith@example.com", "info@example.com", "v.pupkin@example.com",
483 mail.to = ["a.user@example.com", "v.user2@example.com", "e.smith@example.com", "info@example.com", "v.pupkin@example.com",
479 "b.user@example.com", "w.user2@example.com", "f.smith@example.com", "info2@example.com", "w.pupkin@example.com"]
484 "b.user@example.com", "w.user2@example.com", "f.smith@example.com", "info2@example.com", "w.pupkin@example.com"]
480
485
481 assert !mail.encoded.strip.split("\r\n").detect(&:blank?), "#{mail.encoded} malformed"
486 assert !mail.encoded.strip.split("\r\n").detect(&:blank?), "#{mail.encoded} malformed"
482 end
487 end
483
488
484 context "layout" do
489 context "layout" do
485 should "include the emails_header" do
490 should "include the emails_header" do
486 with_settings(:emails_header => "*Header content*") do
491 with_settings(:emails_header => "*Header content*") do
487 assert Mailer.deliver_test(User.find(1))
492 assert Mailer.deliver_test(User.find(1))
488
493
489 assert_select_email do
494 assert_select_email do
490 assert_select ".header" do
495 assert_select ".header" do
491 assert_select "strong", :text => "Header content"
496 assert_select "strong", :text => "Header content"
492 end
497 end
493 end
498 end
494 end
499 end
495 end
500 end
496 end
501 end
497 end
502 end
General Comments 0
You need to be logged in to leave comments. Login now