include Redmine::I18n
include Roadie::Rails::Automatic
+ # This class wraps multiple generated `Mail::Message` objects and allows to
+ # deliver them all at once. It is usually used to handle multiple mails for
+ # different receivers created by a single mail event. The wrapped mails can
+ # then be delivered in one go.
+ #
+ # The public interface of the class resembles a single mail message. You can
+ # directly use any of the deliver_* methods to send the contained messages
+ # now or later.
+ class MultiMessage
+ attr_reader :mails
+
+ # @param mails [Array<Mail, Proc>] an Array of mails or Procs which create
+ # mail objects and allow to call a method on it.
+ def initialize(action, *args)
+ @action = action
+ @args = args
+
+ @mails = []
+ end
+
+ def for(users)
+ Array.wrap(users).each do |user|
+ @mails << ActionMailer::MessageDelivery.new(Mailer, @action, user, *@args)
+ end
+ self
+ end
+
+ def deliver_later(options = {})
+ enqueue_delivery :deliver_now, options
+ end
+
+ def deliver_later!(options = {})
+ enqueue_delivery :deliver_now!, options
+ end
+
+ def processed?
+ @mails.any?(&:processed?)
+ end
+
+ # @return [Object] the delivery method of the first mail.
+ # Usually, this is the very same value for all mails and matches the
+ # default value of the Mailer class
+ def delivery_method
+ (@mails.first || ActionMailer::Base::NullMail.new).delivery_method
+ end
+
+ # @return [ActionMailer::Base] the delivery handler of the first mail. This
+ # is always the `Mailer` class.
+ def delivery_handler
+ (@mails.first || ActionMailer::Base::NullMail.new).delivery_handler
+ end
+
+ private
+
+ def method_missing(method, *args, &block)
+ if method =~ /\Adeliver([_!?]|\z)/
+ @mails.each do |mail|
+ mail.public_send(method, *args, &block)
+ end
+ else
+ super
+ end
+ end
+
+ def respond_to_missing(method, *args)
+ method =~ /\Adeliver([_!?]|\z)/ || method == 'processed?' || super
+ end
+
+ # This method is slightly adapted from ActionMailer::MessageDelivery
+ def enqueue_delivery(delivery_method, options = {})
+ if processed?
+ ::Kernel.raise "You've accessed the message before asking to " \
+ "deliver it later, so you may have made local changes that would " \
+ "be silently lost if we enqueued a job to deliver it. Why? Only " \
+ "the mailer method *arguments* are passed with the delivery job! " \
+ "Do not access the message in any way if you mean to deliver it " \
+ "later. Workarounds: 1. don't touch the message before calling " \
+ "#deliver_later, 2. only touch the message *within your mailer " \
+ "method*, or 3. use a custom Active Job instead of #deliver_later."
+ else
+ args = 'Mailer', @action.to_s, delivery_method.to_s, *@args
+ ::ActionMailer::DeliveryJob.set(options).perform_later(*args)
+ end
+ end
+ end
+
+ def process(action, *args)
+ user = args.shift
+ raise ArgumentError, "First argument has to be a user, was #{user.inspect}" unless user.is_a?(User)
+
+ initial_user = User.current
+ initial_language = ::I18n.locale
+ begin
+ User.current = user
+
+ lang = find_language(user.language) if user.logged?
+ lang ||= Setting.default_language
+ set_language_if_valid(lang)
+
+ super(action, *args)
+ ensure
+ User.current = initial_user
+ ::I18n.locale = initial_language
+ end
+ end
+
+
def self.default_url_options
options = {:protocol => Setting.protocol}
if Setting.host_name.to_s =~ /\A(https?\:\/\/)?(.+?)(\:(\d+))?(\/.+)?\z/i
options
end
- # Builds a mail for notifying to_users and cc_users about a new issue
- def issue_add(issue, to_users, cc_users)
+ # Builds a mail for notifying the current user about a new issue
+ #
+ # Example:
+ # issue_add(issue) => Mail::Message object
+ def issue_add(issue)
redmine_headers 'Project' => issue.project.identifier,
'Issue-Id' => issue.id,
'Issue-Author' => issue.author.login
references issue
@author = issue.author
@issue = issue
- @users = to_users + cc_users
+ @users = [User.current]
@issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue)
- mail :to => to_users,
- :cc => cc_users,
+ mail :to => User.current,
:subject => "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
end
# Notifies users about a new issue
+ #
+ # Example:
+ # Mailer.issue_add(journal).deliver => sends emails to the project's recipients
+ def self.issue_add(issue)
+ users = issue.notified_users | issue.notified_watchers
+ MultiMessage.new(:issue_add, issue).for(users)
+ end
+
+ # Notifies users about a new issue
+ #
+ # Example:
+ # Mailer.deliver_issue_add(issue) => sends emails to the project's recipients
def self.deliver_issue_add(issue)
- to = issue.notified_users
- cc = issue.notified_watchers - to
- issue.each_notification(to + cc) do |users|
- issue_add(issue, to & users, cc & users).deliver
- end
+ issue_add(issue).deliver
end
- # Builds a mail for notifying to_users and cc_users about an issue update
- def issue_edit(journal, to_users, cc_users)
+ # Builds a mail for notifying the current user about an issue update
+ #
+ # Example:
+ # issue_edit(journal) => Mail::Message object
+ def issue_edit(journal)
issue = journal.journalized
redmine_headers 'Project' => issue.project.identifier,
'Issue-Id' => issue.id,
s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
s << issue.subject
@issue = issue
- @users = to_users + cc_users
+ @users = [User.current]
@journal = journal
- @journal_details = journal.visible_details(@users.first)
+ @journal_details = journal.visible_details
@issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
- mail :to => to_users,
- :cc => cc_users,
+
+ mail :to => User.current,
:subject => s
end
+ # Build a MultiMessage to notify users about an issue update
+ #
+ # Example:
+ # Mailer.issue_edit(journal).deliver => sends emails to the project's recipients
+ def self.issue_edit(journal)
+ users = journal.notified_users
+ users |= journal.notified_watchers
+ users.select! do |user|
+ journal.notes? || journal.visible_details(user).any?
+ end
+ MultiMessage.new(:issue_edit, journal).for(users)
+ end
+
# Notifies users about an issue update
+ #
+ # Example:
+ # Mailer.deliver_issue_edit(journal) => sends emails to the project's recipients
def self.deliver_issue_edit(journal)
- issue = journal.journalized.reload
- to = journal.notified_users
- cc = journal.notified_watchers - to
- journal.each_notification(to + cc) do |users|
- issue.each_notification(users) do |users2|
- issue_edit(journal, to & users2, cc & users2).deliver
- end
- end
+ issue_edit(journal).deliver
end
- def reminder(user, issues, days)
- set_language_if_valid user.language
+ # Builds a Mail::Message object used to send en email reminder to the current
+ # user about their due issues.
+ #
+ # Example:
+ # reminder(issues, days) => Mail::Message object
+ def reminder(issues, days)
@issues = issues
@days = days
@issues_url = url_for(:controller => 'issues', :action => 'index',
- :set_filter => 1, :assigned_to_id => user.id,
+ :set_filter => 1, :assigned_to_id => User.current.id,
:sort => 'due_date:asc')
- mail :to => user,
+ mail :to => User.current,
:subject => l(:mail_subject_reminder, :count => issues.size, :days => days)
end
- # Builds a Mail::Message object used to email users belonging to the added document's project.
+ # Builds a Mail::Message object used to email the given user about their due
+ # issues
+ #
+ # Example:
+ # Mailer.reminder(user, issues, days, author).deliver => sends an email to the user
+ def self.reminder(user, issues, days)
+ MultiMessage.new(:reminder, issues, days).for(user)
+ end
+
+ # Builds a Mail::Message object used to email the current user that a document
+ # was added.
#
# Example:
- # document_added(document) => Mail::Message object
- # Mailer.document_added(document).deliver => sends an email to the document's project recipients
- def document_added(document)
+ # document_added(document, author) => Mail::Message object
+ def document_added(document, author)
redmine_headers 'Project' => document.project.identifier
- @author = User.current
+ @author = author
@document = document
@document_url = url_for(:controller => 'documents', :action => 'show', :id => document)
- mail :to => document.notified_users,
+ mail :to => User.current,
:subject => "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
end
- # Builds a Mail::Message object used to email recipients of a project when an attachements are added.
+ # Build a MultiMessage to notify users about an added document.
+ #
+ # Example:
+ # Mailer.document_added(document).deliver => sends emails to the document's project recipients
+ def self.document_added(document)
+ users = document.notified_users
+ MultiMessage.new(:document_added, document, User.current).for(users)
+ end
+
+ # Builds a Mail::Message object used to email the current user when
+ # attachements are added.
#
# Example:
# attachments_added(attachments) => Mail::Message object
- # Mailer.attachments_added(attachments).deliver => sends an email to the project's recipients
def attachments_added(attachments)
container = attachments.first.container
added_to = ''
when 'Project'
added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
added_to = "#{l(:label_project)}: #{container}"
- recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
when 'Version'
added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
added_to = "#{l(:label_version)}: #{container.name}"
- recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
when 'Document'
added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
added_to = "#{l(:label_document)}: #{container.title}"
- recipients = container.notified_users
end
redmine_headers 'Project' => container.project.identifier
@attachments = attachments
@added_to = added_to
@added_to_url = added_to_url
- mail :to => recipients,
+ mail :to => User.current,
:subject => "[#{container.project.name}] #{l(:label_attachment_new)}"
end
- # Builds a Mail::Message object used to email recipients of a news' project when a news item is added.
+ # Build a MultiMessage to notify users about an added attachment
+ #
+ # Example:
+ # Mailer.attachments_added(attachments).deliver => sends emails to the project's recipients
+ def self.attachments_added(attachments)
+ container = attachments.first.container
+ case container.class.name
+ when 'Project', 'Version'
+ users = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
+ when 'Document'
+ users = container.notified_users
+ end
+
+ MultiMessage.new(:attachments_added, attachments).for(users)
+ end
+
+ # Builds a Mail::Message object used to email the current user when a news
+ # item is added.
#
# Example:
# news_added(news) => Mail::Message object
- # Mailer.news_added(news).deliver => sends an email to the news' project recipients
def news_added(news)
redmine_headers 'Project' => news.project.identifier
@author = news.author
references news
@news = news
@news_url = url_for(:controller => 'news', :action => 'show', :id => news)
- mail :to => news.notified_users,
- :cc => news.notified_watchers_for_added_news,
+ mail :to => User.current,
:subject => "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
end
- # Builds a Mail::Message object used to email recipients of a news' project when a news comment is added.
+ # Build a MultiMessage to notify users about a new news item
+ #
+ # Example:
+ # Mailer.news_added(news).deliver => sends emails to the news' project recipients
+ def self.news_added(news)
+ users = news.notified_users | news.notified_watchers_for_added_news
+ MultiMessage.new(:news_added, news).for(users)
+ end
+
+ # Builds a Mail::Message object used to email the current user when a news
+ # comment is added.
#
# Example:
# news_comment_added(comment) => Mail::Message object
- # Mailer.news_comment_added(comment) => sends an email to the news' project recipients
def news_comment_added(comment)
news = comment.commented
redmine_headers 'Project' => news.project.identifier
@news = news
@comment = comment
@news_url = url_for(:controller => 'news', :action => 'show', :id => news)
- mail :to => news.notified_users,
- :cc => news.notified_watchers,
+ mail :to => User.current,
:subject => "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
end
- # Builds a Mail::Message object used to email the recipients of the specified message that was posted.
+ # Build a MultiMessage to notify users about a new news comment
+ #
+ # Example:
+ # Mailer.news_comment_added(comment).deliver => sends emails to the news' project recipients
+ def self.news_comment_added(comment)
+ news = comment.commented
+ users = news.notified_users | news.notified_watchers
+
+ MultiMessage.new(:news_comment_added, comment).for(users)
+ end
+
+ # Builds a Mail::Message object used to email the current user that the
+ # specified message was posted.
#
# Example:
# message_posted(message) => Mail::Message object
- # Mailer.message_posted(message).deliver => sends an email to the recipients
def message_posted(message)
redmine_headers 'Project' => message.project.identifier,
'Topic-Id' => (message.parent_id || message.id)
@author = message.author
message_id message
references message.root
- recipients = message.notified_users
- cc = ((message.root.notified_watchers + message.board.notified_watchers).uniq - recipients)
@message = message
@message_url = url_for(message.event_url)
- mail :to => recipients,
- :cc => cc,
+ mail :to => User.current,
:subject => "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
end
- # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was added.
+ # Build a MultiMessage to notify users about a new forum message
+ #
+ # Example:
+ # Mailer.message_posted(message).deliver => sends emails to the recipients
+ def self.message_posted(message)
+ users = message.notified_users
+ users |= message.root.notified_watchers
+ users |= message.board.notified_watchers
+
+ MultiMessage.new(:message_posted, message).for(users)
+ end
+
+ # Builds a Mail::Message object used to email the current user that the
+ # specified wiki content was added.
#
# Example:
# wiki_content_added(wiki_content) => Mail::Message object
- # Mailer.wiki_content_added(wiki_content).deliver => sends an email to the project's recipients
def wiki_content_added(wiki_content)
redmine_headers 'Project' => wiki_content.project.identifier,
'Wiki-Page-Id' => wiki_content.page.id
@author = wiki_content.author
message_id wiki_content
- recipients = wiki_content.notified_users
- cc = wiki_content.page.wiki.notified_watchers - recipients
@wiki_content = wiki_content
@wiki_content_url = url_for(:controller => 'wiki', :action => 'show',
:project_id => wiki_content.project,
:id => wiki_content.page.title)
- mail :to => recipients,
- :cc => cc,
+ mail :to => User.current,
:subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
end
- # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was updated.
+ # Build a MultiMessage to notify users about added wiki content
+ #
+ # Example:
+ # Mailer.wiki_content_added(wiki_content).deliver => send emails to the project's recipients
+ def self.wiki_content_added(wiki_content)
+ users = wiki_content.notified_users | wiki_content.page.wiki.notified_watchers
+ MultiMessage.new(:wiki_content_added, wiki_content).for(users)
+ end
+
+ # Builds a Mail::Message object used to email the current user about an update
+ # of the specified wiki content.
#
# Example:
# wiki_content_updated(wiki_content) => Mail::Message object
- # Mailer.wiki_content_updated(wiki_content).deliver => sends an email to the project's recipients
def wiki_content_updated(wiki_content)
redmine_headers 'Project' => wiki_content.project.identifier,
'Wiki-Page-Id' => wiki_content.page.id
@author = wiki_content.author
message_id wiki_content
- recipients = wiki_content.notified_users
- cc = wiki_content.page.wiki.notified_watchers + wiki_content.page.notified_watchers - recipients
@wiki_content = wiki_content
@wiki_content_url = url_for(:controller => 'wiki', :action => 'show',
:project_id => wiki_content.project,
@wiki_diff_url = url_for(:controller => 'wiki', :action => 'diff',
:project_id => wiki_content.project, :id => wiki_content.page.title,
:version => wiki_content.version)
- mail :to => recipients,
- :cc => cc,
+ mail :to => User.current,
:subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
end
- # Builds a Mail::Message object used to email the specified user their account information.
+ # Build a MultiMessage to notify users about the update of the specified wiki content
#
# Example:
- # account_information(user, password) => Mail::Message object
- # Mailer.account_information(user, password).deliver => sends account information to the user
- def account_information(user, password)
- set_language_if_valid user.language
- @user = user
+ # Mailer.wiki_content_updated(wiki_content).deliver => sends an email to the project's recipients
+ def self.wiki_content_updated(wiki_content)
+ users = wiki_content.notified_users
+ users |= wiki_content.page.notified_watchers
+ users |= wiki_content.page.wiki.notified_watchers
+
+ MultiMessage.new(:wiki_content_updated, wiki_content).for(users)
+ end
+
+ # Builds a Mail::Message object used to email the current user their account information.
+ #
+ # Example:
+ # account_information(password) => Mail::Message object
+ def account_information(password)
+ @user = User.current
@password = password
@login_url = url_for(:controller => 'account', :action => 'login')
- mail :to => user.mail,
+ mail :to => User.current.mail,
:subject => l(:mail_subject_register, Setting.app_title)
end
- # Builds a Mail::Message object used to email all active administrators of an account activation request.
+ # Build a MultiMessage to mail a user their account information
+ #
+ # Example:
+ # Mailer.account_information(user, password).deliver => sends account information to the user
+ def self.account_information(user, password)
+ MultiMessage.new(:account_information, password).for(user)
+ end
+
+ # Builds a Mail::Message object used to email the current user about an account activation request.
#
# Example:
# account_activation_request(user) => Mail::Message object
- # Mailer.account_activation_request(user).deliver => sends an email to all active administrators
def account_activation_request(user)
- # Send the email to all active administrators
- recipients = User.active.where(:admin => true)
@user = user
@url = url_for(:controller => 'users', :action => 'index',
:status => User::STATUS_REGISTERED,
:sort_key => 'created_on', :sort_order => 'desc')
- mail :to => recipients,
+ mail :to => User.current,
:subject => l(:mail_subject_account_activation_request, Setting.app_title)
end
- # Builds a Mail::Message object used to email the specified user that their account was activated by an administrator.
+ # Build a MultiMessage to email all active administrators of an account activation request.
#
# Example:
- # account_activated(user) => Mail::Message object
- # Mailer.account_activated(user).deliver => sends an email to the registered user
- def account_activated(user)
- set_language_if_valid user.language
- @user = user
+ # Mailer.account_activation_request(user).deliver => sends an email to all active administrators
+ def self.account_activation_request(user)
+ # Send the email to all active administrators
+ users = User.active.where(:admin => true)
+ MultiMessage.new(:account_activation_request, user).for(users)
+ end
+
+ # Builds a Mail::Message object used to email the account of the current user
+ # was activated by an administrator.
+ #
+ # Example:
+ # account_activated => Mail::Message object
+ def account_activated
+ @user = User.current
@login_url = url_for(:controller => 'account', :action => 'login')
- mail :to => user.mail,
+ mail :to => User.current.mail,
:subject => l(:mail_subject_register, Setting.app_title)
end
+ # Build a MultiMessage to email the specified user that their account was
+ # activated by an administrator.
+ #
+ # Example:
+ # Mailer.account_activated(user).deliver => sends an email to the registered user
+ def self.account_activated(user)
+ MultiMessage.new(:account_activated).for(user)
+ end
+
+ # Builds a Mail::Message object used to email the lost password token to the
+ # token's user (or a different recipient).
+ #
+ # Example:
+ # lost_password(token) => Mail::Message object
def lost_password(token, recipient=nil)
- set_language_if_valid(token.user.language)
recipient ||= token.user.mail
@token = token
@url = url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
:subject => l(:mail_subject_lost_password, Setting.app_title)
end
+ # Build a MultiMessage to email the token's user (or a different recipient)
+ # the lost password token for the token's user.
+ #
+ # Example:
+ # Mailer.lost_password(token).deliver => sends an email to the user
+ def self.lost_password(token, recipient=nil)
+ MultiMessage.new(:lost_password, token, recipient).for(token.user)
+ end
+
# Notifies user that his password was updated
def self.password_updated(user, options={})
# Don't send a notification to the dummy email address when changing the password
).deliver
end
+ # Builds a Mail::Message object used to email the user activation link to the
+ # token's user.
+ #
+ # Example:
+ # register(token) => Mail::Message object
def register(token)
- set_language_if_valid(token.user.language)
@token = token
@url = url_for(:controller => 'account', :action => 'activate', :token => token.value)
mail :to => token.user.mail,
:subject => l(:mail_subject_register, Setting.app_title)
end
- def security_notification(recipients, options={})
- @user = Array(recipients).detect{|r| r.is_a? User }
- set_language_if_valid(@user.try :language)
+ # Build a MultiMessage to email the user activation link to the token's user.
+ #
+ # Example:
+ # Mailer.register(token).deliver => sends an email to the token's user
+ def self.register(token)
+ MultiMessage.new(:register, token).for(token.user)
+ end
+
+ # Build a Mail::Message object to email the current user and the additional
+ # recipients given in options[:recipients] about a security related event.
+ #
+ # Example:
+ # security_notification(users,
+ # message: :mail_body_security_notification_add,
+ # field: :field_mail,
+ # value: address
+ # ) => Mail::Message object
+ def security_notification(sender, options={})
+ @sender = sender
+ redmine_headers 'Sender' => sender.login
@message = l(options[:message],
field: (options[:field] && l(options[:field])),
value: options[:value]
)
@title = options[:title] && l(options[:title])
- @originator = options[:originator] || User.current
+ @originator = options[:originator] || sender
@remote_ip = options[:remote_ip] || @originator.remote_ip
@url = options[:url] && (options[:url].is_a?(Hash) ? url_for(options[:url]) : options[:url])
redmine_headers 'Sender' => @originator.login
redmine_headers 'Url' => @url
- mail :to => recipients,
+ mail :to => [User.current, *options[:recipients]].uniq,
:subject => "[#{Setting.app_title}] #{l(:mail_subject_security_notification)}"
end
- def settings_updated(recipients, changes)
- redmine_headers 'Sender' => User.current.login
+ # Build a MultiMessage to email the given users about a security related event.
+ #
+ # You can specify additional recipients in options[:recipients]. These will be
+ # added to all generated mails for all given users. Usually, you'll want to
+ # give only a single user when setting the additional recipients.
+ #
+ # Example:
+ # Mailer.security_notification(users,
+ # message: :mail_body_security_notification_add,
+ # field: :field_mail,
+ # value: address
+ # ).deliver => sends a security notification to the given user(s)
+ def self.security_notification(users, options={})
+ sender = User.current
+ MultiMessage.new(:security_notification, sender, options).for(users)
+ end
+
+ # Build a Mail::Message object to email the current user about an updated
+ # setting.
+ #
+ # Example:
+ # settings_updated(sender, [:host_name]) => Mail::Message object
+ def settings_updated(sender, changes)
+ @sender = sender
+ redmine_headers 'Sender' => sender.login
@changes = changes
@url = url_for(controller: 'settings', action: 'index')
- mail :to => recipients,
+ mail :to => User.current,
:subject => "[#{Setting.app_title}] #{l(:mail_subject_security_notification)}"
end
+ # Build a MultiMessage to email the given users about an update of a setting.
+ #
+ # Example:
+ # Mailer.settings_updated(users, [:host_name]).deliver => sends emails to the given user(s) about the update
+ def self.settings_updated(users, changes)
+ sender = User.current
+ MultiMessage.new(:settings_updated, sender, changes).for(users)
+ end
+
# Notifies admins about settings changes
def self.security_settings_updated(changes)
return unless changes.present?
settings_updated(users, changes).deliver
end
- def test_email(user)
- set_language_if_valid(user.language)
+ # Build a Mail::Message object with a test email for the current user
+ #
+ # Example:
+ # test_email => Mail::Message object
+ def test_email
@url = url_for(:controller => 'welcome')
- mail :to => user.mail,
+ mail :to => User.current.mail,
:subject => 'Redmine test'
end
+ # Build a MultiMessage to send a test email the given user
+ #
+ # Example:
+ # Mailer.test_email(user).deliver => send an email to the given user
+ def self.test_email(user)
+ MultiMessage.new(:test_email).for(user)
+ end
+
# Sends reminders to issue assignees
# Available options:
# * :days => how many days in the future to remind about (defaults to 7)
headers[:references] = @references_objects.collect {|o| "<#{self.class.references_for(o)}>"}.join(' ')
end
- m = if block_given?
+ if block_given?
super headers, &block
else
super headers do |format|
format.html unless Setting.plain_text_mail?
end
end
- set_language_if_valid @initial_language
-
- m
- end
-
- def initialize(*args)
- @initial_language = current_language
- set_language_if_valid Setting.default_language
- super
end
def self.deliver_mail(mail)
if m = method.to_s.match(%r{^deliver_(.+)$})
ActiveSupport::Deprecation.warn "Mailer.deliver_#{m[1]}(*args) is deprecated. Use Mailer.#{m[1]}(*args).deliver instead."
send(m[1], *args).deliver
+ elsif action_methods.include?(method.to_s)
+ MultiMessage.new(method, *args).for(User.current)
else
super
end
:f => ['tracker_id'],
:op => {
'tracker_id' => '='
- },
+ },
:v => {
'tracker_id' => ['1']
}
:f => [filter_name],
:op => {
filter_name => '='
- },
+ },
:v => {
filter_name => ['Foo']
- },
+ },
:c => ['project']
}
assert_response :success
:f => ['start_date'],
:op => {
:start_date => '='
- },
+ },
:format => 'csv'
}
assert_equal 'text/csv', @response.content_type
:tracker_id => 3,
:description => 'Prefilled',
:custom_field_values => {
- '2' => 'Custom field value'}
+ '2' => 'Custom field value'}
}
}
assert !t.disabled_core_fields.include?('parent_issue_id')
get :new, :params => {
- :project_id => 1, issue: { parent_issue_id: 1
+ :project_id => 1, issue: { parent_issue_id: 1
}
}
assert_response :success
t.save!
assert t.disabled_core_fields.include?('parent_issue_id')
get :new, :params => {
- :project_id => 1, issue: { parent_issue_id: 1
+ :project_id => 1, issue: { parent_issue_id: 1
}
}
assert_response :success
:issue => {
:tracker_id => 2,
:status_id => 1
- },
+ },
:was_default_status => 1
}
assert_response :success
:issue => {
:project_id => 1,
:fixed_version_id => ''
- },
+ },
:form_update_triggered_by => 'issue_project_id'
}
assert_response :success
:start_date => '2010-11-07',
:estimated_hours => '',
:custom_field_values => {
- '2' => 'Value for field 2'}
+ '2' => 'Value for field 2'}
}
}
end
:priority_id => 5,
:estimated_hours => '',
:custom_field_values => {
- '2' => 'Value for field 2'}
+ '2' => 'Value for field 2'}
}
}
end
:priority_id => 5,
:estimated_hours => '',
:custom_field_values => {
- '2' => 'Value for field 2'}
+ '2' => 'Value for field 2'}
}
}
end
:tracker_id => 3,
:subject => 'This is first issue',
:priority_id => 5
- },
+ },
:continue => ''
}
end
:description => 'This is the description',
:priority_id => 5,
:custom_field_values => {
- '1' => ['', 'MySQL', 'Oracle']}
+ '1' => ['', 'MySQL', 'Oracle']}
}
}
end
:description => 'This is the description',
:priority_id => 5,
:custom_field_values => {
- '1' => ['']}
+ '1' => ['']}
}
}
end
:description => 'This is the description',
:priority_id => 5,
:custom_field_values => {
- field.id.to_s => ['', '2', '3']}
+ field.id.to_s => ['', '2', '3']}
}
}
end
:due_date => '',
:custom_field_values => {
cf1.id.to_s => '', cf2.id.to_s => ''
- }
-
+ }
+
}
}
assert_response :success
:due_date => '',
:custom_field_values => {
cf1.id.to_s => '', cf2.id.to_s => ['']
- }
-
+ }
+
}
}
assert_response :success
:due_date => '2012-07-16',
:custom_field_values => {
cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
- }
-
+ }
+
}
}
assert_response 302
:tracker_id => 1,
:status_id => 1,
:subject => 'Test'
-
+
}
}
assert_response 302
:project_id => 3,
:tracker_id => 2,
:subject => 'Foo'
- },
+ },
:continue => '1'
}
assert_redirected_to '/issues/new?issue%5Bproject_id%5D=3&issue%5Btracker_id%5D=2'
:priority_id => 5,
:estimated_hours => '',
:custom_field_values => {
- '2' => 'Value for field 2'}
+ '2' => 'Value for field 2'}
}
}
end
assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
- assert_equal 1, ActionMailer::Base.deliveries.size
+ assert_equal 2, ActionMailer::Base.deliveries.size
end
end
post :create, :params => {
:project_id => 1,
:issue => {
- :tracker => "A param can not be a Tracker"
+ :tracker => "A param can not be a Tracker"
}
}
end
:project_id => 1,
:issue => {
:tracker_id => '1',
- :subject => 'With attachment'
- },
+ :subject => 'With attachment'
+ },
:attachments => {
'1' => {
- 'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
+ 'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
}
}
end
:project_id => 1,
:issue => {
:tracker_id => '1',
- :subject => 'With attachment'
- },
+ :subject => 'With attachment'
+ },
:attachments => {
'1' => {
- 'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
+ 'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
}
}
end
:project_id => 1,
:issue => {
:tracker_id => '1',
- :subject => ''
- },
+ :subject => ''
+ },
:attachments => {
'1' => {
- 'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
+ 'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
}
}
assert_response :success
:project_id => 1,
:issue => {
:tracker_id => '1',
- :subject => ''
- },
+ :subject => ''
+ },
:attachments => {
'p0' => {
- 'token' => attachment.token}
+ 'token' => attachment.token}
}
}
assert_response :success
:project_id => 1,
:issue => {
:tracker_id => '1',
- :subject => 'Saved attachments'
- },
+ :subject => 'Saved attachments'
+ },
:attachments => {
'p0' => {
- 'token' => attachment.token}
+ 'token' => attachment.token}
}
}
assert_response 302
:project_id => '1',
:tracker_id => '1',
:status_id => '1'
- },
+ },
:was_default_status => '1'
}
end
:tracker_id => '3',
:status_id => '1',
:subject => 'Copy with attachments'
- },
+ },
:copy_attachments => '1'
}
end
:tracker_id => '3',
:status_id => '1',
:subject => 'Copy with attachments'
- },
+ },
:copy_attachments => '1',
:attachments => {
'1' => {
:tracker_id => '3',
:status_id => '1',
:subject => 'Copy with subtasks'
- },
+ },
:copy_subtasks => '1'
}
end
:status_id => '1',
:subject => 'Copy with subtasks',
:custom_field_values => {
- '2' => 'Foo'}
- },
+ '2' => 'Foo'}
+ },
:copy_subtasks => '1'
}
end
:id => 1,
:issue => {
:status_id => 5,
- :priority_id => 7
- },
+ :priority_id => 7
+ },
:time_entry => {
:hours => '2.5',
:comments => 'test_get_edit_with_params',
- :activity_id => 10
+ :activity_id => 10
}
}
assert_response :success
:project_id => '1',
:tracker_id => '2',
:priority_id => '6'
-
+
}
}
end
:issue => {
:subject => 'Custom field change',
:custom_field_values => {
- '1' => ['', 'Oracle', 'PostgreSQL']
- }
-
+ '1' => ['', 'Oracle', 'PostgreSQL']
+ }
+
}
}
end
:issue => {
:status_id => 2,
:assigned_to_id => 3,
- :notes => 'Assigned to dlopper'
- },
+ :notes => 'Assigned to dlopper'
+ },
:time_entry => {
:hours => '',
:comments => '',
- :activity_id => TimeEntryActivity.first
+ :activity_id => TimeEntryActivity.first
}
}
end
put :update, :params => {
:id => 1,
:issue => {
- :notes => notes
+ :notes => notes
}
}
end
put :update, :params => {
:id => 1,
:issue => {
- :notes => '2.5 hours added'
- },
+ :notes => '2.5 hours added'
+ },
:time_entry => {
:hours => '2.5',
:comments => 'test_put_update_with_note_and_spent_time',
- :activity_id => TimeEntryActivity.first.id
+ :activity_id => TimeEntryActivity.first.id
}
}
end
:id => 1,
:issue => {
:notes => ''
- },
+ },
:attachments => {
'1' => {
- 'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
+ 'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
}
}
end
put :update, :params => {
:id => 1,
:issue => {
- :subject => ''
- },
+ :subject => ''
+ },
:attachments => {
'1' => {
- 'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
+ 'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
}
}
assert_response :success
put :update, :params => {
:id => 1,
:issue => {
- :subject => ''
- },
+ :subject => ''
+ },
:attachments => {
'p0' => {
- 'token' => attachment.token}
+ 'token' => attachment.token}
}
}
assert_response :success
:id => 1,
:issue => {
:notes => 'Attachment added'
- },
+ },
:attachments => {
'p0' => {
- 'token' => attachment.token}
+ 'token' => attachment.token}
}
}
assert_redirected_to '/issues/1'
:id => 1,
:issue => {
:notes => ''
- },
+ },
:attachments => {
'1' => {
- 'file' => uploaded_test_file('testfile.txt', 'text/plain')}
+ 'file' => uploaded_test_file('testfile.txt', 'text/plain')}
}
}
assert_redirected_to :action => 'show', :id => '1'
:issue => {
:notes => 'Removing attachments',
:deleted_attachment_ids => ['1', '5']
-
+
}
}
end
:subject => '',
:notes => 'Removing attachments',
:deleted_attachment_ids => ['1', '5']
-
+
}
}
end
:subject => new_subject,
:priority_id => '6',
:category_id => '1' # no change
-
+
}
}
- assert_equal 1, ActionMailer::Base.deliveries.size
+ assert_equal 2, ActionMailer::Base.deliveries.size
end
end
:id => 1,
:issue => {
:notes => notes
- },
+ },
:time_entry => {
"comments"=>"", "activity_id"=>"", "hours"=>"2z"
}
:id => 1,
:issue => {
:notes => notes
- },
+ },
:time_entry => {
"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""
}
:id => issue.id,
:issue => {
:fixed_version_id => 4
-
+
}
}
:id => issue.id,
:issue => {
:fixed_version_id => 4
-
- },
+
+ },
:back_url => '/issues'
}
:id => issue.id,
:issue => {
:fixed_version_id => 4
-
- },
+
+ },
:back_url => 'http://google.com'
}
:issue => {
:status_id => 6,
:notes => 'Notes'
- },
+ },
:prev_issue_id => 8,
:next_issue_id => 12,
:issue_position => 2,
:priority_id => 7,
:assigned_to_id => '',
:custom_field_values => {
- '2' => ''}
+ '2' => ''}
}
}
:priority_id => '',
:assigned_to_id => group.id,
:custom_field_values => {
- '2' => ''}
+ '2' => ''}
}
}
:priority_id => 7,
:assigned_to_id => '',
:custom_field_values => {
- '2' => ''}
+ '2' => ''}
}
}
:priority_id => 7,
:assigned_to_id => '',
:custom_field_values => {
- '2' => ''}
+ '2' => ''}
}
}
assert_response 403
assert_not_equal "Bulk should fail", Journal.last.notes
end
- def test_bullk_update_should_send_a_notification
+ def test_bulk_update_should_send_a_notification
@request.session[:user_id] = 2
ActionMailer::Base.deliveries.clear
with_settings :notified_events => %w(issue_updated) do
}
}
assert_response 302
- assert_equal 2, ActionMailer::Base.deliveries.size
+ assert_equal 5, ActionMailer::Base.deliveries.size
end
end
:id => 1,
:issue => {
:project_id => '2'
- },
+ },
:follow => '1'
}
assert_redirected_to '/issues/1'
:id => [1, 2],
:issue => {
:project_id => '2'
- },
+ },
:follow => '1'
}
assert_redirected_to '/projects/onlinestore/issues'
:priority_id => '',
:assigned_to_id => '',
:custom_field_values => {
- '2' => '777'}
+ '2' => '777'}
}
}
:priority_id => '',
:assigned_to_id => '',
:custom_field_values => {
- '1' => '__none__'}
+ '1' => '__none__'}
}
}
assert_response 302
:priority_id => '',
:assigned_to_id => '',
:custom_field_values => {
- '1' => ['MySQL', 'Oracle']}
+ '1' => ['MySQL', 'Oracle']}
}
}
:priority_id => '',
:assigned_to_id => '',
:custom_field_values => {
- '1' => ['__none__']}
+ '1' => ['__none__']}
}
}
assert_response 302
:ids => issue_ids,
:issue => {
:project_id => '2'
- },
+ },
:copy => '1'
}
end
:ids => [1, 2, 3],
:issue => {
:project_id => '2'
- },
+ },
:copy => '1'
}
assert_response 302
:ids => [1, 2, 3],
:issue => {
:project_id => ''
- },
+ },
:copy => '1'
}
assert_response 403
:ids => [1, 2, 3],
:issue => {
:project_id => '1'
- },
+ },
:copy => '1'
}
assert_response 403
:status_id => '',
:start_date => '',
:due_date => ''
-
+
}
}
end
:status_id => '1',
:start_date => '2009-12-01',
:due_date => '2009-12-31'
-
+
}
}
end
:status_id => '3',
:start_date => '2009-12-01',
:due_date => '2009-12-31'
-
+
}
}
end
:copy_attachments => '0',
:issue => {
:project_id => ''
-
+
}
}
end
:copy_attachments => '1',
:issue => {
:project_id => ''
-
+
}
}
end
:link_copy => '1',
:issue => {
:project_id => '1'
-
+
}
}
end
:copy_subtasks => '0',
:issue => {
:project_id => ''
-
+
}
}
end
:copy_subtasks => '1',
:issue => {
:project_id => ''
-
+
}
}
end
:copy_watchers => '1',
:issue => {
:project_id => ''
-
+
}
}
end
:copy_subtasks => '1',
:issue => {
:project_id => ''
-
+
}
}
end
:copy => '1',
:issue => {
:project_id => 2
- },
+ },
:follow => '1'
}
issue = Issue.order('id DESC').first