diff options
author | Andreas Brandl <abrandl@gitlab.com> | 2018-02-16 12:35:58 +0100 |
---|---|---|
committer | Andreas Brandl <abrandl@gitlab.com> | 2018-02-20 13:08:24 +0100 |
commit | 336bc95e361ec51b445732129f61f82903a47fdf (patch) | |
tree | a2bc9d2c0eb64be03ff5ccbd6b5aad04bde8a597 | |
parent | 5a5a33a9a6062bac2bded77c434cc56a4e68dac1 (diff) | |
download | gitlab-ce-336bc95e361ec51b445732129f61f82903a47fdf.tar.gz |
Push feature-related query part up.
-rw-r--r-- | app/finders/snippets_finder.rb | 3 | ||||
-rw-r--r-- | app/models/project.rb | 29 |
2 files changed, 30 insertions, 2 deletions
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb index 33359fa1efb..7a343faecdd 100644 --- a/app/finders/snippets_finder.rb +++ b/app/finders/snippets_finder.rb @@ -56,8 +56,7 @@ class SnippetsFinder < UnionFinder end def feature_available_projects - projects = Project.public_or_visible_to_user(current_user) - .with_feature_available_for_user(:snippets, current_user).select(:id) + projects = Project.public_or_visible_to_user_with_feature_available(current_user, :snippets).select(:id) arel_query = Arel::Nodes::SqlLiteral.new(projects.to_sql) table[:project_id].in(arel_query) end diff --git a/app/models/project.rb b/app/models/project.rb index 8bf220b2ae4..e575ab9a728 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -343,6 +343,35 @@ class Project < ActiveRecord::Base end end + # Combination of .public_or_visible_to_user AND .with_feature_available_for_user + # We duplicated this for (database) performance reasons to optimize the query. + def self.public_or_visible_to_user_with_feature_available(user, feature) + if user + authorized = user + .project_authorizations + .select(1) + .where('project_authorizations.project_id = projects.id') + + levels = Gitlab::VisibilityLevel.levels_for_user(user) + + if Gitlab::VisibilityLevel.all_levels?(levels) + # If the user is allowed to see all projects, + # we can shortcut and just return. + return all.with_feature_available_for_user(feature, user) + end + + authorized_projects = where('EXISTS (?)', authorized).with_feature_available_for_user(feature, user).select(:id) + visible_projects = where('visibility_level IN (?)', levels).with_feature_available_for_user(feature, user).select(:id) + + # We use a UNION here instead of OR clauses since this results in better + # performance. + union = Gitlab::SQL::Union.new([authorized_projects, visible_projects]) + from("(#{union.to_sql}) projects") + else + public_to_user.with_feature_available_for_user(feature, user) + end + end + # project features may be "disabled", "internal" or "enabled". If "internal", # they are only available to team members. This scope returns projects where # the feature is either enabled, or internal with permission for the user. |