debian-mirror-gitlab/app/finders/projects_finder.rb

228 lines
6.1 KiB
Ruby
Raw Normal View History

2018-12-05 23:21:45 +05:30
# frozen_string_literal: true
2017-08-17 22:00:37 +05:30
# ProjectsFinder
#
# Used to filter Projects by set of params
#
# Arguments:
# current_user - which user use
# project_ids_relation: int[] - project ids to use
# params:
# trending: boolean
2017-09-10 17:25:29 +05:30
# owned: boolean
2017-08-17 22:00:37 +05:30
# non_public: boolean
# starred: boolean
# sort: string
# visibility_level: int
# tags: string[]
# personal: boolean
# search: string
2020-04-22 19:07:51 +05:30
# search_namespaces: boolean
2017-08-17 22:00:37 +05:30
# non_archived: boolean
2018-11-18 11:00:15 +05:30
# archived: 'only' or boolean
# min_access_level: integer
2020-04-22 19:07:51 +05:30
# last_activity_after: datetime
# last_activity_before: datetime
2017-08-17 22:00:37 +05:30
#
2016-06-02 11:05:42 +05:30
class ProjectsFinder < UnionFinder
2018-03-17 18:26:18 +05:30
include CustomAttributesFilter
2017-08-17 22:00:37 +05:30
attr_accessor :params
attr_reader :current_user, :project_ids_relation
2014-09-02 18:07:02 +05:30
2017-08-17 22:00:37 +05:30
def initialize(params: {}, current_user: nil, project_ids_relation: nil)
@params = params
@current_user = current_user
@project_ids_relation = project_ids_relation
end
def execute
2017-09-10 17:25:29 +05:30
user = params.delete(:user)
collection =
if user
2018-12-05 23:21:45 +05:30
PersonalProjectsFinder.new(user, finder_params).execute(current_user) # rubocop: disable CodeReuse/Finder
2017-09-10 17:25:29 +05:30
else
init_collection
end
2020-03-13 15:44:24 +05:30
use_cte = params.delete(:use_cte)
collection = Project.wrap_with_cte(collection) if use_cte
2018-12-13 13:39:08 +05:30
collection = filter_projects(collection)
2017-09-10 17:25:29 +05:30
sort(collection)
2014-09-02 18:07:02 +05:30
end
private
2017-08-17 22:00:37 +05:30
def init_collection
2017-09-10 17:25:29 +05:30
if current_user
collection_with_user
else
collection_without_user
end
end
2018-12-13 13:39:08 +05:30
# EE would override this to add more filters
def filter_projects(collection)
collection = by_ids(collection)
collection = by_personal(collection)
collection = by_starred(collection)
collection = by_trending(collection)
2019-07-07 11:18:12 +05:30
collection = by_visibility_level(collection)
2018-12-13 13:39:08 +05:30
collection = by_tags(collection)
collection = by_search(collection)
collection = by_archived(collection)
collection = by_custom_attributes(collection)
collection = by_deleted_status(collection)
2020-04-22 19:07:51 +05:30
collection = by_last_activity_after(collection)
collection = by_last_activity_before(collection)
2018-12-13 13:39:08 +05:30
collection
end
2017-09-10 17:25:29 +05:30
def collection_with_user
if owned_projects?
current_user.owned_projects
2018-11-18 11:00:15 +05:30
elsif min_access_level?
2019-07-07 11:18:12 +05:30
current_user.authorized_projects(params[:min_access_level])
2017-09-10 17:25:29 +05:30
else
2020-01-01 13:55:28 +05:30
if private_only? || impossible_visibility_level?
2017-09-10 17:25:29 +05:30
current_user.authorized_projects
else
Project.public_or_visible_to_user(current_user)
end
end
end
2015-11-26 14:37:03 +05:30
2017-09-10 17:25:29 +05:30
# Builds a collection for an anonymous user.
def collection_without_user
2018-11-18 11:00:15 +05:30
if private_only? || owned_projects? || min_access_level?
2017-09-10 17:25:29 +05:30
Project.none
2017-08-17 22:00:37 +05:30
else
2017-09-10 17:25:29 +05:30
Project.public_to_user
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
end
2020-01-01 13:55:28 +05:30
# This is an optimization - surprisingly PostgreSQL does not optimize
# for this.
#
# If the default visiblity level and desired visiblity level filter cancels
# each other out, don't use the SQL clause for visibility level in
# `Project.public_or_visible_to_user`. In fact, this then becames equivalent
# to just authorized projects for the user.
#
# E.g.
# (EXISTS(<authorized_projects>) OR projects.visibility_level IN (10,20))
# AND "projects"."visibility_level" = 0
#
# is essentially
# EXISTS(<authorized_projects>) AND "projects"."visibility_level" = 0
#
# See https://gitlab.com/gitlab-org/gitlab/issues/37007
def impossible_visibility_level?
return unless params[:visibility_level].present?
public_visibility_levels = Gitlab::VisibilityLevel.levels_for_user(current_user)
!public_visibility_levels.include?(params[:visibility_level])
end
2017-09-10 17:25:29 +05:30
def owned_projects?
params[:owned].present?
end
2015-11-26 14:37:03 +05:30
2017-09-10 17:25:29 +05:30
def private_only?
params[:non_public].present?
2015-11-26 14:37:03 +05:30
end
2017-08-17 22:00:37 +05:30
2018-11-18 11:00:15 +05:30
def min_access_level?
params[:min_access_level].present?
end
2018-12-05 23:21:45 +05:30
# rubocop: disable CodeReuse/ActiveRecord
2017-08-17 22:00:37 +05:30
def by_ids(items)
2019-12-26 22:10:19 +05:30
items = items.where(id: project_ids_relation) if project_ids_relation
2020-04-22 19:07:51 +05:30
items = items.where('projects.id > ?', params[:id_after]) if params[:id_after]
items = items.where('projects.id < ?', params[:id_before]) if params[:id_before]
2019-12-26 22:10:19 +05:30
items
2017-08-17 22:00:37 +05:30
end
2018-12-05 23:21:45 +05:30
# rubocop: enable CodeReuse/ActiveRecord
2017-08-17 22:00:37 +05:30
def union(items)
find_union(items, Project).with_route
end
def by_personal(items)
2020-05-24 23:13:21 +05:30
params[:personal].present? && current_user ? items.personal(current_user) : items
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
def by_starred(items)
2020-05-24 23:13:21 +05:30
params[:starred].present? && current_user ? items.starred_by(current_user) : items
2017-09-10 17:25:29 +05:30
end
def by_trending(items)
params[:trending].present? ? items.trending : items
end
2018-12-05 23:21:45 +05:30
# rubocop: disable CodeReuse/ActiveRecord
2019-07-07 11:18:12 +05:30
def by_visibility_level(items)
2017-08-17 22:00:37 +05:30
params[:visibility_level].present? ? items.where(visibility_level: params[:visibility_level]) : items
end
2018-12-05 23:21:45 +05:30
# rubocop: enable CodeReuse/ActiveRecord
2017-08-17 22:00:37 +05:30
def by_tags(items)
params[:tag].present? ? items.tagged_with(params[:tag]) : items
end
def by_search(items)
params[:search] ||= params[:name]
2020-04-22 19:07:51 +05:30
items.optionally_search(params[:search], include_namespace: params[:search_namespaces].present?)
2017-08-17 22:00:37 +05:30
end
2018-12-05 23:21:45 +05:30
def by_deleted_status(items)
params[:without_deleted].present? ? items.without_deleted : items
end
2020-04-22 19:07:51 +05:30
def by_last_activity_after(items)
if params[:last_activity_after].present?
items.where("last_activity_at > ?", params[:last_activity_after]) # rubocop: disable CodeReuse/ActiveRecord
else
items
end
end
def by_last_activity_before(items)
if params[:last_activity_before].present?
items.where("last_activity_at < ?", params[:last_activity_before]) # rubocop: disable CodeReuse/ActiveRecord
else
items
end
end
2017-08-17 22:00:37 +05:30
def sort(items)
2020-03-13 15:44:24 +05:30
params[:sort].present? ? items.sort_by_attribute(params[:sort]) : items.projects_order_id_desc
2017-08-17 22:00:37 +05:30
end
def by_archived(projects)
2018-03-17 18:26:18 +05:30
if params[:non_archived]
projects.non_archived
2018-11-18 11:00:15 +05:30
elsif params.key?(:archived)
2018-03-17 18:26:18 +05:30
if params[:archived] == 'only'
projects.archived
elsif Gitlab::Utils.to_boolean(params[:archived])
projects
else
projects.non_archived
end
else
projects
end
2017-08-17 22:00:37 +05:30
end
2018-11-18 11:00:15 +05:30
def finder_params
return {} unless min_access_level?
{ min_access_level: params[:min_access_level] }
end
2014-09-02 18:07:02 +05:30
end
2020-04-22 19:07:51 +05:30
ProjectsFinder.prepend_if_ee('::EE::ProjectsFinder')