summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2016-06-05 10:06:17 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2016-06-05 10:06:17 +0000
commit79df68e17fc09a4d8bc87cad8efb4bc31c085dcd (patch)
tree33b0e4d2bfa3e26b6d2fa28a35d91a2b659242c7
parent939a7137ef985647d34fdacadf419b313bcd9110 (diff)
downloadredmine-79df68e17fc09a4d8bc87cad8efb4bc31c085dcd.tar.gz
redmine-79df68e17fc09a4d8bc87cad8efb4bc31c085dcd.zip
Limit trackers for new issue to certain roles (#7839).
git-svn-id: http://svn.redmine.org/redmine/trunk@15464 e93f8b46-1217-0410-a6f0-8f06a7374b81
-rw-r--r--app/controllers/issues_controller.rb8
-rw-r--r--app/models/issue.rb23
-rw-r--r--app/models/issue_import.rb2
-rw-r--r--app/models/role.rb51
-rw-r--r--app/views/roles/_form.html.erb44
-rw-r--r--config/locales/en.yml2
-rw-r--r--config/locales/fr.yml2
-rw-r--r--db/migrate/20160529063352_add_roles_settings.rb5
-rw-r--r--test/functional/issues_controller_test.rb42
-rw-r--r--test/functional/roles_controller_test.rb16
-rw-r--r--test/unit/issue_test.rb85
11 files changed, 272 insertions, 8 deletions
diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb
index 1db5e6ff8..37825c995 100644
--- a/app/controllers/issues_controller.rb
+++ b/app/controllers/issues_controller.rb
@@ -467,7 +467,13 @@ class IssuesController < ApplicationController
if @issue.project
@issue.tracker ||= @issue.allowed_target_trackers.first
if @issue.tracker.nil?
- render_error l(:error_no_tracker_in_project)
+ if @issue.project.trackers.any?
+ # None of the project trackers is allowed to the user
+ render_error :message => l(:error_no_tracker_allowed_for_new_issue_in_project), :status => 403
+ else
+ # Project has no trackers
+ render_error l(:error_no_tracker_in_project)
+ end
return false
end
if @issue.status.nil?
diff --git a/app/models/issue.rb b/app/models/issue.rb
index d6133d3a9..2baaea3f8 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -1368,16 +1368,27 @@ class Issue < ActiveRecord::Base
# Returns a scope of trackers that user can assign the issue to
def allowed_target_trackers(user=User.current)
- if project
- self.class.allowed_target_trackers(project, user, tracker_id_was)
- else
- Tracker.none
- end
+ self.class.allowed_target_trackers(project, user, tracker_id_was)
end
# Returns a scope of trackers that user can assign project issues to
def self.allowed_target_trackers(project, user=User.current, current_tracker=nil)
- project.trackers.sorted
+ if project
+ scope = project.trackers.sorted
+ unless user.admin?
+ roles = user.roles_for_project(project).select {|r| r.has_permission?(:add_issues)}
+ unless roles.any? {|r| r.permissions_all_trackers?(:add_issues)}
+ tracker_ids = roles.map {|r| r.permissions_tracker_ids(:add_issues)}.flatten.uniq
+ if current_tracker
+ tracker_ids << current_tracker
+ end
+ scope = scope.where(:id => tracker_ids)
+ end
+ end
+ scope
+ else
+ Tracker.none
+ end
end
private
diff --git a/app/models/issue_import.rb b/app/models/issue_import.rb
index b6b20a1b1..5b19ac966 100644
--- a/app/models/issue_import.rb
+++ b/app/models/issue_import.rb
@@ -37,7 +37,7 @@ class IssueImport < Import
# Returns a scope of trackers that user is allowed to
# import issue to
def allowed_target_trackers
- project.trackers
+ Issue.allowed_target_trackers(project, user)
end
def tracker
diff --git a/app/models/role.rb b/app/models/role.rb
index defbc311d..89538aa4d 100644
--- a/app/models/role.rb
+++ b/app/models/role.rb
@@ -73,6 +73,7 @@ class Role < ActiveRecord::Base
acts_as_positioned :scope => :builtin
serialize :permissions, ::Role::PermissionsAttributeCoder
+ store :settings, :accessors => [:permissions_all_trackers, :permissions_tracker_ids]
attr_protected :builtin
validates_presence_of :name
@@ -188,6 +189,56 @@ class Role < ActiveRecord::Base
setable_permissions
end
+ def permissions_tracker_ids(*args)
+ if args.any?
+ Array(permissions_tracker_ids[args.first.to_s]).map(&:to_i)
+ else
+ super || {}
+ end
+ end
+
+ def permissions_tracker_ids=(arg)
+ h = arg.to_hash
+ h.values.each {|v| v.reject!(&:blank?)}
+ super(h)
+ end
+
+ # Returns true if tracker_id belongs to the list of
+ # trackers for which permission is given
+ def permissions_tracker_ids?(permission, tracker_id)
+ permissions_tracker_ids(permission).include?(tracker_id)
+ end
+
+ def permissions_all_trackers
+ super || {}
+ end
+
+ def permissions_all_trackers=(arg)
+ super(arg.to_hash)
+ end
+
+ # Returns true if permission is given for all trackers
+ def permissions_all_trackers?(permission)
+ permissions_all_trackers[permission.to_s].to_s != '0'
+ end
+
+ # Sets the trackers that are allowed for a permission.
+ # tracker_ids can be an array of tracker ids or :all for
+ # no restrictions.
+ #
+ # Examples:
+ # role.set_permission_trackers :add_issues, [1, 3]
+ # role.set_permission_trackers :add_issues, :all
+ def set_permission_trackers(permission, tracker_ids)
+ h = {permission.to_s => (tracker_ids == :all ? '1' : '0')}
+ self.permissions_all_trackers = permissions_all_trackers.merge(h)
+
+ h = {permission.to_s => (tracker_ids == :all ? [] : tracker_ids)}
+ self.permissions_tracker_ids = permissions_tracker_ids.merge(h)
+
+ self
+ end
+
# Find all the roles that can be given to a project member
def self.find_all_givable
Role.givable.to_a
diff --git a/app/views/roles/_form.html.erb b/app/views/roles/_form.html.erb
index 84d5de185..524c273d0 100644
--- a/app/views/roles/_form.html.erb
+++ b/app/views/roles/_form.html.erb
@@ -62,6 +62,50 @@
<%= hidden_field_tag 'role[permissions][]', '' %>
</div>
+<div id="role-permissions-trackers">
+<h3><%= l(:label_issue_tracking) %></h3>
+<% permissions = %w(add_issues) %>
+<table class="list">
+ <thead>
+ <tr>
+ <th><%= l(:label_tracker) %></th>
+ <% permissions.each do |permission| %>
+ <th><%= l("permission_#{permission}") %></th>
+ <% end %>
+ </thead>
+ <tbody>
+ <tr>
+ <td class="name"><b><%= l(:label_tracker_all) %></b></td>
+ <% permissions.each do |permission| %>
+ <td>
+ <%= hidden_field_tag "role[permissions_all_trackers][#{permission}]", '0', :id => nil %>
+ <%= check_box_tag "role[permissions_all_trackers][#{permission}]",
+ '1',
+ @role.permissions_all_trackers?(permission),
+ :data => {:disables => ".#{permission}_tracker"} %>
+ </td>
+ <% end %>
+ </tr>
+ <% Tracker.sorted.all.each do |tracker| %>
+ <tr>
+ <td class="name"><%= tracker.name %></td>
+ <% permissions.each do |permission| %>
+ <td><%= check_box_tag "role[permissions_tracker_ids][#{permission}][]",
+ tracker.id,
+ @role.permissions_tracker_ids?(permission, tracker.id),
+ :class => "#{permission}_tracker",
+ :id => "role_permissions_tracker_ids_add_issues_#{tracker.id}" %></td>
+ <% end %>
+ </tr>
+ <% end %>
+ </tbody>
+</table>
+
+<% permissions.each do |permission| %>
+ <%= hidden_field_tag "role[permissions_tracker_ids][#{permission}][]", '' %>
+<% end %>
+</div>
+
<%= javascript_tag do %>
$(document).ready(function(){
$("#role_permissions_manage_members").change(function(){
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 9dd03560c..522cb5227 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -213,6 +213,7 @@ en:
error_can_not_read_import_file: "An error occurred while reading the file to import"
error_attachment_extension_not_allowed: "Attachment extension %{extension} is not allowed"
error_ldap_bind_credentials: "Invalid LDAP Account/Password"
+ error_no_tracker_allowed_for_new_issue_in_project: "The project doesn't have any trackers for which you can create an issue"
mail_subject_lost_password: "Your %{value} password"
mail_body_lost_password: 'To change your password, click on the following link:'
@@ -561,6 +562,7 @@ en:
label_member_plural: Members
label_tracker: Tracker
label_tracker_plural: Trackers
+ label_tracker_all: All trackers
label_tracker_new: New tracker
label_workflow: Workflow
label_issue_status: Issue status
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 6a72024f6..760c84c95 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -233,6 +233,7 @@ fr:
error_can_not_read_import_file: "Une erreur est survenue lors de la lecture du fichier à importer"
error_attachment_extension_not_allowed: "L'extension %{extension} n'est pas autorisée"
error_ldap_bind_credentials: "Identifiant ou mot de passe LDAP incorrect"
+ error_no_tracker_allowed_for_new_issue_in_project: "Le projet ne dispose d'aucun tracker sur lequel vous pouvez créer une demande"
mail_subject_lost_password: "Votre mot de passe %{value}"
mail_body_lost_password: 'Pour changer votre mot de passe, cliquez sur le lien suivant :'
@@ -573,6 +574,7 @@ fr:
label_member_plural: Membres
label_tracker: Tracker
label_tracker_plural: Trackers
+ label_tracker_all: Tous les trackers
label_tracker_new: Nouveau tracker
label_workflow: Workflow
label_issue_status: Statut de demandes
diff --git a/db/migrate/20160529063352_add_roles_settings.rb b/db/migrate/20160529063352_add_roles_settings.rb
new file mode 100644
index 000000000..921187ec1
--- /dev/null
+++ b/db/migrate/20160529063352_add_roles_settings.rb
@@ -0,0 +1,5 @@
+class AddRolesSettings < ActiveRecord::Migration
+ def change
+ add_column :roles, :settings, :text
+ end
+end \ No newline at end of file
diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb
index 32f9d8f11..8888cf712 100644
--- a/test/functional/issues_controller_test.rb
+++ b/test/functional/issues_controller_test.rb
@@ -1864,6 +1864,31 @@ class IssuesControllerTest < ActionController::TestCase
end
end
+ def test_new_should_propose_allowed_trackers
+ role = Role.find(1)
+ role.set_permission_trackers 'add_issues', [1, 3]
+ role.save!
+ @request.session[:user_id] = 2
+
+ get :new, :project_id => 1
+ assert_response :success
+ assert_select 'select[name=?]', 'issue[tracker_id]' do
+ assert_select 'option', 2
+ assert_select 'option[value="1"]'
+ assert_select 'option[value="3"]'
+ end
+ end
+
+ def test_new_without_allowed_trackers_should_respond_with_403
+ role = Role.find(1)
+ role.set_permission_trackers 'add_issues', []
+ role.save!
+ @request.session[:user_id] = 2
+
+ get :new, :project_id => 1
+ assert_response 403
+ end
+
def test_new_should_preselect_default_version
version = Version.generate!(:project_id => 1)
Project.find(1).update_attribute :default_version_id, version.id
@@ -2432,6 +2457,23 @@ class IssuesControllerTest < ActionController::TestCase
assert_nil issue.custom_field_value(cf2)
end
+ def test_create_should_ignore_unallowed_trackers
+ role = Role.find(1)
+ role.set_permission_trackers :add_issues, [3]
+ role.save!
+ @request.session[:user_id] = 2
+
+ issue = new_record(Issue) do
+ post :create, :project_id => 1, :issue => {
+ :tracker_id => 1,
+ :status_id => 1,
+ :subject => 'Test'
+ }
+ assert_response 302
+ end
+ assert_equal 3, issue.tracker_id
+ end
+
def test_post_create_with_watchers
@request.session[:user_id] = 2
ActionMailer::Base.deliveries.clear
diff --git a/test/functional/roles_controller_test.rb b/test/functional/roles_controller_test.rb
index 8ce469395..915b658c9 100644
--- a/test/functional/roles_controller_test.rb
+++ b/test/functional/roles_controller_test.rb
@@ -132,6 +132,22 @@ class RolesControllerTest < ActionController::TestCase
assert_equal [:edit_project], role.permissions
end
+ def test_update_trackers_permissions
+ put :update, :id => 1, :role => {
+ :permissions_all_trackers => {'add_issues' => '0'},
+ :permissions_tracker_ids => {'add_issues' => ['1', '3', '']}
+ }
+
+ assert_redirected_to '/roles'
+ role = Role.find(1)
+
+ assert_equal({'add_issues' => '0'}, role.permissions_all_trackers)
+ assert_equal({'add_issues' => ['1', '3']}, role.permissions_tracker_ids)
+
+ assert_equal false, role.permissions_all_trackers?(:add_issues)
+ assert_equal [1, 3], role.permissions_tracker_ids(:add_issues).sort
+ end
+
def test_update_with_failure
put :update, :id => 1, :role => {:name => ''}
assert_response :success
diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb
index 363cdd071..f7f7003d2 100644
--- a/test/unit/issue_test.rb
+++ b/test/unit/issue_test.rb
@@ -1438,6 +1438,91 @@ class IssueTest < ActiveSupport::TestCase
assert_not_include project, Issue.allowed_target_projects(User.find(1))
end
+ def test_allowed_target_trackers_with_one_role_allowed_on_all_trackers
+ user = User.generate!
+ role = Role.generate!
+ role.add_permission! :add_issues
+ role.set_permission_trackers :add_issues, :all
+ role.save!
+ User.add_to_project(user, Project.find(1), role)
+
+ assert_equal [1, 2, 3], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort
+ end
+
+ def test_allowed_target_trackers_with_one_role_allowed_on_some_trackers
+ user = User.generate!
+ role = Role.generate!
+ role.add_permission! :add_issues
+ role.set_permission_trackers :add_issues, [1, 3]
+ role.save!
+ User.add_to_project(user, Project.find(1), role)
+
+ assert_equal [1, 3], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort
+ end
+
+ def test_allowed_target_trackers_with_two_roles_allowed_on_some_trackers
+ user = User.generate!
+ role1 = Role.generate!
+ role1.add_permission! :add_issues
+ role1.set_permission_trackers :add_issues, [1]
+ role1.save!
+ role2 = Role.generate!
+ role2.add_permission! :add_issues
+ role2.set_permission_trackers :add_issues, [3]
+ role2.save!
+ User.add_to_project(user, Project.find(1), [role1, role2])
+
+ assert_equal [1, 3], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort
+ end
+
+ def test_allowed_target_trackers_with_two_roles_allowed_on_all_trackers_and_some_trackers
+ user = User.generate!
+ role1 = Role.generate!
+ role1.add_permission! :add_issues
+ role1.set_permission_trackers :add_issues, :all
+ role1.save!
+ role2 = Role.generate!
+ role2.add_permission! :add_issues
+ role2.set_permission_trackers :add_issues, [1, 3]
+ role2.save!
+ User.add_to_project(user, Project.find(1), [role1, role2])
+
+ assert_equal [1, 2, 3], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort
+ end
+
+ def test_allowed_target_trackers_should_not_consider_roles_without_add_issues_permission
+ user = User.generate!
+ role1 = Role.generate!
+ role1.remove_permission! :add_issues
+ role1.set_permission_trackers :add_issues, :all
+ role1.save!
+ role2 = Role.generate!
+ role2.add_permission! :add_issues
+ role2.set_permission_trackers :add_issues, [1, 3]
+ role2.save!
+ User.add_to_project(user, Project.find(1), [role1, role2])
+
+ assert_equal [1, 3], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort
+ end
+
+ def test_allowed_target_trackers_without_project_should_be_empty
+ issue = Issue.new
+ assert_nil issue.project
+ assert_equal [], issue.allowed_target_trackers(User.find(2)).ids
+ end
+
+ def test_allowed_target_trackers_should_include_current_tracker
+ user = User.generate!
+ role = Role.generate!
+ role.add_permission! :add_issues
+ role.set_permission_trackers :add_issues, [3]
+ role.save!
+ User.add_to_project(user, Project.find(1), role)
+
+ issue = Issue.generate!(:project => Project.find(1), :tracker => Tracker.find(1))
+ assert_equal [1, 3], issue.allowed_target_trackers(user).ids.sort
+ end
+
def test_move_to_another_project_with_same_category
issue = Issue.find(1)
issue.project = Project.find(2)