Coverage C0 Coverage Information - RCov

app/models/mailer.rb

Name Total Lines Lines of Code Total Coverage Code Coverage
app/models/mailer.rb 495 363
96.77%
95.59%

Key

Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.

Coverage Details

1 # Redmine - project management software
2 # Copyright (C) 2006-2014  Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
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
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 
18 class Mailer < ActionMailer::Base
19   layout 'mailer'
20   helper :application
21   helper :issues
22   helper :custom_fields
23 
24   include Redmine::I18n
25 
26   def self.default_url_options
27     { :host => Setting.host_name, :protocol => Setting.protocol }
28   end
29 
30   # Builds a mail for notifying to_users and cc_users about a new issue
31   def issue_add(issue, to_users, cc_users)
32     redmine_headers 'Project' => issue.project.identifier,
33                     'Issue-Id' => issue.id,
34                     'Issue-Author' => issue.author.login
35     redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
36     message_id issue
37     references issue
38     @author = issue.author
39     @issue = issue
40     @users = to_users + cc_users
41     @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue)
42     mail :to => to_users.map(&:mail),
43       :cc => cc_users.map(&:mail),
44       :subject => "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
45   end
46 
47   # Notifies users about a new issue
48   def self.deliver_issue_add(issue)
49     to = issue.notified_users
50     cc = issue.notified_watchers - to
51     issue.each_notification(to + cc) do |users|
52       Mailer.issue_add(issue, to & users, cc & users).deliver
53     end
54   end
55 
56   # Builds a mail for notifying to_users and cc_users about an issue update
57   def issue_edit(journal, to_users, cc_users)
58     issue = journal.journalized
59     redmine_headers 'Project' => issue.project.identifier,
60                     'Issue-Id' => issue.id,
61                     'Issue-Author' => issue.author.login
62     redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
63     message_id journal
64     references issue
65     @author = journal.user
66     s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
67     s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
68     s << issue.subject
69     @issue = issue
70     @users = to_users + cc_users
71     @journal = journal
72     @journal_details = journal.visible_details(@users.first)
73     @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
74     mail :to => to_users.map(&:mail),
75       :cc => cc_users.map(&:mail),
76       :subject => s
77   end
78 
79   # Notifies users about an issue update
80   def self.deliver_issue_edit(journal)
81     issue = journal.journalized.reload
82     to = journal.notified_users
83     cc = journal.notified_watchers - to
84     journal.each_notification(to + cc) do |users|
85       issue.each_notification(users) do |users2|
86         Mailer.issue_edit(journal, to & users2, cc & users2).deliver
87       end
88     end
89   end
90 
91   def reminder(user, issues, days)
92     set_language_if_valid user.language
93     @issues = issues
94     @days = days
95     @issues_url = url_for(:controller => 'issues', :action => 'index',
96                                 :set_filter => 1, :assigned_to_id => user.id,
97                                 :sort => 'due_date:asc')
98     mail :to => user.mail,
99       :subject => l(:mail_subject_reminder, :count => issues.size, :days => days)
100   end
101 
102   # Builds a Mail::Message object used to email users belonging to the added document's project.
103   #
104   # Example:
105   #   document_added(document) => Mail::Message object
106   #   Mailer.document_added(document).deliver => sends an email to the document's project recipients
107   def document_added(document)
108     redmine_headers 'Project' => document.project.identifier
109     @author = User.current
110     @document = document
111     @document_url = url_for(:controller => 'documents', :action => 'show', :id => document)
112     mail :to => document.recipients,
113       :subject => "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
114   end
115 
116   # Builds a Mail::Message object used to email recipients of a project when an attachements are added.
117   #
118   # Example:
119   #   attachments_added(attachments) => Mail::Message object
120   #   Mailer.attachments_added(attachments).deliver => sends an email to the project's recipients
121   def attachments_added(attachments)
122     container = attachments.first.container
123     added_to = ''
124     added_to_url = ''
125     @author = attachments.first.author
126     case container.class.name
127     when 'Project'
128       added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
129       added_to = "#{l(:label_project)}: #{container}"
130       recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect  {|u| u.mail}
131     when 'Version'
132       added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
133       added_to = "#{l(:label_version)}: #{container.name}"
134       recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect  {|u| u.mail}
135     when 'Document'
136       added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
137       added_to = "#{l(:label_document)}: #{container.title}"
138       recipients = container.recipients
139     end
140     redmine_headers 'Project' => container.project.identifier
141     @attachments = attachments
142     @added_to = added_to
143     @added_to_url = added_to_url
144     mail :to => recipients,
145       :subject => "[#{container.project.name}] #{l(:label_attachment_new)}"
146   end
147 
148   # Builds a Mail::Message object used to email recipients of a news' project when a news item is added.
149   #
150   # Example:
151   #   news_added(news) => Mail::Message object
152   #   Mailer.news_added(news).deliver => sends an email to the news' project recipients
153   def news_added(news)
154     redmine_headers 'Project' => news.project.identifier
155     @author = news.author
156     message_id news
157     references news
158     @news = news
159     @news_url = url_for(:controller => 'news', :action => 'show', :id => news)
160     mail :to => news.recipients,
161       :cc => news.cc_for_added_news,
162       :subject => "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
163   end
164 
165   # Builds a Mail::Message object used to email recipients of a news' project when a news comment is added.
166   #
167   # Example:
168   #   news_comment_added(comment) => Mail::Message object
169   #   Mailer.news_comment_added(comment) => sends an email to the news' project recipients
170   def news_comment_added(comment)
171     news = comment.commented
172     redmine_headers 'Project' => news.project.identifier
173     @author = comment.author
174     message_id comment
175     references news
176     @news = news
177     @comment = comment
178     @news_url = url_for(:controller => 'news', :action => 'show', :id => news)
179     mail :to => news.recipients,
180      :cc => news.watcher_recipients,
181      :subject => "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
182   end
183 
184   # Builds a Mail::Message object used to email the recipients of the specified message that was posted.
185   #
186   # Example:
187   #   message_posted(message) => Mail::Message object
188   #   Mailer.message_posted(message).deliver => sends an email to the recipients
189   def message_posted(message)
190     redmine_headers 'Project' => message.project.identifier,
191                     'Topic-Id' => (message.parent_id || message.id)
192     @author = message.author
193     message_id message
194     references message.root
195     recipients = message.recipients
196     cc = ((message.root.watcher_recipients + message.board.watcher_recipients).uniq - recipients)
197     @message = message
198     @message_url = url_for(message.event_url)
199     mail :to => recipients,
200       :cc => cc,
201       :subject => "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
202   end
203 
204   # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was added.
205   #
206   # Example:
207   #   wiki_content_added(wiki_content) => Mail::Message object
208   #   Mailer.wiki_content_added(wiki_content).deliver => sends an email to the project's recipients
209   def wiki_content_added(wiki_content)
210     redmine_headers 'Project' => wiki_content.project.identifier,
211                     'Wiki-Page-Id' => wiki_content.page.id
212     @author = wiki_content.author
213     message_id wiki_content
214     recipients = wiki_content.recipients
215     cc = wiki_content.page.wiki.watcher_recipients - recipients
216     @wiki_content = wiki_content
217     @wiki_content_url = url_for(:controller => 'wiki', :action => 'show',
218                                       :project_id => wiki_content.project,
219                                       :id => wiki_content.page.title)
220     mail :to => recipients,
221       :cc => cc,
222       :subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
223   end
224 
225   # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was updated.
226   #
227   # Example:
228   #   wiki_content_updated(wiki_content) => Mail::Message object
229   #   Mailer.wiki_content_updated(wiki_content).deliver => sends an email to the project's recipients
230   def wiki_content_updated(wiki_content)
231     redmine_headers 'Project' => wiki_content.project.identifier,
232                     'Wiki-Page-Id' => wiki_content.page.id
233     @author = wiki_content.author
234     message_id wiki_content
235     recipients = wiki_content.recipients
236     cc = wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients
237     @wiki_content = wiki_content
238     @wiki_content_url = url_for(:controller => 'wiki', :action => 'show',
239                                       :project_id => wiki_content.project,
240                                       :id => wiki_content.page.title)
241     @wiki_diff_url = url_for(:controller => 'wiki', :action => 'diff',
242                                    :project_id => wiki_content.project, :id => wiki_content.page.title,
243                                    :version => wiki_content.version)
244     mail :to => recipients,
245       :cc => cc,
246       :subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
247   end
248 
249   # Builds a Mail::Message object used to email the specified user their account information.
250   #
251   # Example:
252   #   account_information(user, password) => Mail::Message object
253   #   Mailer.account_information(user, password).deliver => sends account information to the user
254   def account_information(user, password)
255     set_language_if_valid user.language
256     @user = user
257     @password = password
258     @login_url = url_for(:controller => 'account', :action => 'login')
259     mail :to => user.mail,
260       :subject => l(:mail_subject_register, Setting.app_title)
261   end
262 
263   # Builds a Mail::Message object used to email all active administrators of an account activation request.
264   #
265   # Example:
266   #   account_activation_request(user) => Mail::Message object
267   #   Mailer.account_activation_request(user).deliver => sends an email to all active administrators
268   def account_activation_request(user)
269     # Send the email to all active administrators
270     recipients = User.active.where(:admin => true).collect { |u| u.mail }.compact
271     @user = user
272     @url = url_for(:controller => 'users', :action => 'index',
273                          :status => User::STATUS_REGISTERED,
274                          :sort_key => 'created_on', :sort_order => 'desc')
275     mail :to => recipients,
276       :subject => l(:mail_subject_account_activation_request, Setting.app_title)
277   end
278 
279   # Builds a Mail::Message object used to email the specified user that their account was activated by an administrator.
280   #
281   # Example:
282   #   account_activated(user) => Mail::Message object
283   #   Mailer.account_activated(user).deliver => sends an email to the registered user
284   def account_activated(user)
285     set_language_if_valid user.language
286     @user = user
287     @login_url = url_for(:controller => 'account', :action => 'login')
288     mail :to => user.mail,
289       :subject => l(:mail_subject_register, Setting.app_title)
290   end
291 
292   def lost_password(token)
293     set_language_if_valid(token.user.language)
294     @token = token
295     @url = url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
296     mail :to => token.user.mail,
297       :subject => l(:mail_subject_lost_password, Setting.app_title)
298   end
299 
300   def register(token)
301     set_language_if_valid(token.user.language)
302     @token = token
303     @url = url_for(:controller => 'account', :action => 'activate', :token => token.value)
304     mail :to => token.user.mail,
305       :subject => l(:mail_subject_register, Setting.app_title)
306   end
307 
308   def test_email(user)
309     set_language_if_valid(user.language)
310     @url = url_for(:controller => 'welcome')
311     mail :to => user.mail,
312       :subject => 'Redmine test'
313   end
314 
315   # Sends reminders to issue assignees
316   # Available options:
317   # * :days     => how many days in the future to remind about (defaults to 7)
318   # * :tracker  => id of tracker for filtering issues (defaults to all trackers)
319   # * :project  => id or identifier of project to process (defaults to all projects)
320   # * :users    => array of user/group ids who should be reminded
321   def self.reminders(options={})
322     days = options[:days] || 7
323     project = options[:project] ? Project.find(options[:project]) : nil
324     tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
325     user_ids = options[:users]
326 
327     scope = Issue.open.where("#{Issue.table_name}.assigned_to_id IS NOT NULL" +
328       " AND #{Project.table_name}.status = #{Project::STATUS_ACTIVE}" +
329       " AND #{Issue.table_name}.due_date <= ?", days.day.from_now.to_date
330     )
331     scope = scope.where(:assigned_to_id => user_ids) if user_ids.present?
332     scope = scope.where(:project_id => project.id) if project
333     scope = scope.where(:tracker_id => tracker.id) if tracker
334     issues_by_assignee = scope.includes(:status, :assigned_to, :project, :tracker).
335                               group_by(&:assigned_to)
336     issues_by_assignee.keys.each do |assignee|
337       if assignee.is_a?(Group)
338         assignee.users.each do |user|
339           issues_by_assignee[user] ||= []
340           issues_by_assignee[user] += issues_by_assignee[assignee]
341         end
342       end
343     end
344 
345     issues_by_assignee.each do |assignee, issues|
346       reminder(assignee, issues, days).deliver if assignee.is_a?(User) && assignee.active?
347     end
348   end
349 
350   # Activates/desactivates email deliveries during +block+
351   def self.with_deliveries(enabled = true, &block)
352     was_enabled = ActionMailer::Base.perform_deliveries
353     ActionMailer::Base.perform_deliveries = !!enabled
354     yield
355   ensure
356     ActionMailer::Base.perform_deliveries = was_enabled
357   end
358 
359   # Sends emails synchronously in the given block
360   def self.with_synched_deliveries(&block)
361     saved_method = ActionMailer::Base.delivery_method
362     if m = saved_method.to_s.match(%r{^async_(.+)$})
363       synched_method = m[1]
364       ActionMailer::Base.delivery_method = synched_method.to_sym
365       ActionMailer::Base.send "#{synched_method}_settings=", ActionMailer::Base.send("async_#{synched_method}_settings")
366     end
367     yield
368   ensure
369     ActionMailer::Base.delivery_method = saved_method
370   end
371 
372   def mail(headers={}, &block)
373     headers.merge! 'X-Mailer' => 'Redmine',
374             'X-Redmine-Host' => Setting.host_name,
375             'X-Redmine-Site' => Setting.app_title,
376             'X-Auto-Response-Suppress' => 'OOF',
377             'Auto-Submitted' => 'auto-generated',
378             'From' => Setting.mail_from,
379             'List-Id' => "<#{Setting.mail_from.to_s.gsub('@', '.')}>"
380 
381     # Removes the author from the recipients and cc
382     # if the author does not want to receive notifications
383     # about what the author do
384     if @author && @author.logged? && @author.pref.no_self_notified
385       headers[:to].delete(@author.mail) if headers[:to].is_a?(Array)
386       headers[:cc].delete(@author.mail) if headers[:cc].is_a?(Array)
387     end
388 
389     if @author && @author.logged?
390       redmine_headers 'Sender' => @author.login
391     end
392 
393     # Blind carbon copy recipients
394     if Setting.bcc_recipients?
395       headers[:bcc] = [headers[:to], headers[:cc]].flatten.uniq.reject(&:blank?)
396       headers[:to] = nil
397       headers[:cc] = nil
398     end
399 
400     if @message_id_object
401       headers[:message_id] = "<#{self.class.message_id_for(@message_id_object)}>"
402     end
403     if @references_objects
404       headers[:references] = @references_objects.collect {|o| "<#{self.class.references_for(o)}>"}.join(' ')
405     end
406 
407     m = if block_given?
408       super headers, &block
409     else
410       super headers do |format|
411         format.text
412         format.html unless Setting.plain_text_mail?
413       end
414     end
415     set_language_if_valid @initial_language
416 
417     m
418   end
419 
420   def initialize(*args)
421     @initial_language = current_language
422     set_language_if_valid Setting.default_language
423     super
424   end
425 
426   def self.deliver_mail(mail)
427     return false if mail.to.blank? && mail.cc.blank? && mail.bcc.blank?
428     begin
429       # Log errors when raise_delivery_errors is set to false, Rails does not
430       mail.raise_delivery_errors = true
431       super
432     rescue Exception => e
433       if ActionMailer::Base.raise_delivery_errors
434         raise e
435       else
436         Rails.logger.error "Email delivery error: #{e.message}"
437       end
438     end
439   end
440 
441   def self.method_missing(method, *args, &block)
442     if m = method.to_s.match(%r{^deliver_(.+)$})
443       ActiveSupport::Deprecation.warn "Mailer.deliver_#{m[1]}(*args) is deprecated. Use Mailer.#{m[1]}(*args).deliver instead."
444       send(m[1], *args).deliver
445     else
446       super
447     end
448   end
449 
450   private
451 
452   # Appends a Redmine header field (name is prepended with 'X-Redmine-')
453   def redmine_headers(h)
454     h.each { |k,v| headers["X-Redmine-#{k}"] = v.to_s }
455   end
456 
457   def self.token_for(object, rand=true)
458     timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
459     hash = [
460       "redmine",
461       "#{object.class.name.demodulize.underscore}-#{object.id}",
462       timestamp.strftime("%Y%m%d%H%M%S")
463     ]
464     if rand
465       hash << Redmine::Utils.random_hex(8)
466     end
467     host = Setting.mail_from.to_s.strip.gsub(%r{^.*@|>}, '')
468     host = "#{::Socket.gethostname}.redmine" if host.empty?
469     "#{hash.join('.')}@#{host}"
470   end
471 
472   # Returns a Message-Id for the given object
473   def self.message_id_for(object)
474     token_for(object, true)
475   end
476 
477   # Returns a uniq token for a given object referenced by all notifications
478   # related to this object
479   def self.references_for(object)
480     token_for(object, false)
481   end
482 
483   def message_id(object)
484     @message_id_object = object
485   end
486 
487   def references(object)
488     @references_objects ||= []
489     @references_objects << object
490   end
491 
492   def mylogger
493     Rails.logger
494   end
495 end

Generated on Wed Oct 22 05:08:51 +0200 2014 with rcov 1.0.0