See @rake -D redmine:send_reminders@ for options. git-svn-id: http://redmine.rubyforge.org/svn/trunk@1459 e93f8b46-1217-0410-a6f0-8f06a7374b81tags/0.8.0-RC1
@@ -51,6 +51,15 @@ class Mailer < ActionMailer::Base | |||
:issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue) | |||
end | |||
def reminder(user, issues, days) | |||
set_language_if_valid user.language | |||
recipients user.mail | |||
subject l(:mail_subject_reminder, issues.size) | |||
body :issues => issues, | |||
:days => days, | |||
:issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'issues.due_date', :sort_order => 'asc') | |||
end | |||
def document_added(document) | |||
redmine_headers 'Project' => document.project.identifier | |||
recipients document.project.recipients | |||
@@ -144,6 +153,28 @@ class Mailer < ActionMailer::Base | |||
(bcc.nil? || bcc.empty?) | |||
super | |||
end | |||
# Sends reminders to issue assignees | |||
# Available options: | |||
# * :days => how many days in the future to remind about (defaults to 7) | |||
# * :tracker => id of tracker for filtering issues (defaults to all trackers) | |||
# * :project => id or identifier of project to process (defaults to all projects) | |||
def self.reminders(options={}) | |||
days = options[:days] || 7 | |||
project = options[:project] ? Project.find(options[:project]) : nil | |||
tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil | |||
s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ? AND #{Issue.table_name}.assigned_to_id IS NOT NULL", false, days.day.from_now.to_date] | |||
s << "#{Issue.table_name}.project_id = #{project.id}" if project | |||
s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker | |||
issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker], | |||
:conditions => s.conditions | |||
).group_by(&:assigned_to) | |||
issues_by_assignee.each do |assignee, issues| | |||
deliver_reminder(assignee, issues, days) unless assignee.nil? | |||
end | |||
end | |||
private | |||
def initialize_defaults(method_name) |
@@ -0,0 +1,9 @@ | |||
<p><%= l(:mail_body_reminder, @issues.size, @days) %></p> | |||
<ul> | |||
<% @issues.each do |issue| -%> | |||
<li><%=h "#{issue.project} - #{issue.tracker} ##{issue.id}: #{issue.subject}" %></li> | |||
<% end -%> | |||
</ul> | |||
<p><%= link_to l(:label_issue_view_all), @issues_url %></p> |
@@ -0,0 +1,7 @@ | |||
<%= l(:mail_body_reminder, @issues.size, @days) %>: | |||
<% @issues.each do |issue| -%> | |||
* <%= "#{issue.project} - #{issue.tracker} ##{issue.id}: #{issue.subject}" %> | |||
<% end -%> | |||
<%= @issues_url %> |
@@ -619,3 +619,5 @@ error_scm_annotate: "Обектът не съществува или не мож | |||
label_planning: Планиране | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -624,3 +624,5 @@ error_scm_annotate: "Položka neexistuje nebo nemůže být komentována." | |||
label_planning: Plánování | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -621,3 +621,5 @@ error_scm_annotate: "The entry does not exist or can not be annotated." | |||
label_planning: Planlægning | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -620,3 +620,5 @@ enumeration_doc_categories: Dokumentenkategorien | |||
enumeration_activities: Aktivitäten (Zeiterfassung) | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -91,6 +91,8 @@ mail_body_account_information_external: You can use your "%s" account to log in. | |||
mail_body_account_information: Your account information | |||
mail_subject_account_activation_request: %s account activation request | |||
mail_body_account_activation_request: 'A new user (%s) has registered. His account is pending your approval:' | |||
mail_subject_reminder: "%d issue(s) due in the next days" | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
gui_validation_error: 1 error | |||
gui_validation_error_plural: %d errors |
@@ -622,3 +622,5 @@ error_scm_annotate: "No existe la entrada o no ha podido ser anotada" | |||
label_planning: Planificación | |||
text_subprojects_destroy_warning: 'Sus subprojectos: %s también se eliminarán' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -619,3 +619,5 @@ error_scm_annotate: "Merkintää ei ole tai siihen ei voi lisätä selityksiä." | |||
label_planning: Suunnittelu | |||
text_subprojects_destroy_warning: 'Tämän alaprojekti(t): %s tullaan myös poistamaan.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -91,6 +91,8 @@ mail_body_account_information_external: Vous pouvez utiliser votre compte "%s" p | |||
mail_body_account_information: Paramètres de connexion de votre compte | |||
mail_subject_account_activation_request: "Demande d'activation d'un compte %s" | |||
mail_body_account_activation_request: "Un nouvel utilisateur (%s) s'est inscrit. Son compte nécessite votre approbation:" | |||
mail_subject_reminder: "%d demande(s) arrivent à échéance" | |||
mail_body_reminder: "%d demande(s) qui vous sont assignées arrivent à échéance dans les %d prochains jours:" | |||
gui_validation_error: 1 erreur | |||
gui_validation_error_plural: %d erreurs |
@@ -619,3 +619,5 @@ error_scm_annotate: "הכניסה לא קיימת או שלא ניתן לתאר | |||
label_planning: תכנון | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -620,3 +620,5 @@ default_activity_development: Fejlesztés | |||
enumeration_issue_priorities: Feladat prioritások | |||
enumeration_doc_categories: Dokumentum kategóriák | |||
enumeration_activities: Tevékenységek (idő rögzítés) | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -619,3 +619,5 @@ error_scm_annotate: "The entry does not exist or can not be annotated." | |||
label_planning: Planning | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -620,3 +620,5 @@ error_scm_annotate: "エントリが存在しない、もしくはアノテー | |||
label_planning: 計画 | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -619,3 +619,5 @@ error_scm_annotate: "The entry does not exist or can not be annotated." | |||
label_planning: Planning | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -621,3 +621,5 @@ label_planning: Planavimas | |||
text_subprojects_destroy_warning: 'Šis(ie) subprojektas(ai): %s taip pat bus ištrintas(i).' | |||
label_and_its_subprojects: %s projektas ir jo subprojektai | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -620,3 +620,5 @@ error_scm_annotate: "The entry does not exist or can not be annotated." | |||
label_planning: Planning | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -620,3 +620,5 @@ default_activity_development: Utvikling | |||
enumeration_issue_priorities: Sakssprioriteringer | |||
enumeration_doc_categories: Dokument-kategorier | |||
enumeration_activities: Aktiviteter (tidssporing) | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -619,3 +619,5 @@ error_scm_annotate: "Wpis nie istnieje lub nie można do niego dodawać adnotacj | |||
label_planning: Planning | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -619,3 +619,5 @@ label_planning: Planejamento | |||
text_subprojects_destroy_warning: 'Seu(s) subprojeto(s): %s também serão excluídos.' | |||
label_age: Age | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -619,3 +619,5 @@ error_scm_annotate: "The entry does not exist or can not be annotated." | |||
label_planning: Planning | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -619,3 +619,5 @@ error_scm_annotate: "The entry does not exist or can not be annotated." | |||
label_planning: Planning | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -623,3 +623,5 @@ error_scm_annotate: "Данные отсутствуют или не могут | |||
label_planning: Планирование | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -620,3 +620,5 @@ error_scm_annotate: "The entry does not exist or can not be annotated." | |||
label_planning: Planning | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -620,3 +620,5 @@ error_scm_annotate: "The entry does not exist or can not be annotated." | |||
label_planning: Planning | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -622,3 +622,5 @@ enumeration_issue_priorities: ความสำคัญของปัญห | |||
enumeration_doc_categories: ประเภทเอกสาร | |||
enumeration_activities: กิจกรรม (ใช้ในการติดตามเวลา) | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -621,3 +621,5 @@ error_scm_annotate: "The entry does not exist or can not be annotated." | |||
label_planning: Planning | |||
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' | |||
label_and_its_subprojects: %s and its subprojects | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -620,3 +620,5 @@ default_activity_development: 開發 | |||
enumeration_issue_priorities: 項目優先權 | |||
enumeration_doc_categories: 文件分類 | |||
enumeration_activities: 活動 (時間追蹤) | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" |
@@ -619,4 +619,6 @@ default_activity_development: 开发 | |||
enumeration_issue_priorities: 问题优先级 | |||
enumeration_doc_categories: 文档类别 | |||
enumeration_activities: 活动(时间跟踪) | |||
enumeration_activities: 活动(时间跟踪)mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" | |||
mail_subject_reminder: "%d issue(s) due in the next days" | |||
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" |
@@ -0,0 +1,39 @@ | |||
# redMine - project management software | |||
# Copyright (C) 2008 Jean-Philippe Lang | |||
# | |||
# This program is free software; you can redistribute it and/or | |||
# modify it under the terms of the GNU General Public License | |||
# as published by the Free Software Foundation; either version 2 | |||
# of the License, or (at your option) any later version. | |||
# | |||
# This program is distributed in the hope that it will be useful, | |||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
# GNU General Public License for more details. | |||
# | |||
# You should have received a copy of the GNU General Public License | |||
# along with this program; if not, write to the Free Software | |||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
desc <<-END_DESC | |||
Send reminders about issues due in the next days. | |||
Available options: | |||
* days => number of days to remind about (defaults to 7) | |||
* tracker => id of tracker (defaults to all trackers) | |||
* project => id or identifier of project (defaults to all projects) | |||
Example: | |||
rake redmine:send_reminders days=7 RAILS_ENV="production" | |||
END_DESC | |||
namespace :redmine do | |||
task :send_reminders => :environment do | |||
options = {} | |||
options[:days] = ENV['days'].to_i if ENV['days'] | |||
options[:project] = ENV['project'] if ENV['project'] | |||
options[:tracker] = ENV['tracker'].to_i if ENV['tracker'] | |||
Mailer.reminders(options) | |||
end | |||
end |
@@ -42,7 +42,7 @@ issues_003: | |||
category_id: | |||
description: Error 281 is encountered when saving a recipe | |||
tracker_id: 1 | |||
assigned_to_id: | |||
assigned_to_id: 3 | |||
author_id: 2 | |||
status_id: 1 | |||
start_date: <%= 1.day.from_now.to_date.to_s(:db) %> |
@@ -116,4 +116,13 @@ class MailerTest < Test::Unit::TestCase | |||
assert Mailer.deliver_register(token) | |||
end | |||
end | |||
def test_reminders | |||
ActionMailer::Base.deliveries.clear | |||
Mailer.reminders(:days => 42) | |||
assert_equal 1, ActionMailer::Base.deliveries.size | |||
mail = ActionMailer::Base.deliveries.last | |||
assert mail.bcc.include?('dlopper@somenet.foo') | |||
assert mail.body.include?('Bug #3: Error 281 when updating a recipe') | |||
end | |||
end |