diff options
-rw-r--r-- | app/finders/snippets_finder.rb | 5 | ||||
-rw-r--r-- | app/models/project.rb | 46 | ||||
-rw-r--r-- | changelogs/unreleased/revert-project-visibility-changes.yml | 5 |
3 files changed, 18 insertions, 38 deletions
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb index a73c573736e..75e827b7f6e 100644 --- a/app/finders/snippets_finder.rb +++ b/app/finders/snippets_finder.rb @@ -62,9 +62,8 @@ class SnippetsFinder < UnionFinder # Don't return any project related snippets if the user cannot read cross project return table[:id].eq(nil) unless Ability.allowed?(current_user, :read_cross_project) - projects = Project.public_or_visible_to_user(current_user, use_where_in: false) do |part| - part.with_feature_available_for_user(:snippets, current_user) - end.select(:id) + projects = Project.public_or_visible_to_user(current_user) + .with_feature_available_for_user(:snippets, current_user).select(:id) arel_query = Arel::Nodes::SqlLiteral.new(projects.to_sql) table[:project_id].in(arel_query) diff --git a/app/models/project.rb b/app/models/project.rb index ba278a49688..ad4315e1601 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -317,42 +317,18 @@ class Project < ActiveRecord::Base # Returns a collection of projects that is either public or visible to the # logged in user. - # - # A caller may pass in a block to modify individual parts of - # the query, e.g. to apply .with_feature_available_for_user on top of it. - # This is useful for performance as we can stick those additional filters - # at the bottom of e.g. the UNION. - # - # Optionally, turning `use_where_in` off leads to returning a - # relation using #from instead of #where. This can perform much better - # but leads to trouble when used in conjunction with AR's #merge method. - def self.public_or_visible_to_user(user = nil, use_where_in: true, &block) - # If we don't get a block passed, use identity to avoid if/else repetitions - block = ->(part) { part } unless block_given? - - return block.call(public_to_user) unless user - - # If the user is allowed to see all projects, - # we can shortcut and just return. - return block.call(all) if user.full_private_access? - - authorized = user - .project_authorizations - .select(1) - .where('project_authorizations.project_id = projects.id') - authorized_projects = block.call(where('EXISTS (?)', authorized)) - - levels = Gitlab::VisibilityLevel.levels_for_user(user) - visible_projects = block.call(where(visibility_level: levels)) - - # We use a UNION here instead of OR clauses since this results in better - # performance. - union = Gitlab::SQL::Union.new([authorized_projects.select('projects.id'), visible_projects.select('projects.id')]) - - if use_where_in - where("projects.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection + def self.public_or_visible_to_user(user = nil) + if user + authorized = user + .project_authorizations + .select(1) + .where('project_authorizations.project_id = projects.id') + + levels = Gitlab::VisibilityLevel.levels_for_user(user) + + where('EXISTS (?) OR projects.visibility_level IN (?)', authorized, levels) else - from("(#{union.to_sql}) AS #{table_name}") + public_to_user end end diff --git a/changelogs/unreleased/revert-project-visibility-changes.yml b/changelogs/unreleased/revert-project-visibility-changes.yml new file mode 100644 index 00000000000..86bab00b9b1 --- /dev/null +++ b/changelogs/unreleased/revert-project-visibility-changes.yml @@ -0,0 +1,5 @@ +--- +title: Revert Project.public_or_visible_to_user changes +merge_request: +author: +type: fixed |