##// END OF EJS Templates
Don't use #delete on String in Mailer....
Jean-Philippe Lang -
r9117:95b10f3bd388
parent child
Show More
@@ -1,477 +1,487
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 class Mailer < ActionMailer::Base
18 class Mailer < ActionMailer::Base
19 layout 'mailer'
19 layout 'mailer'
20 helper :application
20 helper :application
21 helper :issues
21 helper :issues
22 helper :custom_fields
22 helper :custom_fields
23
23
24 include ActionController::UrlWriter
24 include ActionController::UrlWriter
25 include Redmine::I18n
25 include Redmine::I18n
26
26
27 def self.default_url_options
27 def self.default_url_options
28 h = Setting.host_name
28 h = Setting.host_name
29 h = h.to_s.gsub(%r{\/.*$}, '') unless Redmine::Utils.relative_url_root.blank?
29 h = h.to_s.gsub(%r{\/.*$}, '') unless Redmine::Utils.relative_url_root.blank?
30 { :host => h, :protocol => Setting.protocol }
30 { :host => h, :protocol => Setting.protocol }
31 end
31 end
32
32
33 # Builds a tmail object used to email recipients of the added issue.
33 # Builds a tmail object used to email recipients of the added issue.
34 #
34 #
35 # Example:
35 # Example:
36 # issue_add(issue) => tmail object
36 # issue_add(issue) => tmail object
37 # Mailer.deliver_issue_add(issue) => sends an email to issue recipients
37 # Mailer.deliver_issue_add(issue) => sends an email to issue recipients
38 def issue_add(issue)
38 def issue_add(issue)
39 redmine_headers 'Project' => issue.project.identifier,
39 redmine_headers 'Project' => issue.project.identifier,
40 'Issue-Id' => issue.id,
40 'Issue-Id' => issue.id,
41 'Issue-Author' => issue.author.login
41 'Issue-Author' => issue.author.login
42 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
42 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
43 message_id issue
43 message_id issue
44 @author = issue.author
44 @author = issue.author
45 recipients issue.recipients
45 recipients issue.recipients
46 cc(issue.watcher_recipients - @recipients)
46 cc(issue.watcher_recipients - @recipients)
47 subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
47 subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
48 body :issue => issue,
48 body :issue => issue,
49 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
49 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
50 render_multipart('issue_add', body)
50 render_multipart('issue_add', body)
51 end
51 end
52
52
53 # Builds a tmail object used to email recipients of the edited issue.
53 # Builds a tmail object used to email recipients of the edited issue.
54 #
54 #
55 # Example:
55 # Example:
56 # issue_edit(journal) => tmail object
56 # issue_edit(journal) => tmail object
57 # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients
57 # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients
58 def issue_edit(journal)
58 def issue_edit(journal)
59 issue = journal.journalized.reload
59 issue = journal.journalized.reload
60 redmine_headers 'Project' => issue.project.identifier,
60 redmine_headers 'Project' => issue.project.identifier,
61 'Issue-Id' => issue.id,
61 'Issue-Id' => issue.id,
62 'Issue-Author' => issue.author.login
62 'Issue-Author' => issue.author.login
63 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
63 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
64 message_id journal
64 message_id journal
65 references issue
65 references issue
66 @author = journal.user
66 @author = journal.user
67 recipients issue.recipients
67 recipients issue.recipients
68 # Watchers in cc
68 # Watchers in cc
69 cc(issue.watcher_recipients - @recipients)
69 cc(issue.watcher_recipients - @recipients)
70 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
70 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
71 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
71 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
72 s << issue.subject
72 s << issue.subject
73 subject s
73 subject s
74 body :issue => issue,
74 body :issue => issue,
75 :journal => journal,
75 :journal => journal,
76 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
76 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
77
77
78 render_multipart('issue_edit', body)
78 render_multipart('issue_edit', body)
79 end
79 end
80
80
81 def reminder(user, issues, days)
81 def reminder(user, issues, days)
82 set_language_if_valid user.language
82 set_language_if_valid user.language
83 recipients user.mail
83 recipients user.mail
84 subject l(:mail_subject_reminder, :count => issues.size, :days => days)
84 subject l(:mail_subject_reminder, :count => issues.size, :days => days)
85 body :issues => issues,
85 body :issues => issues,
86 :days => days,
86 :days => days,
87 :issues_url => url_for(:controller => 'issues', :action => 'index',
87 :issues_url => url_for(:controller => 'issues', :action => 'index',
88 :set_filter => 1, :assigned_to_id => user.id,
88 :set_filter => 1, :assigned_to_id => user.id,
89 :sort => 'due_date:asc')
89 :sort => 'due_date:asc')
90 render_multipart('reminder', body)
90 render_multipart('reminder', body)
91 end
91 end
92
92
93 # Builds a tmail object used to email users belonging to the added document's project.
93 # Builds a tmail object used to email users belonging to the added document's project.
94 #
94 #
95 # Example:
95 # Example:
96 # document_added(document) => tmail object
96 # document_added(document) => tmail object
97 # Mailer.deliver_document_added(document) => sends an email to the document's project recipients
97 # Mailer.deliver_document_added(document) => sends an email to the document's project recipients
98 def document_added(document)
98 def document_added(document)
99 redmine_headers 'Project' => document.project.identifier
99 redmine_headers 'Project' => document.project.identifier
100 recipients document.recipients
100 recipients document.recipients
101 @author = User.current
101 subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
102 subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
102 body :document => document,
103 body :document => document,
103 :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
104 :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
104 render_multipart('document_added', body)
105 render_multipart('document_added', body)
105 end
106 end
106
107
107 # 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.
108 #
109 #
109 # Example:
110 # Example:
110 # attachments_added(attachments) => tmail object
111 # attachments_added(attachments) => tmail object
111 # 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
112 def attachments_added(attachments)
113 def attachments_added(attachments)
113 container = attachments.first.container
114 container = attachments.first.container
114 added_to = ''
115 added_to = ''
115 added_to_url = ''
116 added_to_url = ''
117 @author = attachments.first.author
116 case container.class.name
118 case container.class.name
117 when 'Project'
119 when 'Project'
118 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
120 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
119 added_to = "#{l(:label_project)}: #{container}"
121 added_to = "#{l(:label_project)}: #{container}"
120 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
122 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
121 when 'Version'
123 when 'Version'
122 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
124 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
123 added_to = "#{l(:label_version)}: #{container.name}"
125 added_to = "#{l(:label_version)}: #{container.name}"
124 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
126 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
125 when 'Document'
127 when 'Document'
126 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
128 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
127 added_to = "#{l(:label_document)}: #{container.title}"
129 added_to = "#{l(:label_document)}: #{container.title}"
128 recipients container.recipients
130 recipients container.recipients
129 end
131 end
130 redmine_headers 'Project' => container.project.identifier
132 redmine_headers 'Project' => container.project.identifier
131 subject "[#{container.project.name}] #{l(:label_attachment_new)}"
133 subject "[#{container.project.name}] #{l(:label_attachment_new)}"
132 body :attachments => attachments,
134 body :attachments => attachments,
133 :added_to => added_to,
135 :added_to => added_to,
134 :added_to_url => added_to_url
136 :added_to_url => added_to_url
135 render_multipart('attachments_added', body)
137 render_multipart('attachments_added', body)
136 end
138 end
137
139
138 # Builds a tmail object used to email recipients of a news' project when a news item is added.
140 # Builds a tmail object used to email recipients of a news' project when a news item is added.
139 #
141 #
140 # Example:
142 # Example:
141 # news_added(news) => tmail object
143 # news_added(news) => tmail object
142 # Mailer.deliver_news_added(news) => sends an email to the news' project recipients
144 # Mailer.deliver_news_added(news) => sends an email to the news' project recipients
143 def news_added(news)
145 def news_added(news)
144 redmine_headers 'Project' => news.project.identifier
146 redmine_headers 'Project' => news.project.identifier
147 @author = news.author
145 message_id news
148 message_id news
146 recipients news.recipients
149 recipients news.recipients
147 subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
150 subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
148 body :news => news,
151 body :news => news,
149 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
152 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
150 render_multipart('news_added', body)
153 render_multipart('news_added', body)
151 end
154 end
152
155
153 # Builds a tmail object used to email recipients of a news' project when a news comment is added.
156 # Builds a tmail object used to email recipients of a news' project when a news comment is added.
154 #
157 #
155 # Example:
158 # Example:
156 # news_comment_added(comment) => tmail object
159 # news_comment_added(comment) => tmail object
157 # Mailer.news_comment_added(comment) => sends an email to the news' project recipients
160 # Mailer.news_comment_added(comment) => sends an email to the news' project recipients
158 def news_comment_added(comment)
161 def news_comment_added(comment)
159 news = comment.commented
162 news = comment.commented
160 redmine_headers 'Project' => news.project.identifier
163 redmine_headers 'Project' => news.project.identifier
164 @author = comment.author
161 message_id comment
165 message_id comment
162 recipients news.recipients
166 recipients news.recipients
163 cc news.watcher_recipients
167 cc news.watcher_recipients
164 subject "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
168 subject "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
165 body :news => news,
169 body :news => news,
166 :comment => comment,
170 :comment => comment,
167 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
171 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
168 render_multipart('news_comment_added', body)
172 render_multipart('news_comment_added', body)
169 end
173 end
170
174
171 # Builds a tmail object used to email the recipients of the specified message that was posted.
175 # Builds a tmail object used to email the recipients of the specified message that was posted.
172 #
176 #
173 # Example:
177 # Example:
174 # message_posted(message) => tmail object
178 # message_posted(message) => tmail object
175 # Mailer.deliver_message_posted(message) => sends an email to the recipients
179 # Mailer.deliver_message_posted(message) => sends an email to the recipients
176 def message_posted(message)
180 def message_posted(message)
177 redmine_headers 'Project' => message.project.identifier,
181 redmine_headers 'Project' => message.project.identifier,
178 'Topic-Id' => (message.parent_id || message.id)
182 'Topic-Id' => (message.parent_id || message.id)
183 @author = message.author
179 message_id message
184 message_id message
180 references message.parent unless message.parent.nil?
185 references message.parent unless message.parent.nil?
181 recipients(message.recipients)
186 recipients(message.recipients)
182 cc((message.root.watcher_recipients + message.board.watcher_recipients).uniq - @recipients)
187 cc((message.root.watcher_recipients + message.board.watcher_recipients).uniq - @recipients)
183 subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
188 subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
184 body :message => message,
189 body :message => message,
185 :message_url => url_for(message.event_url)
190 :message_url => url_for(message.event_url)
186 render_multipart('message_posted', body)
191 render_multipart('message_posted', body)
187 end
192 end
188
193
189 # Builds a tmail object used to email the recipients of a project of the specified wiki content was added.
194 # Builds a tmail object used to email the recipients of a project of the specified wiki content was added.
190 #
195 #
191 # Example:
196 # Example:
192 # wiki_content_added(wiki_content) => tmail object
197 # wiki_content_added(wiki_content) => tmail object
193 # Mailer.deliver_wiki_content_added(wiki_content) => sends an email to the project's recipients
198 # Mailer.deliver_wiki_content_added(wiki_content) => sends an email to the project's recipients
194 def wiki_content_added(wiki_content)
199 def wiki_content_added(wiki_content)
195 redmine_headers 'Project' => wiki_content.project.identifier,
200 redmine_headers 'Project' => wiki_content.project.identifier,
196 'Wiki-Page-Id' => wiki_content.page.id
201 'Wiki-Page-Id' => wiki_content.page.id
202 @author = wiki_content.author
197 message_id wiki_content
203 message_id wiki_content
198 recipients wiki_content.recipients
204 recipients wiki_content.recipients
199 cc(wiki_content.page.wiki.watcher_recipients - recipients)
205 cc(wiki_content.page.wiki.watcher_recipients - recipients)
200 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
206 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
201 body :wiki_content => wiki_content,
207 body :wiki_content => wiki_content,
202 :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
208 :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
203 :project_id => wiki_content.project,
209 :project_id => wiki_content.project,
204 :id => wiki_content.page.title)
210 :id => wiki_content.page.title)
205 render_multipart('wiki_content_added', body)
211 render_multipart('wiki_content_added', body)
206 end
212 end
207
213
208 # Builds a tmail object used to email the recipients of a project of the specified wiki content was updated.
214 # Builds a tmail object used to email the recipients of a project of the specified wiki content was updated.
209 #
215 #
210 # Example:
216 # Example:
211 # wiki_content_updated(wiki_content) => tmail object
217 # wiki_content_updated(wiki_content) => tmail object
212 # Mailer.deliver_wiki_content_updated(wiki_content) => sends an email to the project's recipients
218 # Mailer.deliver_wiki_content_updated(wiki_content) => sends an email to the project's recipients
213 def wiki_content_updated(wiki_content)
219 def wiki_content_updated(wiki_content)
214 redmine_headers 'Project' => wiki_content.project.identifier,
220 redmine_headers 'Project' => wiki_content.project.identifier,
215 'Wiki-Page-Id' => wiki_content.page.id
221 'Wiki-Page-Id' => wiki_content.page.id
222 @author = wiki_content.author
216 message_id wiki_content
223 message_id wiki_content
217 recipients wiki_content.recipients
224 recipients wiki_content.recipients
218 cc(wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients)
225 cc(wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients)
219 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
226 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
220 body :wiki_content => wiki_content,
227 body :wiki_content => wiki_content,
221 :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
228 :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
222 :project_id => wiki_content.project,
229 :project_id => wiki_content.project,
223 :id => wiki_content.page.title),
230 :id => wiki_content.page.title),
224 :wiki_diff_url => url_for(:controller => 'wiki', :action => 'diff',
231 :wiki_diff_url => url_for(:controller => 'wiki', :action => 'diff',
225 :project_id => wiki_content.project, :id => wiki_content.page.title,
232 :project_id => wiki_content.project, :id => wiki_content.page.title,
226 :version => wiki_content.version)
233 :version => wiki_content.version)
227 render_multipart('wiki_content_updated', body)
234 render_multipart('wiki_content_updated', body)
228 end
235 end
229
236
230 # Builds a tmail object used to email the specified user their account information.
237 # Builds a tmail object used to email the specified user their account information.
231 #
238 #
232 # Example:
239 # Example:
233 # account_information(user, password) => tmail object
240 # account_information(user, password) => tmail object
234 # Mailer.deliver_account_information(user, password) => sends account information to the user
241 # Mailer.deliver_account_information(user, password) => sends account information to the user
235 def account_information(user, password)
242 def account_information(user, password)
236 set_language_if_valid user.language
243 set_language_if_valid user.language
237 recipients user.mail
244 recipients user.mail
238 subject l(:mail_subject_register, Setting.app_title)
245 subject l(:mail_subject_register, Setting.app_title)
239 body :user => user,
246 body :user => user,
240 :password => password,
247 :password => password,
241 :login_url => url_for(:controller => 'account', :action => 'login')
248 :login_url => url_for(:controller => 'account', :action => 'login')
242 render_multipart('account_information', body)
249 render_multipart('account_information', body)
243 end
250 end
244
251
245 # Builds a tmail object used to email all active administrators of an account activation request.
252 # Builds a tmail object used to email all active administrators of an account activation request.
246 #
253 #
247 # Example:
254 # Example:
248 # account_activation_request(user) => tmail object
255 # account_activation_request(user) => tmail object
249 # Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators
256 # Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators
250 def account_activation_request(user)
257 def account_activation_request(user)
251 # Send the email to all active administrators
258 # Send the email to all active administrators
252 recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
259 recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
253 subject l(:mail_subject_account_activation_request, Setting.app_title)
260 subject l(:mail_subject_account_activation_request, Setting.app_title)
254 body :user => user,
261 body :user => user,
255 :url => url_for(:controller => 'users', :action => 'index',
262 :url => url_for(:controller => 'users', :action => 'index',
256 :status => User::STATUS_REGISTERED,
263 :status => User::STATUS_REGISTERED,
257 :sort_key => 'created_on', :sort_order => 'desc')
264 :sort_key => 'created_on', :sort_order => 'desc')
258 render_multipart('account_activation_request', body)
265 render_multipart('account_activation_request', body)
259 end
266 end
260
267
261 # Builds a tmail object used to email the specified user that their account was activated by an administrator.
268 # Builds a tmail object used to email the specified user that their account was activated by an administrator.
262 #
269 #
263 # Example:
270 # Example:
264 # account_activated(user) => tmail object
271 # account_activated(user) => tmail object
265 # Mailer.deliver_account_activated(user) => sends an email to the registered user
272 # Mailer.deliver_account_activated(user) => sends an email to the registered user
266 def account_activated(user)
273 def account_activated(user)
267 set_language_if_valid user.language
274 set_language_if_valid user.language
268 recipients user.mail
275 recipients user.mail
269 subject l(:mail_subject_register, Setting.app_title)
276 subject l(:mail_subject_register, Setting.app_title)
270 body :user => user,
277 body :user => user,
271 :login_url => url_for(:controller => 'account', :action => 'login')
278 :login_url => url_for(:controller => 'account', :action => 'login')
272 render_multipart('account_activated', body)
279 render_multipart('account_activated', body)
273 end
280 end
274
281
275 def lost_password(token)
282 def lost_password(token)
276 set_language_if_valid(token.user.language)
283 set_language_if_valid(token.user.language)
277 recipients token.user.mail
284 recipients token.user.mail
278 subject l(:mail_subject_lost_password, Setting.app_title)
285 subject l(:mail_subject_lost_password, Setting.app_title)
279 body :token => token,
286 body :token => token,
280 :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
287 :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
281 render_multipart('lost_password', body)
288 render_multipart('lost_password', body)
282 end
289 end
283
290
284 def register(token)
291 def register(token)
285 set_language_if_valid(token.user.language)
292 set_language_if_valid(token.user.language)
286 recipients token.user.mail
293 recipients token.user.mail
287 subject l(:mail_subject_register, Setting.app_title)
294 subject l(:mail_subject_register, Setting.app_title)
288 body :token => token,
295 body :token => token,
289 :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
296 :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
290 render_multipart('register', body)
297 render_multipart('register', body)
291 end
298 end
292
299
293 def test_email(user)
300 def test_email(user)
294 set_language_if_valid(user.language)
301 set_language_if_valid(user.language)
295 recipients user.mail
302 recipients user.mail
296 subject 'Redmine test'
303 subject 'Redmine test'
297 body :url => url_for(:controller => 'welcome')
304 body :url => url_for(:controller => 'welcome')
298 render_multipart('test_email', body)
305 render_multipart('test_email', body)
299 end
306 end
300
307
301 # Overrides default deliver! method to prevent from sending an email
308 # Overrides default deliver! method to prevent from sending an email
302 # with no recipient, cc or bcc
309 # with no recipient, cc or bcc
303 def deliver!(mail = @mail)
310 def deliver!(mail = @mail)
304 set_language_if_valid @initial_language
311 set_language_if_valid @initial_language
305 return false if (recipients.nil? || recipients.empty?) &&
312 return false if (recipients.nil? || recipients.empty?) &&
306 (cc.nil? || cc.empty?) &&
313 (cc.nil? || cc.empty?) &&
307 (bcc.nil? || bcc.empty?)
314 (bcc.nil? || bcc.empty?)
308
315
309 # Set Message-Id and References
316 # Set Message-Id and References
310 if @message_id_object
317 if @message_id_object
311 mail.message_id = self.class.message_id_for(@message_id_object)
318 mail.message_id = self.class.message_id_for(@message_id_object)
312 end
319 end
313 if @references_objects
320 if @references_objects
314 mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}
321 mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}
315 end
322 end
316
323
317 # Log errors when raise_delivery_errors is set to false, Rails does not
324 # Log errors when raise_delivery_errors is set to false, Rails does not
318 raise_errors = self.class.raise_delivery_errors
325 raise_errors = self.class.raise_delivery_errors
319 self.class.raise_delivery_errors = true
326 self.class.raise_delivery_errors = true
320 begin
327 begin
321 return super(mail)
328 return super(mail)
322 rescue Exception => e
329 rescue Exception => e
323 if raise_errors
330 if raise_errors
324 raise e
331 raise e
325 elsif mylogger
332 elsif mylogger
326 mylogger.error "The following error occured while sending email notification: \"#{e.message}\". Check your configuration in config/configuration.yml."
333 mylogger.error "The following error occured while sending email notification: \"#{e.message}\". Check your configuration in config/configuration.yml."
327 end
334 end
328 ensure
335 ensure
329 self.class.raise_delivery_errors = raise_errors
336 self.class.raise_delivery_errors = raise_errors
330 end
337 end
331 end
338 end
332
339
333 # Sends reminders to issue assignees
340 # Sends reminders to issue assignees
334 # Available options:
341 # Available options:
335 # * :days => how many days in the future to remind about (defaults to 7)
342 # * :days => how many days in the future to remind about (defaults to 7)
336 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
343 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
337 # * :project => id or identifier of project to process (defaults to all projects)
344 # * :project => id or identifier of project to process (defaults to all projects)
338 # * :users => array of user ids who should be reminded
345 # * :users => array of user ids who should be reminded
339 def self.reminders(options={})
346 def self.reminders(options={})
340 days = options[:days] || 7
347 days = options[:days] || 7
341 project = options[:project] ? Project.find(options[:project]) : nil
348 project = options[:project] ? Project.find(options[:project]) : nil
342 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
349 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
343 user_ids = options[:users]
350 user_ids = options[:users]
344
351
345 scope = Issue.open.scoped(:conditions => ["#{Issue.table_name}.assigned_to_id IS NOT NULL" +
352 scope = Issue.open.scoped(:conditions => ["#{Issue.table_name}.assigned_to_id IS NOT NULL" +
346 " AND #{Project.table_name}.status = #{Project::STATUS_ACTIVE}" +
353 " AND #{Project.table_name}.status = #{Project::STATUS_ACTIVE}" +
347 " AND #{Issue.table_name}.due_date <= ?", days.day.from_now.to_date]
354 " AND #{Issue.table_name}.due_date <= ?", days.day.from_now.to_date]
348 )
355 )
349 scope = scope.scoped(:conditions => {:assigned_to_id => user_ids}) if user_ids.present?
356 scope = scope.scoped(:conditions => {:assigned_to_id => user_ids}) if user_ids.present?
350 scope = scope.scoped(:conditions => {:project_id => project.id}) if project
357 scope = scope.scoped(:conditions => {:project_id => project.id}) if project
351 scope = scope.scoped(:conditions => {:tracker_id => tracker.id}) if tracker
358 scope = scope.scoped(:conditions => {:tracker_id => tracker.id}) if tracker
352
359
353 issues_by_assignee = scope.all(:include => [:status, :assigned_to, :project, :tracker]).group_by(&:assigned_to)
360 issues_by_assignee = scope.all(:include => [:status, :assigned_to, :project, :tracker]).group_by(&:assigned_to)
354 issues_by_assignee.each do |assignee, issues|
361 issues_by_assignee.each do |assignee, issues|
355 deliver_reminder(assignee, issues, days) if assignee && assignee.active?
362 deliver_reminder(assignee, issues, days) if assignee && assignee.active?
356 end
363 end
357 end
364 end
358
365
359 # Activates/desactivates email deliveries during +block+
366 # Activates/desactivates email deliveries during +block+
360 def self.with_deliveries(enabled = true, &block)
367 def self.with_deliveries(enabled = true, &block)
361 was_enabled = ActionMailer::Base.perform_deliveries
368 was_enabled = ActionMailer::Base.perform_deliveries
362 ActionMailer::Base.perform_deliveries = !!enabled
369 ActionMailer::Base.perform_deliveries = !!enabled
363 yield
370 yield
364 ensure
371 ensure
365 ActionMailer::Base.perform_deliveries = was_enabled
372 ActionMailer::Base.perform_deliveries = was_enabled
366 end
373 end
367
374
368 private
375 private
369 def initialize_defaults(method_name)
376 def initialize_defaults(method_name)
370 super
377 super
371 @initial_language = current_language
378 @initial_language = current_language
372 set_language_if_valid Setting.default_language
379 set_language_if_valid Setting.default_language
373 from Setting.mail_from
380 from Setting.mail_from
374
381
375 # Common headers
382 # Common headers
376 headers 'X-Mailer' => 'Redmine',
383 headers 'X-Mailer' => 'Redmine',
377 'X-Redmine-Host' => Setting.host_name,
384 'X-Redmine-Host' => Setting.host_name,
378 'X-Redmine-Site' => Setting.app_title,
385 'X-Redmine-Site' => Setting.app_title,
379 'X-Auto-Response-Suppress' => 'OOF',
386 'X-Auto-Response-Suppress' => 'OOF',
380 'Auto-Submitted' => 'auto-generated'
387 'Auto-Submitted' => 'auto-generated'
381 end
388 end
382
389
383 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
390 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
384 def redmine_headers(h)
391 def redmine_headers(h)
385 h.each { |k,v| headers["X-Redmine-#{k}"] = v.to_s }
392 h.each { |k,v| headers["X-Redmine-#{k}"] = v.to_s }
386 end
393 end
387
394
388 # Overrides the create_mail method
395 # Overrides the create_mail method
389 def create_mail
396 def create_mail
390 # Removes the current user from the recipients and cc
397 # Removes the author from the recipients and cc
391 # if he doesn't want to receive notifications about what he does
398 # if he doesn't want to receive notifications about what he does
392 @author ||= User.current
399 if @author && @author.logged? && @author.pref[:no_self_notified]
393 if @author.pref[:no_self_notified]
400 if recipients
394 recipients.delete(@author.mail) if recipients
401 recipients((recipients.is_a?(Array) ? recipients : [recipients]) - [@author.mail])
395 cc.delete(@author.mail) if cc
402 end
403 if cc
404 cc((cc.is_a?(Array) ? cc : [cc]) - [@author.mail])
405 end
396 end
406 end
397
407
398 if @author.logged?
408 if @author && @author.logged?
399 redmine_headers 'Sender' => @author.login
409 redmine_headers 'Sender' => @author.login
400 end
410 end
401
411
402 notified_users = [recipients, cc].flatten.compact.uniq
412 notified_users = [recipients, cc].flatten.compact.uniq
403 # Rails would log recipients only, not cc and bcc
413 # Rails would log recipients only, not cc and bcc
404 mylogger.info "Sending email notification to: #{notified_users.join(', ')}" if mylogger
414 mylogger.info "Sending email notification to: #{notified_users.join(', ')}" if mylogger
405
415
406 # Blind carbon copy recipients
416 # Blind carbon copy recipients
407 if Setting.bcc_recipients?
417 if Setting.bcc_recipients?
408 bcc(notified_users)
418 bcc(notified_users)
409 recipients []
419 recipients []
410 cc []
420 cc []
411 end
421 end
412 super
422 super
413 end
423 end
414
424
415 # Rails 2.3 has problems rendering implicit multipart messages with
425 # Rails 2.3 has problems rendering implicit multipart messages with
416 # layouts so this method will wrap an multipart messages with
426 # layouts so this method will wrap an multipart messages with
417 # explicit parts.
427 # explicit parts.
418 #
428 #
419 # https://rails.lighthouseapp.com/projects/8994/tickets/2338-actionmailer-mailer-views-and-content-type
429 # https://rails.lighthouseapp.com/projects/8994/tickets/2338-actionmailer-mailer-views-and-content-type
420 # https://rails.lighthouseapp.com/projects/8994/tickets/1799-actionmailer-doesnt-set-template_format-when-rendering-layouts
430 # https://rails.lighthouseapp.com/projects/8994/tickets/1799-actionmailer-doesnt-set-template_format-when-rendering-layouts
421
431
422 def render_multipart(method_name, body)
432 def render_multipart(method_name, body)
423 if Setting.plain_text_mail?
433 if Setting.plain_text_mail?
424 content_type "text/plain"
434 content_type "text/plain"
425 body render(:file => "#{method_name}.text.erb",
435 body render(:file => "#{method_name}.text.erb",
426 :body => body,
436 :body => body,
427 :layout => 'mailer.text.erb')
437 :layout => 'mailer.text.erb')
428 else
438 else
429 content_type "multipart/alternative"
439 content_type "multipart/alternative"
430 part :content_type => "text/plain",
440 part :content_type => "text/plain",
431 :body => render(:file => "#{method_name}.text.erb",
441 :body => render(:file => "#{method_name}.text.erb",
432 :body => body, :layout => 'mailer.text.erb')
442 :body => body, :layout => 'mailer.text.erb')
433 part :content_type => "text/html",
443 part :content_type => "text/html",
434 :body => render_message("#{method_name}.html.erb", body)
444 :body => render_message("#{method_name}.html.erb", body)
435 end
445 end
436 end
446 end
437
447
438 # Makes partial rendering work with Rails 1.2 (retro-compatibility)
448 # Makes partial rendering work with Rails 1.2 (retro-compatibility)
439 def self.controller_path
449 def self.controller_path
440 ''
450 ''
441 end unless respond_to?('controller_path')
451 end unless respond_to?('controller_path')
442
452
443 # Returns a predictable Message-Id for the given object
453 # Returns a predictable Message-Id for the given object
444 def self.message_id_for(object)
454 def self.message_id_for(object)
445 # id + timestamp should reduce the odds of a collision
455 # id + timestamp should reduce the odds of a collision
446 # as far as we don't send multiple emails for the same object
456 # as far as we don't send multiple emails for the same object
447 timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
457 timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
448 hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{timestamp.strftime("%Y%m%d%H%M%S")}"
458 hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{timestamp.strftime("%Y%m%d%H%M%S")}"
449 host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
459 host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
450 host = "#{::Socket.gethostname}.redmine" if host.empty?
460 host = "#{::Socket.gethostname}.redmine" if host.empty?
451 "<#{hash}@#{host}>"
461 "<#{hash}@#{host}>"
452 end
462 end
453
463
454 private
464 private
455
465
456 def message_id(object)
466 def message_id(object)
457 @message_id_object = object
467 @message_id_object = object
458 end
468 end
459
469
460 def references(object)
470 def references(object)
461 @references_objects ||= []
471 @references_objects ||= []
462 @references_objects << object
472 @references_objects << object
463 end
473 end
464
474
465 def mylogger
475 def mylogger
466 Rails.logger
476 Rails.logger
467 end
477 end
468 end
478 end
469
479
470 # Patch TMail so that message_id is not overwritten
480 # Patch TMail so that message_id is not overwritten
471 module TMail
481 module TMail
472 class Mail
482 class Mail
473 def add_message_id( fqdn = nil )
483 def add_message_id( fqdn = nil )
474 self.message_id ||= ::TMail::new_message_id(fqdn)
484 self.message_id ||= ::TMail::new_message_id(fqdn)
475 end
485 end
476 end
486 end
477 end
487 end
@@ -1,159 +1,164
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 AdminControllerTest < ActionController::TestCase
20 class AdminControllerTest < ActionController::TestCase
21 fixtures :projects, :users, :roles
21 fixtures :projects, :users, :roles
22
22
23 def setup
23 def setup
24 User.current = nil
24 User.current = nil
25 @request.session[:user_id] = 1 # admin
25 @request.session[:user_id] = 1 # admin
26 end
26 end
27
27
28 def test_index
28 def test_index
29 get :index
29 get :index
30 assert_no_tag :tag => 'div',
30 assert_no_tag :tag => 'div',
31 :attributes => { :class => /nodata/ }
31 :attributes => { :class => /nodata/ }
32 end
32 end
33
33
34 def test_index_with_no_configuration_data
34 def test_index_with_no_configuration_data
35 delete_configuration_data
35 delete_configuration_data
36 get :index
36 get :index
37 assert_tag :tag => 'div',
37 assert_tag :tag => 'div',
38 :attributes => { :class => /nodata/ }
38 :attributes => { :class => /nodata/ }
39 end
39 end
40
40
41 def test_projects
41 def test_projects
42 get :projects
42 get :projects
43 assert_response :success
43 assert_response :success
44 assert_template 'projects'
44 assert_template 'projects'
45 assert_not_nil assigns(:projects)
45 assert_not_nil assigns(:projects)
46 # active projects only
46 # active projects only
47 assert_nil assigns(:projects).detect {|u| !u.active?}
47 assert_nil assigns(:projects).detect {|u| !u.active?}
48 end
48 end
49
49
50 def test_projects_with_status_filter
50 def test_projects_with_status_filter
51 get :projects, :status => 1
51 get :projects, :status => 1
52 assert_response :success
52 assert_response :success
53 assert_template 'projects'
53 assert_template 'projects'
54 assert_not_nil assigns(:projects)
54 assert_not_nil assigns(:projects)
55 # active projects only
55 # active projects only
56 assert_nil assigns(:projects).detect {|u| !u.active?}
56 assert_nil assigns(:projects).detect {|u| !u.active?}
57 end
57 end
58
58
59 def test_projects_with_name_filter
59 def test_projects_with_name_filter
60 get :projects, :name => 'store', :status => ''
60 get :projects, :name => 'store', :status => ''
61 assert_response :success
61 assert_response :success
62 assert_template 'projects'
62 assert_template 'projects'
63 projects = assigns(:projects)
63 projects = assigns(:projects)
64 assert_not_nil projects
64 assert_not_nil projects
65 assert_equal 1, projects.size
65 assert_equal 1, projects.size
66 assert_equal 'OnlineStore', projects.first.name
66 assert_equal 'OnlineStore', projects.first.name
67 end
67 end
68
68
69 def test_load_default_configuration_data
69 def test_load_default_configuration_data
70 delete_configuration_data
70 delete_configuration_data
71 post :default_configuration, :lang => 'fr'
71 post :default_configuration, :lang => 'fr'
72 assert_response :redirect
72 assert_response :redirect
73 assert_nil flash[:error]
73 assert_nil flash[:error]
74 assert IssueStatus.find_by_name('Nouveau')
74 assert IssueStatus.find_by_name('Nouveau')
75 end
75 end
76
76
77 def test_load_default_configuration_data_should_rescue_error
77 def test_load_default_configuration_data_should_rescue_error
78 delete_configuration_data
78 delete_configuration_data
79 Redmine::DefaultData::Loader.stubs(:load).raises(Exception.new("Something went wrong"))
79 Redmine::DefaultData::Loader.stubs(:load).raises(Exception.new("Something went wrong"))
80 post :default_configuration, :lang => 'fr'
80 post :default_configuration, :lang => 'fr'
81 assert_response :redirect
81 assert_response :redirect
82 assert_not_nil flash[:error]
82 assert_not_nil flash[:error]
83 assert_match /Something went wrong/, flash[:error]
83 assert_match /Something went wrong/, flash[:error]
84 end
84 end
85
85
86 def test_test_email
86 def test_test_email
87 user = User.find(1)
88 user.pref[:no_self_notified] = '1'
89 user.pref.save!
90 ActionMailer::Base.deliveries.clear
91
87 get :test_email
92 get :test_email
88 assert_redirected_to '/settings/edit?tab=notifications'
93 assert_redirected_to '/settings/edit?tab=notifications'
89 mail = ActionMailer::Base.deliveries.last
94 mail = ActionMailer::Base.deliveries.last
90 assert_not_nil mail
95 assert_not_nil mail
91 user = User.find(1)
96 user = User.find(1)
92 assert_equal [user.mail], mail.bcc
97 assert_equal [user.mail], mail.bcc
93 end
98 end
94
99
95 def test_test_email_failure_should_display_the_error
100 def test_test_email_failure_should_display_the_error
96 Mailer.stubs(:deliver_test_email).raises(Exception, 'Some error message')
101 Mailer.stubs(:deliver_test_email).raises(Exception, 'Some error message')
97 get :test_email
102 get :test_email
98 assert_redirected_to '/settings/edit?tab=notifications'
103 assert_redirected_to '/settings/edit?tab=notifications'
99 assert_match /Some error message/, flash[:error]
104 assert_match /Some error message/, flash[:error]
100 end
105 end
101
106
102 def test_no_plugins
107 def test_no_plugins
103 Redmine::Plugin.clear
108 Redmine::Plugin.clear
104
109
105 get :plugins
110 get :plugins
106 assert_response :success
111 assert_response :success
107 assert_template 'plugins'
112 assert_template 'plugins'
108 end
113 end
109
114
110 def test_plugins
115 def test_plugins
111 # Register a few plugins
116 # Register a few plugins
112 Redmine::Plugin.register :foo do
117 Redmine::Plugin.register :foo do
113 name 'Foo plugin'
118 name 'Foo plugin'
114 author 'John Smith'
119 author 'John Smith'
115 description 'This is a test plugin'
120 description 'This is a test plugin'
116 version '0.0.1'
121 version '0.0.1'
117 settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings'
122 settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings'
118 end
123 end
119 Redmine::Plugin.register :bar do
124 Redmine::Plugin.register :bar do
120 end
125 end
121
126
122 get :plugins
127 get :plugins
123 assert_response :success
128 assert_response :success
124 assert_template 'plugins'
129 assert_template 'plugins'
125
130
126 assert_tag :td, :child => { :tag => 'span', :content => 'Foo plugin' }
131 assert_tag :td, :child => { :tag => 'span', :content => 'Foo plugin' }
127 assert_tag :td, :child => { :tag => 'span', :content => 'Bar' }
132 assert_tag :td, :child => { :tag => 'span', :content => 'Bar' }
128 end
133 end
129
134
130 def test_info
135 def test_info
131 get :info
136 get :info
132 assert_response :success
137 assert_response :success
133 assert_template 'info'
138 assert_template 'info'
134 end
139 end
135
140
136 def test_admin_menu_plugin_extension
141 def test_admin_menu_plugin_extension
137 Redmine::MenuManager.map :admin_menu do |menu|
142 Redmine::MenuManager.map :admin_menu do |menu|
138 menu.push :test_admin_menu_plugin_extension, '/foo/bar', :caption => 'Test'
143 menu.push :test_admin_menu_plugin_extension, '/foo/bar', :caption => 'Test'
139 end
144 end
140
145
141 get :index
146 get :index
142 assert_response :success
147 assert_response :success
143 assert_tag :a, :attributes => { :href => '/foo/bar' },
148 assert_tag :a, :attributes => { :href => '/foo/bar' },
144 :content => 'Test'
149 :content => 'Test'
145
150
146 Redmine::MenuManager.map :admin_menu do |menu|
151 Redmine::MenuManager.map :admin_menu do |menu|
147 menu.delete :test_admin_menu_plugin_extension
152 menu.delete :test_admin_menu_plugin_extension
148 end
153 end
149 end
154 end
150
155
151 private
156 private
152
157
153 def delete_configuration_data
158 def delete_configuration_data
154 Role.delete_all('builtin = 0')
159 Role.delete_all('builtin = 0')
155 Tracker.delete_all
160 Tracker.delete_all
156 IssueStatus.delete_all
161 IssueStatus.delete_all
157 Enumeration.delete_all
162 Enumeration.delete_all
158 end
163 end
159 end
164 end
General Comments 0
You need to be logged in to leave comments. Login now