diff options
author | Douwe Maan <douwe@gitlab.com> | 2019-03-27 15:34:35 +0300 |
---|---|---|
committer | Douwe Maan <douwe@gitlab.com> | 2019-03-27 15:34:35 +0300 |
commit | 2cc01f12c2f44a8f1af972cd83ec9cde0d424636 (patch) | |
tree | a1dee42cef8b90a6b7660e078f42ad11af7ca323 /app | |
parent | a9194b60d783b81ece88e037f31e61f977f8fd0b (diff) | |
parent | 33a4fe1f460f64f2c9f56c8f8874982dc45effd2 (diff) |
Merge branch 'sh-optimize-projects-api' into 'master'
Optimize /api/v4/projects endpoint for visibility level
See merge request gitlab-org/gitlab-ce!26481
Diffstat (limited to 'app')
-rw-r--r-- | app/finders/projects_finder.rb | 2 | ||||
-rw-r--r-- | app/models/project.rb | 43 |
2 files changed, 36 insertions, 9 deletions
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb index 93d3c991846..0319e95d439 100644 --- a/app/finders/projects_finder.rb +++ b/app/finders/projects_finder.rb @@ -81,7 +81,7 @@ class ProjectsFinder < UnionFinder if private_only? current_user.authorized_projects else - Project.public_or_visible_to_user(current_user) + Project.public_or_visible_to_user(current_user, params[:visibility_level]) end end end diff --git a/app/models/project.rb b/app/models/project.rb index 97a17d120c6..06010409574 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -459,14 +459,41 @@ class Project < ActiveRecord::Base # Returns a collection of projects that is either public or visible to the # logged in user. - def self.public_or_visible_to_user(user = nil) - if user - where('EXISTS (?) OR projects.visibility_level IN (?)', - user.authorizations_for_projects, - Gitlab::VisibilityLevel.levels_for_user(user)) - else - public_to_user - end + # + # requested_visiblity_levels: Normally all projects that are visible + # to the user (e.g. internal and public) are queried, but this + # parameter allows the caller to narrow the search space to optimize + # database queries. For instance, a caller may only want to see + # internal projects. Instead of querying for internal and public + # projects and throwing away public projects, this parameter allows + # the query to be targeted for only internal projects. + def self.public_or_visible_to_user(user = nil, requested_visibility_levels = []) + return public_to_user unless user + + visible_levels = Gitlab::VisibilityLevel.levels_for_user(user) + include_private = true + requested_visibility_levels = Array(requested_visibility_levels) + + if requested_visibility_levels.present? + visible_levels &= requested_visibility_levels + include_private = requested_visibility_levels.include?(Gitlab::VisibilityLevel::PRIVATE) + end + + public_or_internal_rel = + if visible_levels.present? + where('projects.visibility_level IN (?)', visible_levels) + else + Project.none + end + + private_rel = + if include_private + where('EXISTS (?)', user.authorizations_for_projects) + else + Project.none + end + + public_or_internal_rel.or(private_rel) end # project features may be "disabled", "internal", "enabled" or "public". If "internal", |