summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/finders/issuable_finder.rb35
-rw-r--r--app/finders/issues_finder.rb9
-rw-r--r--lib/api/issues.rb6
-rw-r--r--spec/finders/issues_finder_spec.rb18
-rw-r--r--spec/requests/api/issues_spec.rb15
5 files changed, 65 insertions, 18 deletions
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 8abfe0c4c17..ec4472de0c4 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -14,7 +14,7 @@
# project_id: integer
# milestone_title: string
# author_id: integer
-# assignee_id: integer
+# assignee_id: integer or 'None' or 'Any'
# search: string
# label_name: string
# sort: string
@@ -34,6 +34,11 @@ class IssuableFinder
requires_cross_project_access unless: -> { project? }
+ # This is used as a common filter for None / Any
+ FILTER_NONE = 'None'.freeze
+ FILTER_ANY = 'Any'.freeze
+
+ # This is accepted as a deprecated filter and is also used in unassigning users
NONE = '0'.freeze
attr_accessor :current_user, :params
@@ -236,16 +241,20 @@ class IssuableFinder
# rubocop: enable CodeReuse/ActiveRecord
def assignee_id?
- params[:assignee_id].present? && params[:assignee_id].to_s != NONE
+ params[:assignee_id].present?
end
def assignee_username?
- params[:assignee_username].present? && params[:assignee_username].to_s != NONE
+ params[:assignee_username].present?
end
- def no_assignee?
+ def filter_by_no_assignee?
# Assignee_id takes precedence over assignee_username
- params[:assignee_id].to_s == NONE || params[:assignee_username].to_s == NONE
+ [NONE, FILTER_NONE].include?(params[:assignee_id].to_s) || params[:assignee_username].to_s == NONE
+ end
+
+ def filter_by_any_assignee?
+ params[:assignee_id].to_s == FILTER_ANY
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -399,15 +408,17 @@ class IssuableFinder
# rubocop: disable CodeReuse/ActiveRecord
def by_assignee(items)
- if assignee
- items = items.where(assignee_id: assignee.id)
- elsif no_assignee?
- items = items.where(assignee_id: nil)
+ if filter_by_no_assignee?
+ items.where(assignee_id: nil)
+ elsif filter_by_any_assignee?
+ items.where('assignee_id IS NOT NULL')
+ elsif assignee
+ items.where(assignee_id: assignee.id)
elsif assignee_id? || assignee_username? # assignee not found
- items = items.none
+ items.none
+ else
+ items
end
-
- items
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb
index abdc47b9866..4a95eb44417 100644
--- a/app/finders/issues_finder.rb
+++ b/app/finders/issues_finder.rb
@@ -135,12 +135,13 @@ class IssuesFinder < IssuableFinder
current_user.blank?
end
- # rubocop: disable CodeReuse/ActiveRecord
def by_assignee(items)
- if assignee
- items.assigned_to(assignee)
- elsif no_assignee?
+ if filter_by_no_assignee?
items.unassigned
+ elsif filter_by_any_assignee?
+ items.assigned
+ elsif assignee
+ items.assigned_to(assignee)
elsif assignee_id? || assignee_username? # assignee not found
items.none
else
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 25d78053c88..89232212bc7 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -40,7 +40,11 @@ module API
optional :updated_after, type: DateTime, desc: 'Return issues updated after the specified time'
optional :updated_before, type: DateTime, desc: 'Return issues updated before the specified time'
optional :author_id, type: Integer, desc: 'Return issues which are authored by the user with the given ID'
- optional :assignee_id, type: Integer, desc: 'Return issues which are assigned to the user with the given ID'
+ optional :assignee_id, types: [Integer, String],
+ values: -> (v) {
+ v.is_a?(Integer) or [IssuableFinder::FILTER_NONE, IssuableFinder::FILTER_ANY].include?(v)
+ },
+ desc: 'Return issues which are assigned to the user with the given ID'
optional :scope, type: String, values: %w[created-by-me assigned-to-me created_by_me assigned_to_me all],
desc: 'Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`'
optional :my_reaction_emoji, type: String, desc: 'Return issues reacted by the authenticated user by the given emoji'
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index 0689c843104..7f4f613b406 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -59,11 +59,27 @@ describe IssuesFinder do
context 'filtering by no assignee' do
let(:params) { { assignee_id: 0 } }
- it 'returns issues not assign to any assignee' do
+ it 'returns issues not assigned to any assignee' do
expect(issues).to contain_exactly(issue4)
end
end
+ context 'filtering by no assignee' do
+ let(:params) { { assignee_id: 'None' } }
+
+ it 'returns issues not assigned to any assignee' do
+ expect(issues).to contain_exactly(issue4)
+ end
+ end
+
+ context 'filtering by any assignee' do
+ let(:params) { { assignee_id: 'Any' } }
+
+ it 'returns issues assigned to any assignee' do
+ expect(issues).to contain_exactly(issue1, issue2, issue3)
+ end
+ end
+
context 'filtering by group_id' do
let(:params) { { group_id: group.id } }
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 9f6cf12f9a7..090e8eac768 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -178,6 +178,21 @@ describe API::Issues do
expect(first_issue['id']).to eq(issue2.id)
end
+ it 'returns issues with no assignee' do
+ issue2 = create(:issue, author: user2, project: project)
+
+ get api('/issues', user), assignee_id: 'None', scope: 'all'
+
+ expect_paginated_array_response(size: 1)
+ expect(first_issue['id']).to eq(issue2.id)
+ end
+
+ it 'returns issues with any assignee' do
+ get api('/issues', user), assignee_id: 'Any', scope: 'all'
+
+ expect_paginated_array_response(size: 3)
+ end
+
it 'returns issues reacted by the authenticated user by the given emoji' do
issue2 = create(:issue, project: project, author: user, assignees: [user])
award_emoji = create(:award_emoji, awardable: issue2, user: user2, name: 'star')