090ca9c33e
Search query is especially slow if a user searches a generic string which matches many records, in such case search can take tens of seconds or time out. To speed up the search query, we search only for first 1000 records, if there is >1000 matching records we just display "1000+" instead of precise total count supposing that with such amount the exact count is not so important for the user. Because for issues even limited search was not fast enough, 2-phase approach is used for issues: first we use simpler/faster query to get all public issues, if this exceeds the limit, we just return the limit. If the amount of matching results is lower than limit, we re-run more complex search query (which includes also confidential issues). Re-running the complex query should be fast enough in such case because the amount of matching issues is lower than limit. Because exact total_count is now limited, this patch also switches to to "prev/next" pagination. Related #40540
88 lines
2.3 KiB
Ruby
88 lines
2.3 KiB
Ruby
# Finders::Issues class
|
|
#
|
|
# Used to filter Issues collections by set of params
|
|
#
|
|
# Arguments:
|
|
# current_user - which user use
|
|
# params:
|
|
# scope: 'created-by-me' or 'assigned-to-me' or 'all'
|
|
# state: 'open' or 'closed' or 'all'
|
|
# group_id: integer
|
|
# project_id: integer
|
|
# milestone_title: string
|
|
# assignee_id: integer
|
|
# search: string
|
|
# label_name: string
|
|
# sort: string
|
|
# my_reaction_emoji: string
|
|
# public_only: boolean
|
|
#
|
|
class IssuesFinder < IssuableFinder
|
|
CONFIDENTIAL_ACCESS_LEVEL = Gitlab::Access::REPORTER
|
|
|
|
def klass
|
|
Issue
|
|
end
|
|
|
|
def with_confidentiality_access_check
|
|
return Issue.all if user_can_see_all_confidential_issues?
|
|
return Issue.where('issues.confidential IS NOT TRUE') if user_cannot_see_confidential_issues?
|
|
|
|
Issue.where('
|
|
issues.confidential IS NOT TRUE
|
|
OR (issues.confidential = TRUE
|
|
AND (issues.author_id = :user_id
|
|
OR EXISTS (SELECT TRUE FROM issue_assignees WHERE user_id = :user_id AND issue_id = issues.id)
|
|
OR issues.project_id IN(:project_ids)))',
|
|
user_id: current_user.id,
|
|
project_ids: current_user.authorized_projects(CONFIDENTIAL_ACCESS_LEVEL).select(:id))
|
|
end
|
|
|
|
private
|
|
|
|
def init_collection
|
|
if public_only?
|
|
Issue.public_only
|
|
else
|
|
with_confidentiality_access_check
|
|
end
|
|
end
|
|
|
|
def public_only?
|
|
params.fetch(:public_only, false)
|
|
end
|
|
|
|
def user_can_see_all_confidential_issues?
|
|
return @user_can_see_all_confidential_issues if defined?(@user_can_see_all_confidential_issues)
|
|
|
|
return @user_can_see_all_confidential_issues = false if current_user.blank?
|
|
return @user_can_see_all_confidential_issues = true if current_user.full_private_access?
|
|
|
|
@user_can_see_all_confidential_issues =
|
|
project? &&
|
|
project &&
|
|
project.team.max_member_access(current_user.id) >= CONFIDENTIAL_ACCESS_LEVEL
|
|
end
|
|
|
|
def user_cannot_see_confidential_issues?
|
|
return false if user_can_see_all_confidential_issues?
|
|
|
|
current_user.blank?
|
|
end
|
|
|
|
def by_assignee(items)
|
|
if assignee
|
|
items.assigned_to(assignee)
|
|
elsif no_assignee?
|
|
items.unassigned
|
|
elsif assignee_id? || assignee_username? # assignee not found
|
|
items.none
|
|
else
|
|
items
|
|
end
|
|
end
|
|
|
|
def item_project_ids(items)
|
|
items&.reorder(nil)&.select(:project_id)
|
|
end
|
|
end
|