summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorYorick Peterse <yorickpeterse@gmail.com>2016-10-12 14:01:34 +0200
committerYorick Peterse <yorickpeterse@gmail.com>2016-11-07 12:49:24 +0100
commitf694f94c491452a50035c2ff43c8ba595c0e73aa (patch)
tree125d88eff69df031b590f589ae107f609e2f95db /app
parent89bb29b247b57e3b4ba053a5fd17f2087ac4414f (diff)
downloadgitlab-ce-f694f94c491452a50035c2ff43c8ba595c0e73aa.tar.gz
Added IssueCollection
This class can be used to reduce a list of issues down to a subset based on user permissions. This class operates in such a way that it can reduce issues using as few queries as possible, if any at all.
Diffstat (limited to 'app')
-rw-r--r--app/models/concerns/issuable.rb5
-rw-r--r--app/models/issue_collection.rb40
-rw-r--r--app/policies/issuable_policy.rb2
-rw-r--r--app/policies/issue_policy.rb9
4 files changed, 48 insertions, 8 deletions
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 613444e0d70..93a6b3122e0 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -286,6 +286,11 @@ module Issuable
false
end
+ def assignee_or_author?(user)
+ # We're comparing IDs here so we don't need to load any associations.
+ author_id == user.id || assignee_id == user.id
+ end
+
def record_metrics
metrics = self.metrics || create_metrics
metrics.record!
diff --git a/app/models/issue_collection.rb b/app/models/issue_collection.rb
new file mode 100644
index 00000000000..df36252a5b1
--- /dev/null
+++ b/app/models/issue_collection.rb
@@ -0,0 +1,40 @@
+# IssueCollection can be used to reduce a list of issues down to a subset.
+#
+# IssueCollection is not meant to be some sort of Enumerable, instead it's meant
+# to take a list of issues and return a new list of issues based on some
+# criteria. For example, given a list of issues you may want to return a list of
+# issues that can be read or updated by a given user.
+class IssueCollection
+ attr_reader :collection
+
+ def initialize(collection)
+ @collection = collection
+ end
+
+ # Returns all the issues that can be updated by the user.
+ def updatable_by_user(user)
+ return collection if user.admin?
+
+ # Given all the issue projects we get a list of projects that the current
+ # user has at least reporter access to.
+ projects_with_reporter_access = user.
+ projects_with_reporter_access_limited_to(project_ids).
+ pluck(:id)
+
+ collection.select do |issue|
+ if projects_with_reporter_access.include?(issue.project_id)
+ true
+ elsif issue.is_a?(Issue)
+ issue.assignee_or_author?(user)
+ else
+ false
+ end
+ end
+ end
+
+ private
+
+ def project_ids
+ @project_ids ||= collection.map(&:project_id).uniq
+ end
+end
diff --git a/app/policies/issuable_policy.rb b/app/policies/issuable_policy.rb
index c253f9a9399..9501e499507 100644
--- a/app/policies/issuable_policy.rb
+++ b/app/policies/issuable_policy.rb
@@ -4,7 +4,7 @@ class IssuablePolicy < BasePolicy
end
def rules
- if @user && (@subject.author == @user || @subject.assignee == @user)
+ if @user && @subject.assignee_or_author?(@user)
can! :"read_#{action_name}"
can! :"update_#{action_name}"
end
diff --git a/app/policies/issue_policy.rb b/app/policies/issue_policy.rb
index bd1811a3c54..f3ede58a001 100644
--- a/app/policies/issue_policy.rb
+++ b/app/policies/issue_policy.rb
@@ -8,9 +8,8 @@ class IssuePolicy < IssuablePolicy
if @subject.confidential? && !can_read_confidential?
cannot! :read_issue
- cannot! :admin_issue
cannot! :update_issue
- cannot! :read_issue
+ cannot! :admin_issue
end
end
@@ -18,11 +17,7 @@ class IssuePolicy < IssuablePolicy
def can_read_confidential?
return false unless @user
- return true if @user.admin?
- return true if @subject.author == @user
- return true if @subject.assignee == @user
- return true if @subject.project.team.member?(@user, Gitlab::Access::REPORTER)
- false
+ IssueCollection.new([@subject]).updatable_by_user(@user).any?
end
end