Project

General

Profile

Feature #26791 » 0001-Send-individual-emails-for-each-mail-recipient_v2.patch

Marius BĂLTEANU, 2018-09-30 11:22

View differences:

app/models/email_address.rb
52 52
    # in that case, the user is just being created and
53 53
    # should not receive this email.
54 54
    if user.mails != [address]
55
      deliver_security_notification(user,
55
      deliver_security_notification(
56 56
        message: :mail_body_security_notification_add,
57 57
        field: :field_mail,
58 58
        value: address
......
63 63
  # send a security notification to user that an email has been changed (notified/not notified)
64 64
  def deliver_security_notification_update
65 65
    if saved_change_to_address?
66
      recipients = [user, address_before_last_save]
67 66
      options = {
67
        recipients: [address_before_last_save],
68 68
        message: :mail_body_security_notification_change_to,
69 69
        field: :field_mail,
70 70
        value: address
71 71
      }
72 72
    elsif saved_change_to_notify?
73
      recipients = [user, address]
74 73
      options = {
74
        recipients: [address],
75 75
        message: notify_before_last_save ? :mail_body_security_notification_notify_disabled : :mail_body_security_notification_notify_enabled,
76 76
        value: address
77 77
      }
78 78
    end
79
    deliver_security_notification(recipients, options)
79
    deliver_security_notification(options)
80 80
  end
81 81

  
82 82
  # send a security notification to user that an email address was deleted
83 83
  def deliver_security_notification_destroy
84
    deliver_security_notification([user, address],
84
    deliver_security_notification(
85
      recipients: [address],
85 86
      message: :mail_body_security_notification_remove,
86 87
      field: :field_mail,
87 88
      value: address
......
89 90
  end
90 91

  
91 92
  # generic method to send security notifications for email addresses
92
  def deliver_security_notification(recipients, options={})
93
    Mailer.security_notification(recipients,
93
  def deliver_security_notification(options={})
94
    Mailer.security_notification(user,
94 95
      options.merge(
95 96
        title: :label_my_account,
96 97
        url: {controller: 'my', action: 'account'}
app/models/mailer.rb
26 26
  include Redmine::I18n
27 27
  include Roadie::Rails::Automatic
28 28

  
29
  # This class wraps multiple generated `Mail::Message` objects and allows to
30
  # deliver them all at once. It is usually used to handle multiple mails for
31
  # different receivers created by a single mail event. The wrapped mails can
32
  # then be delivered in one go.
33
  #
34
  # The public interface of the class resembles a single mail message. You can
35
  # directly use any of the deliver_* methods to send the contained messages
36
  # now or later.
37
  class MultiMessage
38
    attr_reader :mails
39

  
40
    # @param mails [Array<Mail, Proc>] an Array of mails or Procs which create
41
    #   mail objects and allow to call a method on it.
42
    def initialize(action, *args)
43
      @action = action
44
      @args = args
45

  
46
      @mails = []
47
    end
48

  
49
    def for(users)
50
      Array.wrap(users).each do |user|
51
        @mails << ActionMailer::MessageDelivery.new(Mailer, @action, user, *@args)
52
      end
53
      self
54
    end
55

  
56
    def deliver_later(options = {})
57
      enqueue_delivery :deliver_now, options
58
    end
59

  
60
    def deliver_later!(options = {})
61
      enqueue_delivery :deliver_now!, options
62
    end
63

  
64
    def processed?
65
      @mails.any?(&:processed?)
66
    end
67

  
68
    # @return [Object] the delivery method of the first mail.
69
    #   Usually, this is the very same value for all mails and matches the
70
    #   default value of the Mailer class
71
    def delivery_method
72
      (@mails.first || ActionMailer::Base::NullMail.new).delivery_method
73
    end
74

  
75
    # @return [ActionMailer::Base] the delivery handler of the first mail. This
76
    #   is always the `Mailer` class.
77
    def delivery_handler
78
      (@mails.first || ActionMailer::Base::NullMail.new).delivery_handler
79
    end
80

  
81
    private
82

  
83
    def method_missing(method, *args, &block)
84
      if method =~ /\Adeliver([_!?]|\z)/
85
        @mails.each do |mail|
86
          mail.public_send(method, *args, &block)
87
        end
88
      else
89
        super
90
      end
91
    end
92

  
93
    def respond_to_missing(method, *args)
94
      method =~ /\Adeliver([_!?]|\z)/ || method == 'processed?' || super
95
    end
96

  
97
    # This method is slightly adapted from ActionMailer::MessageDelivery
98
    def enqueue_delivery(delivery_method, options = {})
99
      if processed?
100
        ::Kernel.raise "You've accessed the message before asking to " \
101
          "deliver it later, so you may have made local changes that would " \
102
          "be silently lost if we enqueued a job to deliver it. Why? Only " \
103
          "the mailer method *arguments* are passed with the delivery job! " \
104
          "Do not access the message in any way if you mean to deliver it " \
105
          "later. Workarounds: 1. don't touch the message before calling " \
106
          "#deliver_later, 2. only touch the message *within your mailer " \
107
          "method*, or 3. use a custom Active Job instead of #deliver_later."
108
      else
109
        args = 'Mailer', @action.to_s, delivery_method.to_s, *@args
110
        ::ActionMailer::DeliveryJob.set(options).perform_later(*args)
111
      end
112
    end
113
  end
114

  
115
  def process(action, *args)
116
    user = args.shift
117
    raise ArgumentError, "First argument has to be a user, was #{user.inspect}" unless user.is_a?(User)
118

  
119
    initial_user = User.current
120
    initial_language = ::I18n.locale
121
    begin
122
      User.current = user
123

  
124
      lang = find_language(user.language) if user.logged?
125
      lang ||= Setting.default_language
126
      set_language_if_valid(lang)
127

  
128
      super(action, *args)
129
    ensure
130
      User.current = initial_user
131
      ::I18n.locale = initial_language
132
    end
133
  end
134

  
135

  
29 136
  def self.default_url_options
30 137
    options = {:protocol => Setting.protocol}
31 138
    if Setting.host_name.to_s =~ /\A(https?\:\/\/)?(.+?)(\:(\d+))?(\/.+)?\z/i
......
39 146
    options
40 147
  end
41 148

  
42
  # Builds a mail for notifying to_users and cc_users about a new issue
43
  def issue_add(issue, to_users, cc_users)
149
  # Builds a mail for notifying the current user about a new issue
150
  #
151
  # Example:
152
  #   issue_add(issue) => Mail::Message object
153
  def issue_add(issue)
44 154
    redmine_headers 'Project' => issue.project.identifier,
45 155
                    'Issue-Id' => issue.id,
46 156
                    'Issue-Author' => issue.author.login
......
49 159
    references issue
50 160
    @author = issue.author
51 161
    @issue = issue
52
    @users = to_users + cc_users
162
    @users = [User.current]
53 163
    @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue)
54
    mail :to => to_users,
55
      :cc => cc_users,
164
    mail :to => User.current,
56 165
      :subject => "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
57 166
  end
58 167

  
59 168
  # Notifies users about a new issue
169
  #
170
  # Example:
171
  #   Mailer.issue_add(journal).deliver => sends emails to the project's recipients
172
  def self.issue_add(issue)
173
    users = issue.notified_users | issue.notified_watchers
174
    MultiMessage.new(:issue_add, issue).for(users)
175
  end
176

  
177
  # Notifies users about a new issue
178
  #
179
  # Example:
180
  #   Mailer.deliver_issue_add(issue) => sends emails to the project's recipients
60 181
  def self.deliver_issue_add(issue)
61
    to = issue.notified_users
62
    cc = issue.notified_watchers - to
63
    issue.each_notification(to + cc) do |users|
64
      issue_add(issue, to & users, cc & users).deliver
65
    end
182
    issue_add(issue).deliver
66 183
  end
67 184

  
68
  # Builds a mail for notifying to_users and cc_users about an issue update
69
  def issue_edit(journal, to_users, cc_users)
185
  # Builds a mail for notifying the current user about an issue update
186
  #
187
  # Example:
188
  #   issue_edit(journal) => Mail::Message object
189
  def issue_edit(journal)
70 190
    issue = journal.journalized
71 191
    redmine_headers 'Project' => issue.project.identifier,
72 192
                    'Issue-Id' => issue.id,
......
79 199
    s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
80 200
    s << issue.subject
81 201
    @issue = issue
82
    @users = to_users + cc_users
202
    @users = [User.current]
83 203
    @journal = journal
84
    @journal_details = journal.visible_details(@users.first)
204
    @journal_details = journal.visible_details
85 205
    @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
86
    mail :to => to_users,
87
      :cc => cc_users,
206

  
207
    mail :to => User.current,
88 208
      :subject => s
89 209
  end
90 210

  
211
  # Build a MultiMessage to notify users about an issue update
212
  #
213
  # Example:
214
  #   Mailer.issue_edit(journal).deliver => sends emails to the project's recipients
215
  def self.issue_edit(journal)
216
    users  = journal.notified_users
217
    users |= journal.notified_watchers
218
    users.select! do |user|
219
      journal.notes? || journal.visible_details(user).any?
220
    end
221
    MultiMessage.new(:issue_edit, journal).for(users)
222
  end
223

  
91 224
  # Notifies users about an issue update
225
  #
226
  # Example:
227
  #   Mailer.deliver_issue_edit(journal) => sends emails to the project's recipients
92 228
  def self.deliver_issue_edit(journal)
93
    issue = journal.journalized.reload
94
    to = journal.notified_users
95
    cc = journal.notified_watchers - to
96
    journal.each_notification(to + cc) do |users|
97
      issue.each_notification(users) do |users2|
98
        issue_edit(journal, to & users2, cc & users2).deliver
99
      end
100
    end
229
    issue_edit(journal).deliver
101 230
  end
102 231

  
103
  def reminder(user, issues, days)
104
    set_language_if_valid user.language
232
  # Builds a Mail::Message object used to send en email reminder to the current
233
  # user about their due issues.
234
  #
235
  # Example:
236
  #   reminder(issues, days) => Mail::Message object
237
  def reminder(issues, days)
105 238
    @issues = issues
106 239
    @days = days
107 240
    @issues_url = url_for(:controller => 'issues', :action => 'index',
108
                                :set_filter => 1, :assigned_to_id => user.id,
241
                                :set_filter => 1, :assigned_to_id => User.current.id,
109 242
                                :sort => 'due_date:asc')
110
    mail :to => user,
243
    mail :to => User.current,
111 244
      :subject => l(:mail_subject_reminder, :count => issues.size, :days => days)
112 245
  end
113 246

  
114
  # Builds a Mail::Message object used to email users belonging to the added document's project.
247
  # Builds a Mail::Message object used to email the given user about their due
248
  # issues
249
  #
250
  # Example:
251
  #   Mailer.reminder(user, issues, days, author).deliver => sends an email to the user
252
  def self.reminder(user, issues, days)
253
    MultiMessage.new(:reminder, issues, days).for(user)
254
  end
255

  
256
  # Builds a Mail::Message object used to email the current user that a document
257
  # was added.
115 258
  #
116 259
  # Example:
117
  #   document_added(document) => Mail::Message object
118
  #   Mailer.document_added(document).deliver => sends an email to the document's project recipients
119
  def document_added(document)
260
  #   document_added(document, author) => Mail::Message object
261
  def document_added(document, author)
120 262
    redmine_headers 'Project' => document.project.identifier
121
    @author = User.current
263
    @author = author
122 264
    @document = document
123 265
    @document_url = url_for(:controller => 'documents', :action => 'show', :id => document)
124
    mail :to => document.notified_users,
266
    mail :to => User.current,
125 267
      :subject => "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
126 268
  end
127 269

  
128
  # Builds a Mail::Message object used to email recipients of a project when an attachements are added.
270
  # Build a MultiMessage to notify users about an added document.
271
  #
272
  # Example:
273
  #   Mailer.document_added(document).deliver => sends emails to the document's project recipients
274
  def self.document_added(document)
275
    users = document.notified_users
276
    MultiMessage.new(:document_added, document, User.current).for(users)
277
  end
278

  
279
  # Builds a Mail::Message object used to email the current user when
280
  # attachements are added.
129 281
  #
130 282
  # Example:
131 283
  #   attachments_added(attachments) => Mail::Message object
132
  #   Mailer.attachments_added(attachments).deliver => sends an email to the project's recipients
133 284
  def attachments_added(attachments)
134 285
    container = attachments.first.container
135 286
    added_to = ''
......
139 290
    when 'Project'
140 291
      added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
141 292
      added_to = "#{l(:label_project)}: #{container}"
142
      recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
143 293
    when 'Version'
144 294
      added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
145 295
      added_to = "#{l(:label_version)}: #{container.name}"
146
      recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
147 296
    when 'Document'
148 297
      added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
149 298
      added_to = "#{l(:label_document)}: #{container.title}"
150
      recipients = container.notified_users
151 299
    end
152 300
    redmine_headers 'Project' => container.project.identifier
153 301
    @attachments = attachments
154 302
    @added_to = added_to
155 303
    @added_to_url = added_to_url
156
    mail :to => recipients,
304
    mail :to => User.current,
157 305
      :subject => "[#{container.project.name}] #{l(:label_attachment_new)}"
158 306
  end
159 307

  
160
  # Builds a Mail::Message object used to email recipients of a news' project when a news item is added.
308
  # Build a MultiMessage to notify users about an added attachment
309
  #
310
  # Example:
311
  #   Mailer.attachments_added(attachments).deliver => sends emails to the project's recipients
312
  def self.attachments_added(attachments)
313
    container = attachments.first.container
314
    case container.class.name
315
    when 'Project', 'Version'
316
      users = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
317
    when 'Document'
318
      users = container.notified_users
319
    end
320

  
321
    MultiMessage.new(:attachments_added, attachments).for(users)
322
  end
323

  
324
  # Builds a Mail::Message object used to email the current user when a news
325
  # item is added.
161 326
  #
162 327
  # Example:
163 328
  #   news_added(news) => Mail::Message object
164
  #   Mailer.news_added(news).deliver => sends an email to the news' project recipients
165 329
  def news_added(news)
166 330
    redmine_headers 'Project' => news.project.identifier
167 331
    @author = news.author
......
169 333
    references news
170 334
    @news = news
171 335
    @news_url = url_for(:controller => 'news', :action => 'show', :id => news)
172
    mail :to => news.notified_users,
173
      :cc => news.notified_watchers_for_added_news,
336
    mail :to => User.current,
174 337
      :subject => "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
175 338
  end
176 339

  
177
  # Builds a Mail::Message object used to email recipients of a news' project when a news comment is added.
340
  # Build a MultiMessage to notify users about a new news item
341
  #
342
  # Example:
343
  #   Mailer.news_added(news).deliver => sends emails to the news' project recipients
344
  def self.news_added(news)
345
    users = news.notified_users | news.notified_watchers_for_added_news
346
    MultiMessage.new(:news_added, news).for(users)
347
  end
348

  
349
  # Builds a Mail::Message object used to email the current user when a news
350
  # comment is added.
178 351
  #
179 352
  # Example:
180 353
  #   news_comment_added(comment) => Mail::Message object
181
  #   Mailer.news_comment_added(comment) => sends an email to the news' project recipients
182 354
  def news_comment_added(comment)
183 355
    news = comment.commented
184 356
    redmine_headers 'Project' => news.project.identifier
......
188 360
    @news = news
189 361
    @comment = comment
190 362
    @news_url = url_for(:controller => 'news', :action => 'show', :id => news)
191
    mail :to => news.notified_users,
192
     :cc => news.notified_watchers,
363
    mail :to => User.current,
193 364
     :subject => "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
194 365
  end
195 366

  
196
  # Builds a Mail::Message object used to email the recipients of the specified message that was posted.
367
  # Build a MultiMessage to notify users about a new news comment
368
  #
369
  # Example:
370
  #   Mailer.news_comment_added(comment).deliver => sends emails to the news' project recipients
371
  def self.news_comment_added(comment)
372
    news = comment.commented
373
    users = news.notified_users | news.notified_watchers
374

  
375
    MultiMessage.new(:news_comment_added, comment).for(users)
376
  end
377

  
378
  # Builds a Mail::Message object used to email the current user that the
379
  # specified message was posted.
197 380
  #
198 381
  # Example:
199 382
  #   message_posted(message) => Mail::Message object
200
  #   Mailer.message_posted(message).deliver => sends an email to the recipients
201 383
  def message_posted(message)
202 384
    redmine_headers 'Project' => message.project.identifier,
203 385
                    'Topic-Id' => (message.parent_id || message.id)
204 386
    @author = message.author
205 387
    message_id message
206 388
    references message.root
207
    recipients = message.notified_users
208
    cc = ((message.root.notified_watchers + message.board.notified_watchers).uniq - recipients)
209 389
    @message = message
210 390
    @message_url = url_for(message.event_url)
211
    mail :to => recipients,
212
      :cc => cc,
391
    mail :to => User.current,
213 392
      :subject => "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
214 393
  end
215 394

  
216
  # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was added.
395
  # Build a MultiMessage to notify users about a new forum message
396
  #
397
  # Example:
398
  #   Mailer.message_posted(message).deliver => sends emails to the recipients
399
  def self.message_posted(message)
400
    users  = message.notified_users
401
    users |= message.root.notified_watchers
402
    users |= message.board.notified_watchers
403

  
404
    MultiMessage.new(:message_posted, message).for(users)
405
  end
406

  
407
  # Builds a Mail::Message object used to email the current user that the
408
  # specified wiki content was added.
217 409
  #
218 410
  # Example:
219 411
  #   wiki_content_added(wiki_content) => Mail::Message object
220
  #   Mailer.wiki_content_added(wiki_content).deliver => sends an email to the project's recipients
221 412
  def wiki_content_added(wiki_content)
222 413
    redmine_headers 'Project' => wiki_content.project.identifier,
223 414
                    'Wiki-Page-Id' => wiki_content.page.id
224 415
    @author = wiki_content.author
225 416
    message_id wiki_content
226
    recipients = wiki_content.notified_users
227
    cc = wiki_content.page.wiki.notified_watchers - recipients
228 417
    @wiki_content = wiki_content
229 418
    @wiki_content_url = url_for(:controller => 'wiki', :action => 'show',
230 419
                                      :project_id => wiki_content.project,
231 420
                                      :id => wiki_content.page.title)
232
    mail :to => recipients,
233
      :cc => cc,
421
    mail :to => User.current,
234 422
      :subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
235 423
  end
236 424

  
237
  # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was updated.
425
  # Build a MultiMessage to notify users about added wiki content
426
  #
427
  # Example:
428
  #   Mailer.wiki_content_added(wiki_content).deliver => send emails to the project's recipients
429
  def self.wiki_content_added(wiki_content)
430
    users = wiki_content.notified_users | wiki_content.page.wiki.notified_watchers
431
    MultiMessage.new(:wiki_content_added, wiki_content).for(users)
432
  end
433

  
434
  # Builds a Mail::Message object used to email the current user about an update
435
  # of the specified wiki content.
238 436
  #
239 437
  # Example:
240 438
  #   wiki_content_updated(wiki_content) => Mail::Message object
241
  #   Mailer.wiki_content_updated(wiki_content).deliver => sends an email to the project's recipients
242 439
  def wiki_content_updated(wiki_content)
243 440
    redmine_headers 'Project' => wiki_content.project.identifier,
244 441
                    'Wiki-Page-Id' => wiki_content.page.id
245 442
    @author = wiki_content.author
246 443
    message_id wiki_content
247
    recipients = wiki_content.notified_users
248
    cc = wiki_content.page.wiki.notified_watchers + wiki_content.page.notified_watchers - recipients
249 444
    @wiki_content = wiki_content
250 445
    @wiki_content_url = url_for(:controller => 'wiki', :action => 'show',
251 446
                                      :project_id => wiki_content.project,
......
253 448
    @wiki_diff_url = url_for(:controller => 'wiki', :action => 'diff',
254 449
                                   :project_id => wiki_content.project, :id => wiki_content.page.title,
255 450
                                   :version => wiki_content.version)
256
    mail :to => recipients,
257
      :cc => cc,
451
    mail :to => User.current,
258 452
      :subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
259 453
  end
260 454

  
261
  # Builds a Mail::Message object used to email the specified user their account information.
455
  # Build a MultiMessage to notify users about the update of the specified wiki content
262 456
  #
263 457
  # Example:
264
  #   account_information(user, password) => Mail::Message object
265
  #   Mailer.account_information(user, password).deliver => sends account information to the user
266
  def account_information(user, password)
267
    set_language_if_valid user.language
268
    @user = user
458
  #   Mailer.wiki_content_updated(wiki_content).deliver => sends an email to the project's recipients
459
  def self.wiki_content_updated(wiki_content)
460
    users  = wiki_content.notified_users
461
    users |= wiki_content.page.notified_watchers
462
    users |= wiki_content.page.wiki.notified_watchers
463

  
464
    MultiMessage.new(:wiki_content_updated, wiki_content).for(users)
465
  end
466

  
467
  # Builds a Mail::Message object used to email the current user their account information.
468
  #
469
  # Example:
470
  #   account_information(password) => Mail::Message object
471
  def account_information(password)
472
    @user = User.current
269 473
    @password = password
270 474
    @login_url = url_for(:controller => 'account', :action => 'login')
271
    mail :to => user.mail,
475
    mail :to => User.current.mail,
272 476
      :subject => l(:mail_subject_register, Setting.app_title)
273 477
  end
274 478

  
275
  # Builds a Mail::Message object used to email all active administrators of an account activation request.
479
  # Build a MultiMessage to mail a user their account information
480
  #
481
  # Example:
482
  #   Mailer.account_information(user, password).deliver => sends account information to the user
483
  def self.account_information(user, password)
484
    MultiMessage.new(:account_information, password).for(user)
485
  end
486

  
487
  # Builds a Mail::Message object used to email the current user about an account activation request.
276 488
  #
277 489
  # Example:
278 490
  #   account_activation_request(user) => Mail::Message object
279
  #   Mailer.account_activation_request(user).deliver => sends an email to all active administrators
280 491
  def account_activation_request(user)
281
    # Send the email to all active administrators
282
    recipients = User.active.where(:admin => true)
283 492
    @user = user
284 493
    @url = url_for(:controller => 'users', :action => 'index',
285 494
                         :status => User::STATUS_REGISTERED,
286 495
                         :sort_key => 'created_on', :sort_order => 'desc')
287
    mail :to => recipients,
496
    mail :to => User.current,
288 497
      :subject => l(:mail_subject_account_activation_request, Setting.app_title)
289 498
  end
290 499

  
291
  # Builds a Mail::Message object used to email the specified user that their account was activated by an administrator.
500
  # Build a MultiMessage to email all active administrators of an account activation request.
292 501
  #
293 502
  # Example:
294
  #   account_activated(user) => Mail::Message object
295
  #   Mailer.account_activated(user).deliver => sends an email to the registered user
296
  def account_activated(user)
297
    set_language_if_valid user.language
298
    @user = user
503
  #   Mailer.account_activation_request(user).deliver => sends an email to all active administrators
504
  def self.account_activation_request(user)
505
    # Send the email to all active administrators
506
    users = User.active.where(:admin => true)
507
    MultiMessage.new(:account_activation_request, user).for(users)
508
  end
509

  
510
  # Builds a Mail::Message object used to email the account of the current user
511
  # was activated by an administrator.
512
  #
513
  # Example:
514
  #   account_activated => Mail::Message object
515
  def account_activated
516
    @user = User.current
299 517
    @login_url = url_for(:controller => 'account', :action => 'login')
300
    mail :to => user.mail,
518
    mail :to => User.current.mail,
301 519
      :subject => l(:mail_subject_register, Setting.app_title)
302 520
  end
303 521

  
522
  # Build a MultiMessage to email the specified user that their account was
523
  # activated by an administrator.
524
  #
525
  # Example:
526
  #   Mailer.account_activated(user).deliver => sends an email to the registered user
527
  def self.account_activated(user)
528
    MultiMessage.new(:account_activated).for(user)
529
  end
530

  
531
  # Builds a Mail::Message object used to email the lost password token to the
532
  # token's user (or a different recipient).
533
  #
534
  # Example:
535
  #   lost_password(token) => Mail::Message object
304 536
  def lost_password(token, recipient=nil)
305
    set_language_if_valid(token.user.language)
306 537
    recipient ||= token.user.mail
307 538
    @token = token
308 539
    @url = url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
......
310 541
      :subject => l(:mail_subject_lost_password, Setting.app_title)
311 542
  end
312 543

  
544
  # Build a MultiMessage to email the token's user (or a different recipient)
545
  # the lost password token for the token's user.
546
  #
547
  # Example:
548
  #   Mailer.lost_password(token).deliver => sends an email to the user
549
  def self.lost_password(token, recipient=nil)
550
    MultiMessage.new(:lost_password, token, recipient).for(token.user)
551
  end
552

  
313 553
  # Notifies user that his password was updated
314 554
  def self.password_updated(user, options={})
315 555
    # Don't send a notification to the dummy email address when changing the password
......
326 566
    ).deliver
327 567
  end
328 568

  
569
  # Builds a Mail::Message object used to email the user activation link to the
570
  # token's user.
571
  #
572
  # Example:
573
  #   register(token) => Mail::Message object
329 574
  def register(token)
330
    set_language_if_valid(token.user.language)
331 575
    @token = token
332 576
    @url = url_for(:controller => 'account', :action => 'activate', :token => token.value)
333 577
    mail :to => token.user.mail,
334 578
      :subject => l(:mail_subject_register, Setting.app_title)
335 579
  end
336 580

  
337
  def security_notification(recipients, options={})
338
    @user = Array(recipients).detect{|r| r.is_a? User }
339
    set_language_if_valid(@user.try :language)
581
  # Build a MultiMessage to email the user activation link to the token's user.
582
  #
583
  # Example:
584
  #   Mailer.register(token).deliver => sends an email to the token's user
585
  def self.register(token)
586
    MultiMessage.new(:register, token).for(token.user)
587
  end
588

  
589
  # Build a Mail::Message object to email the current user and the additional
590
  # recipients given in options[:recipients] about a security related event.
591
  #
592
  # Example:
593
  #   security_notification(users,
594
  #     message: :mail_body_security_notification_add,
595
  #     field: :field_mail,
596
  #     value: address
597
  #   ) => Mail::Message object
598
  def security_notification(sender, options={})
599
    @sender = sender
600
    redmine_headers 'Sender' => sender.login
601
    @user = User.current
340 602
    @message = l(options[:message],
341 603
      field: (options[:field] && l(options[:field])),
342 604
      value: options[:value]
......
347 609
    @url = options[:url] && (options[:url].is_a?(Hash) ? url_for(options[:url]) : options[:url])
348 610
    redmine_headers 'Sender' => @originator.login
349 611
    redmine_headers 'Url' => @url
350
    mail :to => recipients,
612
    mail :to => [User.current, *options[:recipients]].uniq,
351 613
      :subject => "[#{Setting.app_title}] #{l(:mail_subject_security_notification)}"
352 614
  end
353 615

  
354
  def settings_updated(recipients, changes)
355
    redmine_headers 'Sender' => User.current.login
616
  # Build a MultiMessage to email the given users about a security related event.
617
  #
618
  # You can specify additional recipients in options[:recipients]. These will be
619
  # added to all generated mails for all given users. Usually, you'll want to
620
  # give only a single user when setting the additional recipients.
621
  #
622
  # Example:
623
  #   Mailer.security_notification(users,
624
  #     message: :mail_body_security_notification_add,
625
  #     field: :field_mail,
626
  #     value: address
627
  #   ).deliver => sends a security notification to the given user(s)
628
  def self.security_notification(users, options={})
629
    sender = User.current
630
    MultiMessage.new(:security_notification, sender, options).for(users)
631
  end
632

  
633
  # Build a Mail::Message object to email the current user about an updated
634
  # setting.
635
  #
636
  # Example:
637
  #   settings_updated(sender, [:host_name]) => Mail::Message object
638
  def settings_updated(sender, changes)
639
    @sender = sender
640
    redmine_headers 'Sender' => sender.login
356 641
    @changes = changes
357 642
    @url = url_for(controller: 'settings', action: 'index')
358
    mail :to => recipients,
643
    mail :to => User.current,
359 644
      :subject => "[#{Setting.app_title}] #{l(:mail_subject_security_notification)}"
360 645
  end
361 646

  
647
  # Build a MultiMessage to email the given users about an update of a setting.
648
  #
649
  # Example:
650
  #   Mailer.settings_updated(users, [:host_name]).deliver => sends emails to the given user(s) about the update
651
  def self.settings_updated(users, changes)
652
    sender = User.current
653
    MultiMessage.new(:settings_updated, sender, changes).for(users)
654
  end
655
  
362 656
  # Notifies admins about settings changes
363 657
  def self.security_settings_updated(changes)
364 658
    return unless changes.present?
......
367 661
    settings_updated(users, changes).deliver
368 662
  end
369 663

  
370
  def test_email(user)
371
    set_language_if_valid(user.language)
664
  # Build a Mail::Message object with a test email for the current user
665
  #
666
  # Example:
667
  #   test_email => Mail::Message object
668
  def test_email
372 669
    @url = url_for(:controller => 'welcome')
373
    mail :to => user.mail,
670
    mail :to => User.current.mail,
374 671
      :subject => 'Redmine test'
375 672
  end
376 673

  
674
  # Build a MultiMessage to send a test email the given user
675
  #
676
  # Example:
677
  #   Mailer.test_email(user).deliver => send an email to the given user
678
  def self.test_email(user)
679
    MultiMessage.new(:test_email).for(user)
680
  end
681

  
377 682
  # Sends reminders to issue assignees
378 683
  # Available options:
379 684
  # * :days     => how many days in the future to remind about (defaults to 7)
......
483 788
      headers[:references] = @references_objects.collect {|o| "<#{self.class.references_for(o)}>"}.join(' ')
484 789
    end
485 790

  
486
    m = if block_given?
791
    if block_given?
487 792
      super headers, &block
488 793
    else
489 794
      super headers do |format|
......
491 796
        format.html unless Setting.plain_text_mail?
492 797
      end
493 798
    end
494
    set_language_if_valid @initial_language
495

  
496
    m
497
  end
498

  
499
  def initialize(*args)
500
    @initial_language = current_language
501
    set_language_if_valid Setting.default_language
502
    super
503 799
  end
504 800

  
505 801
  def self.deliver_mail(mail)
......
521 817
    if m = method.to_s.match(%r{^deliver_(.+)$})
522 818
      ActiveSupport::Deprecation.warn "Mailer.deliver_#{m[1]}(*args) is deprecated. Use Mailer.#{m[1]}(*args).deliver instead."
523 819
      send(m[1], *args).deliver
820
    elsif action_methods.include?(method.to_s)
821
      MultiMessage.new(method, *args).for(User.current)
524 822
    else
525 823
      super
526 824
    end
app/views/mailer/security_notification.html.erb
9 9

  
10 10
<p><%= l(:field_user) %>: <strong><%= @originator.login %></strong><br/>
11 11
<%= l(:field_remote_ip) %>: <strong><%= @remote_ip %></strong><br/>
12
<%= l(:label_date) %>: <strong><%= format_time Time.now, true, @user %></strong></p>
13

  
12
<%= l(:label_date) %>: <strong><%= format_time Time.now, true %></strong></p>
app/views/mailer/security_notification.text.erb
4 4

  
5 5
<%= l(:field_user) %>: <%= @originator.login %>
6 6
<%= l(:field_remote_ip) %>: <%= @remote_ip %>
7
<%= l(:label_date) %>: <%= format_time Time.now, true, @user %>
8

  
7
<%= l(:label_date) %>: <%= format_time Time.now, true %>
app/views/mailer/settings_updated.html.erb
8 8

  
9 9
<%= link_to @url, @url %>
10 10

  
11
<p><%= l(:field_user) %>: <strong><%= User.current.login %></strong><br/>
12
<%= l(:field_remote_ip) %>: <strong><%= User.current.remote_ip %></strong><br/>
11
<p><%= l(:field_user) %>: <strong><%= @sender.login %></strong><br/>
12
<%= l(:field_remote_ip) %>: <strong><%= @sender.remote_ip %></strong><br/>
13 13
<%= l(:label_date) %>: <strong><%= format_time Time.now, true %></strong></p>
14 14

  
app/views/mailer/settings_updated.text.erb
6 6

  
7 7
<%= @url %>
8 8

  
9
<%= l(:field_user) %>: <%= User.current.login %>
10
<%= l(:field_remote_ip) %>: <%= User.current.remote_ip %>
9
<%= l(:field_user) %>: <%= @sender.login %>
10
<%= l(:field_remote_ip) %>: <%= @sender.remote_ip %>
11 11
<%= l(:label_date) %>: <%= format_time Time.now, true %>
12 12

  
test/functional/documents_controller_test.rb
132 132
    assert_equal Enumeration.find(2), document.category
133 133
    assert_equal 1, document.attachments.size
134 134
    assert_equal 'testfile.txt', document.attachments.first.filename
135
    assert_equal 1, ActionMailer::Base.deliveries.size
135
    assert_equal 2, ActionMailer::Base.deliveries.size
136 136
  end
137 137

  
138 138
  def test_create_with_failure
test/functional/issues_controller_test.rb
152 152
        :f => ['tracker_id'],
153 153
        :op => {
154 154
          'tracker_id' => '='
155
        },  
155
        },
156 156
        :v => {
157 157
          'tracker_id' => ['1']
158 158
        }
......
253 253
        :f => [filter_name],
254 254
        :op => {
255 255
          filter_name => '='
256
        },  
256
        },
257 257
        :v => {
258 258
          filter_name => ['Foo']
259
        },  
259
        },
260 260
        :c => ['project']
261 261
      }
262 262
    assert_response :success
......
1459 1459
        :f => ['start_date'],
1460 1460
        :op => {
1461 1461
          :start_date => '='
1462
        },  
1462
        },
1463 1463
        :format => 'csv'
1464 1464
      }
1465 1465
    assert_equal 'text/csv', @response.content_type
......
2678 2678
          :tracker_id => 3,
2679 2679
          :description => 'Prefilled',
2680 2680
          :custom_field_values => {
2681
          '2' => 'Custom field value'}    
2681
          '2' => 'Custom field value'}
2682 2682
        }
2683 2683
      }
2684 2684

  
......
2802 2802
    assert !t.disabled_core_fields.include?('parent_issue_id')
2803 2803

  
2804 2804
    get :new, :params => {
2805
        :project_id => 1, issue: { parent_issue_id: 1 
2805
        :project_id => 1, issue: { parent_issue_id: 1
2806 2806
      }
2807 2807
      }
2808 2808
    assert_response :success
......
2812 2812
    t.save!
2813 2813
    assert t.disabled_core_fields.include?('parent_issue_id')
2814 2814
    get :new, :params => {
2815
        :project_id => 1, issue: { parent_issue_id: 1 
2815
        :project_id => 1, issue: { parent_issue_id: 1
2816 2816
      }
2817 2817
      }
2818 2818
    assert_response :success
......
2870 2870
        :issue => {
2871 2871
          :tracker_id => 2,
2872 2872
          :status_id => 1
2873
        },  
2873
        },
2874 2874
        :was_default_status => 1
2875 2875
      }
2876 2876
    assert_response :success
......
2889 2889
        :issue => {
2890 2890
          :project_id => 1,
2891 2891
          :fixed_version_id => ''
2892
        },  
2892
        },
2893 2893
        :form_update_triggered_by => 'issue_project_id'
2894 2894
      }
2895 2895
    assert_response :success
......
2917 2917
              :start_date => '2010-11-07',
2918 2918
              :estimated_hours => '',
2919 2919
              :custom_field_values => {
2920
              '2' => 'Value for field 2'}    
2920
              '2' => 'Value for field 2'}
2921 2921
            }
2922 2922
          }
2923 2923
      end
......
2976 2976
              :priority_id => 5,
2977 2977
              :estimated_hours => '',
2978 2978
              :custom_field_values => {
2979
              '2' => 'Value for field 2'}    
2979
              '2' => 'Value for field 2'}
2980 2980
            }
2981 2981
          }
2982 2982
      end
......
3002 3002
              :priority_id => 5,
3003 3003
              :estimated_hours => '',
3004 3004
              :custom_field_values => {
3005
              '2' => 'Value for field 2'}    
3005
              '2' => 'Value for field 2'}
3006 3006
            }
3007 3007
          }
3008 3008
      end
......
3023 3023
            :tracker_id => 3,
3024 3024
            :subject => 'This is first issue',
3025 3025
            :priority_id => 5
3026
          },  
3026
          },
3027 3027
          :continue => ''
3028 3028
        }
3029 3029
    end
......
3065 3065
            :description => 'This is the description',
3066 3066
            :priority_id => 5,
3067 3067
            :custom_field_values => {
3068
            '1' => ['', 'MySQL', 'Oracle']}    
3068
            '1' => ['', 'MySQL', 'Oracle']}
3069 3069
          }
3070 3070
        }
3071 3071
    end
......
3088 3088
            :description => 'This is the description',
3089 3089
            :priority_id => 5,
3090 3090
            :custom_field_values => {
3091
            '1' => ['']}    
3091
            '1' => ['']}
3092 3092
          }
3093 3093
        }
3094 3094
    end
......
3111 3111
            :description => 'This is the description',
3112 3112
            :priority_id => 5,
3113 3113
            :custom_field_values => {
3114
            field.id.to_s => ['', '2', '3']}    
3114
            field.id.to_s => ['', '2', '3']}
3115 3115
          }
3116 3116
        }
3117 3117
    end
......
3159 3159
            :due_date => '',
3160 3160
            :custom_field_values => {
3161 3161
              cf1.id.to_s => '', cf2.id.to_s => ''
3162
            }    
3163
            
3162
            }
3163

  
3164 3164
          }
3165 3165
        }
3166 3166
      assert_response :success
......
3189 3189
            :due_date => '',
3190 3190
            :custom_field_values => {
3191 3191
              cf1.id.to_s => '', cf2.id.to_s => ['']
3192
            }    
3193
            
3192
            }
3193

  
3194 3194
          }
3195 3195
        }
3196 3196
      assert_response :success
......
3219 3219
            :due_date => '2012-07-16',
3220 3220
            :custom_field_values => {
3221 3221
              cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
3222
            }    
3223
            
3222
            }
3223

  
3224 3224
          }
3225 3225
        }
3226 3226
      assert_response 302
......
3246 3246
            :tracker_id => 1,
3247 3247
            :status_id => 1,
3248 3248
            :subject => 'Test'
3249
            
3249

  
3250 3250
          }
3251 3251
        }
3252 3252
      assert_response 302
......
3424 3424
            :project_id => 3,
3425 3425
            :tracker_id => 2,
3426 3426
            :subject => 'Foo'
3427
          },  
3427
          },
3428 3428
          :continue => '1'
3429 3429
        }
3430 3430
      assert_redirected_to '/issues/new?issue%5Bproject_id%5D=3&issue%5Btracker_id%5D=2'
......
3477 3477
              :priority_id => 5,
3478 3478
              :estimated_hours => '',
3479 3479
              :custom_field_values => {
3480
              '2' => 'Value for field 2'}    
3480
              '2' => 'Value for field 2'}
3481 3481
            }
3482 3482
          }
3483 3483
      end
3484 3484
      assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
3485 3485

  
3486
      assert_equal 1, ActionMailer::Base.deliveries.size
3486
      assert_equal 2, ActionMailer::Base.deliveries.size
3487 3487
    end
3488 3488
  end
3489 3489

  
......
3536 3536
      post :create, :params => {
3537 3537
          :project_id => 1,
3538 3538
          :issue => {
3539
            :tracker => "A param can not be a Tracker" 
3539
            :tracker => "A param can not be a Tracker"
3540 3540
          }
3541 3541
        }
3542 3542
    end
......
3553 3553
              :project_id => 1,
3554 3554
              :issue => {
3555 3555
                :tracker_id => '1',
3556
                :subject => 'With attachment' 
3557
              },  
3556
                :subject => 'With attachment'
3557
              },
3558 3558
              :attachments => {
3559 3559
                '1' => {
3560
                'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}    
3560
                'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
3561 3561
              }
3562 3562
            }
3563 3563
        end
......
3588 3588
            :project_id => 1,
3589 3589
            :issue => {
3590 3590
              :tracker_id => '1',
3591
              :subject => 'With attachment' 
3592
            },  
3591
              :subject => 'With attachment'
3592
            },
3593 3593
            :attachments => {
3594 3594
              '1' => {
3595
              'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}    
3595
              'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
3596 3596
            }
3597 3597
          }
3598 3598
      end
......
3614 3614
            :project_id => 1,
3615 3615
            :issue => {
3616 3616
              :tracker_id => '1',
3617
              :subject => '' 
3618
            },  
3617
              :subject => ''
3618
            },
3619 3619
            :attachments => {
3620 3620
              '1' => {
3621
              'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}    
3621
              'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
3622 3622
            }
3623 3623
          }
3624 3624
        assert_response :success
......
3645 3645
            :project_id => 1,
3646 3646
            :issue => {
3647 3647
              :tracker_id => '1',
3648
              :subject => '' 
3649
            },  
3648
              :subject => ''
3649
            },
3650 3650
            :attachments => {
3651 3651
              'p0' => {
3652
              'token' => attachment.token}    
3652
              'token' => attachment.token}
3653 3653
            }
3654 3654
          }
3655 3655
        assert_response :success
......
3671 3671
            :project_id => 1,
3672 3672
            :issue => {
3673 3673
              :tracker_id => '1',
3674
              :subject => 'Saved attachments' 
3675
            },  
3674
              :subject => 'Saved attachments'
3675
            },
3676 3676
            :attachments => {
3677 3677
              'p0' => {
3678
              'token' => attachment.token}    
3678
              'token' => attachment.token}
3679 3679
            }
3680 3680
          }
3681 3681
        assert_response 302
......
3997 3997
            :project_id => '1',
3998 3998
            :tracker_id => '1',
3999 3999
            :status_id => '1'
4000
          },  
4000
          },
4001 4001
          :was_default_status => '1'
4002 4002
        }
4003 4003
    end
......
4041 4041
              :tracker_id => '3',
4042 4042
              :status_id => '1',
4043 4043
              :subject => 'Copy with attachments'
4044
            },  
4044
            },
4045 4045
            :copy_attachments => '1'
4046 4046
          }
4047 4047
      end
......
4089 4089
              :tracker_id => '3',
4090 4090
              :status_id => '1',
4091 4091
              :subject => 'Copy with attachments'
4092
            },  
4092
            },
4093 4093
            :copy_attachments => '1',
4094 4094
            :attachments => {
4095 4095
              '1' => {
......
4188 4188
            :tracker_id => '3',
4189 4189
            :status_id => '1',
4190 4190
            :subject => 'Copy with subtasks'
4191
          },  
4191
          },
4192 4192
          :copy_subtasks => '1'
4193 4193
        }
4194 4194
    end
......
4212 4212
            :status_id => '1',
4213 4213
            :subject => 'Copy with subtasks',
4214 4214
            :custom_field_values => {
4215
            '2' => 'Foo'}    
4216
          },  
4215
            '2' => 'Foo'}
4216
          },
4217 4217
          :copy_subtasks => '1'
4218 4218
        }
4219 4219
    end
......
4394 4394
        :id => 1,
4395 4395
        :issue => {
4396 4396
          :status_id => 5,
4397
          :priority_id => 7 
4398
        },  
4397
          :priority_id => 7
4398
        },
4399 4399
        :time_entry => {
4400 4400
          :hours => '2.5',
4401 4401
          :comments => 'test_get_edit_with_params',
4402
          :activity_id => 10 
4402
          :activity_id => 10
4403 4403
        }
4404 4404
      }
4405 4405
    assert_response :success
......
4638 4638
                :project_id => '1',
4639 4639
                :tracker_id => '2',
4640 4640
                :priority_id => '6'
4641
                
4641

  
4642 4642
              }
4643 4643
            }
4644 4644
        end
......
4701 4701
            :issue => {
4702 4702
              :subject => 'Custom field change',
4703 4703
              :custom_field_values => {
4704
                '1' => ['', 'Oracle', 'PostgreSQL'] 
4705
              }    
4706
              
4704
                '1' => ['', 'Oracle', 'PostgreSQL']
4705
              }
4706

  
4707 4707
            }
4708 4708
          }
4709 4709
      end
......
4724 4724
            :issue => {
4725 4725
              :status_id => 2,
4726 4726
              :assigned_to_id => 3,
4727
              :notes => 'Assigned to dlopper' 
4728
            },  
4727
              :notes => 'Assigned to dlopper'
4728
            },
4729 4729
            :time_entry => {
4730 4730
              :hours => '',
4731 4731
              :comments => '',
4732
              :activity_id => TimeEntryActivity.first 
4732
              :activity_id => TimeEntryActivity.first
4733 4733
            }
4734 4734
          }
4735 4735
      end
......
4755 4755
      put :update, :params => {
4756 4756
          :id => 1,
4757 4757
          :issue => {
4758
            :notes => notes 
4758
            :notes => notes
4759 4759
          }
4760 4760
        }
4761 4761
    end
......
4823 4823
      put :update, :params => {
4824 4824
          :id => 1,
4825 4825
          :issue => {
4826
            :notes => '2.5 hours added' 
4827
          },  
4826
            :notes => '2.5 hours added'
4827
          },
4828 4828
          :time_entry => {
4829 4829
            :hours => '2.5',
4830 4830
            :comments => 'test_put_update_with_note_and_spent_time',
4831
            :activity_id => TimeEntryActivity.first.id 
4831
            :activity_id => TimeEntryActivity.first.id
4832 4832
          }
4833 4833
        }
4834 4834
    end
......
4883 4883
            :id => 1,
4884 4884
            :issue => {
4885 4885
              :notes => ''
4886
            },  
4886
            },
4887 4887
            :attachments => {
4888 4888
              '1' => {
4889
              'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}    
4889
              'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
4890 4890
            }
4891 4891
          }
4892 4892
      end
......
4922 4922
        put :update, :params => {
4923 4923
            :id => 1,
4924 4924
            :issue => {
4925
              :subject => '' 
4926
            },  
4925
              :subject => ''
4926
            },
4927 4927
            :attachments => {
4928 4928
              '1' => {
4929
              'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}    
4929
              'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
4930 4930
            }
4931 4931
          }
4932 4932
        assert_response :success
......
4952 4952
        put :update, :params => {
4953 4953
            :id => 1,
4954 4954
            :issue => {
4955
              :subject => '' 
4956
            },  
4955
              :subject => ''
4956
            },
4957 4957
            :attachments => {
4958 4958
              'p0' => {
4959
              'token' => attachment.token}    
4959
              'token' => attachment.token}
4960 4960
            }
4961 4961
          }
4962 4962
        assert_response :success
......
4979 4979
              :id => 1,
4980 4980
              :issue => {
4981 4981
                :notes => 'Attachment added'
4982
              },  
4982
              },
4983 4983
              :attachments => {
4984 4984
                'p0' => {
4985
                'token' => attachment.token}    
4985
                'token' => attachment.token}
4986 4986
              }
4987 4987
            }
4988 4988
          assert_redirected_to '/issues/1'
......
5007 5007
          :id => 1,
5008 5008
          :issue => {
5009 5009
            :notes => ''
5010
          },  
5010
          },
5011 5011
          :attachments => {
5012 5012
            '1' => {
5013
            'file' => uploaded_test_file('testfile.txt', 'text/plain')}    
5013
            'file' => uploaded_test_file('testfile.txt', 'text/plain')}
5014 5014
          }
5015 5015
        }
5016 5016
      assert_redirected_to :action => 'show', :id => '1'
......
5030 5030
            :issue => {
5031 5031
              :notes => 'Removing attachments',
5032 5032
              :deleted_attachment_ids => ['1', '5']
5033
              
5033

  
5034 5034
            }
5035 5035
          }
5036 5036
      end
......
5057 5057
              :subject => '',
5058 5058
              :notes => 'Removing attachments',
5059 5059
              :deleted_attachment_ids => ['1', '5']
5060
              
5060

  
5061 5061
            }
5062 5062
          }
5063 5063
      end
......
5100 5100
            :subject => new_subject,
5101 5101
            :priority_id => '6',
5102 5102
            :category_id => '1' # no change
5103
            
5103

  
5104 5104
          }
5105 5105
        }
5106
      assert_equal 1, ActionMailer::Base.deliveries.size
5106
      assert_equal 2, ActionMailer::Base.deliveries.size
5107 5107
    end
5108 5108
  end
5109 5109

  
......
5116 5116
          :id => 1,
5117 5117
          :issue => {
5118 5118
            :notes => notes
5119
          },  
5119
          },
5120 5120
          :time_entry => {
5121 5121
            "comments"=>"", "activity_id"=>"", "hours"=>"2z"
5122 5122
          }
......
5138 5138
          :id => 1,
5139 5139
          :issue => {
5140 5140
            :notes => notes
5141
          },  
5141
          },
5142 5142
          :time_entry => {
5143 5143
            "comments"=>"this is my comment", "activity_id"=>"", "hours"=>""
5144 5144
          }
......
5160 5160
        :id => issue.id,
5161 5161
        :issue => {
5162 5162
          :fixed_version_id => 4
5163
          
5163

  
5164 5164
        }
5165 5165
      }
5166 5166

  
......
5178 5178
        :id => issue.id,
5179 5179
        :issue => {
5180 5180
          :fixed_version_id => 4
5181
          
5182
        },  
5181

  
5182
        },
5183 5183
        :back_url => '/issues'
5184 5184
      }
5185 5185

  
......
5195 5195
        :id => issue.id,
5196 5196
        :issue => {
5197 5197
          :fixed_version_id => 4
5198
          
5199
        },  
5198

  
5199
        },
5200 5200
        :back_url => 'http://google.com'
5201 5201
      }
5202 5202

  
......
5212 5212
        :issue => {
... This diff was truncated because it exceeds the maximum size that can be displayed.
(4-4/4)