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