Feature #2477 ยป 2477-reminder-to-watchers.diff
app/models/mailer.rb (working copy) | ||
---|---|---|
376 | 376 |
# * :project => id or identifier of project to process (defaults to all projects) |
377 | 377 |
# * :users => array of user/group ids who should be reminded |
378 | 378 |
# * :version => name of target version for filtering issues (defaults to none) |
379 |
# * :recipients => array of recipient types (available values are :assignee and :watcher, default to :assignee) |
|
379 | 380 |
def self.reminders(options={}) |
380 | 381 |
days = options[:days] || 7 |
381 | 382 |
project = options[:project] ? Project.find(options[:project]) : nil |
... | ... | |
385 | 386 |
raise ActiveRecord::RecordNotFound.new("Couldn't find Version with named #{options[:version]}") |
386 | 387 |
end |
387 | 388 |
user_ids = options[:users] |
389 |
recipients = options[:recipients] |
|
390 |
recipients = [:assignee] if recipients.blank? |
|
388 | 391 | |
389 |
scope = Issue.open.where("#{Issue.table_name}.assigned_to_id IS NOT NULL" +
|
|
390 |
" AND #{Project.table_name}.status = #{Project::STATUS_ACTIVE}" +
|
|
392 |
scope = Issue.open.where( |
|
393 |
"#{Project.table_name}.status = #{Project::STATUS_ACTIVE}" + |
|
391 | 394 |
" AND #{Issue.table_name}.due_date <= ?", days.day.from_now.to_date |
392 | 395 |
) |
393 | 396 |
scope = scope.where(:assigned_to_id => user_ids) if user_ids.present? |
394 | 397 |
scope = scope.where(:project_id => project.id) if project |
395 | 398 |
scope = scope.where(:fixed_version_id => target_version_id) if target_version_id.present? |
396 | 399 |
scope = scope.where(:tracker_id => tracker.id) if tracker |
397 |
issues_by_assignee = scope.includes(:status, :assigned_to, :project, :tracker). |
|
398 |
group_by(&:assigned_to) |
|
399 |
issues_by_assignee.keys.each do |assignee| |
|
400 |
if assignee.is_a?(Group) |
|
401 |
assignee.users.each do |user| |
|
402 |
issues_by_assignee[user] ||= [] |
|
403 |
issues_by_assignee[user] += issues_by_assignee[assignee] |
|
400 |
issues = scope.includes(:status, :assigned_to, :project, :tracker) |
|
401 |
issues_by_recipient = {} |
|
402 | ||
403 |
if recipients.include?(:assignee) |
|
404 |
issues_by_recipient = |
|
405 |
issues.where('assigned_to_id IS NOT NULL').group_by(&:assigned_to) |
|
406 |
issues_by_recipient.keys.each do |assignee| |
|
407 |
if assignee.is_a?(Group) |
|
408 |
assignee.users.each do |user| |
|
409 |
issues_by_recipient[user] ||= [] |
|
410 |
issues_by_recipient[user] += issues_by_recipient[assignee] |
|
411 |
end |
|
404 | 412 |
end |
405 | 413 |
end |
406 | 414 |
end |
407 | ||
408 |
issues_by_assignee.each do |assignee, issues| |
|
409 |
reminder(assignee, issues, days).deliver if assignee.is_a?(User) && assignee.active? |
|
415 |
if recipients.include?(:watcher) |
|
416 |
issues.each do |issue| |
|
417 |
issue.notified_watchers.each do |watcher| |
|
418 |
issues_by_recipient[watcher] ||= [] |
|
419 |
issues_by_recipient[watcher] |= [issue] |
|
420 |
end |
|
421 |
end |
|
410 | 422 |
end |
423 |
issues_by_recipient.each do |recipient, issues| |
|
424 |
reminder(recipient, issues, days).deliver if recipient.is_a?(User) && recipient.active? |
|
425 |
end |
|
411 | 426 |
end |
412 | 427 | |
413 | 428 |
# Activates/desactivates email deliveries during +block+ |
lib/tasks/reminder.rake (working copy) | ||
---|---|---|
24 | 24 |
* project => id or identifier of project (defaults to all projects) |
25 | 25 |
* users => comma separated list of user/group ids who should be reminded |
26 | 26 |
* version => name of target version for filtering issues (defaults to none) |
27 |
* recipients => comma separated list of recipient types |
|
28 |
(default to 'assignee', available values are 'assignee' and 'watcher') |
|
27 | 29 | |
28 | 30 |
Example: |
29 | 31 |
rake redmine:send_reminders days=7 users="1,23, 56" RAILS_ENV="production" |
... | ... | |
36 | 38 |
options[:project] = ENV['project'] if ENV['project'] |
37 | 39 |
options[:tracker] = ENV['tracker'].to_i if ENV['tracker'] |
38 | 40 |
options[:users] = (ENV['users'] || '').split(',').each(&:strip!) |
39 |
options[:version] = ENV['version'] if ENV['version'] |
|
41 |
options[:version] = ENV['version'] if ENV['version'] |
|
42 |
options[:recipients] = |
|
43 |
ENV['recipients'].to_s.downcase.split(',').map(&:strip).map(&:to_sym) & |
|
44 |
[:assignee, :watcher] |
|
40 | 45 | |
41 | 46 |
Mailer.with_synched_deliveries do |
42 | 47 |
Mailer.reminders(options) |
test/unit/mailer_test.rb (working copy) | ||
---|---|---|
663 | 663 |
end |
664 | 664 |
end |
665 | 665 | |
666 |
def test_reminders_with_recipient_option |
|
667 |
with_settings :default_language => 'en' do |
|
668 |
# assigned to dlopper, watched by jsmith |
|
669 |
issues(:issues_003).add_watcher(users(:users_002)) |
|
670 |
# assigned to nobody, watched by jsmith |
|
671 |
Issue.generate!(:assigned_to => nil, :due_date => 5.days.from_now, :subject => 'Assigned to nobody').add_watcher(users(:users_002)) |
|
672 |
ActionMailer::Base.deliveries.clear |
|
673 | ||
674 |
Mailer.reminders(:days => 42, :recipients => [:assignee]) |
|
675 |
assert_equal 1, ActionMailer::Base.deliveries.size |
|
676 |
assert last_email.bcc.include?('dlopper@somenet.foo') |
|
677 |
ActionMailer::Base.deliveries.clear |
|
678 | ||
679 |
Mailer.reminders(:days => 42, :recipients => [:watcher]) |
|
680 |
assert_equal 1, ActionMailer::Base.deliveries.size |
|
681 |
mail = last_email |
|
682 |
assert mail.bcc.include?('jsmith@somenet.foo') |
|
683 |
assert_mail_body_match 'Bug #3: Error 281 when updating a recipe', mail |
|
684 |
assert_mail_body_match 'Assigned to nobody', mail |
|
685 |
ActionMailer::Base.deliveries.clear |
|
686 | ||
687 |
Mailer.reminders(:days => 42, :recipients => [:assignee, :watcher]) |
|
688 |
assert_equal 2, ActionMailer::Base.deliveries.size |
|
689 |
assert_equal %w(dlopper@somenet.foo jsmith@somenet.foo), ActionMailer::Base.deliveries.map(&:bcc).flatten.sort |
|
690 |
end |
|
691 |
end |
|
692 | ||
666 | 693 |
def test_security_notification |
667 | 694 |
set_language_if_valid User.find(1).language |
668 | 695 |
with_settings :emails_footer => "footer without link" do |