diff options
-rw-r--r-- | app/controllers/issues_controller.rb | 8 | ||||
-rw-r--r-- | app/models/issue.rb | 23 | ||||
-rw-r--r-- | app/models/issue_import.rb | 2 | ||||
-rw-r--r-- | app/models/role.rb | 51 | ||||
-rw-r--r-- | app/views/roles/_form.html.erb | 44 | ||||
-rw-r--r-- | config/locales/en.yml | 2 | ||||
-rw-r--r-- | config/locales/fr.yml | 2 | ||||
-rw-r--r-- | db/migrate/20160529063352_add_roles_settings.rb | 5 | ||||
-rw-r--r-- | test/functional/issues_controller_test.rb | 42 | ||||
-rw-r--r-- | test/functional/roles_controller_test.rb | 16 | ||||
-rw-r--r-- | test/unit/issue_test.rb | 85 |
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) |