Skip to content

Commit

Permalink
add ability to send digest by issue query
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Leishman committed Mar 23, 2017
1 parent 4d1e421 commit 8c3c7b1
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 12 deletions.
13 changes: 13 additions & 0 deletions app/helpers/digest_rules_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ def project_ids_options_for_select
result
end

def query_ids_options_for_select
issue_query = IssueQuery.visible.select('projects.name as project_name', 'queries.*').
order('project_name', 'queries.name')
issue_query.map do |issue_query|
prefix = issue_query.project_name? ? "#{issue_query.project_name} > " : '';
["#{prefix}#{issue_query.name}", issue_query.id]
end
end

def issue_query_ids
@digest_rule.project_ids if @digest_rule.issue_query?
end

# expected option keys are:
# only: [] - array of projects that will be included in tree
# except: [] - array of projects that will be excluded from tree
Expand Down
28 changes: 25 additions & 3 deletions app/models/digest_rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ class DigestRule < ActiveRecord::Base
MEMBER = 'member'
MEMBER_NOT_SELECTED = 'member_not_selected'
ALL_INVOLVED = 'all_involved'
PROJECT_SELECTOR_VALUES = [ALL, SELECTED, NOT_SELECTED, MEMBER, MEMBER_NOT_SELECTED, ALL_INVOLVED]
ISSUE_QUERY = 'issue_query'
PROJECT_SELECTOR_VALUES = [ALL, SELECTED, NOT_SELECTED, MEMBER, MEMBER_NOT_SELECTED, ALL_INVOLVED, ISSUE_QUERY]

NOTIFY_AND_DIGEST = 'all'
NOTIFY_ONLY = 'notify'
Expand Down Expand Up @@ -73,6 +74,20 @@ def affected_project_ids
uniq.pluck('projects.id')
end

def affected_issue_query_journal_ids
return [] unless issue_query? && issue_query
issue_query.journals_scope.pluck(:id)
end

def affected_issue_query_issue_ids
return [] unless issue_query? && issue_query
issue_query.journal_scope.pluck(:id)
end

def issue_query
@issue_query ||= IssueQuery.find(project_ids.first)
end

def calculate_time_from(time_to)
case recurrent
when DAILY
Expand All @@ -87,7 +102,8 @@ def calculate_time_from(time_to)
end

def find_events_by_journal(journal)
return [] unless affected_project_ids.include?(journal.issue.project_id)
return [] unless affected_issue_query_journal_ids.include?(journal.id) ||
affected_project_ids.include?(journal.issue.project_id)

events = []

Expand All @@ -110,7 +126,7 @@ def find_events_by_journal(journal)

def apply_for_created_issue?(issue)
event_type_enabled?(DigestEvent::ISSUE_CREATED) &&
affected_project_ids.include?(issue.project_id)
(affected_project_ids.include?(issue.project_id) || affected_issue_query_issue_ids.include?(issue.id))
end

def apply_for_updated_issue?(journal)
Expand All @@ -133,6 +149,10 @@ def all_involved_only?
project_selector == ALL_INVOLVED
end

def issue_query?
project_selector == ISSUE_QUERY
end

private

def event_for_journal_detail(journal, jdetail)
Expand Down Expand Up @@ -166,6 +186,8 @@ def get_projects_scope
['members.user_id = ?', user.id]
when MEMBER_NOT_SELECTED
['members.user_id = ? and projects.id not in (?)', user.id, project_ids]
when ISSUE_QUERY
['0 = 1']
else
raise RedmineDigest::Error.new "Unknown project selector (#{project_selector})"
end
Expand Down
5 changes: 5 additions & 0 deletions app/views/digest_rules/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
data: { options: project_ids_options_for_select } %>
</p>

<p id="digest-rule-issue-queries" class="select2-field">
<%= select_tag 'digest_rule[raw_project_ids]',
options_for_select(query_ids_options_for_select, issue_query_ids) %>
</p>

<p>
<%= f.select :template, templates_for_select %>
</p>
Expand Down
23 changes: 19 additions & 4 deletions assets/javascripts/redmine_digest.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,20 @@ $(document).ready(function () {

var toggleProjectList = function () {
var selectedVal = $("#digest_rule_project_selector").val();
if ($.inArray(selectedVal, ["selected", "not_selected", "member_not_selected"]) < 0) {
$("#digest-rule-projects").hide();
} else {
$("#digest-rule-projects").show();
switch (selectedVal) {
case 'selected':
case 'not_selected':
case 'member_not_selected':
$("#digest-rule-issue-queries").hide();
$("#digest-rule-projects").show();
break;
case 'issue_query':
$("#digest-rule-issue-queries").show();
$("#digest-rule-projects").hide();
break;
default:
$("#digest-rule-issue-queries").hide();
$("#digest-rule-projects").hide();
}
};

Expand All @@ -14,6 +24,11 @@ $(document).ready(function () {
allowClear: false
}).on("change", toggleProjectList);

$("#digest-rule-issue-queries > select").select2({
width: "40%",
allowClear: false
});

$("#digest_rule_raw_project_ids").select2({
width: "40%",
multiple: true,
Expand Down
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ en:
all: "For any issue update on all projects"
selected: "For any issue update on the selected projects only"
not_selected: "For any issue update except for the selected projects"
issue_query: "For any issue update on the selected issue query only"
member: "For any update on all projects I am a member of"
member_not_selected: "For any update on projects I am a member of, except for the selected projects"
all_involved: "For any update to issues I watch or I'm involved in for all projects"
Expand All @@ -35,6 +36,7 @@ en:
all: "All projects"
selected: "Selected projects only"
not_selected: "Except for the selected projects"
issue_query: "Selected issue query only"
member: "Projects I am a member of"
member_not_selected: "Projects I am a member of, except for the selected projects"
all_involved: "All projects I watch or I'm involved in"
Expand Down
1 change: 1 addition & 0 deletions lib/redmine_digest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class DigestError < RuntimeError
require_dependency 'redmine_digest/patches/user_patch'
require_dependency 'redmine_digest/patches/my_controller_patch'
require_dependency 'redmine_digest/patches/issue_patch'
require_dependency 'redmine_digest/patches/issue_query_patch'
require_dependency 'redmine_digest/patches/journal_patch'

ActionDispatch::Callbacks.to_prepare do
Expand Down
18 changes: 15 additions & 3 deletions lib/redmine_digest/digest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Digest

attr_reader :digest_rule, :time_to

delegate :name, :user, :recurrent, :project_selector, :all_involved_only?,
delegate :name, :user, :recurrent, :project_selector, :all_involved_only?, :issue_query, :issue_query?,
to: :digest_rule, allow_nil: true

def initialize(digest_rule, time_to = nil, issue_limit = nil)
Expand Down Expand Up @@ -37,6 +37,7 @@ def sorted_digest_issues
end

def projects_count
@projects_count = 0 if issue_query?
@projects_count ||= issues.map(&:project_id).uniq.count
end

Expand Down Expand Up @@ -101,7 +102,7 @@ def get_digest_issue_with_events(issue)
d_issue.status_id = status_id_change.value if status_id_change

next if journal.private_notes? &&
!user.allowed_to?(:view_private_notes, issue.project)
!user.allowed_to?(:view_private_notes, issue.project)

events.each do |event|
d_issue.last_updated_on = journal.created_on
Expand Down Expand Up @@ -178,12 +179,21 @@ def get_changed_issue_ids
end

def get_created_issue_ids
return issue_query_issue_ids if issue_query?
Issue.where('issues.project_id in (?)', project_ids).
where('issues.created_on >= ? and issues.created_on < ?', time_from, time_to).
where(issue_created_in_range).
where(user_is_involved_in_issues).
uniq.pluck(:id)
end

def issue_query_issue_ids
issue_query.issue_ids(conditions: issue_created_in_range)
end

def issue_created_in_range
['issues.created_on >= ? and issues.created_on < ?', time_from, time_to]
end

def user_is_involved_in_issues
['issues.assigned_to_id = :user_id OR issues.author_id = :user_id', {user_id: user.id}] if all_involved_only?
end
Expand All @@ -197,6 +207,8 @@ def get_issues_scope(issue_ids)
def get_journal_scope
if all_involved_only?
get_journal_all_involved_scope
elsif issue_query?
issue_query.journals_scope
else
Journal.joins(:issue).where('issues.project_id in (?)', project_ids)
end
Expand Down
22 changes: 22 additions & 0 deletions lib/redmine_digest/patches/issue_query_patch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require_dependency 'issue_query'

module RedmineDigest
module Patches
module IssueQueryPatch
# Returns the journals
# Valid options are :order, :offset, :limit
def journals_scope
Journal.visible.
joins(:issue => [:project, :status]).
where(statement).
preload(:details, :user, {:issue => [:project, :author, :tracker, :status]})
rescue ::ActiveRecord::StatementInvalid => e
raise StatementInvalid.new(e.message)
end
end
end
end

unless IssueQuery.included_modules.include?(RedmineDigest::Patches::IssueQueryPatch)
IssueQuery.send :include, RedmineDigest::Patches::IssueQueryPatch
end
14 changes: 13 additions & 1 deletion lib/tasks/redmine_digest.rake
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,22 @@ namespace :redmine_digest do
rules_count = rules.count
puts "#{Time.now} Found #{rules_count} rules."
rules.each_with_index do |rule, idx|
send_digest_by_rule(rule, "#{idx + 1} / #{rules_count}")
current_user_for(rule) do
send_digest_by_rule(rule, "#{idx + 1} / #{rules_count}")
end
end
end

# Temporarily change User.current for rule 'issue_query'
# for IssueQuery %w(assigned_to_id author_id user_id watcher_id) == <me>
def current_user_for(rule)
original_user = User.current
User.current = User.find(rule.user_id) if rule.issue_query?
yield
ensure
User.current = original_user
end

def send_digest_by_rule(rule, npp)
puts "#{Time.now} #{npp} Sending #{rule.recurrent} digest [#{rule.id}] to #{rule.user.mail} <#{rule.user.login}>"

Expand Down
18 changes: 17 additions & 1 deletion test/unit/redmine_digest/digest_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

class RedmineDigest::DigestTest < ActiveSupport::TestCase
fixtures :users, :user_preferences, :roles, :projects, :members, :member_roles, :email_addresses,
:issues, :issue_statuses, :trackers, :journals, :journal_details,
:issues, :issue_statuses, :trackers, :journals, :journal_details, :queries,
:enabled_modules, :enumerations

def setup
Expand Down Expand Up @@ -141,6 +141,22 @@ def test_all_involved
assert_equal exp_ids, issue_ids
end

def test_issue_query
user = User.find(2)
rule = user.digest_rules.create(
name: 'test',
recurrent: DigestRule::MONTHLY,
project_selector: DigestRule::ISSUE_QUERY,
raw_project_ids: '5',
event_ids: DigestEvent::TYPES
)
time_to = Journal.last.created_on + 1.hour
digest = RedmineDigest::Digest.new(rule, time_to)
exp_ids = [1, 2, 5, 7, 13]
issue_ids = digest.issues.map(&:id).sort
assert_equal exp_ids, issue_ids
end

def test_time_zone
Time.use_zone('UTC') do
# leave only ane issue at midnight UTC
Expand Down

0 comments on commit 8c3c7b1

Please sign in to comment.