Issues API: Add None/Any option to assignee_id
This commit is contained in:
parent
679c0048a8
commit
227e30f7fe
5 changed files with 65 additions and 18 deletions
|
@ -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,16 +408,18 @@ 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
|
||||
end
|
||||
|
||||
items.none
|
||||
else
|
||||
items
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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 } }
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in a new issue