6ff7788d4c
Use project scopes to filter project labels Add changelog file Check issuables visibility in LabelsFinder Add specs for issuables visibility cases Rename Project method to reuse in LabelsFinder Remove commented code Improve changelog title
196 lines
5.5 KiB
Ruby
196 lines
5.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Gitlab
|
|
class SearchResults
|
|
COUNT_LIMIT = 100
|
|
COUNT_LIMIT_MESSAGE = "#{COUNT_LIMIT - 1}+"
|
|
|
|
attr_reader :current_user, :query, :per_page
|
|
|
|
# Limit search results by passed projects
|
|
# It allows us to search only for projects user has access to
|
|
attr_reader :limit_projects
|
|
|
|
# Whether a custom filter is used to restrict scope of projects.
|
|
# If the default filter (which lists all projects user has access to)
|
|
# is used, we can skip it when filtering merge requests and optimize the
|
|
# query
|
|
attr_reader :default_project_filter
|
|
|
|
def initialize(current_user, limit_projects, query, default_project_filter: false, per_page: 20)
|
|
@current_user = current_user
|
|
@limit_projects = limit_projects || Project.all
|
|
@query = query
|
|
@default_project_filter = default_project_filter
|
|
@per_page = per_page
|
|
end
|
|
|
|
def objects(scope, page = nil, without_count = true)
|
|
collection = case scope
|
|
when 'projects'
|
|
projects
|
|
when 'issues'
|
|
issues
|
|
when 'merge_requests'
|
|
merge_requests
|
|
when 'milestones'
|
|
milestones
|
|
when 'users'
|
|
users
|
|
else
|
|
Kaminari.paginate_array([])
|
|
end.page(page).per(per_page)
|
|
|
|
without_count ? collection.without_count : collection
|
|
end
|
|
|
|
def formatted_count(scope)
|
|
case scope
|
|
when 'projects'
|
|
formatted_limited_count(limited_projects_count)
|
|
when 'issues'
|
|
formatted_limited_count(limited_issues_count)
|
|
when 'merge_requests'
|
|
formatted_limited_count(limited_merge_requests_count)
|
|
when 'milestones'
|
|
formatted_limited_count(limited_milestones_count)
|
|
when 'users'
|
|
formatted_limited_count(limited_users_count)
|
|
end
|
|
end
|
|
|
|
def formatted_limited_count(count)
|
|
if count >= COUNT_LIMIT
|
|
COUNT_LIMIT_MESSAGE
|
|
else
|
|
count.to_s
|
|
end
|
|
end
|
|
|
|
def limited_projects_count
|
|
@limited_projects_count ||= limited_count(projects)
|
|
end
|
|
|
|
def limited_issues_count
|
|
return @limited_issues_count if @limited_issues_count
|
|
|
|
# By default getting limited count (e.g. 1000+) is fast on issuable
|
|
# collections except for issues, where filtering both not confidential
|
|
# and confidential issues user has access to, is too complex.
|
|
# It's faster to try to fetch all public issues first, then only
|
|
# if necessary try to fetch all issues.
|
|
sum = limited_count(issues(public_only: true))
|
|
@limited_issues_count = sum < count_limit ? limited_count(issues) : sum
|
|
end
|
|
|
|
def limited_merge_requests_count
|
|
@limited_merge_requests_count ||= limited_count(merge_requests)
|
|
end
|
|
|
|
def limited_milestones_count
|
|
@limited_milestones_count ||= limited_count(milestones)
|
|
end
|
|
|
|
def limited_users_count
|
|
@limited_users_count ||= limited_count(users)
|
|
end
|
|
|
|
def single_commit_result?
|
|
false
|
|
end
|
|
|
|
def count_limit
|
|
COUNT_LIMIT
|
|
end
|
|
|
|
def users
|
|
return User.none unless Ability.allowed?(current_user, :read_users_list)
|
|
|
|
UsersFinder.new(current_user, search: query).execute
|
|
end
|
|
|
|
private
|
|
|
|
def projects
|
|
limit_projects.search(query)
|
|
end
|
|
|
|
def issues(finder_params = {})
|
|
issues = IssuesFinder.new(current_user, issuable_params.merge(finder_params)).execute
|
|
|
|
unless default_project_filter
|
|
issues = issues.where(project_id: project_ids_relation) # rubocop: disable CodeReuse/ActiveRecord
|
|
end
|
|
|
|
issues
|
|
end
|
|
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
def milestones
|
|
milestones = Milestone.search(query)
|
|
|
|
milestones = filter_milestones_by_project(milestones)
|
|
|
|
milestones.reorder('updated_at DESC')
|
|
end
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
|
|
|
def merge_requests
|
|
merge_requests = MergeRequestsFinder.new(current_user, issuable_params).execute
|
|
|
|
unless default_project_filter
|
|
merge_requests = merge_requests.in_projects(project_ids_relation)
|
|
end
|
|
|
|
merge_requests
|
|
end
|
|
|
|
def default_scope
|
|
'projects'
|
|
end
|
|
|
|
# Filter milestones by authorized projects.
|
|
# For performance reasons project_id is being plucked
|
|
# to be used on a smaller query.
|
|
#
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
def filter_milestones_by_project(milestones)
|
|
project_ids =
|
|
milestones.where(project_id: project_ids_relation)
|
|
.select(:project_id).distinct
|
|
.pluck(:project_id)
|
|
|
|
return Milestone.none if project_ids.nil?
|
|
|
|
authorized_project_ids_relation =
|
|
Project.where(id: project_ids).ids_with_issuables_available_for(current_user)
|
|
|
|
milestones.where(project_id: authorized_project_ids_relation)
|
|
end
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
|
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
def project_ids_relation
|
|
limit_projects.select(:id).reorder(nil)
|
|
end
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
|
|
|
def issuable_params
|
|
{}.tap do |params|
|
|
params[:sort] = 'updated_desc'
|
|
|
|
if query =~ /#(\d+)\z/
|
|
params[:iids] = $1
|
|
else
|
|
params[:search] = query
|
|
end
|
|
end
|
|
end
|
|
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
def limited_count(relation)
|
|
relation.reorder(nil).limit(count_limit).size
|
|
end
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
|
end
|
|
end
|