├── .gitignore
├── Gemfile
├── LICENSE
├── README.md
├── app
├── models
│ └── reminding_mailer.rb
└── views
│ ├── reminding_mailer
│ ├── remind_user_issue_estimates.html.erb
│ ├── remind_user_issue_estimates.text.erb
│ ├── remind_user_issue_statuses.html.erb
│ ├── remind_user_issue_statuses.text.erb
│ ├── remind_user_issue_trackers.html.erb
│ ├── remind_user_issue_trackers.text.erb
│ ├── remind_user_past_due_issues.html.erb
│ ├── remind_user_past_due_issues.text.erb
│ ├── reminder_issue_email.html.erb
│ ├── reminder_issue_email.text.erb
│ ├── reminder_status_email.html.erb
│ └── reminder_status_email.text.erb
│ └── settings
│ └── _reminder_settings.html.erb
├── config
├── locales
│ └── en.yml
├── routes.rb
└── schedule.rb
├── init.rb
├── lib
├── redmine_update_reminder
│ └── patches
│ │ └── user_patch.rb
└── tasks
│ └── reminder.rake
└── test
└── test_helper.rb
/.gitignore:
--------------------------------------------------------------------------------
1 | *.rbc
2 | *.sassc
3 | .sass-cache
4 | capybara-*.html
5 | .rspec
6 | /.bundle
7 | /vendor/bundle
8 | /log/*
9 | /tmp/*
10 | /db/*.sqlite3
11 | /public/system/*
12 | /coverage/
13 | /spec/tmp/*
14 | **.orig
15 | rerun.txt
16 | pickle-email-*.html
17 | *~
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | gem 'whenever',">=0.8.4"
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Hisham Malik
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Redmine Update Reminder:
2 | ========================
3 |
4 | This plugin sends reminder email to assigned users if an issue is not updated within specified duration.
5 |
6 | Functionality:
7 | ==============
8 |
9 | All the mails are cc'ed to a single Group (generally scrum master/HR) along with the assigned user for notifying that a given task needs updation.
10 | The duration for each kind of tracker can be set in settings.
11 | Duration takes input in days, and can be decimal point numbers (for instance .5 for 12 hours).
12 | Emails Headers and Footers are configurable for personalization.
13 |
14 | Installation:
15 | =============
16 |
17 | The plugin is available for download from
18 | `github.com:arkhitech/redmine_update_reminder`
19 |
20 | Go to redmine's plugins directory and `wheneverize` the downloaded redmine_update_reminder plugin directory.
21 | Open config directory and edit schedule.rb
22 |
23 |
24 | for example:
25 |
26 | set :environment, "production"
27 | every 1.day do
28 | rake "redmine_update_reminder:send_user_reminders"
29 | end
30 |
31 | This will check for all issues that have not been updated in the specified duration by the user and send them email.
32 |
33 | Check whenever gems documentation for detailed description of its working.
34 |
35 | There are two rake tasks. These can be run without scheduling using this command
36 |
37 | RAILS_ENV=production rake redmine_update_reminder:send_issue_reminders
38 |
39 | RAILS_ENV=production rake redmine_update_reminder:send_user_reminders
40 |
--------------------------------------------------------------------------------
/app/models/reminding_mailer.rb:
--------------------------------------------------------------------------------
1 | class RemindingMailer < ActionMailer::Base
2 | layout 'mailer'
3 | default from: Setting.mail_from
4 | helper :issues
5 | include Redmine::Utils::DateCalculation
6 |
7 | def self.default_url_options
8 | ::Mailer.default_url_options
9 | end
10 |
11 | def cc_group_email_addresses
12 | @cc_group_email_addresses ||= begin
13 | cc_group = Setting.plugin_redmine_update_reminder['cc']
14 | if cc_group.present?
15 | Group.includes(:users).find(cc_group).users.map(&:mail)
16 | else
17 | []
18 | end
19 |
20 | end
21 | end
22 | private :cc_group_email_addresses
23 |
24 | def cc_role_email_addresses(user)
25 | cc_role_ids = Setting.plugin_redmine_update_reminder['cc_roles']
26 | if cc_role_ids.present?
27 | User.active.preload(:email_address).joins(members: :member_roles).where("#{Member.table_name}.project_id" => user.projects.pluck(:id)).
28 | where("#{MemberRole.table_name}.role_id IN (?)", cc_role_ids).map(&:email_address).map(&:address)
29 | else
30 | []
31 | end
32 | end
33 | private :cc_role_email_addresses
34 |
35 | def cc_email_addresses(user)
36 | return [] if non_working_week_days.include?(Date.today.cwday)
37 | cc_email_addresses = cc_group_email_addresses
38 | cc_email_addresses += cc_role_email_addresses(user)
39 | cc_email_addresses.uniq
40 | end
41 | private :cc_email_addresses
42 |
43 | def reminder_issue_email(user, issue, updated_since)
44 | @user = user
45 | @issue = issue
46 | @updated_since = updated_since
47 |
48 | mail(to: @user.mail, subject: @issue.subject, cc: cc_email_addresses(user))
49 | end
50 |
51 | def reminder_status_email(user, issue, updated_since)
52 | @user = user
53 | @issue = issue
54 | @updated_since = updated_since
55 |
56 | mail(to: user.mail, subject: @issue.subject, cc: cc_email_addresses(user))
57 | end
58 |
59 | def remind_user_issue_trackers(user, issues_with_updated_since)
60 | @user = user
61 | @issues_with_updated_since = issues_with_updated_since
62 | subject = I18n.t('update_reminder.issue_tracker_update_required',
63 | user_name: user.name, issue_count: @issues_with_updated_since.count)
64 |
65 | mail(to: user.mail, subject: subject, cc: cc_email_addresses(user))
66 | end
67 |
68 | def remind_user_issue_statuses(user, issues_with_updated_since)
69 | @user = user
70 | @issues_with_updated_since = issues_with_updated_since
71 |
72 | subject = I18n.t('update_reminder.issue_status_update_required',
73 | user_name: user.name, issue_count: @issues_with_updated_since.count)
74 | mail(to: user.mail, subject: subject, cc: cc_email_addresses(user))
75 | end
76 |
77 | def remind_user_past_due_issues(user, issues)
78 | @user = user
79 | @issues = issues
80 |
81 | subject = I18n.t('update_reminder.past_due_issue_update_required',
82 | user_name: user.name, issue_count: @issues.count)
83 | mail(to: user.mail, subject: subject, cc: cc_email_addresses(user))
84 | end
85 |
86 | def remind_user_issue_estimates(user, issues_with_updated_since)
87 | @user = user
88 | @issues_with_updated_since = issues_with_updated_since
89 |
90 | subject = I18n.t('update_reminder.issue_estimate_required',
91 | user_name: user.name, issue_count: @issues_with_updated_since.count)
92 | mail(to: user.mail, subject: subject, cc: cc_email_addresses(user))
93 | end
94 |
95 | end
--------------------------------------------------------------------------------
/app/views/reminding_mailer/remind_user_issue_estimates.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%=@user.name%>,
3 |
4 | <%= Setting.plugin_redmine_update_reminder['header'] %>
5 |
6 |
7 | <% @issues_with_updated_since.each do |issue_with_updated_since| -%>
8 | <%issue, updated_since = issue_with_updated_since%>
9 |
10 | <%= link_to_issue(issue, project: true, only_path: false) %>
11 | is missing estimates for <%=time_ago_in_words(updated_since)%> .
12 |
13 | <% end -%>
14 |
15 |
16 | Immediate attention is required.
17 |
18 |
19 | <%= Setting.plugin_redmine_update_reminder['footer'] %>
20 |
--------------------------------------------------------------------------------
/app/views/reminding_mailer/remind_user_issue_estimates.text.erb:
--------------------------------------------------------------------------------
1 | <%=@user.name%>,
2 |
3 | <%= Setting.plugin_redmine_update_reminder['header'] %>
4 |
5 | <% @issues_with_updated_since.each_with_index do |issue_with_updated_since, i| -%>
6 | <%issue, updated_since = issue_with_updated_since%>
7 | <%= i+1%>. <%= link_to_issue(issue, project: true, only_path: false) %>
8 | is missing estimates for *<%=time_ago_in_words(updated_since)%>*.
9 | <% end -%>
10 |
11 |
12 | Immediate attention is required.
13 |
14 | <%= Setting.plugin_redmine_update_reminder['footer'] %>
--------------------------------------------------------------------------------
/app/views/reminding_mailer/remind_user_issue_statuses.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%=@user.name%>,
3 |
4 | <%= Setting.plugin_redmine_update_reminder['header'] %>
5 |
6 |
7 | <% @issues_with_updated_since.each do |issue_with_updated_since| -%>
8 | <%issue, updated_since = issue_with_updated_since%>
9 |
10 | <%= link_to_issue(issue, project: true, only_path: false) %>
11 | has been in <%=issue.status.name%> status for <%=time_ago_in_words(updated_since)%> .
12 |
13 | <% end -%>
14 |
15 |
16 | Immediate attention is required.
17 |
18 |
19 | <%= Setting.plugin_redmine_update_reminder['footer'] %>
20 |
--------------------------------------------------------------------------------
/app/views/reminding_mailer/remind_user_issue_statuses.text.erb:
--------------------------------------------------------------------------------
1 | <%=@user.name%>,
2 |
3 | <%= Setting.plugin_redmine_update_reminder['header'] %>
4 |
5 | <% @issues_with_updated_since.each_with_index do |issue_with_updated_since, i| -%>
6 | <%issue, updated_since = issue_with_updated_since%>
7 | <%= i+1%>. <%= link_to_issue(issue, project: true, only_path: false) %>
8 | has been in *<%=issue.status.name%>* status for *<%=time_ago_in_words(updated_since)%>*.
9 | <% end -%>
10 |
11 |
12 | Immediate attention is required.
13 |
14 | <%= Setting.plugin_redmine_update_reminder['footer'] %>
--------------------------------------------------------------------------------
/app/views/reminding_mailer/remind_user_issue_trackers.html.erb:
--------------------------------------------------------------------------------
1 | <%=@user.name%>,
2 |
3 | <%= Setting.plugin_redmine_update_reminder['header'] %>
4 |
5 |
6 | <% @issues_with_updated_since.each do |issue_with_updated_since| -%>
7 | <%issue, updated_since = issue_with_updated_since%>
8 |
9 | <%= link_to_issue(issue, project: true, only_path: false) %>
10 | has not been updated for <%=time_ago_in_words(updated_since)%> .
11 |
12 | <% end -%>
13 |
14 |
15 | Immediate attention is required.
16 |
17 |
18 | <%= Setting.plugin_redmine_update_reminder['footer'] %>
--------------------------------------------------------------------------------
/app/views/reminding_mailer/remind_user_issue_trackers.text.erb:
--------------------------------------------------------------------------------
1 | <%=@user.name%>,
2 |
3 | <%= Setting.plugin_redmine_update_reminder['header'] %>
4 |
5 | <% @issues_with_updated_since.each_with_index do |issue_with_updated_since, i| -%>
6 | <%issue, updated_since = issue_with_updated_since%>
7 | <% i+1%>. <%= link_to_issue(issue, project: true, only_path: false) %>
8 | has not been updated for *<%=time_ago_in_words(updated_since)%>*.
9 | <% end -%>
10 |
11 |
12 | Immediate attention is required.
13 |
14 |
15 | <%= Setting.plugin_redmine_update_reminder['footer'] %>
--------------------------------------------------------------------------------
/app/views/reminding_mailer/remind_user_past_due_issues.html.erb:
--------------------------------------------------------------------------------
1 | <%=@user.name%>,
2 |
3 | <%= Setting.plugin_redmine_update_reminder['header'] %>
4 |
5 |
6 | <% @issues.each do |issue| -%>
7 |
8 | <%= link_to_issue(issue, project: true, only_path: false) %>
9 | has been past due for <%=time_ago_in_words(issue.due_date)%>
10 | and last update was provided <%=time_ago_in_words(issue.updated_on)%> ago.
11 |
12 | <% end -%>
13 |
14 |
15 | Immediate attention is required.
16 |
17 |
18 | <%= Setting.plugin_redmine_update_reminder['footer'] %>
--------------------------------------------------------------------------------
/app/views/reminding_mailer/remind_user_past_due_issues.text.erb:
--------------------------------------------------------------------------------
1 | <%=@user.name%>,
2 |
3 | <%= Setting.plugin_redmine_update_reminder['header'] %>
4 |
5 | <% @issues.each_with_index do |issue, i| -%>
6 | <% i+1%>. <%= link_to_issue(issue, project: true, only_path: false) %>
7 | has been past due for *<%=time_ago_in_words(issue.due_date)%>*
8 | and last update was provided *<%=time_ago_in_words(issue.updated_on)%>* ago.
9 |
10 | <% end -%>
11 |
12 |
13 | Immediate attention is required.
14 |
15 |
16 | <%= Setting.plugin_redmine_update_reminder['footer'] %>
--------------------------------------------------------------------------------
/app/views/reminding_mailer/reminder_issue_email.html.erb:
--------------------------------------------------------------------------------
1 |
5 |
6 | <%= @user.name %>,
7 |
8 | <%= link_to("#{h(@issue.tracker)} ##{@issue.id}",
9 | {controller: 'issues', action: 'show', id: @issue, only_path: false}) %>
10 | has not been updated for <%=time_ago_in_words(@updated_since)%>. Immediate attention is required.
11 |
12 |
13 |
17 |
18 |
19 | <%= Setting.plugin_redmine_update_reminder['footer'] %>
20 |
--------------------------------------------------------------------------------
/app/views/reminding_mailer/reminder_issue_email.text.erb:
--------------------------------------------------------------------------------
1 | <%= Setting.plugin_redmine_update_reminder['header'] %>
2 |
3 | <%=@user.name%>,
4 |
5 | <%="#{h(@issue.tracker)} ##{@issue.id}"%>,
6 | <%= url_for({controller: 'issues', action: 'show', id: @issue}) %>
7 | has not been updated for *<%=time_ago_in_words(@updated_since)%>*.
8 |
9 | Immediate attention is required.
10 |
11 | <%= Setting.plugin_redmine_update_reminder['footer'] %>
--------------------------------------------------------------------------------
/app/views/reminding_mailer/reminder_status_email.html.erb:
--------------------------------------------------------------------------------
1 |
5 |
6 | <%= @user.name %>,
7 |
8 | <%= link_to("#{h(@issue.tracker)} ##{@issue.id}",
9 | {controller: 'issues', action: 'show', id: @issue, only_path: false}) %>
10 | has been in <%=@issue.status.name%> status for <%=time_ago_in_words(@updated_since)%>. Attention is required at the earliest.
11 |
12 |
13 |
17 |
18 |
19 | <%= Setting.plugin_redmine_update_reminder['footer'] %>
20 |
--------------------------------------------------------------------------------
/app/views/reminding_mailer/reminder_status_email.text.erb:
--------------------------------------------------------------------------------
1 | <%= Setting.plugin_redmine_update_reminder['header'] %>
2 |
3 | <%=@user.name%>,
4 |
5 | <%="#{h(@issue.tracker)} ##{@issue.id}"%>,
6 | <%= url_for({controller: 'issues', action: 'show', id: @issue}) %> has been in
7 | *<%=@issue.status.name%>* status for *<%=time_ago_in_words(@updated_since)%>*.
8 |
9 | Attention is required at the earliest.
10 |
11 | <%= Setting.plugin_redmine_update_reminder['footer'] %>
--------------------------------------------------------------------------------
/app/views/settings/_reminder_settings.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | Remind Users:
4 | <%= select_tag('settings[remind_group]',
5 | options_for_select(Group.all.collect{|g| [g.name, g.id]}, @settings['remind_group'])) %>
6 |
7 |
8 | Cc'd Group:
9 | <%= select_tag('settings[cc]',
10 | options_for_select(Group.all.collect{|g| [g.name, g.id]}, @settings['cc'])) %>
11 |
12 |
13 | Cc'd Project Roles:
14 | <%= select_tag('settings[cc_roles]',
15 | options_for_select(Role.all.collect{|r| [r.name, r.id]}, @settings['cc_roles']), multiple: true) %>
16 |
17 |
18 |
19 | Header
20 | <%= text_area_tag 'settings[header]', @settings['header'] %>
21 |
22 |
23 |
24 | Footer
25 | <%= text_area_tag 'settings[footer]', @settings['footer'] %>
26 |
27 |
28 |
29 |
30 |
31 | Update Interval for Tracker (Days)
32 |
33 |
34 |
35 |
36 |
37 | Tracker
38 | General
39 | <%IssueStatus.where(is_closed: false).each do |issue_status|%>
40 | <%=issue_status.name%>
41 | <%end%>
42 |
43 | <%Tracker.all.each do |tracker| -%>
44 |
45 | <%=tracker.name%>
46 |
47 | <%= text_field_tag "settings[#{tracker.id}_update_duration]",
48 | @settings["#{tracker.id}_update_duration"], size: 3 %>
49 |
50 | <%IssueStatus.where(is_closed: false).each do |issue_status| -%>
51 |
52 | <%= text_field_tag "settings[#{tracker.id}-status-#{issue_status.id}-update]",
53 | @settings["#{tracker.id}-status-#{issue_status.id}-update"], size: 3 %>
54 |
55 | <%end%>
56 |
57 | <%end%>
58 |
59 |
60 |
61 |
62 |
63 | Estimate Turnaround for Tracker (Days)
64 |
65 |
66 |
67 |
68 |
69 | Tracker
70 | <%IssueStatus.where(is_closed: false).each do |issue_status|%>
71 | <%=issue_status.name%>
72 | <%end%>
73 |
74 | <%Tracker.all.each do |tracker| -%>
75 |
76 | <%=tracker.name%>
77 | <%IssueStatus.where(is_closed: false).each do |issue_status| -%>
78 |
79 | <%= text_field_tag "settings[#{tracker.id}-status-#{issue_status.id}-estimate]",
80 | @settings["#{tracker.id}-status-#{issue_status.id}-estimate"], size: 3 %>
81 |
82 | <%end%>
83 |
84 | <%end%>
85 |
86 |
87 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # English strings go here for Rails i18n
2 | en:
3 | update_reminder:
4 | issue_tracker_update_required: '%{user_name} - Tracker - Missing update on %{issue_count} issues!'
5 | issue_status_update_required: '%{user_name} - Missing status update on %{issue_count} issues!'
6 | past_due_issue_update_required: '%{user_name} - Past Due - Missing update on %{issue_count} issues!'
7 | issue_estimate_required: '%{user_name} - Missing estimates on %{issue_count} issues!'
8 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | # Plugin's routes
2 | # See: http://guides.rubyonrails.org/routing.html
3 |
--------------------------------------------------------------------------------
/config/schedule.rb:
--------------------------------------------------------------------------------
1 | # Use this file to easily define all of your cron jobs.
2 | #
3 | # It's helpful, but not entirely necessary to understand cron before proceeding.
4 | # http://en.wikipedia.org/wiki/Cron
5 |
6 | # Example:
7 | #
8 | # set :output, "/path/to/my/cron_log.log"
9 | #
10 | # every 2.hours do
11 | # command "/usr/bin/some_great_command"
12 | # runner "MyModel.some_method"
13 | # rake "some:great:rake:task"
14 | # end
15 | #
16 | #set :environment, "production"
17 | #every 15.minutes do
18 | #rake "trackers"
19 | #end
20 | # every 4.days do
21 | # runner "AnotherModel.prune_old_records"
22 | # end
23 |
24 | # Learn more: http://github.com/javan/whenever
25 |
--------------------------------------------------------------------------------
/init.rb:
--------------------------------------------------------------------------------
1 | Rails.configuration.to_prepare do
2 | require_dependency 'user'
3 | User.send(:include, RedmineUpdateReminder::Patches::UserPatch)
4 | end
5 |
6 | Redmine::Plugin.register :redmine_update_reminder do
7 | name 'Redmine Update Reminder'
8 | author 'Arkhitech'
9 | url 'https://github.com/arkhitech/redmine_update_reminder'
10 | author_url 'http://www.arkhitech.com'
11 | description 'This is a plugin for Redmine which sends a reminder email to the assignee working on a task, whose status is not updated with-in allowed duration'
12 | version '1.1'
13 | settings(default: {
14 | 'header' => 'Missing Required Task Update',
15 | 'footer' => 'powered by arkhitech.com',
16 | }, partial: 'settings/reminder_settings')
17 | end
18 |
--------------------------------------------------------------------------------
/lib/redmine_update_reminder/patches/user_patch.rb:
--------------------------------------------------------------------------------
1 | module RedmineUpdateReminder
2 | module Patches
3 | module UserPatch
4 | def self.included(base)
5 |
6 | base.class_eval do
7 | unloadable
8 | has_many :members, inverse_of: :user
9 | end
10 | end
11 |
12 | end
13 | end
14 | end
--------------------------------------------------------------------------------
/lib/tasks/reminder.rake:
--------------------------------------------------------------------------------
1 | namespace :redmine_update_reminder do
2 | require 'redmine/utils'
3 | include Redmine::Utils::DateCalculation
4 |
5 | def send_user_issue_estimates_reminders(issue_status_ids, user, mailed_issue_ids)
6 | issues_with_updated_since = []
7 | trackers = Tracker.all
8 | trackers.each do |tracker|
9 | issue_status_ids.each do |issue_status_id|
10 | estimate_update = Setting.plugin_redmine_update_reminder["#{tracker.id}-status-#{issue_status_id}-estimate"].to_f
11 |
12 | if estimate_update > 0
13 | oldest_estimated_since = estimate_update.days.ago
14 |
15 | issues = Issue.where(tracker_id: tracker.id, assigned_to_id: user.id, status_id: issue_status_id).
16 | where('estimated_hours IS NULL OR estimated_hours <= 0').
17 | where.not(id: mailed_issue_ids.to_a)
18 |
19 | issues.each do |issue|
20 | if issue.updated_on < oldest_estimated_since
21 | issues_with_updated_since << [issue, issue.updated_on]
22 | end
23 | end
24 | end
25 | end
26 | end
27 | RemindingMailer.remind_user_issue_estimates(user,
28 | issues_with_updated_since).deliver_now if issues_with_updated_since.count > 0
29 | end
30 |
31 | def send_user_past_due_issues_reminders(issue_status_ids, user, mailed_issue_ids)
32 | issues = Issue.where(assigned_to_id: user.id,
33 | status_id: issue_status_ids).where('due_date < ?', Date.today).
34 | where.not(id: mailed_issue_ids.to_a)
35 |
36 | RemindingMailer.remind_user_past_due_issues(user, issues).deliver_now if issues.exists?
37 | end
38 | def send_user_tracker_reminders(issue_status_ids, user, mailed_issue_ids)
39 | trackers = Tracker.all
40 | issues_with_updated_since = []
41 | trackers.each do |tracker|
42 | update_duration = Setting.plugin_redmine_update_reminder["#{tracker.id}_update_duration"].to_f
43 | if update_duration > 0
44 |
45 | updated_since = update_duration.days.ago
46 | issues = Issue.where(tracker_id: tracker.id, assigned_to_id: user.id, status_id: issue_status_ids).
47 | where('updated_on < ?', updated_since).where.not(id: mailed_issue_ids.to_a)
48 |
49 | issues.find_each do |issue|
50 | issues_with_updated_since << [issue, issue.updated_on]
51 | end
52 | end
53 | end
54 | RemindingMailer.remind_user_issue_trackers(user,
55 | issues_with_updated_since).deliver_now if issues_with_updated_since.count > 0
56 | end
57 |
58 | def send_user_status_reminders(issue_status_ids, user, mailed_issue_ids)
59 | issues_with_updated_since = []
60 | trackers = Tracker.all
61 | trackers.each do |tracker|
62 | issue_status_ids.each do |issue_status_id|
63 | update_duration = Setting.plugin_redmine_update_reminder["#{tracker.id}-status-#{issue_status_id}-update"].to_f
64 | if update_duration > 0
65 |
66 | oldest_status_date = update_duration.days.ago
67 | issues = Issue.where(tracker_id: tracker.id, assigned_to_id: user.id, status_id: issue_status_id).
68 | where.not(id: mailed_issue_ids.to_a)
69 |
70 | issues.find_each do |issue|
71 | issue.journals.each do |journal|
72 | journal.visible_details do |detail|
73 | if detail[:prop_key] == 'status_id' &&
74 | detail[:new_value] == issue_status_id &&
75 | oldest_status_date > journal.created_on
76 | issues_with_updated_since << [issue, journal.created_on]
77 | break
78 | end
79 | end
80 | end
81 | end
82 | end
83 | end
84 | end
85 | RemindingMailer.remind_user_issue_statuses(user,
86 | issues_with_updated_since).deliver_now if issues_with_updated_since.count > 0
87 | end
88 |
89 | def send_issue_status_reminders(issue_status_ids, user_ids, mailed_issue_ids)
90 | Tracker.all.each do |tracker|
91 | issue_status_ids.each do |issue_status_id|
92 | update_duration = Setting.plugin_redmine_update_reminder["#{tracker.id}-status-#{issue_status_id}-update"].to_f
93 | if update_duration > 0
94 |
95 | oldest_status_date = update_duration.days.ago
96 | issues = Issue.where(tracker_id: tracker.id, assigned_to_id: user_ids,
97 | status_id: issue_status_id).where.not(id: mailed_issue_ids.to_a)
98 |
99 | issues.find_each do |issue|
100 | issue.journals.each do |journal|
101 | journal.visible_details do |detail|
102 | if detail[:prop_key] == 'status_id' &&
103 | detail[:new_value] == issue_status_id &&
104 | oldest_status_date > journal.created_on
105 | RemindingMailer.reminder_status_email(issue.assigned_to, issue,
106 | journal.created_on).deliver_now
107 | mailed_issue_ids << issue.id
108 | break
109 | end
110 | end
111 | end
112 | end
113 | end
114 | end
115 | end
116 | end
117 |
118 | def send_issue_tracker_reminders(issue_status_ids, user_ids, mailed_issue_ids)
119 | trackers = Tracker.all
120 |
121 | trackers.each do |tracker|
122 | update_duration = Setting.plugin_redmine_update_reminder["#{tracker.id}_update_duration"].to_f
123 | if update_duration > 0
124 |
125 | updated_since = update_duration.days.ago
126 | issues = Issue.where(tracker_id: tracker.id, assigned_to_id: user_ids,
127 | status_id: issue_status_ids).where('updated_on < ?', updated_since).
128 | where.not(id: mailed_issue_ids.to_a)
129 |
130 | issues.find_each do |issue|
131 | RemindingMailer.reminder_issue_email(issue.assigned_to, issue, issue.updated_on).deliver_now
132 | mailed_issue_ids << issue.id
133 | end
134 | end
135 | end
136 |
137 | end
138 |
139 | task send_user_reminders: :environment do
140 | open_issue_status_ids = IssueStatus.where(is_closed: false).pluck('id')
141 | remind_group = Setting.plugin_redmine_update_reminder['remind_group']
142 | users = Group.includes(:users).find(remind_group).users
143 |
144 | users.find_each do |user|
145 | mailed_issue_ids = Set.new
146 | send_user_tracker_reminders(open_issue_status_ids, user, mailed_issue_ids)
147 | send_user_status_reminders(open_issue_status_ids, user, mailed_issue_ids)
148 | send_user_past_due_issues_reminders(open_issue_status_ids, user, mailed_issue_ids)
149 | send_user_issue_estimates_reminders(open_issue_status_ids, user, mailed_issue_ids)
150 | end
151 | end
152 |
153 | task send_issue_reminders: :environment do
154 | open_issue_status_ids = IssueStatus.where(is_closed: false).pluck('id')
155 |
156 | remind_group = Setting.plugin_redmine_update_reminder['remind_group']
157 | user_ids = Group.includes(:users).find(remind_group).user_ids
158 |
159 | mailed_issue_ids = Set.new
160 |
161 | send_issue_tracker_reminders(open_issue_status_ids, user_ids, mailed_issue_ids)
162 | send_issue_status_reminders(open_issue_status_ids, user_ids, mailed_issue_ids)
163 | end
164 | end
165 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | # Load the Redmine helper
2 | require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper')
3 |
--------------------------------------------------------------------------------