mirror of
https://github.com/redmine/redmine.git
synced 2025-11-07 13:55:52 +01:00
Limit trackers for new issue to certain roles (#7839).
git-svn-id: http://svn.redmine.org/redmine/trunk@15464 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
@@ -467,7 +467,13 @@ class IssuesController < ApplicationController
|
|||||||
if @issue.project
|
if @issue.project
|
||||||
@issue.tracker ||= @issue.allowed_target_trackers.first
|
@issue.tracker ||= @issue.allowed_target_trackers.first
|
||||||
if @issue.tracker.nil?
|
if @issue.tracker.nil?
|
||||||
|
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)
|
render_error l(:error_no_tracker_in_project)
|
||||||
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if @issue.status.nil?
|
if @issue.status.nil?
|
||||||
|
|||||||
@@ -1368,16 +1368,27 @@ class Issue < ActiveRecord::Base
|
|||||||
|
|
||||||
# Returns a scope of trackers that user can assign the issue to
|
# Returns a scope of trackers that user can assign the issue to
|
||||||
def allowed_target_trackers(user=User.current)
|
def allowed_target_trackers(user=User.current)
|
||||||
if project
|
|
||||||
self.class.allowed_target_trackers(project, user, tracker_id_was)
|
self.class.allowed_target_trackers(project, user, tracker_id_was)
|
||||||
else
|
|
||||||
Tracker.none
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a scope of trackers that user can assign project issues to
|
# Returns a scope of trackers that user can assign project issues to
|
||||||
def self.allowed_target_trackers(project, user=User.current, current_tracker=nil)
|
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
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class IssueImport < Import
|
|||||||
# Returns a scope of trackers that user is allowed to
|
# Returns a scope of trackers that user is allowed to
|
||||||
# import issue to
|
# import issue to
|
||||||
def allowed_target_trackers
|
def allowed_target_trackers
|
||||||
project.trackers
|
Issue.allowed_target_trackers(project, user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def tracker
|
def tracker
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ class Role < ActiveRecord::Base
|
|||||||
acts_as_positioned :scope => :builtin
|
acts_as_positioned :scope => :builtin
|
||||||
|
|
||||||
serialize :permissions, ::Role::PermissionsAttributeCoder
|
serialize :permissions, ::Role::PermissionsAttributeCoder
|
||||||
|
store :settings, :accessors => [:permissions_all_trackers, :permissions_tracker_ids]
|
||||||
attr_protected :builtin
|
attr_protected :builtin
|
||||||
|
|
||||||
validates_presence_of :name
|
validates_presence_of :name
|
||||||
@@ -188,6 +189,56 @@ class Role < ActiveRecord::Base
|
|||||||
setable_permissions
|
setable_permissions
|
||||||
end
|
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
|
# Find all the roles that can be given to a project member
|
||||||
def self.find_all_givable
|
def self.find_all_givable
|
||||||
Role.givable.to_a
|
Role.givable.to_a
|
||||||
|
|||||||
@@ -62,6 +62,50 @@
|
|||||||
<%= hidden_field_tag 'role[permissions][]', '' %>
|
<%= hidden_field_tag 'role[permissions][]', '' %>
|
||||||
</div>
|
</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 %>
|
<%= javascript_tag do %>
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
$("#role_permissions_manage_members").change(function(){
|
$("#role_permissions_manage_members").change(function(){
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ en:
|
|||||||
error_can_not_read_import_file: "An error occurred while reading the file to import"
|
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_attachment_extension_not_allowed: "Attachment extension %{extension} is not allowed"
|
||||||
error_ldap_bind_credentials: "Invalid LDAP Account/Password"
|
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_subject_lost_password: "Your %{value} password"
|
||||||
mail_body_lost_password: 'To change your password, click on the following link:'
|
mail_body_lost_password: 'To change your password, click on the following link:'
|
||||||
@@ -561,6 +562,7 @@ en:
|
|||||||
label_member_plural: Members
|
label_member_plural: Members
|
||||||
label_tracker: Tracker
|
label_tracker: Tracker
|
||||||
label_tracker_plural: Trackers
|
label_tracker_plural: Trackers
|
||||||
|
label_tracker_all: All trackers
|
||||||
label_tracker_new: New tracker
|
label_tracker_new: New tracker
|
||||||
label_workflow: Workflow
|
label_workflow: Workflow
|
||||||
label_issue_status: Issue status
|
label_issue_status: Issue status
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ fr:
|
|||||||
error_can_not_read_import_file: "Une erreur est survenue lors de la lecture du fichier à importer"
|
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_attachment_extension_not_allowed: "L'extension %{extension} n'est pas autorisée"
|
||||||
error_ldap_bind_credentials: "Identifiant ou mot de passe LDAP incorrect"
|
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_subject_lost_password: "Votre mot de passe %{value}"
|
||||||
mail_body_lost_password: 'Pour changer votre mot de passe, cliquez sur le lien suivant :'
|
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_member_plural: Membres
|
||||||
label_tracker: Tracker
|
label_tracker: Tracker
|
||||||
label_tracker_plural: Trackers
|
label_tracker_plural: Trackers
|
||||||
|
label_tracker_all: Tous les trackers
|
||||||
label_tracker_new: Nouveau tracker
|
label_tracker_new: Nouveau tracker
|
||||||
label_workflow: Workflow
|
label_workflow: Workflow
|
||||||
label_issue_status: Statut de demandes
|
label_issue_status: Statut de demandes
|
||||||
|
|||||||
5
db/migrate/20160529063352_add_roles_settings.rb
Normal file
5
db/migrate/20160529063352_add_roles_settings.rb
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class AddRolesSettings < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :roles, :settings, :text
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1864,6 +1864,31 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
end
|
end
|
||||||
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
|
def test_new_should_preselect_default_version
|
||||||
version = Version.generate!(:project_id => 1)
|
version = Version.generate!(:project_id => 1)
|
||||||
Project.find(1).update_attribute :default_version_id, version.id
|
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)
|
assert_nil issue.custom_field_value(cf2)
|
||||||
end
|
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
|
def test_post_create_with_watchers
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
ActionMailer::Base.deliveries.clear
|
ActionMailer::Base.deliveries.clear
|
||||||
|
|||||||
@@ -132,6 +132,22 @@ class RolesControllerTest < ActionController::TestCase
|
|||||||
assert_equal [:edit_project], role.permissions
|
assert_equal [:edit_project], role.permissions
|
||||||
end
|
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
|
def test_update_with_failure
|
||||||
put :update, :id => 1, :role => {:name => ''}
|
put :update, :id => 1, :role => {:name => ''}
|
||||||
assert_response :success
|
assert_response :success
|
||||||
|
|||||||
@@ -1438,6 +1438,91 @@ class IssueTest < ActiveSupport::TestCase
|
|||||||
assert_not_include project, Issue.allowed_target_projects(User.find(1))
|
assert_not_include project, Issue.allowed_target_projects(User.find(1))
|
||||||
end
|
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
|
def test_move_to_another_project_with_same_category
|
||||||
issue = Issue.find(1)
|
issue = Issue.find(1)
|
||||||
issue.project = Project.find(2)
|
issue.project = Project.find(2)
|
||||||
|
|||||||
Reference in New Issue
Block a user