summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Brandl <abrandl@gitlab.com>2018-02-16 12:35:58 +0100
committerAndreas Brandl <abrandl@gitlab.com>2018-02-20 13:08:24 +0100
commit336bc95e361ec51b445732129f61f82903a47fdf (patch)
treea2bc9d2c0eb64be03ff5ccbd6b5aad04bde8a597
parent5a5a33a9a6062bac2bded77c434cc56a4e68dac1 (diff)
downloadgitlab-ce-336bc95e361ec51b445732129f61f82903a47fdf.tar.gz
Push feature-related query part up.
-rw-r--r--app/finders/snippets_finder.rb3
-rw-r--r--app/models/project.rb29
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.