Project

General

Profile

Feature #7867 » add-author-group-filtering.patch

Takenori TAKAKI, 2024-02-09 03:24

View differences:

app/helpers/queries_helper.rb
37 37
        group = query.is_a?(IssueQuery) ? :label_relations : nil
38 38
      elsif %w(member_of_group assigned_to_role).include?(field)
39 39
        group = :field_assigned_to
40
      elsif %w(author_group author_role).include?(field)
41
        group = :field_author
40 42
      elsif field_options[:type] == :date_past || field_options[:type] == :date
41 43
        group = :label_date
42 44
      elsif %w(estimated_hours spent_time).include?(field)
app/models/issue_query.rb
180 180
      :type => :list_optional,
181 181
      :values => lambda {Role.givable.pluck(:name, :id).map {|name, id| [name, id.to_s]}}
182 182
    )
183
    add_available_filter(
184
      "author_group",
185
      :type => :list,
186
      :values => lambda {Group.givable.visible.pluck(:name, :id).map {|name, id| [name, id.to_s]}}
187
    )
188
    add_available_filter(
189
      "author_role",
190
      :type => :list,
191
      :values => lambda {Role.givable.pluck(:name, :id).map {|name, id| [name, id.to_s]}}
192
    )
183 193
    add_available_filter(
184 194
      "fixed_version_id",
185 195
      :type => :list_optional_with_history, :values => lambda {fixed_version_values}
......
592 602
    end
593 603
  end
594 604

  
605
  def sql_for_author_group_field(field, operator, value)
606
    groups = if value.empty?
607
      Group.givable
608
    else
609
      Group.where(:id => value).to_a
610
    end
611

  
612
    author_groups = groups.inject([]) do |user_ids, group|
613
      user_ids + group.user_ids + [group.id]
614
    end.uniq.compact.sort.collect(&:to_s)
615

  
616
    '(' + sql_for_field("author_id", operator, author_groups, Issue.table_name, "author_id", false) + ')'
617
  end
618

  
619
  def sql_for_author_role_field(field, operator, value)
620
    role_cond =
621
      if value.any?
622
        "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + ")"
623
      else
624
        "1=0"
625
      end
626
    sw = operator == "!" ? 'NOT' : ''
627
    nl = operator == "!" ? "#{Issue.table_name}.author_id IS NULL OR" : ''
628
    subquery =
629
      "SELECT 1" +
630
      " FROM #{Member.table_name} inner join #{MemberRole.table_name} on members.id = member_roles.member_id" +
631
      " 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}"
632
    "(#{nl} #{sw} EXISTS (#{subquery}))"
633
  end
634

  
595 635
  def sql_for_fixed_version_status_field(field, operator, value)
596 636
    where = sql_for_field(field, operator, value, Version.table_name, "status")
597 637
    version_id_scope = project ? project.shared_versions : Version.visible
config/locales/en.yml
376 376
  field_parent_issue_subject: Parent task subject
377 377
  field_member_of_group: "Assignee's group"
378 378
  field_assigned_to_role: "Assignee's role"
379
  field_author_group: "Author's group"
380
  field_author_role: "Author's role"
379 381
  field_text: Text field
380 382
  field_visible: Visible
381 383
  field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text"
config/locales/ja.yml
334 334
  field_parent_issue: 親チケット
335 335
  field_member_of_group: 担当者のグループ
336 336
  field_assigned_to_role: 担当者のロール
337
  field_author_group: 作成者のグループ
338
  field_author_role: 作成者のロール
337 339
  field_text: テキスト
338 340
  field_visible: 表示
339 341
  field_warn_on_leaving_unsaved: データを保存せずにページから移動するときに警告
test/helpers/queries_helper_test.rb
117 117
    assert_select_in options, 'option[value=?]', "cf_#{i_cf.id}.cf_#{u_cf.id}", text: "User's Phone number"
118 118
    assert_select_in options, 'optgroup[label=?]', 'User', 1
119 119
  end
120

  
121
  def test_filters_options_for_select_should_group_author_filters
122
    with_locale 'en' do
123
      options = filters_options_for_select(IssueQuery.new)
124
      assert_select_in options, 'optgroup[label=?]', "Author", 1
125
      assert_select_in options, 'optgroup > option[value=author_group]', :text => "Author's group"
126
      assert_select_in options, 'optgroup > option[value=author_role]', :text => "Author's role"
127
    end
128
  end
120 129
end
test/unit/query_test.rb
2788 2788
    assert ! query.available_filters["assigned_to_role"][:values].include?(['Anonymous', '5'])
2789 2789
  end
2790 2790

  
2791
  def test_available_filters_should_include_author_group_filter
2792
    query = IssueQuery.new
2793
    assert query.available_filters.key?("author_group")
2794
    assert_equal :list, query.available_filters["author_group"][:type]
2795
    assert query.available_filters["author_group"][:values].present?
2796
    assert_equal Group.givable.sort.map {|g| [g.name, g.id.to_s]},
2797
                 query.available_filters["author_group"][:values].sort
2798
  end
2799

  
2800
  def test_available_filters_should_include_author_role_filter
2801
    query = IssueQuery.new
2802
    assert query.available_filters.key?("author_role")
2803
    assert_equal :list, query.available_filters["author_role"][:type]
2804

  
2805
    assert query.available_filters["author_role"][:values].include?(['Manager', '1'])
2806
    assert query.available_filters["author_role"][:values].include?(['Developer', '2'])
2807
    assert query.available_filters["author_role"][:values].include?(['Reporter', '3'])
2808

  
2809
    assert ! query.available_filters["author_role"][:values].include?(['Non member', '4'])
2810
    assert ! query.available_filters["author_role"][:values].include?(['Anonymous', '5'])
2811
  end
2812

  
2791 2813
  def test_available_filters_should_include_custom_field_according_to_user_visibility
2792 2814
    visible_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => true)
2793 2815
    hidden_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => false, :role_ids => [1])
......
2958 2980
    assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query
2959 2981
  end
2960 2982

  
2983
  def test_author_group_filter_should_return_issues_with_or_without_author_in_group
2984
    project = Project.generate!
2985
    author = User.generate!
2986
    author_group = Group.generate!
2987
    not_author_group = Group.generate!
2988
    author.groups << author_group
2989
    issues = 3.times.collect { Issue.generate!(:project => project, :author => author) }
2990

  
2991
    query = IssueQuery.new(:name => '_', :project => project)
2992
    query.add_filter('author_group', '=', [author_group.id.to_s])
2993
    assert_equal 3, query.issues.count
2994
    assert_query_result issues, query
2995

  
2996
    query = IssueQuery.new(:name => '_', :project => project)
2997
    query.add_filter('author_group', '!', [not_author_group.id.to_s])
2998
    assert_equal 3, query.issues.count
2999
    assert_query_result issues, query
3000
  end
3001

  
3002
  def test_author_role_filter_should_return_issues_with_or_without_author_in_role
3003
    project = Project.generate!
3004
    author = User.generate!
3005
    manager_role = Role.find_by_name('Manager')
3006
    developer_role = Role.find_by_name('Developer')
3007
    User.add_to_project(author, project, manager_role)
3008
    issues = 3.times.collect { Issue.generate!(:project => project, :author => author) }
3009

  
3010
    query = IssueQuery.new(:name => 'issues generated by manager', :project => project)
3011
    query.add_filter('author_role', '=', [manager_role.id.to_s])
3012
    assert_equal 3, query.issues.count
3013
    assert_query_result issues, query
3014

  
3015
    query = IssueQuery.new(:name => 'issues does not generated by developer', :project => project)
3016
    query.add_filter('author_role', '!', [developer_role.id.to_s])
3017
    assert_equal 3, query.issues.count
3018
    assert_query_result issues, query
3019
  end
3020

  
2961 3021
  def test_query_column_should_accept_a_symbol_as_caption
2962 3022
    set_language_if_valid 'en'
2963 3023
    c = QueryColumn.new('foo', :caption => :general_text_Yes)
(1-1/2)