Patch #5535 » Ability_to_use_nobody_in_Assigned_to_field_filter_2.patch
| app/models/query.rb | ||
|---|---|---|
| 607 | 607 |
end |
| 608 | 608 |
principals.uniq! |
| 609 | 609 |
principals.sort! |
| 610 | 610 |
principals.reject! {|p| p.is_a?(GroupBuiltin)}
|
| 611 | 611 |
principals |
| 612 | 612 |
end |
| 613 | 613 |
end |
| 614 | 614 | |
| 615 | 615 |
def users |
| 616 | 616 |
principals.select {|p| p.is_a?(User)}
|
| 617 | 617 |
end |
| 618 | 618 | |
| 619 | 619 |
def author_values |
| 620 | 620 |
author_values = [] |
| 621 | 621 |
author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
|
| 622 | 622 |
author_values += |
| 623 | 623 |
users.sort_by{|p| [p.status, p]}.
|
| 624 | 624 |
collect{|s| [s.name, s.id.to_s, l("status_#{User::LABEL_BY_STATUS[s.status]}")]}
|
| 625 | 625 |
author_values << [l(:label_user_anonymous), User.anonymous.id.to_s] |
| 626 | 626 |
author_values |
| 627 | 627 |
end |
| 628 | 628 | |
| 629 | 629 |
def assigned_to_values |
| 630 | 630 |
assigned_to_values = [] |
| 631 | 631 |
assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
|
| 632 |
assigned_to_values << ["<< #{l(:label_nobody)} >>", "none"]
|
|
| 632 | 633 |
assigned_to_values += |
| 633 | 634 |
(Setting.issue_group_assignment? ? principals : users).sort_by{|p| [p.status, p]}.
|
| 634 | 635 |
collect{|s| [s.name, s.id.to_s, l("status_#{User::LABEL_BY_STATUS[s.status]}")]}
|
| 635 | 636 |
assigned_to_values |
| 636 | 637 |
end |
| 637 | 638 | |
| 638 | 639 |
def fixed_version_values |
| 639 | 640 |
versions = [] |
| 640 | 641 |
if project |
| 641 | 642 |
versions = project.shared_versions.to_a |
| 642 | 643 |
else |
| 643 | 644 |
versions = Version.visible.to_a |
| 644 | 645 |
end |
| 645 | 646 |
Version.sort_by_status(versions). |
| 646 | 647 |
collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s, l("version_status_#{s.status}")]}
|
| 647 | 648 |
end |
| 648 | 649 | |
| 649 | 650 |
# Returns a scope of issue statuses that are available as columns for filters |
| 650 | 651 |
def issue_statuses_values |
| 651 | 652 |
if project |
| 652 | 653 |
statuses = project.rolled_up_statuses |
| 653 | 654 |
else |
| 654 | 655 |
statuses = IssueStatus.all.sorted |
| 655 | 656 |
end |
| 656 | 657 |
statuses.collect{|s| [s.name, s.id.to_s]}
|
| ... | ... | |
| 983 | 984 |
next unless v and !v.empty? |
| 984 | 985 | |
| 985 | 986 |
operator = operator_for(field) |
| 986 | 987 | |
| 987 | 988 |
# "me" value substitution |
| 988 | 989 |
if %w(assigned_to_id author_id user_id watcher_id updated_by last_updated_by).include?(field) |
| 989 | 990 |
if v.delete("me")
|
| 990 | 991 |
if User.current.logged? |
| 991 | 992 |
v.push(User.current.id.to_s) |
| 992 | 993 |
v += User.current.group_ids.map(&:to_s) if %w(assigned_to_id watcher_id).include?(field) |
| 993 | 994 |
else |
| 994 | 995 |
v.push("0")
|
| 995 | 996 |
end |
| 996 | 997 |
end |
| 997 | 998 |
end |
| 998 | 999 | |
| 999 | 1000 |
if field == 'project_id' || (is_a?(ProjectQuery) && %w[id parent_id].include?(field)) |
| 1000 | 1001 |
if v.delete('mine')
|
| 1001 | 1002 |
v += User.current.memberships.map {|m| m.project_id.to_s}
|
| 1002 | 1003 |
end |
| 1003 | 1004 |
if v.delete('bookmarks')
|
| 1004 | 1005 |
v += User.current.bookmarked_project_ids |
| 1005 | 1006 |
end |
| 1006 | 1007 |
end |
| 1007 | 1008 | |
| 1009 |
include_none = (field == 'assigned_to_id' && operator == '=' && v.delete('none'))
|
|
| 1010 | ||
| 1008 | 1011 |
if field =~ /^cf_(\d+)\.cf_(\d+)$/ |
| 1009 | 1012 |
filters_clauses << sql_for_chained_custom_field(field, operator, v, $1, $2) |
| 1010 | 1013 |
elsif field =~ /cf_(\d+)$/ |
| 1011 | 1014 |
# custom field |
| 1012 | 1015 |
filters_clauses << sql_for_custom_field(field, operator, v, $1) |
| 1013 | 1016 |
elsif field =~ /^cf_(\d+)\.(.+)$/ |
| 1014 | 1017 |
filters_clauses << sql_for_custom_field_attribute(field, operator, v, $1, $2) |
| 1015 | 1018 |
elsif respond_to?(method = "sql_for_#{field.tr('.', '_')}_field")
|
| 1016 | 1019 |
# specific statement |
| 1017 | 1020 |
filters_clauses << send(method, field, operator, v) |
| 1021 |
elsif include_none |
|
| 1022 |
clause = sql_for_field(field, operator, v, queried_table_name, field) |
|
| 1023 |
clause = if v.empty? |
|
| 1024 |
"#{queried_table_name}.#{field} IS NULL"
|
|
| 1025 |
else |
|
| 1026 |
"(#{queried_table_name}.#{field} IS NULL OR #{clause})"
|
|
| 1027 |
end |
|
| 1028 |
filters_clauses << '(' + clause + ')'
|
|
| 1018 | 1029 |
else |
| 1019 | 1030 |
# regular field |
| 1020 | 1031 |
filters_clauses << '(' + sql_for_field(field, operator, v, queried_table_name, field) + ')'
|
| 1021 | 1032 |
end |
| 1022 | 1033 |
end if filters and valid? |
| 1023 | 1034 | |
| 1024 | 1035 |
if (c = group_by_column) && c.is_a?(QueryCustomFieldColumn) |
| 1025 | 1036 |
# Excludes results for which the grouped custom field is not visible |
| 1026 | 1037 |
filters_clauses << c.custom_field.visibility_by_project_condition |
| 1027 | 1038 |
end |
| 1028 | 1039 | |
| 1029 | 1040 |
filters_clauses << project_statement |
| 1030 | 1041 |
filters_clauses.reject!(&:blank?) |
| 1031 | 1042 | |
| 1032 | 1043 |
filters_clauses.any? ? filters_clauses.join(' AND ') : nil
|
| 1033 | 1044 |
end |
| 1034 | 1045 | |
| 1035 | 1046 |
# Returns the result count by group or nil if query is not grouped |
| 1036 | 1047 |
def result_count_by_group |
| 1037 | 1048 |
grouped_query do |scope| |
| 1038 | 1049 |
scope.count |
| 1039 | 1050 |
end |
| 1040 | 1051 |
end |
| 1041 | 1052 | |
| 1042 | 1053 |
# Returns the sum of values for the given column |
| test/unit/query_test.rb | ||
|---|---|---|
| 938 | 938 |
with_settings :issue_group_assignment => '1' do |
| 939 | 939 |
i1 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => user) |
| 940 | 940 |
i2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => group) |
| 941 | 941 |
i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => other_group) |
| 942 | 942 |
query = |
| 943 | 943 |
IssueQuery.new( |
| 944 | 944 |
:name => '_', |
| 945 | 945 |
:filters => {
|
| 946 | 946 |
'assigned_to_id' => {
|
| 947 | 947 |
:operator => '=', |
| 948 | 948 |
:values => ['me'] |
| 949 | 949 |
} |
| 950 | 950 |
} |
| 951 | 951 |
) |
| 952 | 952 |
result = query.issues |
| 953 | 953 |
assert_equal( |
| 954 | 954 |
Issue.visible.where(:assigned_to_id => ([2] + user.reload.group_ids)).sort_by(&:id), |
| 955 | 955 |
result.sort_by(&:id) |
| 956 | 956 |
) |
| 957 | 957 |
assert result.include?(i1) |
| 958 | 958 |
assert result.include?(i2) |
| 959 | 959 |
assert !result.include?(i3) |
| 960 | 960 |
end |
| 961 | 961 |
end |
| 962 | 962 | |
| 963 |
def test_filter_assigned_to_none_or_selected_user |
|
| 964 |
user = User.find(2) |
|
| 965 | ||
| 966 |
issue_with_user = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => user) |
|
| 967 |
issue_without_user = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => nil) |
|
| 968 |
issue_with_other_user = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to_id => 3) |
|
| 969 | ||
| 970 |
query = IssueQuery.new(:name => '_') |
|
| 971 |
query.add_filter('assigned_to_id', '=', ['none', user.id.to_s])
|
|
| 972 | ||
| 973 |
results = query.issues |
|
| 974 | ||
| 975 |
assert_includes results, issue_with_user |
|
| 976 |
assert_includes results, issue_without_user |
|
| 977 |
assert_not_includes results, issue_with_other_user |
|
| 978 |
end |
|
| 979 | ||
| 963 | 980 |
def test_filter_notes |
| 964 | 981 |
user = User.generate! |
| 965 | 982 |
Journal.create!(:user_id => user.id, :journalized => Issue.find(2), :notes => 'Notes.') |
| 966 | 983 |
Journal.create!(:user_id => user.id, :journalized => Issue.find(3), :notes => 'Notes.') |
| 967 | 984 | |
| 968 | 985 |
issue_journals = Issue.find(1).journals.sort |
| 969 | 986 |
assert_equal ['Journal notes', 'Some notes with Redmine links: #2, r2.'], issue_journals.map(&:notes) |
| 970 | 987 |
assert_equal [false, false], issue_journals.map(&:private_notes) |
| 971 | 988 | |
| 972 | 989 |
query = IssueQuery.new(:name => '_') |
| 973 | 990 |
filter_name = 'notes' |
| 974 | 991 |
assert_include filter_name, query.available_filters.keys |
| 975 | 992 | |
| 976 | 993 |
{
|
| 977 | 994 |
'~' => [1, 2, 3], |
| 978 | 995 |
'!~' => Issue.ids.sort - [1, 2, 3], |
| 979 | 996 |
'^' => [2, 3], |
| 980 | 997 |
'$' => [1], |
| 981 | 998 |
}.each do |operator, expected| |
| 982 | 999 |
query.filters = {filter_name => {:operator => operator, :values => ['Notes']}}
|
| 983 | 1000 |
assert_equal expected, find_issues_with_query(query).map(&:id).sort |
| 984 | 1001 |
end |
| 985 | 1002 |
end |
| 986 | 1003 | |
| 987 | 1004 |
def test_filter_notes_should_ignore_private_notes_that_are_not_visible |
| ... | ... | |
| 2727 | 2744 |
IssueQuery.create!( |
| 2728 | 2745 |
:name => 'Query', |
| 2729 | 2746 |
:type => "IssueQuery", |
| 2730 | 2747 |
:user => User.find(7), |
| 2731 | 2748 |
:filters => {"status_id" => {:values => ["1"], :operator => "o"}},
|
| 2732 | 2749 |
:column_names => [:tracker, :status], |
| 2733 | 2750 |
:sort_criteria => ['id', 'asc'], |
| 2734 | 2751 |
:group_by => "project", |
| 2735 | 2752 |
:options => {
|
| 2736 | 2753 |
:totalable_names=>[:estimated_hours], |
| 2737 | 2754 |
:draw_relations => '1', |
| 2738 | 2755 |
:draw_progress_line => '1' |
| 2739 | 2756 |
} |
| 2740 | 2757 |
) |
| 2741 | 2758 |
old_attributes = q.attributes |
| 2742 | 2759 |
q.build_from_params({})
|
| 2743 | 2760 |
assert_equal old_attributes, q.attributes |
| 2744 | 2761 |
end |
| 2745 | 2762 | |
| 2746 | 2763 |
test "#available_filters should include users of visible projects in cross-project view" do |
| 2747 | 2764 |
users = IssueQuery.new.available_filters["assigned_to_id"] |
| 2748 | 2765 |
assert_not_nil users |
| 2749 | 2766 |
assert users[:values].pluck(1).include?("3")
|
| 2750 | 2767 |
end |
| 2751 | 2768 | |
| 2769 |
def test_assigned_to_filter_values_should_include_nobody |
|
| 2770 |
set_language_if_valid('en')
|
|
| 2771 | ||
| 2772 |
users = IssueQuery.new.available_filters["assigned_to_id"] |
|
| 2773 | ||
| 2774 |
assert_include ["<< #{l(:label_nobody)} >>", 'none'], users[:values]
|
|
| 2775 |
end |
|
| 2776 | ||
| 2752 | 2777 |
test "#available_filters should include users of subprojects" do |
| 2753 | 2778 |
user1 = User.generate! |
| 2754 | 2779 |
user2 = User.generate! |
| 2755 | 2780 |
project = Project.find(1) |
| 2756 | 2781 |
Member.create!(:principal => user1, :project => project.children.visible.first, :role_ids => [1]) |
| 2757 | 2782 |
users = IssueQuery.new(:project => project).available_filters["assigned_to_id"] |
| 2758 | 2783 |
assert_not_nil users |
| 2759 | 2784 |
assert users[:values].pluck(1).include?(user1.id.to_s) |
| 2760 | 2785 |
assert !users[:values].pluck(1).include?(user2.id.to_s) |
| 2761 | 2786 |
end |
| 2762 | 2787 | |
| 2763 | 2788 |
test "#available_filters should include visible projects in cross-project view" do |
| 2764 | 2789 |
projects = IssueQuery.new.available_filters["project_id"] |
| 2765 | 2790 |
assert_not_nil projects |
| 2766 | 2791 |
assert projects[:values].pluck(1).include?("1")
|
| 2767 | 2792 |
end |
| 2768 | 2793 | |
| 2769 | 2794 |
test "#available_filters should include 'member_of_group' filter" do |
| 2770 | 2795 |
query = IssueQuery.new |
| 2771 | 2796 |
assert query.available_filters.key?("member_of_group")
|
| 2772 | 2797 |
assert_equal :list_optional, query.available_filters["member_of_group"][:type] |
| 2773 | 2798 |
assert query.available_filters["member_of_group"][:values].present? |
| 2774 | 2799 |
assert_equal Group.givable.sort.map {|g| [g.name, g.id.to_s]},
|
| 2775 | 2800 |
query.available_filters["member_of_group"][:values].sort |
| 2776 | 2801 |
end |
- « Previous
- 1
- 2
- Next »