To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / app / models / mailer.rb @ 1591:63650ae64bf2

History | View | Annotate | Download (19.9 KB)

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 the specified member that they were
31
  # added to a project
32
  def member_added_to_project(member, project)
33

    
34
    principal = Principal.find(member.user_id)
35

    
36
    users = []
37
    if principal.type == "User"
38
      users = [User.find(member.user_id)]
39
    else
40
      users = Principal.find(member.user_id).users      
41
    end
42

    
43
    users.map do |user|
44

    
45
      set_language_if_valid user.language
46
      @project_url = url_for(:controller => 'projects', :action => 'show', :id => project.id)
47
      @project_name = project.name
48
      mail :to => user.mail,
49
        :subject => l(:mail_subject_added_to_project, Setting.app_title)
50

    
51
    end
52
  end
53
  
54
  # Builds a mail for notifying to_users and cc_users about a new issue
55
  def issue_add(issue, to_users, cc_users)
56
    redmine_headers 'Project' => issue.project.identifier,
57
                    'Issue-Id' => issue.id,
58
                    'Issue-Author' => issue.author.login
59
    redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
60
    message_id issue
61
    references issue
62
    @author = issue.author
63
    @issue = issue
64
    @users = to_users + cc_users
65
    @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue)
66
    mail :to => to_users.map(&:mail),
67
      :cc => cc_users.map(&:mail),
68
      :subject => "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
69
  end
70

    
71
  # Notifies users about a new issue
72
  def self.deliver_issue_add(issue)
73
    to = issue.notified_users
74
    cc = issue.notified_watchers - to
75
    issue.each_notification(to + cc) do |users|
76
      Mailer.issue_add(issue, to & users, cc & users).deliver
77
    end
78
  end
79

    
80
  # Builds a mail for notifying to_users and cc_users about an issue update
81
  def issue_edit(journal, to_users, cc_users)
82
    issue = journal.journalized
83
    redmine_headers 'Project' => issue.project.identifier,
84
                    'Issue-Id' => issue.id,
85
                    'Issue-Author' => issue.author.login
86
    redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
87
    message_id journal
88
    references issue
89
    @author = journal.user
90
    s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
91
    s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
92
    s << issue.subject
93
    @issue = issue
94
    @users = to_users + cc_users
95
    @journal = journal
96
    @journal_details = journal.visible_details(@users.first)
97
    @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
98
    mail :to => to_users.map(&:mail),
99
      :cc => cc_users.map(&:mail),
100
      :subject => s
101
  end
102

    
103
  # Notifies users about an issue update
104
  def self.deliver_issue_edit(journal)
105
    issue = journal.journalized.reload
106
    to = journal.notified_users
107
    cc = journal.notified_watchers - to
108
    journal.each_notification(to + cc) do |users|
109
      issue.each_notification(users) do |users2|
110
        Mailer.issue_edit(journal, to & users2, cc & users2).deliver
111
      end
112
    end
113
  end
114

    
115
  def reminder(user, issues, days)
116
    set_language_if_valid user.language
117
    @issues = issues
118
    @days = days
119
    @issues_url = url_for(:controller => 'issues', :action => 'index',
120
                                :set_filter => 1, :assigned_to_id => user.id,
121
                                :sort => 'due_date:asc')
122
    mail :to => user.mail,
123
      :subject => l(:mail_subject_reminder, :count => issues.size, :days => days)
124
  end
125

    
126
  # Builds a Mail::Message object used to email users belonging to the added document's project.
127
  #
128
  # Example:
129
  #   document_added(document) => Mail::Message object
130
  #   Mailer.document_added(document).deliver => sends an email to the document's project recipients
131
  def document_added(document)
132
    redmine_headers 'Project' => document.project.identifier
133
    @author = User.current
134
    @document = document
135
    @document_url = url_for(:controller => 'documents', :action => 'show', :id => document)
136
    mail :to => document.recipients,
137
      :subject => "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
138
  end
139

    
140
  # Builds a Mail::Message object used to email recipients of a project when an attachements are added.
141
  #
142
  # Example:
143
  #   attachments_added(attachments) => Mail::Message object
144
  #   Mailer.attachments_added(attachments).deliver => sends an email to the project's recipients
145
  def attachments_added(attachments)
146
    container = attachments.first.container
147
    added_to = ''
148
    added_to_url = ''
149
    @author = attachments.first.author
150
    case container.class.name
151
    when 'Project'
152
      added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
153
      added_to = "#{l(:label_project)}: #{container}"
154
      recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect  {|u| u.mail}
155
    when 'Version'
156
      added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
157
      added_to = "#{l(:label_version)}: #{container.name}"
158
      recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect  {|u| u.mail}
159
    when 'Document'
160
      added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
161
      added_to = "#{l(:label_document)}: #{container.title}"
162
      recipients = container.recipients
163
    end
164
    redmine_headers 'Project' => container.project.identifier
165
    @attachments = attachments
166
    @added_to = added_to
167
    @added_to_url = added_to_url
168
    mail :to => recipients,
169
      :subject => "[#{container.project.name}] #{l(:label_attachment_new)}"
170
  end
171

    
172
  # Builds a Mail::Message object used to email recipients of a news' project when a news item is added.
173
  #
174
  # Example:
175
  #   news_added(news) => Mail::Message object
176
  #   Mailer.news_added(news).deliver => sends an email to the news' project recipients
177
  def news_added(news)
178
    redmine_headers 'Project' => news.project.identifier
179
    @author = news.author
180
    message_id news
181
    references news
182
    @news = news
183
    @news_url = url_for(:controller => 'news', :action => 'show', :id => news)
184
    mail :to => news.recipients,
185
      :cc => news.cc_for_added_news,
186
      :subject => "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
187
  end
188

    
189
  # Builds a Mail::Message object used to email recipients of a news' project when a news comment is added.
190
  #
191
  # Example:
192
  #   news_comment_added(comment) => Mail::Message object
193
  #   Mailer.news_comment_added(comment) => sends an email to the news' project recipients
194
  def news_comment_added(comment)
195
    news = comment.commented
196
    redmine_headers 'Project' => news.project.identifier
197
    @author = comment.author
198
    message_id comment
199
    references news
200
    @news = news
201
    @comment = comment
202
    @news_url = url_for(:controller => 'news', :action => 'show', :id => news)
203
    mail :to => news.recipients,
204
     :cc => news.watcher_recipients,
205
     :subject => "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
206
  end
207

    
208
  # Builds a Mail::Message object used to email the recipients of the specified message that was posted.
209
  #
210
  # Example:
211
  #   message_posted(message) => Mail::Message object
212
  #   Mailer.message_posted(message).deliver => sends an email to the recipients
213
  def message_posted(message)
214
    redmine_headers 'Project' => message.project.identifier,
215
                    'Topic-Id' => (message.parent_id || message.id)
216
    @author = message.author
217
    message_id message
218
    references message.root
219
    recipients = message.recipients
220
    cc = ((message.root.watcher_recipients + message.board.watcher_recipients).uniq - recipients)
221
    @message = message
222
    @message_url = url_for(message.event_url)
223
    mail :to => recipients,
224
      :cc => cc,
225
      :subject => "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
226
  end
227

    
228
  # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was added.
229
  #
230
  # Example:
231
  #   wiki_content_added(wiki_content) => Mail::Message object
232
  #   Mailer.wiki_content_added(wiki_content).deliver => sends an email to the project's recipients
233
  def wiki_content_added(wiki_content)
234
    redmine_headers 'Project' => wiki_content.project.identifier,
235
                    'Wiki-Page-Id' => wiki_content.page.id
236
    @author = wiki_content.author
237
    message_id wiki_content
238
    recipients = wiki_content.recipients
239
    cc = wiki_content.page.wiki.watcher_recipients - recipients
240
    @wiki_content = wiki_content
241
    @wiki_content_url = url_for(:controller => 'wiki', :action => 'show',
242
                                      :project_id => wiki_content.project,
243
                                      :id => wiki_content.page.title)
244
    mail :to => recipients,
245
      :cc => cc,
246
      :subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
247
  end
248

    
249
  # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was updated.
250
  #
251
  # Example:
252
  #   wiki_content_updated(wiki_content) => Mail::Message object
253
  #   Mailer.wiki_content_updated(wiki_content).deliver => sends an email to the project's recipients
254
  def wiki_content_updated(wiki_content)
255
    redmine_headers 'Project' => wiki_content.project.identifier,
256
                    'Wiki-Page-Id' => wiki_content.page.id
257
    @author = wiki_content.author
258
    message_id wiki_content
259
    recipients = wiki_content.recipients
260
    cc = wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients
261
    @wiki_content = wiki_content
262
    @wiki_content_url = url_for(:controller => 'wiki', :action => 'show',
263
                                      :project_id => wiki_content.project,
264
                                      :id => wiki_content.page.title)
265
    @wiki_diff_url = url_for(:controller => 'wiki', :action => 'diff',
266
                                   :project_id => wiki_content.project, :id => wiki_content.page.title,
267
                                   :version => wiki_content.version)
268
    mail :to => recipients,
269
      :cc => cc,
270
      :subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
271
  end
272

    
273
  # Builds a Mail::Message object used to email the specified user their account information.
274
  #
275
  # Example:
276
  #   account_information(user, password) => Mail::Message object
277
  #   Mailer.account_information(user, password).deliver => sends account information to the user
278
  def account_information(user, password)
279
    set_language_if_valid user.language
280
    @user = user
281
    @password = password
282
    @login_url = url_for(:controller => 'account', :action => 'login')
283
    mail :to => user.mail,
284
      :subject => l(:mail_subject_register, Setting.app_title)
285
  end
286

    
287
  # Builds a Mail::Message object used to email all active administrators of an account activation request.
288
  #
289
  # Example:
290
  #   account_activation_request(user) => Mail::Message object
291
  #   Mailer.account_activation_request(user).deliver => sends an email to all active administrators
292
  def account_activation_request(user)
293
    # Send the email to all active administrators
294
    recipients = User.active.where(:admin => true).collect { |u| u.mail }.compact
295
    @user = user
296
    @url = url_for(:controller => 'users', :action => 'index',
297
                         :status => User::STATUS_REGISTERED,
298
                         :sort_key => 'created_on', :sort_order => 'desc')
299
    mail :to => recipients,
300
      :subject => l(:mail_subject_account_activation_request, Setting.app_title)
301
  end
302

    
303
  # Builds a Mail::Message object used to email the specified user that their account was activated by an administrator.
304
  #
305
  # Example:
306
  #   account_activated(user) => Mail::Message object
307
  #   Mailer.account_activated(user).deliver => sends an email to the registered user
308
  def account_activated(user)
309
    set_language_if_valid user.language
310
    @user = user
311
    @login_url = url_for(:controller => 'account', :action => 'login')
312
    mail :to => user.mail,
313
      :subject => l(:mail_subject_register, Setting.app_title)
314
  end
315

    
316
  def lost_password(token)
317
    set_language_if_valid(token.user.language)
318
    @token = token
319
    @url = url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
320
    mail :to => token.user.mail,
321
      :subject => l(:mail_subject_lost_password, Setting.app_title)
322
  end
323

    
324
  def register(token)
325
    set_language_if_valid(token.user.language)
326
    @token = token
327
    @url = url_for(:controller => 'account', :action => 'activate', :token => token.value)
328
    mail :to => token.user.mail,
329
      :subject => l(:mail_subject_register, Setting.app_title)
330
  end
331

    
332
  def test_email(user)
333
    set_language_if_valid(user.language)
334
    @url = url_for(:controller => 'welcome')
335
    mail :to => user.mail,
336
      :subject => 'Redmine test'
337
  end
338

    
339
  # Sends reminders to issue assignees
340
  # Available options:
341
  # * :days     => how many days in the future to remind about (defaults to 7)
342
  # * :tracker  => id of tracker for filtering issues (defaults to all trackers)
343
  # * :project  => id or identifier of project to process (defaults to all projects)
344
  # * :users    => array of user/group ids who should be reminded
345
  def self.reminders(options={})
346
    days = options[:days] || 7
347
    project = options[:project] ? Project.find(options[:project]) : nil
348
    tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
349
    user_ids = options[:users]
350

    
351
    scope = Issue.open.where("#{Issue.table_name}.assigned_to_id IS NOT NULL" +
352
      " AND #{Project.table_name}.status = #{Project::STATUS_ACTIVE}" +
353
      " AND #{Issue.table_name}.due_date <= ?", days.day.from_now.to_date
354
    )
355
    scope = scope.where(:assigned_to_id => user_ids) if user_ids.present?
356
    scope = scope.where(:project_id => project.id) if project
357
    scope = scope.where(:tracker_id => tracker.id) if tracker
358
    issues_by_assignee = scope.includes(:status, :assigned_to, :project, :tracker).
359
                              group_by(&:assigned_to)
360
    issues_by_assignee.keys.each do |assignee|
361
      if assignee.is_a?(Group)
362
        assignee.users.each do |user|
363
          issues_by_assignee[user] ||= []
364
          issues_by_assignee[user] += issues_by_assignee[assignee]
365
        end
366
      end
367
    end
368

    
369
    issues_by_assignee.each do |assignee, issues|
370
      reminder(assignee, issues, days).deliver if assignee.is_a?(User) && assignee.active?
371
    end
372
  end
373

    
374
  # Activates/desactivates email deliveries during +block+
375
  def self.with_deliveries(enabled = true, &block)
376
    was_enabled = ActionMailer::Base.perform_deliveries
377
    ActionMailer::Base.perform_deliveries = !!enabled
378
    yield
379
  ensure
380
    ActionMailer::Base.perform_deliveries = was_enabled
381
  end
382

    
383
  # Sends emails synchronously in the given block
384
  def self.with_synched_deliveries(&block)
385
    saved_method = ActionMailer::Base.delivery_method
386
    if m = saved_method.to_s.match(%r{^async_(.+)$})
387
      synched_method = m[1]
388
      ActionMailer::Base.delivery_method = synched_method.to_sym
389
      ActionMailer::Base.send "#{synched_method}_settings=", ActionMailer::Base.send("async_#{synched_method}_settings")
390
    end
391
    yield
392
  ensure
393
    ActionMailer::Base.delivery_method = saved_method
394
  end
395

    
396
  def mail(headers={}, &block)
397
    headers.merge! 'X-Mailer' => 'Redmine',
398
            'X-Redmine-Host' => Setting.host_name,
399
            'X-Redmine-Site' => Setting.app_title,
400
            'X-Auto-Response-Suppress' => 'OOF',
401
            'Auto-Submitted' => 'auto-generated',
402
            'From' => Setting.mail_from,
403
            'Reply-To' => Setting.mail_reply_to,
404
            'List-Id' => "<#{Setting.mail_reply_to.to_s.gsub('@', '.')}>"
405

    
406
    # Removes the author from the recipients and cc
407
    # if the author does not want to receive notifications
408
    # about what the author do
409
    if @author && @author.logged? && @author.pref.no_self_notified
410
      headers[:to].delete(@author.mail) if headers[:to].is_a?(Array)
411
      headers[:cc].delete(@author.mail) if headers[:cc].is_a?(Array)
412
    end
413

    
414
    if @author && @author.logged?
415
      redmine_headers 'Sender' => @author.login
416
    end
417

    
418
    # Blind carbon copy recipients
419
    if Setting.bcc_recipients?
420
      headers[:bcc] = [headers[:to], headers[:cc]].flatten.uniq.reject(&:blank?)
421
      headers[:to] = nil
422
      headers[:cc] = nil
423
    end
424

    
425
    if @message_id_object
426
      headers[:message_id] = "<#{self.class.message_id_for(@message_id_object)}>"
427
    end
428
    if @references_objects
429
      headers[:references] = @references_objects.collect {|o| "<#{self.class.references_for(o)}>"}.join(' ')
430
    end
431

    
432
    m = if block_given?
433
      super headers, &block
434
    else
435
      super headers do |format|
436
        format.text
437
        format.html unless Setting.plain_text_mail?
438
      end
439
    end
440
    set_language_if_valid @initial_language
441

    
442
    m
443
  end
444

    
445
  def initialize(*args)
446
    @initial_language = current_language
447
    set_language_if_valid Setting.default_language
448
    super
449
  end
450

    
451
  def self.deliver_mail(mail)
452
    return false if mail.to.blank? && mail.cc.blank? && mail.bcc.blank?
453
    begin
454
      # Log errors when raise_delivery_errors is set to false, Rails does not
455
      mail.raise_delivery_errors = true
456
      super
457
    rescue Exception => e
458
      if ActionMailer::Base.raise_delivery_errors
459
        raise e
460
      else
461
        Rails.logger.error "Email delivery error: #{e.message}"
462
      end
463
    end
464
  end
465

    
466
  def self.method_missing(method, *args, &block)
467
    if m = method.to_s.match(%r{^deliver_(.+)$})
468
      ActiveSupport::Deprecation.warn "Mailer.deliver_#{m[1]}(*args) is deprecated. Use Mailer.#{m[1]}(*args).deliver instead."
469
      send(m[1], *args).deliver
470
    else
471
      super
472
    end
473
  end
474

    
475
  private
476

    
477
  # Appends a Redmine header field (name is prepended with 'X-Redmine-')
478
  def redmine_headers(h)
479
    h.each { |k,v| headers["X-Redmine-#{k}"] = v.to_s }
480
  end
481

    
482
  def self.token_for(object, rand=true)
483
    timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
484
    hash = [
485
      "redmine",
486
      "#{object.class.name.demodulize.underscore}-#{object.id}",
487
      timestamp.strftime("%Y%m%d%H%M%S")
488
    ]
489
    if rand
490
      hash << Redmine::Utils.random_hex(8)
491
    end
492
    host = Setting.mail_from.to_s.strip.gsub(%r{^.*@|>}, '')
493
    host = "#{::Socket.gethostname}.redmine" if host.empty?
494
    "#{hash.join('.')}@#{host}"
495
  end
496

    
497
  # Returns a Message-Id for the given object
498
  def self.message_id_for(object)
499
    token_for(object, true)
500
  end
501

    
502
  # Returns a uniq token for a given object referenced by all notifications
503
  # related to this object
504
  def self.references_for(object)
505
    token_for(object, false)
506
  end
507

    
508
  def message_id(object)
509
    @message_id_object = object
510
  end
511

    
512
  def references(object)
513
    @references_objects ||= []
514
    @references_objects << object
515
  end
516

    
517
  def mylogger
518
    Rails.logger
519
  end
520
end
521

    
522
# Patch TMail so that message_id is not overwritten
523

    
524
### NB: Redmine 2.2 no longer uses TMail I think? This function has
525
### been removed there
526

    
527
module TMail
528
  class Mail
529
    def add_message_id( fqdn = nil )
530
      self.message_id ||= ::TMail::new_message_id(fqdn)
531
    end
532
  end
533
end
534