diff --git a/app/models/issue_query.rb b/app/models/issue_query.rb index 9c78fd734..e0be3fa5d 100644 --- a/app/models/issue_query.rb +++ b/app/models/issue_query.rb @@ -171,6 +171,18 @@ class IssueQuery < Query "author_id", :type => :list, :values => lambda {author_values} ) + add_available_filter( + "author.group", + :type => :list, + :values => lambda {Group.givable.visible.pluck(:name, :id).map {|name, id| [name, id.to_s]}}, + :name => l(:label_attribute_of_author, :name => l(:label_group)) + ) + add_available_filter( + "author.role", + :type => :list, + :values => lambda {Role.givable.pluck(:name, :id).map {|name, id| [name, id.to_s]}}, + :name => l(:label_attribute_of_author, :name => l(:field_role)) + ) add_available_filter( "assigned_to_id", :type => :list_optional_with_history, :values => lambda {assigned_to_values} @@ -608,6 +620,36 @@ class IssueQuery < Query end end + def sql_for_author_group_field(field, operator, value) + groups = if value.empty? + Group.givable + else + Group.where(:id => value).to_a + end + + author_groups = groups.inject([]) do |user_ids, group| + user_ids + group.user_ids + [group.id] + end.uniq.compact.sort.collect(&:to_s) + + '(' + sql_for_field("author_id", operator, author_groups, Issue.table_name, "author_id", false) + ')' + end + + def sql_for_author_role_field(field, operator, value) + role_cond = + if value.any? + "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + ")" + else + "1=0" + end + sw = operator == "!" ? 'NOT' : '' + nl = operator == "!" ? "#{Issue.table_name}.author_id IS NULL OR" : '' + subquery = + "SELECT 1" + + " FROM #{Member.table_name} inner join #{MemberRole.table_name} on members.id = member_roles.member_id" + + " WHERE #{Issue.table_name}.project_id = #{Member.table_name}.project_id AND #{Member.table_name}.user_id = #{Issue.table_name}.author_id AND #{role_cond}" + "(#{nl} #{sw} EXISTS (#{subquery}))" + end + def sql_for_fixed_version_status_field(field, operator, value) where = sql_for_field(field, operator, value, Version.table_name, "status") version_id_scope = project ? project.shared_versions : Version.visible diff --git a/test/unit/query_test.rb b/test/unit/query_test.rb index d26743cad..26aaf8c92 100644 --- a/test/unit/query_test.rb +++ b/test/unit/query_test.rb @@ -2851,6 +2851,28 @@ class QueryTest < ActiveSupport::TestCase assert ! query.available_filters["assigned_to_role"][:values].include?(['Anonymous', '5']) end + def test_available_filters_should_include_author_group_filter + query = IssueQuery.new + assert query.available_filters.key?("author.group") + assert_equal :list, query.available_filters["author.group"][:type] + assert query.available_filters["author.group"][:values].present? + assert_equal Group.givable.sort.map {|g| [g.name, g.id.to_s]}, + query.available_filters["author.group"][:values].sort + end + + def test_available_filters_should_include_author_role_filter + query = IssueQuery.new + assert query.available_filters.key?("author.role") + assert_equal :list, query.available_filters["author.role"][:type] + + assert query.available_filters["author.role"][:values].include?(['Manager', '1']) + assert query.available_filters["author.role"][:values].include?(['Developer', '2']) + assert query.available_filters["author.role"][:values].include?(['Reporter', '3']) + + assert_not query.available_filters["author.role"][:values].include?(['Non member', '4']) + assert_not query.available_filters["author.role"][:values].include?(['Anonymous', '5']) + end + def test_available_filters_should_include_custom_field_according_to_user_visibility visible_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => true) hidden_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => false, :role_ids => [1]) @@ -3021,6 +3043,44 @@ class QueryTest < ActiveSupport::TestCase assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query end + def test_author_group_filter_should_return_issues_with_or_without_author_in_group + project = Project.generate! + author = User.generate! + author_group = Group.generate! + not_author_group = Group.generate! + author.groups << author_group + issues = 3.times.collect { Issue.generate!(:project => project, :author => author) } + + query = IssueQuery.new(:name => '_', :project => project) + query.add_filter('author_group', '=', [author_group.id.to_s]) + assert_equal 3, query.issues.count + assert_query_result issues, query + + query = IssueQuery.new(:name => '_', :project => project) + query.add_filter('author_group', '!', [not_author_group.id.to_s]) + assert_equal 3, query.issues.count + assert_query_result issues, query + end + + def test_author_role_filter_should_return_issues_with_or_without_author_in_role + project = Project.generate! + author = User.generate! + manager_role = Role.find_by_name('Manager') + developer_role = Role.find_by_name('Developer') + User.add_to_project(author, project, manager_role) + issues = 3.times.collect { Issue.generate!(:project => project, :author => author) } + + query = IssueQuery.new(:name => 'issues generated by manager', :project => project) + query.add_filter('author_role', '=', [manager_role.id.to_s]) + assert_equal 3, query.issues.count + assert_query_result issues, query + + query = IssueQuery.new(:name => 'issues does not generated by developer', :project => project) + query.add_filter('author_role', '!', [developer_role.id.to_s]) + assert_equal 3, query.issues.count + assert_query_result issues, query + end + def test_query_column_should_accept_a_symbol_as_caption set_language_if_valid 'en' c = QueryColumn.new('foo', :caption => :general_text_Yes)