Skip to content

Commit 79df68e

Browse files
committed
Limit trackers for new issue to certain roles (#7839).
git-svn-id: http://svn.redmine.org/redmine/trunk@15464 e93f8b46-1217-0410-a6f0-8f06a7374b81
1 parent 939a713 commit 79df68e

File tree

11 files changed

+272
-8
lines changed

11 files changed

+272
-8
lines changed

app/controllers/issues_controller.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,13 @@ def build_new_issue_from_params
467467
if @issue.project
468468
@issue.tracker ||= @issue.allowed_target_trackers.first
469469
if @issue.tracker.nil?
470-
render_error l(:error_no_tracker_in_project)
470+
if @issue.project.trackers.any?
471+
# None of the project trackers is allowed to the user
472+
render_error :message => l(:error_no_tracker_allowed_for_new_issue_in_project), :status => 403
473+
else
474+
# Project has no trackers
475+
render_error l(:error_no_tracker_in_project)
476+
end
471477
return false
472478
end
473479
if @issue.status.nil?

app/models/issue.rb

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,16 +1368,27 @@ def self.allowed_target_projects(user=User.current, current_project=nil)
13681368

13691369
# Returns a scope of trackers that user can assign the issue to
13701370
def allowed_target_trackers(user=User.current)
1371-
if project
1372-
self.class.allowed_target_trackers(project, user, tracker_id_was)
1373-
else
1374-
Tracker.none
1375-
end
1371+
self.class.allowed_target_trackers(project, user, tracker_id_was)
13761372
end
13771373

13781374
# Returns a scope of trackers that user can assign project issues to
13791375
def self.allowed_target_trackers(project, user=User.current, current_tracker=nil)
1380-
project.trackers.sorted
1376+
if project
1377+
scope = project.trackers.sorted
1378+
unless user.admin?
1379+
roles = user.roles_for_project(project).select {|r| r.has_permission?(:add_issues)}
1380+
unless roles.any? {|r| r.permissions_all_trackers?(:add_issues)}
1381+
tracker_ids = roles.map {|r| r.permissions_tracker_ids(:add_issues)}.flatten.uniq
1382+
if current_tracker
1383+
tracker_ids << current_tracker
1384+
end
1385+
scope = scope.where(:id => tracker_ids)
1386+
end
1387+
end
1388+
scope
1389+
else
1390+
Tracker.none
1391+
end
13811392
end
13821393

13831394
private

app/models/issue_import.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def project
3737
# Returns a scope of trackers that user is allowed to
3838
# import issue to
3939
def allowed_target_trackers
40-
project.trackers
40+
Issue.allowed_target_trackers(project, user)
4141
end
4242

4343
def tracker

app/models/role.rb

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def copy(source_role)
7373
acts_as_positioned :scope => :builtin
7474

7575
serialize :permissions, ::Role::PermissionsAttributeCoder
76+
store :settings, :accessors => [:permissions_all_trackers, :permissions_tracker_ids]
7677
attr_protected :builtin
7778

7879
validates_presence_of :name
@@ -188,6 +189,56 @@ def setable_permissions
188189
setable_permissions
189190
end
190191

192+
def permissions_tracker_ids(*args)
193+
if args.any?
194+
Array(permissions_tracker_ids[args.first.to_s]).map(&:to_i)
195+
else
196+
super || {}
197+
end
198+
end
199+
200+
def permissions_tracker_ids=(arg)
201+
h = arg.to_hash
202+
h.values.each {|v| v.reject!(&:blank?)}
203+
super(h)
204+
end
205+
206+
# Returns true if tracker_id belongs to the list of
207+
# trackers for which permission is given
208+
def permissions_tracker_ids?(permission, tracker_id)
209+
permissions_tracker_ids(permission).include?(tracker_id)
210+
end
211+
212+
def permissions_all_trackers
213+
super || {}
214+
end
215+
216+
def permissions_all_trackers=(arg)
217+
super(arg.to_hash)
218+
end
219+
220+
# Returns true if permission is given for all trackers
221+
def permissions_all_trackers?(permission)
222+
permissions_all_trackers[permission.to_s].to_s != '0'
223+
end
224+
225+
# Sets the trackers that are allowed for a permission.
226+
# tracker_ids can be an array of tracker ids or :all for
227+
# no restrictions.
228+
#
229+
# Examples:
230+
# role.set_permission_trackers :add_issues, [1, 3]
231+
# role.set_permission_trackers :add_issues, :all
232+
def set_permission_trackers(permission, tracker_ids)
233+
h = {permission.to_s => (tracker_ids == :all ? '1' : '0')}
234+
self.permissions_all_trackers = permissions_all_trackers.merge(h)
235+
236+
h = {permission.to_s => (tracker_ids == :all ? [] : tracker_ids)}
237+
self.permissions_tracker_ids = permissions_tracker_ids.merge(h)
238+
239+
self
240+
end
241+
191242
# Find all the roles that can be given to a project member
192243
def self.find_all_givable
193244
Role.givable.to_a

app/views/roles/_form.html.erb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,50 @@
6262
<%= hidden_field_tag 'role[permissions][]', '' %>
6363
</div>
6464

65+
<div id="role-permissions-trackers">
66+
<h3><%= l(:label_issue_tracking) %></h3>
67+
<% permissions = %w(add_issues) %>
68+
<table class="list">
69+
<thead>
70+
<tr>
71+
<th><%= l(:label_tracker) %></th>
72+
<% permissions.each do |permission| %>
73+
<th><%= l("permission_#{permission}") %></th>
74+
<% end %>
75+
</thead>
76+
<tbody>
77+
<tr>
78+
<td class="name"><b><%= l(:label_tracker_all) %></b></td>
79+
<% permissions.each do |permission| %>
80+
<td>
81+
<%= hidden_field_tag "role[permissions_all_trackers][#{permission}]", '0', :id => nil %>
82+
<%= check_box_tag "role[permissions_all_trackers][#{permission}]",
83+
'1',
84+
@role.permissions_all_trackers?(permission),
85+
:data => {:disables => ".#{permission}_tracker"} %>
86+
</td>
87+
<% end %>
88+
</tr>
89+
<% Tracker.sorted.all.each do |tracker| %>
90+
<tr>
91+
<td class="name"><%= tracker.name %></td>
92+
<% permissions.each do |permission| %>
93+
<td><%= check_box_tag "role[permissions_tracker_ids][#{permission}][]",
94+
tracker.id,
95+
@role.permissions_tracker_ids?(permission, tracker.id),
96+
:class => "#{permission}_tracker",
97+
:id => "role_permissions_tracker_ids_add_issues_#{tracker.id}" %></td>
98+
<% end %>
99+
</tr>
100+
<% end %>
101+
</tbody>
102+
</table>
103+
104+
<% permissions.each do |permission| %>
105+
<%= hidden_field_tag "role[permissions_tracker_ids][#{permission}][]", '' %>
106+
<% end %>
107+
</div>
108+
65109
<%= javascript_tag do %>
66110
$(document).ready(function(){
67111
$("#role_permissions_manage_members").change(function(){

config/locales/en.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ en:
213213
error_can_not_read_import_file: "An error occurred while reading the file to import"
214214
error_attachment_extension_not_allowed: "Attachment extension %{extension} is not allowed"
215215
error_ldap_bind_credentials: "Invalid LDAP Account/Password"
216+
error_no_tracker_allowed_for_new_issue_in_project: "The project doesn't have any trackers for which you can create an issue"
216217

217218
mail_subject_lost_password: "Your %{value} password"
218219
mail_body_lost_password: 'To change your password, click on the following link:'
@@ -561,6 +562,7 @@ en:
561562
label_member_plural: Members
562563
label_tracker: Tracker
563564
label_tracker_plural: Trackers
565+
label_tracker_all: All trackers
564566
label_tracker_new: New tracker
565567
label_workflow: Workflow
566568
label_issue_status: Issue status

config/locales/fr.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ fr:
233233
error_can_not_read_import_file: "Une erreur est survenue lors de la lecture du fichier à importer"
234234
error_attachment_extension_not_allowed: "L'extension %{extension} n'est pas autorisée"
235235
error_ldap_bind_credentials: "Identifiant ou mot de passe LDAP incorrect"
236+
error_no_tracker_allowed_for_new_issue_in_project: "Le projet ne dispose d'aucun tracker sur lequel vous pouvez créer une demande"
236237

237238
mail_subject_lost_password: "Votre mot de passe %{value}"
238239
mail_body_lost_password: 'Pour changer votre mot de passe, cliquez sur le lien suivant :'
@@ -573,6 +574,7 @@ fr:
573574
label_member_plural: Membres
574575
label_tracker: Tracker
575576
label_tracker_plural: Trackers
577+
label_tracker_all: Tous les trackers
576578
label_tracker_new: Nouveau tracker
577579
label_workflow: Workflow
578580
label_issue_status: Statut de demandes
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class AddRolesSettings < ActiveRecord::Migration
2+
def change
3+
add_column :roles, :settings, :text
4+
end
5+
end

test/functional/issues_controller_test.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1864,6 +1864,31 @@ def test_new_should_propose_allowed_statuses_without_default_status_allowed
18641864
end
18651865
end
18661866

1867+
def test_new_should_propose_allowed_trackers
1868+
role = Role.find(1)
1869+
role.set_permission_trackers 'add_issues', [1, 3]
1870+
role.save!
1871+
@request.session[:user_id] = 2
1872+
1873+
get :new, :project_id => 1
1874+
assert_response :success
1875+
assert_select 'select[name=?]', 'issue[tracker_id]' do
1876+
assert_select 'option', 2
1877+
assert_select 'option[value="1"]'
1878+
assert_select 'option[value="3"]'
1879+
end
1880+
end
1881+
1882+
def test_new_without_allowed_trackers_should_respond_with_403
1883+
role = Role.find(1)
1884+
role.set_permission_trackers 'add_issues', []
1885+
role.save!
1886+
@request.session[:user_id] = 2
1887+
1888+
get :new, :project_id => 1
1889+
assert_response 403
1890+
end
1891+
18671892
def test_new_should_preselect_default_version
18681893
version = Version.generate!(:project_id => 1)
18691894
Project.find(1).update_attribute :default_version_id, version.id
@@ -2432,6 +2457,23 @@ def test_create_should_ignore_readonly_fields
24322457
assert_nil issue.custom_field_value(cf2)
24332458
end
24342459

2460+
def test_create_should_ignore_unallowed_trackers
2461+
role = Role.find(1)
2462+
role.set_permission_trackers :add_issues, [3]
2463+
role.save!
2464+
@request.session[:user_id] = 2
2465+
2466+
issue = new_record(Issue) do
2467+
post :create, :project_id => 1, :issue => {
2468+
:tracker_id => 1,
2469+
:status_id => 1,
2470+
:subject => 'Test'
2471+
}
2472+
assert_response 302
2473+
end
2474+
assert_equal 3, issue.tracker_id
2475+
end
2476+
24352477
def test_post_create_with_watchers
24362478
@request.session[:user_id] = 2
24372479
ActionMailer::Base.deliveries.clear

test/functional/roles_controller_test.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,22 @@ def test_update
132132
assert_equal [:edit_project], role.permissions
133133
end
134134

135+
def test_update_trackers_permissions
136+
put :update, :id => 1, :role => {
137+
:permissions_all_trackers => {'add_issues' => '0'},
138+
:permissions_tracker_ids => {'add_issues' => ['1', '3', '']}
139+
}
140+
141+
assert_redirected_to '/roles'
142+
role = Role.find(1)
143+
144+
assert_equal({'add_issues' => '0'}, role.permissions_all_trackers)
145+
assert_equal({'add_issues' => ['1', '3']}, role.permissions_tracker_ids)
146+
147+
assert_equal false, role.permissions_all_trackers?(:add_issues)
148+
assert_equal [1, 3], role.permissions_tracker_ids(:add_issues).sort
149+
end
150+
135151
def test_update_with_failure
136152
put :update, :id => 1, :role => {:name => ''}
137153
assert_response :success

test/unit/issue_test.rb

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,6 +1438,91 @@ def test_allowed_target_projects_should_not_include_projects_without_trackers
14381438
assert_not_include project, Issue.allowed_target_projects(User.find(1))
14391439
end
14401440

1441+
def test_allowed_target_trackers_with_one_role_allowed_on_all_trackers
1442+
user = User.generate!
1443+
role = Role.generate!
1444+
role.add_permission! :add_issues
1445+
role.set_permission_trackers :add_issues, :all
1446+
role.save!
1447+
User.add_to_project(user, Project.find(1), role)
1448+
1449+
assert_equal [1, 2, 3], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort
1450+
end
1451+
1452+
def test_allowed_target_trackers_with_one_role_allowed_on_some_trackers
1453+
user = User.generate!
1454+
role = Role.generate!
1455+
role.add_permission! :add_issues
1456+
role.set_permission_trackers :add_issues, [1, 3]
1457+
role.save!
1458+
User.add_to_project(user, Project.find(1), role)
1459+
1460+
assert_equal [1, 3], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort
1461+
end
1462+
1463+
def test_allowed_target_trackers_with_two_roles_allowed_on_some_trackers
1464+
user = User.generate!
1465+
role1 = Role.generate!
1466+
role1.add_permission! :add_issues
1467+
role1.set_permission_trackers :add_issues, [1]
1468+
role1.save!
1469+
role2 = Role.generate!
1470+
role2.add_permission! :add_issues
1471+
role2.set_permission_trackers :add_issues, [3]
1472+
role2.save!
1473+
User.add_to_project(user, Project.find(1), [role1, role2])
1474+
1475+
assert_equal [1, 3], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort
1476+
end
1477+
1478+
def test_allowed_target_trackers_with_two_roles_allowed_on_all_trackers_and_some_trackers
1479+
user = User.generate!
1480+
role1 = Role.generate!
1481+
role1.add_permission! :add_issues
1482+
role1.set_permission_trackers :add_issues, :all
1483+
role1.save!
1484+
role2 = Role.generate!
1485+
role2.add_permission! :add_issues
1486+
role2.set_permission_trackers :add_issues, [1, 3]
1487+
role2.save!
1488+
User.add_to_project(user, Project.find(1), [role1, role2])
1489+
1490+
assert_equal [1, 2, 3], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort
1491+
end
1492+
1493+
def test_allowed_target_trackers_should_not_consider_roles_without_add_issues_permission
1494+
user = User.generate!
1495+
role1 = Role.generate!
1496+
role1.remove_permission! :add_issues
1497+
role1.set_permission_trackers :add_issues, :all
1498+
role1.save!
1499+
role2 = Role.generate!
1500+
role2.add_permission! :add_issues
1501+
role2.set_permission_trackers :add_issues, [1, 3]
1502+
role2.save!
1503+
User.add_to_project(user, Project.find(1), [role1, role2])
1504+
1505+
assert_equal [1, 3], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort
1506+
end
1507+
1508+
def test_allowed_target_trackers_without_project_should_be_empty
1509+
issue = Issue.new
1510+
assert_nil issue.project
1511+
assert_equal [], issue.allowed_target_trackers(User.find(2)).ids
1512+
end
1513+
1514+
def test_allowed_target_trackers_should_include_current_tracker
1515+
user = User.generate!
1516+
role = Role.generate!
1517+
role.add_permission! :add_issues
1518+
role.set_permission_trackers :add_issues, [3]
1519+
role.save!
1520+
User.add_to_project(user, Project.find(1), role)
1521+
1522+
issue = Issue.generate!(:project => Project.find(1), :tracker => Tracker.find(1))
1523+
assert_equal [1, 3], issue.allowed_target_trackers(user).ids.sort
1524+
end
1525+
14411526
def test_move_to_another_project_with_same_category
14421527
issue = Issue.find(1)
14431528
issue.project = Project.find(2)

0 commit comments

Comments
 (0)