diff --git a/app/models/issue_query.rb b/app/models/issue_query.rb index 3431750f64..470f9d3172 100644 --- a/app/models/issue_query.rb +++ b/app/models/issue_query.rb @@ -254,6 +254,10 @@ class IssueQuery < Query "watcher_id", :type => :list, :values => lambda {watcher_values} ) + add_available_filter( + "assigned_to_or_watcher_id", + :type => :list, :values => lambda {assigned_to_or_watcher_values} + ) end add_available_filter( "updated_by", @@ -577,6 +581,22 @@ class IssueQuery < Query "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (#{sql})" end + def assigned_to_or_watcher_values + (assigned_to_values + watcher_values).uniq {|value| value[1]} + end + + def sql_for_assigned_to_or_watcher_id_field(field, operator, value) + assigned_to_sql = + sql_for_field( + "assigned_to_id", operator, value, + Issue.table_name, "assigned_to_id", false + ) + watcher_sql = sql_for_watcher_id_field("watcher_id", operator, value) + conjunction = operator == '=' ? ' OR ' : ' AND ' + + "(#{assigned_to_sql}#{conjunction}#{watcher_sql})" + end + def sql_for_member_of_group_field(field, operator, value) if operator == '*' # Any group groups = Group.givable @@ -905,6 +925,7 @@ class IssueQuery < Query Principal.visible.where(:id => values).map {|p| [p.name, p.id.to_s]} end alias :find_author_id_filter_values :find_assigned_to_id_filter_values + alias :find_assigned_to_or_watcher_id_filter_values :find_assigned_to_id_filter_values IssueRelation::TYPES.each_key do |relation_type| alias_method :"sql_for_#{relation_type}_field", :sql_for_relations diff --git a/app/models/query.rb b/app/models/query.rb index 7558f74096..5f98e716af 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -1006,11 +1006,11 @@ class Query < ApplicationRecord operator = operator_for(field) # "me" value substitution - if %w(assigned_to_id author_id user_id watcher_id updated_by last_updated_by).include?(field) + if %w(assigned_to_id assigned_to_or_watcher_id author_id user_id watcher_id updated_by last_updated_by).include?(field) if v.delete("me") if User.current.logged? v.push(User.current.id.to_s) - v += User.current.group_ids.map(&:to_s) if %w(assigned_to_id watcher_id).include?(field) + v += User.current.group_ids.map(&:to_s) if %w(assigned_to_id assigned_to_or_watcher_id watcher_id).include?(field) else v.push("0") end diff --git a/config/locales/en.yml b/config/locales/en.yml index d0d93746a2..0b0c002128 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -318,6 +318,7 @@ en: field_subject: Subject field_due_date: Due date field_assigned_to: Assignee + field_assigned_to_or_watcher: Assignee or watcher field_priority: Priority field_fixed_version: Target version field_user: User diff --git a/config/locales/ja.yml b/config/locales/ja.yml index e7f8bbe9da..cfe52a3f0f 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -273,6 +273,7 @@ ja: field_subject: 題名 field_due_date: 期日 field_assigned_to: 担当者 + field_assigned_to_or_watcher: 担当者またはウォッチャー field_priority: 優先度 field_fixed_version: 対象バージョン field_user: ユーザー diff --git a/test/unit/query_test.rb b/test/unit/query_test.rb index ebf7fc991d..173090aa02 100644 --- a/test/unit/query_test.rb +++ b/test/unit/query_test.rb @@ -1425,6 +1425,99 @@ class QueryTest < ActiveSupport::TestCase assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id) end + def test_assigned_to_or_watcher_filter_should_be_available_only_for_logged_users + assert_not IssueQuery.new.available_filters.key?('assigned_to_or_watcher_id') + + User.current = User.find(2) + assert IssueQuery.new.available_filters.key?('assigned_to_or_watcher_id') + end + + def test_filter_assigned_or_watched_issues_by_me_should_include_user_groups + user = User.find(2) + group = Group.find(10) + group.users << user + Member.create!(:project_id => 1, :principal => group, :role_ids => [1]) + User.current = user + + manager = Role.find(1) + manager.remove_permission! :view_issue_watchers + + with_settings :issue_group_assignment => '1' do + assigned_to_user = Issue.generate!(:project_id => 1, :assigned_to => user) + assigned_to_group = Issue.generate!(:project_id => 1, :assigned_to => group) + watched_by_user = Issue.generate!(:project_id => 1) + watched_by_user.add_watcher(user) + watched_by_group = Issue.generate!(:project_id => 1) + watched_by_group.add_watcher(group) + assigned_and_watched = Issue.generate!(:project_id => 1, :assigned_to => user) + assigned_and_watched.add_watcher(user) + unrelated = Issue.generate!(:project_id => 1, :assigned_to => User.find(3)) + + query = + IssueQuery.new( + :name => '_', + :filters => { + 'assigned_to_or_watcher_id' => { + :operator => '=', + :values => ['me'] + } + } + ) + result = find_issues_with_query(query) + + assert_includes result, assigned_to_user + assert_includes result, assigned_to_group + assert_includes result, watched_by_user + assert_includes result, watched_by_group + assert_includes result, assigned_and_watched + assert_equal 1, result.count {|issue| issue == assigned_and_watched} + assert_not_includes result, unrelated + + query.filters = { + 'assigned_to_or_watcher_id' => { + :operator => '!', + :values => ['me'] + } + } + result = find_issues_with_query(query) + + assert_not_includes result, assigned_to_user + assert_not_includes result, assigned_to_group + assert_not_includes result, watched_by_user + assert_not_includes result, watched_by_group + assert_not_includes result, assigned_and_watched + assert_includes result, unrelated + end + end + + def test_filter_assigned_or_watched_issues_by_other_user_should_honor_watcher_visibility + user = User.find(2) + other_user = User.find(3) + User.current = user + + manager = Role.find(1) + manager.remove_permission! :view_issue_watchers + + assigned_to_other_user = Issue.generate!(:project_id => 1, :assigned_to => other_user) + watched_by_other_user = Issue.generate!(:project_id => 1) + watched_by_other_user.add_watcher(other_user) + + query = + IssueQuery.new( + :name => '_', + :filters => { + 'assigned_to_or_watcher_id' => { + :operator => '=', + :values => [other_user.id.to_s] + } + } + ) + result = find_issues_with_query(query) + + assert_includes result, assigned_to_other_user + assert_not_includes result, watched_by_other_user + end + def test_filter_watched_issues_by_me_should_include_user_groups user = User.find(2) group = Group.find(10)