##// END OF EJS Templates
Make sure users don't get notified for thing they can not view (#3589)....
Jean-Philippe Lang -
r3055:bb477a3a0fe7
parent child
Show More
@@ -1,45 +1,56
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 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 Document < ActiveRecord::Base
18 class Document < ActiveRecord::Base
19 belongs_to :project
19 belongs_to :project
20 belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
20 belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
21 acts_as_attachable :delete_permission => :manage_documents
21 acts_as_attachable :delete_permission => :manage_documents
22
22
23 acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
23 acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
24 acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
24 acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
25 :author => Proc.new {|o| (a = o.attachments.find(:first, :order => "#{Attachment.table_name}.created_on ASC")) ? a.author : nil },
25 :author => Proc.new {|o| (a = o.attachments.find(:first, :order => "#{Attachment.table_name}.created_on ASC")) ? a.author : nil },
26 :url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
26 :url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
27 acts_as_activity_provider :find_options => {:include => :project}
27 acts_as_activity_provider :find_options => {:include => :project}
28
28
29 validates_presence_of :project, :title, :category
29 validates_presence_of :project, :title, :category
30 validates_length_of :title, :maximum => 60
30 validates_length_of :title, :maximum => 60
31
31
32 def visible?(user=User.current)
33 !user.nil? && user.allowed_to?(:view_documents, project)
34 end
35
32 def after_initialize
36 def after_initialize
33 if new_record?
37 if new_record?
34 self.category ||= DocumentCategory.default
38 self.category ||= DocumentCategory.default
35 end
39 end
36 end
40 end
37
41
38 def updated_on
42 def updated_on
39 unless @updated_on
43 unless @updated_on
40 a = attachments.find(:first, :order => 'created_on DESC')
44 a = attachments.find(:first, :order => 'created_on DESC')
41 @updated_on = (a && a.created_on) || created_on
45 @updated_on = (a && a.created_on) || created_on
42 end
46 end
43 @updated_on
47 @updated_on
44 end
48 end
49
50 # Returns the mail adresses of users that should be notified
51 def recipients
52 notified = project.notified_users
53 notified.reject! {|user| !visible?(user)}
54 notified.collect(&:mail)
55 end
45 end
56 end
@@ -1,400 +1,403
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 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 recipients issue.recipients
44 recipients issue.recipients
45 cc(issue.watcher_recipients - @recipients)
45 cc(issue.watcher_recipients - @recipients)
46 subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
46 subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
47 body :issue => issue,
47 body :issue => issue,
48 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
48 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
49 render_multipart('issue_add', body)
49 render_multipart('issue_add', body)
50 end
50 end
51
51
52 # Builds a tmail object used to email recipients of the edited issue.
52 # Builds a tmail object used to email recipients of the edited issue.
53 #
53 #
54 # Example:
54 # Example:
55 # issue_edit(journal) => tmail object
55 # issue_edit(journal) => tmail object
56 # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients
56 # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients
57 def issue_edit(journal)
57 def issue_edit(journal)
58 issue = journal.journalized.reload
58 issue = journal.journalized.reload
59 redmine_headers 'Project' => issue.project.identifier,
59 redmine_headers 'Project' => issue.project.identifier,
60 'Issue-Id' => issue.id,
60 'Issue-Id' => issue.id,
61 'Issue-Author' => issue.author.login
61 'Issue-Author' => issue.author.login
62 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
62 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
63 message_id journal
63 message_id journal
64 references issue
64 references issue
65 @author = journal.user
65 @author = journal.user
66 recipients issue.recipients
66 recipients issue.recipients
67 # Watchers in cc
67 # Watchers in cc
68 cc(issue.watcher_recipients - @recipients)
68 cc(issue.watcher_recipients - @recipients)
69 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
69 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
70 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
70 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
71 s << issue.subject
71 s << issue.subject
72 subject s
72 subject s
73 body :issue => issue,
73 body :issue => issue,
74 :journal => journal,
74 :journal => journal,
75 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
75 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
76
76
77 render_multipart('issue_edit', body)
77 render_multipart('issue_edit', body)
78 end
78 end
79
79
80 def reminder(user, issues, days)
80 def reminder(user, issues, days)
81 set_language_if_valid user.language
81 set_language_if_valid user.language
82 recipients user.mail
82 recipients user.mail
83 subject l(:mail_subject_reminder, issues.size)
83 subject l(:mail_subject_reminder, issues.size)
84 body :issues => issues,
84 body :issues => issues,
85 :days => days,
85 :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')
86 :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)
87 render_multipart('reminder', body)
88 end
88 end
89
89
90 # Builds a tmail object used to email users belonging to the added document's project.
90 # Builds a tmail object used to email users belonging to the added document's project.
91 #
91 #
92 # Example:
92 # Example:
93 # document_added(document) => tmail object
93 # document_added(document) => tmail object
94 # Mailer.deliver_document_added(document) => sends an email to the document's project recipients
94 # Mailer.deliver_document_added(document) => sends an email to the document's project recipients
95 def document_added(document)
95 def document_added(document)
96 redmine_headers 'Project' => document.project.identifier
96 redmine_headers 'Project' => document.project.identifier
97 recipients document.project.recipients
97 recipients document.recipients
98 subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
98 subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
99 body :document => document,
99 body :document => document,
100 :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
100 :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
101 render_multipart('document_added', body)
101 render_multipart('document_added', body)
102 end
102 end
103
103
104 # Builds a tmail object used to email recipients of a project when an attachements are added.
104 # Builds a tmail object used to email recipients of a project when an attachements are added.
105 #
105 #
106 # Example:
106 # Example:
107 # attachments_added(attachments) => tmail object
107 # attachments_added(attachments) => tmail object
108 # Mailer.deliver_attachments_added(attachments) => sends an email to the project's recipients
108 # Mailer.deliver_attachments_added(attachments) => sends an email to the project's recipients
109 def attachments_added(attachments)
109 def attachments_added(attachments)
110 container = attachments.first.container
110 container = attachments.first.container
111 added_to = ''
111 added_to = ''
112 added_to_url = ''
112 added_to_url = ''
113 case container.class.name
113 case container.class.name
114 when 'Project'
114 when 'Project'
115 added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container)
115 added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container)
116 added_to = "#{l(:label_project)}: #{container}"
116 added_to = "#{l(:label_project)}: #{container}"
117 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
117 when 'Version'
118 when 'Version'
118 added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container.project_id)
119 added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container.project_id)
119 added_to = "#{l(:label_version)}: #{container.name}"
120 added_to = "#{l(:label_version)}: #{container.name}"
121 recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
120 when 'Document'
122 when 'Document'
121 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
123 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
122 added_to = "#{l(:label_document)}: #{container.title}"
124 added_to = "#{l(:label_document)}: #{container.title}"
125 recipients container.recipients
123 end
126 end
124 redmine_headers 'Project' => container.project.identifier
127 redmine_headers 'Project' => container.project.identifier
125 recipients container.project.recipients
126 subject "[#{container.project.name}] #{l(:label_attachment_new)}"
128 subject "[#{container.project.name}] #{l(:label_attachment_new)}"
127 body :attachments => attachments,
129 body :attachments => attachments,
128 :added_to => added_to,
130 :added_to => added_to,
129 :added_to_url => added_to_url
131 :added_to_url => added_to_url
130 render_multipart('attachments_added', body)
132 render_multipart('attachments_added', body)
131 end
133 end
132
134
133 # Builds a tmail object used to email recipients of a news' project when a news item is added.
135 # Builds a tmail object used to email recipients of a news' project when a news item is added.
134 #
136 #
135 # Example:
137 # Example:
136 # news_added(news) => tmail object
138 # news_added(news) => tmail object
137 # Mailer.deliver_news_added(news) => sends an email to the news' project recipients
139 # Mailer.deliver_news_added(news) => sends an email to the news' project recipients
138 def news_added(news)
140 def news_added(news)
139 redmine_headers 'Project' => news.project.identifier
141 redmine_headers 'Project' => news.project.identifier
140 message_id news
142 message_id news
141 recipients news.project.recipients
143 recipients news.recipients
142 subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
144 subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
143 body :news => news,
145 body :news => news,
144 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
146 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
145 render_multipart('news_added', body)
147 render_multipart('news_added', body)
146 end
148 end
147
149
148 # Builds a tmail object used to email the specified recipients of the specified message that was posted.
150 # Builds a tmail object used to email the recipients of the specified message that was posted.
149 #
151 #
150 # Example:
152 # Example:
151 # message_posted(message, recipients) => tmail object
153 # message_posted(message) => tmail object
152 # Mailer.deliver_message_posted(message, recipients) => sends an email to the recipients
154 # Mailer.deliver_message_posted(message) => sends an email to the recipients
153 def message_posted(message, recipients)
155 def message_posted(message)
154 redmine_headers 'Project' => message.project.identifier,
156 redmine_headers 'Project' => message.project.identifier,
155 'Topic-Id' => (message.parent_id || message.id)
157 'Topic-Id' => (message.parent_id || message.id)
156 message_id message
158 message_id message
157 references message.parent unless message.parent.nil?
159 references message.parent unless message.parent.nil?
158 recipients(recipients)
160 recipients(message.recipients)
161 cc((message.root.watcher_recipients + message.board.watcher_recipients).uniq - @recipients)
159 subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
162 subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
160 body :message => message,
163 body :message => message,
161 :message_url => url_for(:controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root)
164 :message_url => url_for(:controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root)
162 render_multipart('message_posted', body)
165 render_multipart('message_posted', body)
163 end
166 end
164
167
165 # Builds a tmail object used to email the recipients of a project of the specified wiki content was added.
168 # Builds a tmail object used to email the recipients of a project of the specified wiki content was added.
166 #
169 #
167 # Example:
170 # Example:
168 # wiki_content_added(wiki_content) => tmail object
171 # wiki_content_added(wiki_content) => tmail object
169 # Mailer.deliver_wiki_content_added(wiki_content) => sends an email to the project's recipients
172 # Mailer.deliver_wiki_content_added(wiki_content) => sends an email to the project's recipients
170 def wiki_content_added(wiki_content)
173 def wiki_content_added(wiki_content)
171 redmine_headers 'Project' => wiki_content.project.identifier,
174 redmine_headers 'Project' => wiki_content.project.identifier,
172 'Wiki-Page-Id' => wiki_content.page.id
175 'Wiki-Page-Id' => wiki_content.page.id
173 message_id wiki_content
176 message_id wiki_content
174 recipients wiki_content.project.recipients
177 recipients wiki_content.recipients
175 cc(wiki_content.page.wiki.watcher_recipients - recipients)
178 cc(wiki_content.page.wiki.watcher_recipients - recipients)
176 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :page => wiki_content.page.pretty_title)}"
179 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :page => wiki_content.page.pretty_title)}"
177 body :wiki_content => wiki_content,
180 body :wiki_content => wiki_content,
178 :wiki_content_url => url_for(:controller => 'wiki', :action => 'index', :id => wiki_content.project, :page => wiki_content.page.title)
181 :wiki_content_url => url_for(:controller => 'wiki', :action => 'index', :id => wiki_content.project, :page => wiki_content.page.title)
179 render_multipart('wiki_content_added', body)
182 render_multipart('wiki_content_added', body)
180 end
183 end
181
184
182 # Builds a tmail object used to email the recipients of a project of the specified wiki content was updated.
185 # Builds a tmail object used to email the recipients of a project of the specified wiki content was updated.
183 #
186 #
184 # Example:
187 # Example:
185 # wiki_content_updated(wiki_content) => tmail object
188 # wiki_content_updated(wiki_content) => tmail object
186 # Mailer.deliver_wiki_content_updated(wiki_content) => sends an email to the project's recipients
189 # Mailer.deliver_wiki_content_updated(wiki_content) => sends an email to the project's recipients
187 def wiki_content_updated(wiki_content)
190 def wiki_content_updated(wiki_content)
188 redmine_headers 'Project' => wiki_content.project.identifier,
191 redmine_headers 'Project' => wiki_content.project.identifier,
189 'Wiki-Page-Id' => wiki_content.page.id
192 'Wiki-Page-Id' => wiki_content.page.id
190 message_id wiki_content
193 message_id wiki_content
191 recipients wiki_content.project.recipients
194 recipients wiki_content.recipients
192 cc(wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients)
195 cc(wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients)
193 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :page => wiki_content.page.pretty_title)}"
196 subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :page => wiki_content.page.pretty_title)}"
194 body :wiki_content => wiki_content,
197 body :wiki_content => wiki_content,
195 :wiki_content_url => url_for(:controller => 'wiki', :action => 'index', :id => wiki_content.project, :page => wiki_content.page.title),
198 :wiki_content_url => url_for(:controller => 'wiki', :action => 'index', :id => wiki_content.project, :page => wiki_content.page.title),
196 :wiki_diff_url => url_for(:controller => 'wiki', :action => 'diff', :id => wiki_content.project, :page => wiki_content.page.title, :version => wiki_content.version)
199 :wiki_diff_url => url_for(:controller => 'wiki', :action => 'diff', :id => wiki_content.project, :page => wiki_content.page.title, :version => wiki_content.version)
197 render_multipart('wiki_content_updated', body)
200 render_multipart('wiki_content_updated', body)
198 end
201 end
199
202
200 # Builds a tmail object used to email the specified user their account information.
203 # Builds a tmail object used to email the specified user their account information.
201 #
204 #
202 # Example:
205 # Example:
203 # account_information(user, password) => tmail object
206 # account_information(user, password) => tmail object
204 # Mailer.deliver_account_information(user, password) => sends account information to the user
207 # Mailer.deliver_account_information(user, password) => sends account information to the user
205 def account_information(user, password)
208 def account_information(user, password)
206 set_language_if_valid user.language
209 set_language_if_valid user.language
207 recipients user.mail
210 recipients user.mail
208 subject l(:mail_subject_register, Setting.app_title)
211 subject l(:mail_subject_register, Setting.app_title)
209 body :user => user,
212 body :user => user,
210 :password => password,
213 :password => password,
211 :login_url => url_for(:controller => 'account', :action => 'login')
214 :login_url => url_for(:controller => 'account', :action => 'login')
212 render_multipart('account_information', body)
215 render_multipart('account_information', body)
213 end
216 end
214
217
215 # Builds a tmail object used to email all active administrators of an account activation request.
218 # Builds a tmail object used to email all active administrators of an account activation request.
216 #
219 #
217 # Example:
220 # Example:
218 # account_activation_request(user) => tmail object
221 # account_activation_request(user) => tmail object
219 # Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators
222 # Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators
220 def account_activation_request(user)
223 def account_activation_request(user)
221 # Send the email to all active administrators
224 # Send the email to all active administrators
222 recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
225 recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
223 subject l(:mail_subject_account_activation_request, Setting.app_title)
226 subject l(:mail_subject_account_activation_request, Setting.app_title)
224 body :user => user,
227 body :user => user,
225 :url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc')
228 :url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc')
226 render_multipart('account_activation_request', body)
229 render_multipart('account_activation_request', body)
227 end
230 end
228
231
229 # Builds a tmail object used to email the specified user that their account was activated by an administrator.
232 # Builds a tmail object used to email the specified user that their account was activated by an administrator.
230 #
233 #
231 # Example:
234 # Example:
232 # account_activated(user) => tmail object
235 # account_activated(user) => tmail object
233 # Mailer.deliver_account_activated(user) => sends an email to the registered user
236 # Mailer.deliver_account_activated(user) => sends an email to the registered user
234 def account_activated(user)
237 def account_activated(user)
235 set_language_if_valid user.language
238 set_language_if_valid user.language
236 recipients user.mail
239 recipients user.mail
237 subject l(:mail_subject_register, Setting.app_title)
240 subject l(:mail_subject_register, Setting.app_title)
238 body :user => user,
241 body :user => user,
239 :login_url => url_for(:controller => 'account', :action => 'login')
242 :login_url => url_for(:controller => 'account', :action => 'login')
240 render_multipart('account_activated', body)
243 render_multipart('account_activated', body)
241 end
244 end
242
245
243 def lost_password(token)
246 def lost_password(token)
244 set_language_if_valid(token.user.language)
247 set_language_if_valid(token.user.language)
245 recipients token.user.mail
248 recipients token.user.mail
246 subject l(:mail_subject_lost_password, Setting.app_title)
249 subject l(:mail_subject_lost_password, Setting.app_title)
247 body :token => token,
250 body :token => token,
248 :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
251 :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
249 render_multipart('lost_password', body)
252 render_multipart('lost_password', body)
250 end
253 end
251
254
252 def register(token)
255 def register(token)
253 set_language_if_valid(token.user.language)
256 set_language_if_valid(token.user.language)
254 recipients token.user.mail
257 recipients token.user.mail
255 subject l(:mail_subject_register, Setting.app_title)
258 subject l(:mail_subject_register, Setting.app_title)
256 body :token => token,
259 body :token => token,
257 :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
260 :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
258 render_multipart('register', body)
261 render_multipart('register', body)
259 end
262 end
260
263
261 def test(user)
264 def test(user)
262 set_language_if_valid(user.language)
265 set_language_if_valid(user.language)
263 recipients user.mail
266 recipients user.mail
264 subject 'Redmine test'
267 subject 'Redmine test'
265 body :url => url_for(:controller => 'welcome')
268 body :url => url_for(:controller => 'welcome')
266 render_multipart('test', body)
269 render_multipart('test', body)
267 end
270 end
268
271
269 # Overrides default deliver! method to prevent from sending an email
272 # Overrides default deliver! method to prevent from sending an email
270 # with no recipient, cc or bcc
273 # with no recipient, cc or bcc
271 def deliver!(mail = @mail)
274 def deliver!(mail = @mail)
272 return false if (recipients.nil? || recipients.empty?) &&
275 return false if (recipients.nil? || recipients.empty?) &&
273 (cc.nil? || cc.empty?) &&
276 (cc.nil? || cc.empty?) &&
274 (bcc.nil? || bcc.empty?)
277 (bcc.nil? || bcc.empty?)
275
278
276 # Set Message-Id and References
279 # Set Message-Id and References
277 if @message_id_object
280 if @message_id_object
278 mail.message_id = self.class.message_id_for(@message_id_object)
281 mail.message_id = self.class.message_id_for(@message_id_object)
279 end
282 end
280 if @references_objects
283 if @references_objects
281 mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}
284 mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}
282 end
285 end
283 super(mail)
286 super(mail)
284 end
287 end
285
288
286 # Sends reminders to issue assignees
289 # Sends reminders to issue assignees
287 # Available options:
290 # Available options:
288 # * :days => how many days in the future to remind about (defaults to 7)
291 # * :days => how many days in the future to remind about (defaults to 7)
289 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
292 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
290 # * :project => id or identifier of project to process (defaults to all projects)
293 # * :project => id or identifier of project to process (defaults to all projects)
291 def self.reminders(options={})
294 def self.reminders(options={})
292 days = options[:days] || 7
295 days = options[:days] || 7
293 project = options[:project] ? Project.find(options[:project]) : nil
296 project = options[:project] ? Project.find(options[:project]) : nil
294 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
297 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
295
298
296 s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?", false, days.day.from_now.to_date]
299 s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?", false, days.day.from_now.to_date]
297 s << "#{Issue.table_name}.assigned_to_id IS NOT NULL"
300 s << "#{Issue.table_name}.assigned_to_id IS NOT NULL"
298 s << "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}"
301 s << "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}"
299 s << "#{Issue.table_name}.project_id = #{project.id}" if project
302 s << "#{Issue.table_name}.project_id = #{project.id}" if project
300 s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker
303 s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker
301
304
302 issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker],
305 issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker],
303 :conditions => s.conditions
306 :conditions => s.conditions
304 ).group_by(&:assigned_to)
307 ).group_by(&:assigned_to)
305 issues_by_assignee.each do |assignee, issues|
308 issues_by_assignee.each do |assignee, issues|
306 deliver_reminder(assignee, issues, days) unless assignee.nil?
309 deliver_reminder(assignee, issues, days) unless assignee.nil?
307 end
310 end
308 end
311 end
309
312
310 private
313 private
311 def initialize_defaults(method_name)
314 def initialize_defaults(method_name)
312 super
315 super
313 set_language_if_valid Setting.default_language
316 set_language_if_valid Setting.default_language
314 from Setting.mail_from
317 from Setting.mail_from
315
318
316 # Common headers
319 # Common headers
317 headers 'X-Mailer' => 'Redmine',
320 headers 'X-Mailer' => 'Redmine',
318 'X-Redmine-Host' => Setting.host_name,
321 'X-Redmine-Host' => Setting.host_name,
319 'X-Redmine-Site' => Setting.app_title,
322 'X-Redmine-Site' => Setting.app_title,
320 'Precedence' => 'bulk',
323 'Precedence' => 'bulk',
321 'Auto-Submitted' => 'auto-generated'
324 'Auto-Submitted' => 'auto-generated'
322 end
325 end
323
326
324 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
327 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
325 def redmine_headers(h)
328 def redmine_headers(h)
326 h.each { |k,v| headers["X-Redmine-#{k}"] = v }
329 h.each { |k,v| headers["X-Redmine-#{k}"] = v }
327 end
330 end
328
331
329 # Overrides the create_mail method
332 # Overrides the create_mail method
330 def create_mail
333 def create_mail
331 # Removes the current user from the recipients and cc
334 # Removes the current user from the recipients and cc
332 # if he doesn't want to receive notifications about what he does
335 # if he doesn't want to receive notifications about what he does
333 @author ||= User.current
336 @author ||= User.current
334 if @author.pref[:no_self_notified]
337 if @author.pref[:no_self_notified]
335 recipients.delete(@author.mail) if recipients
338 recipients.delete(@author.mail) if recipients
336 cc.delete(@author.mail) if cc
339 cc.delete(@author.mail) if cc
337 end
340 end
338 # Blind carbon copy recipients
341 # Blind carbon copy recipients
339 if Setting.bcc_recipients?
342 if Setting.bcc_recipients?
340 bcc([recipients, cc].flatten.compact.uniq)
343 bcc([recipients, cc].flatten.compact.uniq)
341 recipients []
344 recipients []
342 cc []
345 cc []
343 end
346 end
344 super
347 super
345 end
348 end
346
349
347 # Rails 2.3 has problems rendering implicit multipart messages with
350 # Rails 2.3 has problems rendering implicit multipart messages with
348 # layouts so this method will wrap an multipart messages with
351 # layouts so this method will wrap an multipart messages with
349 # explicit parts.
352 # explicit parts.
350 #
353 #
351 # https://rails.lighthouseapp.com/projects/8994/tickets/2338-actionmailer-mailer-views-and-content-type
354 # https://rails.lighthouseapp.com/projects/8994/tickets/2338-actionmailer-mailer-views-and-content-type
352 # https://rails.lighthouseapp.com/projects/8994/tickets/1799-actionmailer-doesnt-set-template_format-when-rendering-layouts
355 # https://rails.lighthouseapp.com/projects/8994/tickets/1799-actionmailer-doesnt-set-template_format-when-rendering-layouts
353
356
354 def render_multipart(method_name, body)
357 def render_multipart(method_name, body)
355 if Setting.plain_text_mail?
358 if Setting.plain_text_mail?
356 content_type "text/plain"
359 content_type "text/plain"
357 body render(:file => "#{method_name}.text.plain.rhtml", :body => body, :layout => 'mailer.text.plain.erb')
360 body render(:file => "#{method_name}.text.plain.rhtml", :body => body, :layout => 'mailer.text.plain.erb')
358 else
361 else
359 content_type "multipart/alternative"
362 content_type "multipart/alternative"
360 part :content_type => "text/plain", :body => render(:file => "#{method_name}.text.plain.rhtml", :body => body, :layout => 'mailer.text.plain.erb')
363 part :content_type => "text/plain", :body => render(:file => "#{method_name}.text.plain.rhtml", :body => body, :layout => 'mailer.text.plain.erb')
361 part :content_type => "text/html", :body => render_message("#{method_name}.text.html.rhtml", body)
364 part :content_type => "text/html", :body => render_message("#{method_name}.text.html.rhtml", body)
362 end
365 end
363 end
366 end
364
367
365 # Makes partial rendering work with Rails 1.2 (retro-compatibility)
368 # Makes partial rendering work with Rails 1.2 (retro-compatibility)
366 def self.controller_path
369 def self.controller_path
367 ''
370 ''
368 end unless respond_to?('controller_path')
371 end unless respond_to?('controller_path')
369
372
370 # Returns a predictable Message-Id for the given object
373 # Returns a predictable Message-Id for the given object
371 def self.message_id_for(object)
374 def self.message_id_for(object)
372 # id + timestamp should reduce the odds of a collision
375 # id + timestamp should reduce the odds of a collision
373 # as far as we don't send multiple emails for the same object
376 # as far as we don't send multiple emails for the same object
374 timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
377 timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
375 hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{timestamp.strftime("%Y%m%d%H%M%S")}"
378 hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{timestamp.strftime("%Y%m%d%H%M%S")}"
376 host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
379 host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
377 host = "#{::Socket.gethostname}.redmine" if host.empty?
380 host = "#{::Socket.gethostname}.redmine" if host.empty?
378 "<#{hash}@#{host}>"
381 "<#{hash}@#{host}>"
379 end
382 end
380
383
381 private
384 private
382
385
383 def message_id(object)
386 def message_id(object)
384 @message_id_object = object
387 @message_id_object = object
385 end
388 end
386
389
387 def references(object)
390 def references(object)
388 @references_objects ||= []
391 @references_objects ||= []
389 @references_objects << object
392 @references_objects << object
390 end
393 end
391 end
394 end
392
395
393 # Patch TMail so that message_id is not overwritten
396 # Patch TMail so that message_id is not overwritten
394 module TMail
397 module TMail
395 class Mail
398 class Mail
396 def add_message_id( fqdn = nil )
399 def add_message_id( fqdn = nil )
397 self.message_id ||= ::TMail::new_message_id(fqdn)
400 self.message_id ||= ::TMail::new_message_id(fqdn)
398 end
401 end
399 end
402 end
400 end
403 end
@@ -1,98 +1,105
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 Message < ActiveRecord::Base
18 class Message < ActiveRecord::Base
19 belongs_to :board
19 belongs_to :board
20 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
20 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
21 acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC"
21 acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC"
22 acts_as_attachable
22 acts_as_attachable
23 belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id'
23 belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id'
24
24
25 acts_as_searchable :columns => ['subject', 'content'],
25 acts_as_searchable :columns => ['subject', 'content'],
26 :include => {:board => :project},
26 :include => {:board => :project},
27 :project_key => 'project_id',
27 :project_key => 'project_id',
28 :date_column => "#{table_name}.created_on"
28 :date_column => "#{table_name}.created_on"
29 acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"},
29 acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"},
30 :description => :content,
30 :description => :content,
31 :type => Proc.new {|o| o.parent_id.nil? ? 'message' : 'reply'},
31 :type => Proc.new {|o| o.parent_id.nil? ? 'message' : 'reply'},
32 :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} :
32 :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} :
33 {:id => o.parent_id, :anchor => "message-#{o.id}"})}
33 {:id => o.parent_id, :anchor => "message-#{o.id}"})}
34
34
35 acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]},
35 acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]},
36 :author_key => :author_id
36 :author_key => :author_id
37 acts_as_watchable
37 acts_as_watchable
38
38
39 attr_protected :locked, :sticky
39 attr_protected :locked, :sticky
40 validates_presence_of :board, :subject, :content
40 validates_presence_of :board, :subject, :content
41 validates_length_of :subject, :maximum => 255
41 validates_length_of :subject, :maximum => 255
42
42
43 after_create :add_author_as_watcher
43 after_create :add_author_as_watcher
44
44
45 def visible?(user=User.current)
45 def visible?(user=User.current)
46 !user.nil? && user.allowed_to?(:view_messages, project)
46 !user.nil? && user.allowed_to?(:view_messages, project)
47 end
47 end
48
48
49 def validate_on_create
49 def validate_on_create
50 # Can not reply to a locked topic
50 # Can not reply to a locked topic
51 errors.add_to_base 'Topic is locked' if root.locked? && self != root
51 errors.add_to_base 'Topic is locked' if root.locked? && self != root
52 end
52 end
53
53
54 def after_create
54 def after_create
55 if parent
55 if parent
56 parent.reload.update_attribute(:last_reply_id, self.id)
56 parent.reload.update_attribute(:last_reply_id, self.id)
57 end
57 end
58 board.reset_counters!
58 board.reset_counters!
59 end
59 end
60
60
61 def after_update
61 def after_update
62 if board_id_changed?
62 if board_id_changed?
63 Message.update_all("board_id = #{board_id}", ["id = ? OR parent_id = ?", root.id, root.id])
63 Message.update_all("board_id = #{board_id}", ["id = ? OR parent_id = ?", root.id, root.id])
64 Board.reset_counters!(board_id_was)
64 Board.reset_counters!(board_id_was)
65 Board.reset_counters!(board_id)
65 Board.reset_counters!(board_id)
66 end
66 end
67 end
67 end
68
68
69 def after_destroy
69 def after_destroy
70 board.reset_counters!
70 board.reset_counters!
71 end
71 end
72
72
73 def sticky=(arg)
73 def sticky=(arg)
74 write_attribute :sticky, (arg == true || arg.to_s == '1' ? 1 : 0)
74 write_attribute :sticky, (arg == true || arg.to_s == '1' ? 1 : 0)
75 end
75 end
76
76
77 def sticky?
77 def sticky?
78 sticky == 1
78 sticky == 1
79 end
79 end
80
80
81 def project
81 def project
82 board.project
82 board.project
83 end
83 end
84
84
85 def editable_by?(usr)
85 def editable_by?(usr)
86 usr && usr.logged? && (usr.allowed_to?(:edit_messages, project) || (self.author == usr && usr.allowed_to?(:edit_own_messages, project)))
86 usr && usr.logged? && (usr.allowed_to?(:edit_messages, project) || (self.author == usr && usr.allowed_to?(:edit_own_messages, project)))
87 end
87 end
88
88
89 def destroyable_by?(usr)
89 def destroyable_by?(usr)
90 usr && usr.logged? && (usr.allowed_to?(:delete_messages, project) || (self.author == usr && usr.allowed_to?(:delete_own_messages, project)))
90 usr && usr.logged? && (usr.allowed_to?(:delete_messages, project) || (self.author == usr && usr.allowed_to?(:delete_own_messages, project)))
91 end
91 end
92
92
93 # Returns the mail adresses of users that should be notified
94 def recipients
95 notified = project.notified_users
96 notified.reject! {|user| !visible?(user)}
97 notified.collect(&:mail)
98 end
99
93 private
100 private
94
101
95 def add_author_as_watcher
102 def add_author_as_watcher
96 Watcher.create(:watchable => self.root, :user => author)
103 Watcher.create(:watchable => self.root, :user => author)
97 end
104 end
98 end
105 end
@@ -1,30 +1,22
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 MessageObserver < ActiveRecord::Observer
18 class MessageObserver < ActiveRecord::Observer
19 def after_create(message)
19 def after_create(message)
20 recipients = []
20 Mailer.deliver_message_posted(message) if Setting.notified_events.include?('message_posted')
21 # send notification to the topic watchers
22 recipients += message.root.watcher_recipients
23 # send notification to the board watchers
24 recipients += message.board.watcher_recipients
25 # send notification to project members who want to be notified
26 recipients += message.board.project.recipients
27 recipients = recipients.compact.uniq
28 Mailer.deliver_message_posted(message, recipients) if !recipients.empty? && Setting.notified_events.include?('message_posted')
29 end
21 end
30 end
22 end
@@ -1,36 +1,47
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-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 class News < ActiveRecord::Base
18 class News < ActiveRecord::Base
19 belongs_to :project
19 belongs_to :project
20 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
20 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
21 has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on"
21 has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on"
22
22
23 validates_presence_of :title, :description
23 validates_presence_of :title, :description
24 validates_length_of :title, :maximum => 60
24 validates_length_of :title, :maximum => 60
25 validates_length_of :summary, :maximum => 255
25 validates_length_of :summary, :maximum => 255
26
26
27 acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"], :include => :project
27 acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"], :include => :project
28 acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}}
28 acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}}
29 acts_as_activity_provider :find_options => {:include => [:project, :author]},
29 acts_as_activity_provider :find_options => {:include => [:project, :author]},
30 :author_key => :author_id
30 :author_key => :author_id
31
31
32 def visible?(user=User.current)
33 !user.nil? && user.allowed_to?(:view_news, project)
34 end
35
36 # Returns the mail adresses of users that should be notified
37 def recipients
38 notified = project.notified_users
39 notified.reject! {|user| !visible?(user)}
40 notified.collect(&:mail)
41 end
42
32 # returns latest news for projects visible by user
43 # returns latest news for projects visible by user
33 def self.latest(user = User.current, count = 5)
44 def self.latest(user = User.current, count = 5)
34 find(:all, :limit => count, :conditions => Project.allowed_to_condition(user, :view_news), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
45 find(:all, :limit => count, :conditions => Project.allowed_to_condition(user, :view_news), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
35 end
46 end
36 end
47 end
@@ -1,95 +1,106
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 'zlib'
18 require 'zlib'
19
19
20 class WikiContent < ActiveRecord::Base
20 class WikiContent < ActiveRecord::Base
21 set_locking_column :version
21 set_locking_column :version
22 belongs_to :page, :class_name => 'WikiPage', :foreign_key => 'page_id'
22 belongs_to :page, :class_name => 'WikiPage', :foreign_key => 'page_id'
23 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
23 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
24 validates_presence_of :text
24 validates_presence_of :text
25 validates_length_of :comments, :maximum => 255, :allow_nil => true
25 validates_length_of :comments, :maximum => 255, :allow_nil => true
26
26
27 acts_as_versioned
27 acts_as_versioned
28
29 def visible?(user=User.current)
30 page.visible?(user)
31 end
28
32
29 def project
33 def project
30 page.project
34 page.project
31 end
35 end
32
36
37 # Returns the mail adresses of users that should be notified
38 def recipients
39 notified = project.notified_users
40 notified.reject! {|user| !visible?(user)}
41 notified.collect(&:mail)
42 end
43
33 class Version
44 class Version
34 belongs_to :page, :class_name => '::WikiPage', :foreign_key => 'page_id'
45 belongs_to :page, :class_name => '::WikiPage', :foreign_key => 'page_id'
35 belongs_to :author, :class_name => '::User', :foreign_key => 'author_id'
46 belongs_to :author, :class_name => '::User', :foreign_key => 'author_id'
36 attr_protected :data
47 attr_protected :data
37
48
38 acts_as_event :title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"},
49 acts_as_event :title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"},
39 :description => :comments,
50 :description => :comments,
40 :datetime => :updated_on,
51 :datetime => :updated_on,
41 :type => 'wiki-page',
52 :type => 'wiki-page',
42 :url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}}
53 :url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}}
43
54
44 acts_as_activity_provider :type => 'wiki_edits',
55 acts_as_activity_provider :type => 'wiki_edits',
45 :timestamp => "#{WikiContent.versioned_table_name}.updated_on",
56 :timestamp => "#{WikiContent.versioned_table_name}.updated_on",
46 :author_key => "#{WikiContent.versioned_table_name}.author_id",
57 :author_key => "#{WikiContent.versioned_table_name}.author_id",
47 :permission => :view_wiki_edits,
58 :permission => :view_wiki_edits,
48 :find_options => {:select => "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " +
59 :find_options => {:select => "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " +
49 "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " +
60 "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " +
50 "#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " +
61 "#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " +
51 "#{WikiContent.versioned_table_name}.id",
62 "#{WikiContent.versioned_table_name}.id",
52 :joins => "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
63 :joins => "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
53 "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
64 "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
54 "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"}
65 "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"}
55
66
56 def text=(plain)
67 def text=(plain)
57 case Setting.wiki_compression
68 case Setting.wiki_compression
58 when 'gzip'
69 when 'gzip'
59 begin
70 begin
60 self.data = Zlib::Deflate.deflate(plain, Zlib::BEST_COMPRESSION)
71 self.data = Zlib::Deflate.deflate(plain, Zlib::BEST_COMPRESSION)
61 self.compression = 'gzip'
72 self.compression = 'gzip'
62 rescue
73 rescue
63 self.data = plain
74 self.data = plain
64 self.compression = ''
75 self.compression = ''
65 end
76 end
66 else
77 else
67 self.data = plain
78 self.data = plain
68 self.compression = ''
79 self.compression = ''
69 end
80 end
70 plain
81 plain
71 end
82 end
72
83
73 def text
84 def text
74 @text ||= case compression
85 @text ||= case compression
75 when 'gzip'
86 when 'gzip'
76 Zlib::Inflate.inflate(data)
87 Zlib::Inflate.inflate(data)
77 else
88 else
78 # uncompressed data
89 # uncompressed data
79 data
90 data
80 end
91 end
81 end
92 end
82
93
83 def project
94 def project
84 page.project
95 page.project
85 end
96 end
86
97
87 # Returns the previous version or nil
98 # Returns the previous version or nil
88 def previous
99 def previous
89 @previous ||= WikiContent::Version.find(:first,
100 @previous ||= WikiContent::Version.find(:first,
90 :order => 'version DESC',
101 :order => 'version DESC',
91 :include => :author,
102 :include => :author,
92 :conditions => ["wiki_content_id = ? AND version < ?", wiki_content_id, version])
103 :conditions => ["wiki_content_id = ? AND version < ?", wiki_content_id, version])
93 end
104 end
94 end
105 end
95 end
106 end
@@ -1,259 +1,299
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, :issues, :users, :members, :member_roles, :documents, :attachments, :news, :tokens, :journals, :journal_details, :changesets, :trackers, :issue_statuses, :enumerations, :messages, :boards, :repositories
23 fixtures :projects, :issues, :users, :members, :member_roles, :documents, :attachments, :news, :tokens, :journals, :journal_details, :changesets, :trackers, :issue_statuses, :enumerations, :messages, :boards, :repositories
24
24
25 def test_generated_links_in_emails
25 def test_generated_links_in_emails
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 = 'https'
28 Setting.protocol = 'https'
29
29
30 journal = Journal.find(2)
30 journal = Journal.find(2)
31 assert Mailer.deliver_issue_edit(journal)
31 assert Mailer.deliver_issue_edit(journal)
32
32
33 mail = ActionMailer::Base.deliveries.last
33 mail = ActionMailer::Base.deliveries.last
34 assert_kind_of TMail::Mail, mail
34 assert_kind_of TMail::Mail, mail
35
35
36 assert_select_email do
36 assert_select_email do
37 # link to the main ticket
37 # link to the main ticket
38 assert_select "a[href=?]", "https://mydomain.foo/issues/1", :text => "Bug #1: Can't print recipes"
38 assert_select "a[href=?]", "https://mydomain.foo/issues/1", :text => "Bug #1: Can't print recipes"
39 # link to a referenced ticket
39 # link to a referenced ticket
40 assert_select "a[href=?][title=?]", "https://mydomain.foo/issues/2", "Add ingredients categories (Assigned)", :text => "#2"
40 assert_select "a[href=?][title=?]", "https://mydomain.foo/issues/2", "Add ingredients categories (Assigned)", :text => "#2"
41 # link to a changeset
41 # link to a changeset
42 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"
42 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"
43 end
43 end
44 end
44 end
45
45
46 def test_generated_links_with_prefix
46 def test_generated_links_with_prefix
47 relative_url_root = Redmine::Utils.relative_url_root
47 relative_url_root = Redmine::Utils.relative_url_root
48 ActionMailer::Base.deliveries.clear
48 ActionMailer::Base.deliveries.clear
49 Setting.host_name = 'mydomain.foo/rdm'
49 Setting.host_name = 'mydomain.foo/rdm'
50 Setting.protocol = 'http'
50 Setting.protocol = 'http'
51 Redmine::Utils.relative_url_root = '/rdm'
51 Redmine::Utils.relative_url_root = '/rdm'
52
52
53 journal = Journal.find(2)
53 journal = Journal.find(2)
54 assert Mailer.deliver_issue_edit(journal)
54 assert Mailer.deliver_issue_edit(journal)
55
55
56 mail = ActionMailer::Base.deliveries.last
56 mail = ActionMailer::Base.deliveries.last
57 assert_kind_of TMail::Mail, mail
57 assert_kind_of TMail::Mail, mail
58
58
59 assert_select_email do
59 assert_select_email do
60 # link to the main ticket
60 # link to the main ticket
61 assert_select "a[href=?]", "http://mydomain.foo/rdm/issues/1", :text => "Bug #1: Can't print recipes"
61 assert_select "a[href=?]", "http://mydomain.foo/rdm/issues/1", :text => "Bug #1: Can't print recipes"
62 # link to a referenced ticket
62 # link to a referenced ticket
63 assert_select "a[href=?][title=?]", "http://mydomain.foo/rdm/issues/2", "Add ingredients categories (Assigned)", :text => "#2"
63 assert_select "a[href=?][title=?]", "http://mydomain.foo/rdm/issues/2", "Add ingredients categories (Assigned)", :text => "#2"
64 # link to a changeset
64 # link to a changeset
65 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"
65 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"
66 end
66 end
67 ensure
67 ensure
68 # restore it
68 # restore it
69 Redmine::Utils.relative_url_root = relative_url_root
69 Redmine::Utils.relative_url_root = relative_url_root
70 end
70 end
71
71
72 def test_generated_links_with_prefix_and_no_relative_url_root
72 def test_generated_links_with_prefix_and_no_relative_url_root
73 relative_url_root = Redmine::Utils.relative_url_root
73 relative_url_root = Redmine::Utils.relative_url_root
74 ActionMailer::Base.deliveries.clear
74 ActionMailer::Base.deliveries.clear
75 Setting.host_name = 'mydomain.foo/rdm'
75 Setting.host_name = 'mydomain.foo/rdm'
76 Setting.protocol = 'http'
76 Setting.protocol = 'http'
77 Redmine::Utils.relative_url_root = nil
77 Redmine::Utils.relative_url_root = nil
78
78
79 journal = Journal.find(2)
79 journal = Journal.find(2)
80 assert Mailer.deliver_issue_edit(journal)
80 assert Mailer.deliver_issue_edit(journal)
81
81
82 mail = ActionMailer::Base.deliveries.last
82 mail = ActionMailer::Base.deliveries.last
83 assert_kind_of TMail::Mail, mail
83 assert_kind_of TMail::Mail, mail
84
84
85 assert_select_email do
85 assert_select_email do
86 # link to the main ticket
86 # link to the main ticket
87 assert_select "a[href=?]", "http://mydomain.foo/rdm/issues/1", :text => "Bug #1: Can't print recipes"
87 assert_select "a[href=?]", "http://mydomain.foo/rdm/issues/1", :text => "Bug #1: Can't print recipes"
88 # link to a referenced ticket
88 # link to a referenced ticket
89 assert_select "a[href=?][title=?]", "http://mydomain.foo/rdm/issues/2", "Add ingredients categories (Assigned)", :text => "#2"
89 assert_select "a[href=?][title=?]", "http://mydomain.foo/rdm/issues/2", "Add ingredients categories (Assigned)", :text => "#2"
90 # link to a changeset
90 # link to a changeset
91 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"
91 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"
92 end
92 end
93 ensure
93 ensure
94 # restore it
94 # restore it
95 Redmine::Utils.relative_url_root = relative_url_root
95 Redmine::Utils.relative_url_root = relative_url_root
96 end
96 end
97
97
98 def test_email_headers
98 def test_email_headers
99 ActionMailer::Base.deliveries.clear
99 ActionMailer::Base.deliveries.clear
100 issue = Issue.find(1)
100 issue = Issue.find(1)
101 Mailer.deliver_issue_add(issue)
101 Mailer.deliver_issue_add(issue)
102 mail = ActionMailer::Base.deliveries.last
102 mail = ActionMailer::Base.deliveries.last
103 assert_not_nil mail
103 assert_not_nil mail
104 assert_equal 'bulk', mail.header_string('Precedence')
104 assert_equal 'bulk', mail.header_string('Precedence')
105 assert_equal 'auto-generated', mail.header_string('Auto-Submitted')
105 assert_equal 'auto-generated', mail.header_string('Auto-Submitted')
106 end
106 end
107
107
108 def test_plain_text_mail
108 def test_plain_text_mail
109 Setting.plain_text_mail = 1
109 Setting.plain_text_mail = 1
110 journal = Journal.find(2)
110 journal = Journal.find(2)
111 Mailer.deliver_issue_edit(journal)
111 Mailer.deliver_issue_edit(journal)
112 mail = ActionMailer::Base.deliveries.last
112 mail = ActionMailer::Base.deliveries.last
113 assert_equal "text/plain", mail.content_type
113 assert_equal "text/plain", mail.content_type
114 assert_equal 0, mail.parts.size
114 assert_equal 0, mail.parts.size
115 assert !mail.encoded.include?('href')
115 assert !mail.encoded.include?('href')
116 end
116 end
117
117
118 def test_html_mail
118 def test_html_mail
119 Setting.plain_text_mail = 0
119 Setting.plain_text_mail = 0
120 journal = Journal.find(2)
120 journal = Journal.find(2)
121 Mailer.deliver_issue_edit(journal)
121 Mailer.deliver_issue_edit(journal)
122 mail = ActionMailer::Base.deliveries.last
122 mail = ActionMailer::Base.deliveries.last
123 assert_equal 2, mail.parts.size
123 assert_equal 2, mail.parts.size
124 assert mail.encoded.include?('href')
124 assert mail.encoded.include?('href')
125 end
125 end
126
126
127 def test_issue_add_message_id
127 def test_issue_add_message_id
128 ActionMailer::Base.deliveries.clear
128 ActionMailer::Base.deliveries.clear
129 issue = Issue.find(1)
129 issue = Issue.find(1)
130 Mailer.deliver_issue_add(issue)
130 Mailer.deliver_issue_add(issue)
131 mail = ActionMailer::Base.deliveries.last
131 mail = ActionMailer::Base.deliveries.last
132 assert_not_nil mail
132 assert_not_nil mail
133 assert_equal Mailer.message_id_for(issue), mail.message_id
133 assert_equal Mailer.message_id_for(issue), mail.message_id
134 assert_nil mail.references
134 assert_nil mail.references
135 end
135 end
136
136
137 def test_issue_edit_message_id
137 def test_issue_edit_message_id
138 ActionMailer::Base.deliveries.clear
138 ActionMailer::Base.deliveries.clear
139 journal = Journal.find(1)
139 journal = Journal.find(1)
140 Mailer.deliver_issue_edit(journal)
140 Mailer.deliver_issue_edit(journal)
141 mail = ActionMailer::Base.deliveries.last
141 mail = ActionMailer::Base.deliveries.last
142 assert_not_nil mail
142 assert_not_nil mail
143 assert_equal Mailer.message_id_for(journal), mail.message_id
143 assert_equal Mailer.message_id_for(journal), mail.message_id
144 assert_equal Mailer.message_id_for(journal.issue), mail.references.first.to_s
144 assert_equal Mailer.message_id_for(journal.issue), mail.references.first.to_s
145 end
145 end
146
146
147 def test_message_posted_message_id
147 def test_message_posted_message_id
148 ActionMailer::Base.deliveries.clear
148 ActionMailer::Base.deliveries.clear
149 message = Message.find(1)
149 message = Message.find(1)
150 Mailer.deliver_message_posted(message, message.author.mail)
150 Mailer.deliver_message_posted(message)
151 mail = ActionMailer::Base.deliveries.last
151 mail = ActionMailer::Base.deliveries.last
152 assert_not_nil mail
152 assert_not_nil mail
153 assert_equal Mailer.message_id_for(message), mail.message_id
153 assert_equal Mailer.message_id_for(message), mail.message_id
154 assert_nil mail.references
154 assert_nil mail.references
155 end
155 end
156
156
157 def test_reply_posted_message_id
157 def test_reply_posted_message_id
158 ActionMailer::Base.deliveries.clear
158 ActionMailer::Base.deliveries.clear
159 message = Message.find(3)
159 message = Message.find(3)
160 Mailer.deliver_message_posted(message, message.author.mail)
160 Mailer.deliver_message_posted(message)
161 mail = ActionMailer::Base.deliveries.last
161 mail = ActionMailer::Base.deliveries.last
162 assert_not_nil mail
162 assert_not_nil mail
163 assert_equal Mailer.message_id_for(message), mail.message_id
163 assert_equal Mailer.message_id_for(message), mail.message_id
164 assert_equal Mailer.message_id_for(message.parent), mail.references.first.to_s
164 assert_equal Mailer.message_id_for(message.parent), mail.references.first.to_s
165 end
165 end
166
166
167 context("#issue_add") do
168 setup do
169 ActionMailer::Base.deliveries.clear
170 Setting.bcc_recipients = '1'
171 @issue = Issue.find(1)
172 end
173
174 should "notify project members" do
175 assert Mailer.deliver_issue_add(@issue)
176 assert last_email.bcc.include?('dlopper@somenet.foo')
177 end
178
179 should "not notify project members that are not allow to view the issue" do
180 Role.find(2).remove_permission!(:view_issues)
181 assert Mailer.deliver_issue_add(@issue)
182 assert !last_email.bcc.include?('dlopper@somenet.foo')
183 end
184
185 should "notify issue watchers" do
186 user = User.find(9)
187 Watcher.create!(:watchable => @issue, :user => user)
188 assert Mailer.deliver_issue_add(@issue)
189 assert last_email.bcc.include?(user.mail)
190 end
191
192 should "not notify watchers not allowed to view the issue" do
193 user = User.find(9)
194 Watcher.create!(:watchable => @issue, :user => user)
195 Role.non_member.remove_permission!(:view_issues)
196 assert Mailer.deliver_issue_add(@issue)
197 assert !last_email.bcc.include?(user.mail)
198 end
199 end
200
167 # test mailer methods for each language
201 # test mailer methods for each language
168 def test_issue_add
202 def test_issue_add
169 issue = Issue.find(1)
203 issue = Issue.find(1)
170 valid_languages.each do |lang|
204 valid_languages.each do |lang|
171 Setting.default_language = lang.to_s
205 Setting.default_language = lang.to_s
172 assert Mailer.deliver_issue_add(issue)
206 assert Mailer.deliver_issue_add(issue)
173 end
207 end
174 end
208 end
175
209
176 def test_issue_edit
210 def test_issue_edit
177 journal = Journal.find(1)
211 journal = Journal.find(1)
178 valid_languages.each do |lang|
212 valid_languages.each do |lang|
179 Setting.default_language = lang.to_s
213 Setting.default_language = lang.to_s
180 assert Mailer.deliver_issue_edit(journal)
214 assert Mailer.deliver_issue_edit(journal)
181 end
215 end
182 end
216 end
183
217
184 def test_document_added
218 def test_document_added
185 document = Document.find(1)
219 document = Document.find(1)
186 valid_languages.each do |lang|
220 valid_languages.each do |lang|
187 Setting.default_language = lang.to_s
221 Setting.default_language = lang.to_s
188 assert Mailer.deliver_document_added(document)
222 assert Mailer.deliver_document_added(document)
189 end
223 end
190 end
224 end
191
225
192 def test_attachments_added
226 def test_attachments_added
193 attachements = [ Attachment.find_by_container_type('Document') ]
227 attachements = [ Attachment.find_by_container_type('Document') ]
194 valid_languages.each do |lang|
228 valid_languages.each do |lang|
195 Setting.default_language = lang.to_s
229 Setting.default_language = lang.to_s
196 assert Mailer.deliver_attachments_added(attachements)
230 assert Mailer.deliver_attachments_added(attachements)
197 end
231 end
198 end
232 end
199
233
200 def test_news_added
234 def test_news_added
201 news = News.find(:first)
235 news = News.find(:first)
202 valid_languages.each do |lang|
236 valid_languages.each do |lang|
203 Setting.default_language = lang.to_s
237 Setting.default_language = lang.to_s
204 assert Mailer.deliver_news_added(news)
238 assert Mailer.deliver_news_added(news)
205 end
239 end
206 end
240 end
207
241
208 def test_message_posted
242 def test_message_posted
209 message = Message.find(:first)
243 message = Message.find(:first)
210 recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author}
244 recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author}
211 recipients = recipients.compact.uniq
245 recipients = recipients.compact.uniq
212 valid_languages.each do |lang|
246 valid_languages.each do |lang|
213 Setting.default_language = lang.to_s
247 Setting.default_language = lang.to_s
214 assert Mailer.deliver_message_posted(message, recipients)
248 assert Mailer.deliver_message_posted(message)
215 end
249 end
216 end
250 end
217
251
218 def test_account_information
252 def test_account_information
219 user = User.find(:first)
253 user = User.find(:first)
220 valid_languages.each do |lang|
254 valid_languages.each do |lang|
221 user.update_attribute :language, lang.to_s
255 user.update_attribute :language, lang.to_s
222 user.reload
256 user.reload
223 assert Mailer.deliver_account_information(user, 'pAsswORd')
257 assert Mailer.deliver_account_information(user, 'pAsswORd')
224 end
258 end
225 end
259 end
226
260
227 def test_lost_password
261 def test_lost_password
228 token = Token.find(2)
262 token = Token.find(2)
229 valid_languages.each do |lang|
263 valid_languages.each do |lang|
230 token.user.update_attribute :language, lang.to_s
264 token.user.update_attribute :language, lang.to_s
231 token.reload
265 token.reload
232 assert Mailer.deliver_lost_password(token)
266 assert Mailer.deliver_lost_password(token)
233 end
267 end
234 end
268 end
235
269
236 def test_register
270 def test_register
237 token = Token.find(1)
271 token = Token.find(1)
238 Setting.host_name = 'redmine.foo'
272 Setting.host_name = 'redmine.foo'
239 Setting.protocol = 'https'
273 Setting.protocol = 'https'
240
274
241 valid_languages.each do |lang|
275 valid_languages.each do |lang|
242 token.user.update_attribute :language, lang.to_s
276 token.user.update_attribute :language, lang.to_s
243 token.reload
277 token.reload
244 ActionMailer::Base.deliveries.clear
278 ActionMailer::Base.deliveries.clear
245 assert Mailer.deliver_register(token)
279 assert Mailer.deliver_register(token)
246 mail = ActionMailer::Base.deliveries.last
280 mail = ActionMailer::Base.deliveries.last
247 assert mail.body.include?("https://redmine.foo/account/activate?token=#{token.value}")
281 assert mail.body.include?("https://redmine.foo/account/activate?token=#{token.value}")
248 end
282 end
249 end
283 end
250
284
251 def test_reminders
285 def test_reminders
252 ActionMailer::Base.deliveries.clear
286 ActionMailer::Base.deliveries.clear
253 Mailer.reminders(:days => 42)
287 Mailer.reminders(:days => 42)
254 assert_equal 1, ActionMailer::Base.deliveries.size
288 assert_equal 1, ActionMailer::Base.deliveries.size
255 mail = ActionMailer::Base.deliveries.last
289 mail = ActionMailer::Base.deliveries.last
256 assert mail.bcc.include?('dlopper@somenet.foo')
290 assert mail.bcc.include?('dlopper@somenet.foo')
257 assert mail.body.include?('Bug #3: Error 281 when updating a recipe')
291 assert mail.body.include?('Bug #3: Error 281 when updating a recipe')
258 end
292 end
293
294 def last_email
295 mail = ActionMailer::Base.deliveries.last
296 assert_not_nil mail
297 mail
298 end
259 end
299 end
General Comments 0
You need to be logged in to leave comments. Login now