From 467b346f0684053081d7e762df1a2b5df5888543 Mon Sep 17 00:00:00 2001
From: Yorick Peterse <yorickpeterse@gmail.com>
Date: Thu, 13 Oct 2016 17:53:47 +0200
Subject: [PATCH] Add User#projects_with_reporter_access_limited_to

This method can be used to retrieve a list of projects for a user that
said user has reporter access to. This list is then be reduced down to
a specific set of projects. This allows you to reduce a list of projects
to a list of projects you have reporter access to in an efficient
manner.
---
 app/models/user.rb       | 10 ++++++++++
 spec/models/user_spec.rb | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/app/models/user.rb b/app/models/user.rb
index 65e96ee6b2e..c0dffa7b6ea 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -444,6 +444,16 @@ class User < ActiveRecord::Base
     Project.where("projects.id IN (#{projects_union(min_access_level).to_sql})")
   end
 
+  # Returns the projects this user has reporter (or greater) access to, limited
+  # to at most the given projects.
+  #
+  # This method is useful when you have a list of projects and want to
+  # efficiently check to which of these projects the user has at least reporter
+  # access.
+  def projects_with_reporter_access_limited_to(projects)
+    authorized_projects(Gitlab::Access::REPORTER).where(id: projects)
+  end
+
   def viewable_starred_projects
     starred_projects.where("projects.visibility_level IN (?) OR projects.id IN (#{projects_union.to_sql})",
                            [Project::PUBLIC, Project::INTERNAL])
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index ba47479a2e1..3b152e15b61 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1205,4 +1205,40 @@ describe User, models: true do
       expect(user.viewable_starred_projects).not_to include(private_project)
     end
   end
+
+  describe '#projects_with_reporter_access_limited_to' do
+    let(:project1) { create(:project) }
+    let(:project2) { create(:project) }
+    let(:user) { create(:user) }
+
+    before do
+      project1.team << [user, :reporter]
+      project2.team << [user, :guest]
+    end
+
+    it 'returns the projects when using a single project ID' do
+      projects = user.projects_with_reporter_access_limited_to(project1.id)
+
+      expect(projects).to eq([project1])
+    end
+
+    it 'returns the projects when using an Array of project IDs' do
+      projects = user.projects_with_reporter_access_limited_to([project1.id])
+
+      expect(projects).to eq([project1])
+    end
+
+    it 'returns the projects when using an ActiveRecord relation' do
+      projects = user.
+        projects_with_reporter_access_limited_to(Project.select(:id))
+
+      expect(projects).to eq([project1])
+    end
+
+    it 'does not return projects you do not have reporter access to' do
+      projects = user.projects_with_reporter_access_limited_to(project2.id)
+
+      expect(projects).to be_empty
+    end
+  end
 end
-- 
2.30.9