diff --git a/app/models/issue.rb b/app/models/issue.rb
index 2baaea3f8..91ea73a6f 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -120,10 +120,10 @@ class Issue < ActiveRecord::Base
# Returns a SQL conditions string used to find all issues visible by the specified user
def self.visible_condition(user, options={})
Project.allowed_to_condition(user, :view_issues, options) do |role, user|
- if user.id && user.logged?
+ sql = if user.id && user.logged?
case role.issues_visibility
when 'all'
- nil
+ '1=1'
when 'default'
user_ids = [user.id] + user.groups.map(&:id).compact
"(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
@@ -136,13 +136,22 @@ class Issue < ActiveRecord::Base
else
"(#{table_name}.is_private = #{connection.quoted_false})"
end
+ unless role.permissions_all_trackers?(:view_issues)
+ tracker_ids = role.permissions_tracker_ids(:view_issues)
+ if tracker_ids.any?
+ sql = "(#{sql} AND #{table_name}.tracker_id IN (#{tracker_ids.join(',')}))"
+ else
+ sql = '1=0'
+ end
+ end
+ sql
end
end
# Returns true if usr or current user is allowed to view the issue
def visible?(usr=nil)
(usr || User.current).allowed_to?(:view_issues, self.project) do |role, user|
- if user.logged?
+ visible = if user.logged?
case role.issues_visibility
when 'all'
true
@@ -156,6 +165,10 @@ class Issue < ActiveRecord::Base
else
!self.is_private?
end
+ unless role.permissions_all_trackers?(:view_issues)
+ visible &&= role.permissions_tracker_ids?(:view_issues, tracker_id)
+ end
+ visible
end
end
diff --git a/app/views/roles/_form.html.erb b/app/views/roles/_form.html.erb
index 524c273d0..c8a3a61cc 100644
--- a/app/views/roles/_form.html.erb
+++ b/app/views/roles/_form.html.erb
@@ -64,7 +64,7 @@
<%= l(:label_issue_tracking) %>
-<% permissions = %w(add_issues) %>
+<% permissions = %w(view_issues add_issues) %>
diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb
index f7f7003d2..3b7391a3c 100644
--- a/test/unit/issue_test.rb
+++ b/test/unit/issue_test.rb
@@ -342,6 +342,69 @@ class IssueTest < ActiveSupport::TestCase
assert_include issue, issues
end
+ def test_visible_scope_for_member_with_limited_tracker_ids
+ role = Role.find(1)
+ role.set_permission_trackers :view_issues, [2]
+ role.save!
+ user = User.find(2)
+
+ issues = Issue.where(:project_id => 1).visible(user).to_a
+ assert issues.any?
+ assert_equal [2], issues.map(&:tracker_id).uniq
+
+ assert Issue.where(:project_id => 1).all? {|issue| issue.visible?(user) ^ issue.tracker_id != 2}
+ end
+
+ def test_visible_scope_should_consider_tracker_ids_on_each_project
+ user = User.generate!
+
+ project1 = Project.generate!
+ role1 = Role.generate!
+ role1.add_permission! :view_issues
+ role1.set_permission_trackers :view_issues, :all
+ role1.save!
+ User.add_to_project(user, project1, role1)
+
+ project2 = Project.generate!
+ role2 = Role.generate!
+ role2.add_permission! :view_issues
+ role2.set_permission_trackers :view_issues, [2]
+ role2.save!
+ User.add_to_project(user, project2, role2)
+
+ visible_issues = [
+ Issue.generate!(:project => project1, :tracker_id => 1),
+ Issue.generate!(:project => project1, :tracker_id => 2),
+ Issue.generate!(:project => project2, :tracker_id => 2)
+ ]
+ hidden_issue = Issue.generate!(:project => project2, :tracker_id => 1)
+
+ issues = Issue.where(:project_id => [project1.id, project2.id]).visible(user)
+ assert_equal visible_issues.map(&:id), issues.ids.sort
+
+ assert visible_issues.all? {|issue| issue.visible?(user)}
+ assert !hidden_issue.visible?(user)
+ end
+
+ def test_visible_scope_should_not_consider_roles_without_view_issues_permission
+ user = User.generate!
+ role1 = Role.generate!
+ role1.remove_permission! :view_issues
+ role1.set_permission_trackers :view_issues, :all
+ role1.save!
+ role2 = Role.generate!
+ role2.add_permission! :view_issues
+ role2.set_permission_trackers :view_issues, [2]
+ role2.save!
+ User.add_to_project(user, Project.find(1), [role1, role2])
+
+ issues = Issue.where(:project_id => 1).visible(user).to_a
+ assert issues.any?
+ assert_equal [2], issues.map(&:tracker_id).uniq
+
+ assert Issue.where(:project_id => 1).all? {|issue| issue.visible?(user) ^ issue.tracker_id != 2}
+ end
+
def test_visible_scope_for_admin
user = User.find(1)
user.members.each(&:destroy)