##// END OF EJS Templates
Fixed: email notification for changes I make still occurs when running Repository.fetch_changesets (#1957)....
Jean-Philippe Lang -
r2223:dfc937340d6b
parent child
Show More
@@ -1,251 +1,253
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Mailer < ActionMailer::Base
18 class Mailer < ActionMailer::Base
19 helper :application
19 helper :application
20 helper :issues
20 helper :issues
21 helper :custom_fields
21 helper :custom_fields
22
22
23 include ActionController::UrlWriter
23 include ActionController::UrlWriter
24
24
25 def issue_add(issue)
25 def issue_add(issue)
26 redmine_headers 'Project' => issue.project.identifier,
26 redmine_headers 'Project' => issue.project.identifier,
27 'Issue-Id' => issue.id,
27 'Issue-Id' => issue.id,
28 'Issue-Author' => issue.author.login
28 'Issue-Author' => issue.author.login
29 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
29 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
30 recipients issue.recipients
30 recipients issue.recipients
31 cc(issue.watcher_recipients - @recipients)
31 cc(issue.watcher_recipients - @recipients)
32 subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
32 subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
33 body :issue => issue,
33 body :issue => issue,
34 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
34 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
35 end
35 end
36
36
37 def issue_edit(journal)
37 def issue_edit(journal)
38 issue = journal.journalized
38 issue = journal.journalized
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 @author = journal.user
43 recipients issue.recipients
44 recipients issue.recipients
44 # Watchers in cc
45 # Watchers in cc
45 cc(issue.watcher_recipients - @recipients)
46 cc(issue.watcher_recipients - @recipients)
46 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
47 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
47 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
48 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
48 s << issue.subject
49 s << issue.subject
49 subject s
50 subject s
50 body :issue => issue,
51 body :issue => issue,
51 :journal => journal,
52 :journal => journal,
52 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
53 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
53 end
54 end
54
55
55 def reminder(user, issues, days)
56 def reminder(user, issues, days)
56 set_language_if_valid user.language
57 set_language_if_valid user.language
57 recipients user.mail
58 recipients user.mail
58 subject l(:mail_subject_reminder, issues.size)
59 subject l(:mail_subject_reminder, issues.size)
59 body :issues => issues,
60 body :issues => issues,
60 :days => days,
61 :days => days,
61 :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'due_date', :sort_order => 'asc')
62 :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'due_date', :sort_order => 'asc')
62 end
63 end
63
64
64 def document_added(document)
65 def document_added(document)
65 redmine_headers 'Project' => document.project.identifier
66 redmine_headers 'Project' => document.project.identifier
66 recipients document.project.recipients
67 recipients document.project.recipients
67 subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
68 subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
68 body :document => document,
69 body :document => document,
69 :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
70 :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
70 end
71 end
71
72
72 def attachments_added(attachments)
73 def attachments_added(attachments)
73 container = attachments.first.container
74 container = attachments.first.container
74 added_to = ''
75 added_to = ''
75 added_to_url = ''
76 added_to_url = ''
76 case container.class.name
77 case container.class.name
77 when 'Project'
78 when 'Project'
78 added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container)
79 added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container)
79 added_to = "#{l(:label_project)}: #{container}"
80 added_to = "#{l(:label_project)}: #{container}"
80 when 'Version'
81 when 'Version'
81 added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container.project_id)
82 added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container.project_id)
82 added_to = "#{l(:label_version)}: #{container.name}"
83 added_to = "#{l(:label_version)}: #{container.name}"
83 when 'Document'
84 when 'Document'
84 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
85 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
85 added_to = "#{l(:label_document)}: #{container.title}"
86 added_to = "#{l(:label_document)}: #{container.title}"
86 end
87 end
87 redmine_headers 'Project' => container.project.identifier
88 redmine_headers 'Project' => container.project.identifier
88 recipients container.project.recipients
89 recipients container.project.recipients
89 subject "[#{container.project.name}] #{l(:label_attachment_new)}"
90 subject "[#{container.project.name}] #{l(:label_attachment_new)}"
90 body :attachments => attachments,
91 body :attachments => attachments,
91 :added_to => added_to,
92 :added_to => added_to,
92 :added_to_url => added_to_url
93 :added_to_url => added_to_url
93 end
94 end
94
95
95 def news_added(news)
96 def news_added(news)
96 redmine_headers 'Project' => news.project.identifier
97 redmine_headers 'Project' => news.project.identifier
97 recipients news.project.recipients
98 recipients news.project.recipients
98 subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
99 subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
99 body :news => news,
100 body :news => news,
100 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
101 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
101 end
102 end
102
103
103 def message_posted(message, recipients)
104 def message_posted(message, recipients)
104 redmine_headers 'Project' => message.project.identifier,
105 redmine_headers 'Project' => message.project.identifier,
105 'Topic-Id' => (message.parent_id || message.id)
106 'Topic-Id' => (message.parent_id || message.id)
106 recipients(recipients)
107 recipients(recipients)
107 subject "[#{message.board.project.name} - #{message.board.name}] #{message.subject}"
108 subject "[#{message.board.project.name} - #{message.board.name}] #{message.subject}"
108 body :message => message,
109 body :message => message,
109 :message_url => url_for(:controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root)
110 :message_url => url_for(:controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root)
110 end
111 end
111
112
112 def account_information(user, password)
113 def account_information(user, password)
113 set_language_if_valid user.language
114 set_language_if_valid user.language
114 recipients user.mail
115 recipients user.mail
115 subject l(:mail_subject_register, Setting.app_title)
116 subject l(:mail_subject_register, Setting.app_title)
116 body :user => user,
117 body :user => user,
117 :password => password,
118 :password => password,
118 :login_url => url_for(:controller => 'account', :action => 'login')
119 :login_url => url_for(:controller => 'account', :action => 'login')
119 end
120 end
120
121
121 def account_activation_request(user)
122 def account_activation_request(user)
122 # Send the email to all active administrators
123 # Send the email to all active administrators
123 recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
124 recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
124 subject l(:mail_subject_account_activation_request, Setting.app_title)
125 subject l(:mail_subject_account_activation_request, Setting.app_title)
125 body :user => user,
126 body :user => user,
126 :url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc')
127 :url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc')
127 end
128 end
128
129
129 def lost_password(token)
130 def lost_password(token)
130 set_language_if_valid(token.user.language)
131 set_language_if_valid(token.user.language)
131 recipients token.user.mail
132 recipients token.user.mail
132 subject l(:mail_subject_lost_password, Setting.app_title)
133 subject l(:mail_subject_lost_password, Setting.app_title)
133 body :token => token,
134 body :token => token,
134 :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
135 :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
135 end
136 end
136
137
137 def register(token)
138 def register(token)
138 set_language_if_valid(token.user.language)
139 set_language_if_valid(token.user.language)
139 recipients token.user.mail
140 recipients token.user.mail
140 subject l(:mail_subject_register, Setting.app_title)
141 subject l(:mail_subject_register, Setting.app_title)
141 body :token => token,
142 body :token => token,
142 :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
143 :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
143 end
144 end
144
145
145 def test(user)
146 def test(user)
146 set_language_if_valid(user.language)
147 set_language_if_valid(user.language)
147 recipients user.mail
148 recipients user.mail
148 subject 'Redmine test'
149 subject 'Redmine test'
149 body :url => url_for(:controller => 'welcome')
150 body :url => url_for(:controller => 'welcome')
150 end
151 end
151
152
152 # Overrides default deliver! method to prevent from sending an email
153 # Overrides default deliver! method to prevent from sending an email
153 # with no recipient, cc or bcc
154 # with no recipient, cc or bcc
154 def deliver!(mail = @mail)
155 def deliver!(mail = @mail)
155 return false if (recipients.nil? || recipients.empty?) &&
156 return false if (recipients.nil? || recipients.empty?) &&
156 (cc.nil? || cc.empty?) &&
157 (cc.nil? || cc.empty?) &&
157 (bcc.nil? || bcc.empty?)
158 (bcc.nil? || bcc.empty?)
158 super
159 super
159 end
160 end
160
161
161 # Sends reminders to issue assignees
162 # Sends reminders to issue assignees
162 # Available options:
163 # Available options:
163 # * :days => how many days in the future to remind about (defaults to 7)
164 # * :days => how many days in the future to remind about (defaults to 7)
164 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
165 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
165 # * :project => id or identifier of project to process (defaults to all projects)
166 # * :project => id or identifier of project to process (defaults to all projects)
166 def self.reminders(options={})
167 def self.reminders(options={})
167 days = options[:days] || 7
168 days = options[:days] || 7
168 project = options[:project] ? Project.find(options[:project]) : nil
169 project = options[:project] ? Project.find(options[:project]) : nil
169 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
170 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
170
171
171 s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?", false, days.day.from_now.to_date]
172 s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?", false, days.day.from_now.to_date]
172 s << "#{Issue.table_name}.assigned_to_id IS NOT NULL"
173 s << "#{Issue.table_name}.assigned_to_id IS NOT NULL"
173 s << "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}"
174 s << "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}"
174 s << "#{Issue.table_name}.project_id = #{project.id}" if project
175 s << "#{Issue.table_name}.project_id = #{project.id}" if project
175 s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker
176 s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker
176
177
177 issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker],
178 issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker],
178 :conditions => s.conditions
179 :conditions => s.conditions
179 ).group_by(&:assigned_to)
180 ).group_by(&:assigned_to)
180 issues_by_assignee.each do |assignee, issues|
181 issues_by_assignee.each do |assignee, issues|
181 deliver_reminder(assignee, issues, days) unless assignee.nil?
182 deliver_reminder(assignee, issues, days) unless assignee.nil?
182 end
183 end
183 end
184 end
184
185
185 private
186 private
186 def initialize_defaults(method_name)
187 def initialize_defaults(method_name)
187 super
188 super
188 set_language_if_valid Setting.default_language
189 set_language_if_valid Setting.default_language
189 from Setting.mail_from
190 from Setting.mail_from
190
191
191 # URL options
192 # URL options
192 h = Setting.host_name
193 h = Setting.host_name
193 h = h.to_s.gsub(%r{\/.*$}, '') unless ActionController::AbstractRequest.relative_url_root.blank?
194 h = h.to_s.gsub(%r{\/.*$}, '') unless ActionController::AbstractRequest.relative_url_root.blank?
194 default_url_options[:host] = h
195 default_url_options[:host] = h
195 default_url_options[:protocol] = Setting.protocol
196 default_url_options[:protocol] = Setting.protocol
196
197
197 # Common headers
198 # Common headers
198 headers 'X-Mailer' => 'Redmine',
199 headers 'X-Mailer' => 'Redmine',
199 'X-Redmine-Host' => Setting.host_name,
200 'X-Redmine-Host' => Setting.host_name,
200 'X-Redmine-Site' => Setting.app_title
201 'X-Redmine-Site' => Setting.app_title
201 end
202 end
202
203
203 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
204 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
204 def redmine_headers(h)
205 def redmine_headers(h)
205 h.each { |k,v| headers["X-Redmine-#{k}"] = v }
206 h.each { |k,v| headers["X-Redmine-#{k}"] = v }
206 end
207 end
207
208
208 # Overrides the create_mail method
209 # Overrides the create_mail method
209 def create_mail
210 def create_mail
210 # Removes the current user from the recipients and cc
211 # Removes the current user from the recipients and cc
211 # if he doesn't want to receive notifications about what he does
212 # if he doesn't want to receive notifications about what he does
212 if User.current.pref[:no_self_notified]
213 @author ||= User.current
213 recipients.delete(User.current.mail) if recipients
214 if @author.pref[:no_self_notified]
214 cc.delete(User.current.mail) if cc
215 recipients.delete(@author.mail) if recipients
216 cc.delete(@author.mail) if cc
215 end
217 end
216 # Blind carbon copy recipients
218 # Blind carbon copy recipients
217 if Setting.bcc_recipients?
219 if Setting.bcc_recipients?
218 bcc([recipients, cc].flatten.compact.uniq)
220 bcc([recipients, cc].flatten.compact.uniq)
219 recipients []
221 recipients []
220 cc []
222 cc []
221 end
223 end
222 super
224 super
223 end
225 end
224
226
225 # Renders a message with the corresponding layout
227 # Renders a message with the corresponding layout
226 def render_message(method_name, body)
228 def render_message(method_name, body)
227 layout = method_name.match(%r{text\.html\.(rhtml|rxml)}) ? 'layout.text.html.rhtml' : 'layout.text.plain.rhtml'
229 layout = method_name.match(%r{text\.html\.(rhtml|rxml)}) ? 'layout.text.html.rhtml' : 'layout.text.plain.rhtml'
228 body[:content_for_layout] = render(:file => method_name, :body => body)
230 body[:content_for_layout] = render(:file => method_name, :body => body)
229 ActionView::Base.new(template_root, body, self).render(:file => "mailer/#{layout}", :use_full_path => true)
231 ActionView::Base.new(template_root, body, self).render(:file => "mailer/#{layout}", :use_full_path => true)
230 end
232 end
231
233
232 # for the case of plain text only
234 # for the case of plain text only
233 def body(*params)
235 def body(*params)
234 value = super(*params)
236 value = super(*params)
235 if Setting.plain_text_mail?
237 if Setting.plain_text_mail?
236 templates = Dir.glob("#{template_path}/#{@template}.text.plain.{rhtml,erb}")
238 templates = Dir.glob("#{template_path}/#{@template}.text.plain.{rhtml,erb}")
237 unless String === @body or templates.empty?
239 unless String === @body or templates.empty?
238 template = File.basename(templates.first)
240 template = File.basename(templates.first)
239 @body[:content_for_layout] = render(:file => template, :body => @body)
241 @body[:content_for_layout] = render(:file => template, :body => @body)
240 @body = ActionView::Base.new(template_root, @body, self).render(:file => "mailer/layout.text.plain.rhtml", :use_full_path => true)
242 @body = ActionView::Base.new(template_root, @body, self).render(:file => "mailer/layout.text.plain.rhtml", :use_full_path => true)
241 return @body
243 return @body
242 end
244 end
243 end
245 end
244 return value
246 return value
245 end
247 end
246
248
247 # Makes partial rendering work with Rails 1.2 (retro-compatibility)
249 # Makes partial rendering work with Rails 1.2 (retro-compatibility)
248 def self.controller_path
250 def self.controller_path
249 ''
251 ''
250 end unless respond_to?('controller_path')
252 end unless respond_to?('controller_path')
251 end
253 end
General Comments 0
You need to be logged in to leave comments. Login now