##// END OF EJS Templates
Adds a :copy_issues permission (#18855)....
Jean-Philippe Lang -
r13603:c3c7d9a4d27b
parent child
Show More
@@ -31,7 +31,7 class ContextMenusController < ApplicationController
31
31
32 @can = {:edit => User.current.allowed_to?(:edit_issues, @projects),
32 @can = {:edit => User.current.allowed_to?(:edit_issues, @projects),
33 :log_time => (@project && User.current.allowed_to?(:log_time, @project)),
33 :log_time => (@project && User.current.allowed_to?(:log_time, @project)),
34 :copy => User.current.allowed_to?(:add_issues, @projects),
34 :copy => User.current.allowed_to?(:copy_issues, @projects) && Issue.allowed_target_projects.any?,
35 :delete => User.current.allowed_to?(:delete_issues, @projects)
35 :delete => User.current.allowed_to?(:delete_issues, @projects)
36 }
36 }
37 if @project
37 if @project
@@ -143,6 +143,9 class IssuesController < ApplicationController
143 end
143 end
144
144
145 def create
145 def create
146 unless User.current.allowed_to?(:add_issues, @issue.project)
147 raise ::Unauthorized
148 end
146 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
149 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
147 @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
150 @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
148 if @issue.save
151 if @issue.save
@@ -219,6 +222,12 class IssuesController < ApplicationController
219 @copy = params[:copy].present?
222 @copy = params[:copy].present?
220 @notes = params[:notes]
223 @notes = params[:notes]
221
224
225 if @copy
226 unless User.current.allowed_to?(:copy_issues, @projects)
227 raise ::Unauthorized
228 end
229 end
230
222 @allowed_projects = Issue.allowed_target_projects
231 @allowed_projects = Issue.allowed_target_projects
223 if params[:issue]
232 if params[:issue]
224 @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:issue][:project_id].to_s}
233 @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:issue][:project_id].to_s}
@@ -255,6 +264,19 class IssuesController < ApplicationController
255 @copy = params[:copy].present?
264 @copy = params[:copy].present?
256 attributes = parse_params_for_bulk_issue_attributes(params)
265 attributes = parse_params_for_bulk_issue_attributes(params)
257
266
267 if @copy
268 unless User.current.allowed_to?(:copy_issues, @projects)
269 raise ::Unauthorized
270 end
271 target_projects = @projects
272 if attributes['project_id'].present?
273 target_projects = Project.where(:id => attributes['project_id']).to_a
274 end
275 unless User.current.allowed_to?(:add_issues, target_projects)
276 raise ::Unauthorized
277 end
278 end
279
258 unsaved_issues = []
280 unsaved_issues = []
259 saved_issues = []
281 saved_issues = []
260
282
@@ -407,6 +429,9 class IssuesController < ApplicationController
407 begin
429 begin
408 @issue.init_journal(User.current)
430 @issue.init_journal(User.current)
409 @copy_from = Issue.visible.find(params[:copy_from])
431 @copy_from = Issue.visible.find(params[:copy_from])
432 unless User.current.allowed_to?(:copy_issues, @copy_from.project)
433 raise ::Unauthorized
434 end
410 @link_copy = link_copy?(params[:link_copy]) || request.get?
435 @link_copy = link_copy?(params[:link_copy]) || request.get?
411 @copy_attachments = params[:copy_attachments].present? || request.get?
436 @copy_attachments = params[:copy_attachments].present? || request.get?
412 @copy_subtasks = params[:copy_subtasks].present? || request.get?
437 @copy_subtasks = params[:copy_subtasks].present? || request.get?
@@ -343,8 +343,11 module ApplicationHelper
343
343
344 def project_tree_options_for_select(projects, options = {})
344 def project_tree_options_for_select(projects, options = {})
345 s = ''.html_safe
345 s = ''.html_safe
346 if options[:include_blank]
346 if blank_text = options[:include_blank]
347 s << content_tag('option', '&nbsp;'.html_safe, :value => '')
347 if blank_text == true
348 blank_text = '&nbsp;'.html_safe
349 end
350 s << content_tag('option', blank_text, :value => '')
348 end
351 end
349 project_tree(projects) do |project, level|
352 project_tree(projects) do |project, level|
350 name_prefix = (level > 0 ? '&nbsp;' * 2 * level + '&#187; ' : '').html_safe
353 name_prefix = (level > 0 ? '&nbsp;' * 2 * level + '&#187; ' : '').html_safe
@@ -424,6 +424,9 class Issue < ActiveRecord::Base
424 names = super
424 names = super
425 names -= disabled_core_fields
425 names -= disabled_core_fields
426 names -= read_only_attribute_names(user)
426 names -= read_only_attribute_names(user)
427 if new_record? && copy?
428 names |= %w(project_id)
429 end
427 names
430 names
428 end
431 end
429
432
@@ -2,6 +2,6
2 <%= link_to l(:button_edit), edit_issue_path(@issue), :onclick => 'showAndScrollTo("update", "issue_notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit) if @issue.editable? %>
2 <%= link_to l(:button_edit), edit_issue_path(@issue), :onclick => 'showAndScrollTo("update", "issue_notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit) if @issue.editable? %>
3 <%= link_to l(:button_log_time), new_issue_time_entry_path(@issue), :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project) %>
3 <%= link_to l(:button_log_time), new_issue_time_entry_path(@issue), :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project) %>
4 <%= watcher_link(@issue, User.current) %>
4 <%= watcher_link(@issue, User.current) %>
5 <%= link_to l(:button_copy), project_copy_issue_path(@project, @issue), :class => 'icon icon-copy' if User.current.allowed_to?(:add_issues, @project) %>
5 <%= link_to l(:button_copy), project_copy_issue_path(@project, @issue), :class => 'icon icon-copy' if User.current.allowed_to?(:copy_issues, @project) && Issue.allowed_target_projects.any? %>
6 <%= link_to l(:button_delete), issue_path(@issue), :data => {:confirm => issues_destroy_confirmation_message(@issue)}, :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %>
6 <%= link_to l(:button_delete), issue_path(@issue), :data => {:confirm => issues_destroy_confirmation_message(@issue)}, :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %>
7 </div>
7 </div>
@@ -33,8 +33,9
33 <p>
33 <p>
34 <label for="issue_project_id"><%= l(:field_project) %></label>
34 <label for="issue_project_id"><%= l(:field_project) %></label>
35 <%= select_tag('issue[project_id]',
35 <%= select_tag('issue[project_id]',
36 content_tag('option', l(:label_no_change_option), :value => '') +
36 project_tree_options_for_select(@allowed_projects,
37 project_tree_options_for_select(@allowed_projects, :selected => @target_project),
37 :include_blank => ((!@copy || (@projects & @allowed_projects == @projects)) ? l(:label_no_change_option) : false),
38 :selected => @target_project),
38 :onchange => "updateBulkEditFrom('#{escape_javascript url_for(:action => 'bulk_edit', :format => 'js')}')") %>
39 :onchange => "updateBulkEditFrom('#{escape_javascript url_for(:action => 'bulk_edit', :format => 'js')}')") %>
39 </p>
40 </p>
40 <% end %>
41 <% end %>
@@ -429,6 +429,7 en:
429 permission_view_issues: View Issues
429 permission_view_issues: View Issues
430 permission_add_issues: Add issues
430 permission_add_issues: Add issues
431 permission_edit_issues: Edit issues
431 permission_edit_issues: Edit issues
432 permission_copy_issues: Copy issues
432 permission_manage_issue_relations: Manage issue relations
433 permission_manage_issue_relations: Manage issue relations
433 permission_set_issues_private: Set issues public or private
434 permission_set_issues_private: Set issues public or private
434 permission_set_own_issues_private: Set own issues public or private
435 permission_set_own_issues_private: Set own issues public or private
@@ -449,6 +449,7 fr:
449 permission_view_issues: Voir les demandes
449 permission_view_issues: Voir les demandes
450 permission_add_issues: CrΓ©er des demandes
450 permission_add_issues: CrΓ©er des demandes
451 permission_edit_issues: Modifier les demandes
451 permission_edit_issues: Modifier les demandes
452 permission_copy_issues: Copier les demandes
452 permission_manage_issue_relations: GΓ©rer les relations
453 permission_manage_issue_relations: GΓ©rer les relations
453 permission_set_issues_private: Rendre les demandes publiques ou privΓ©es
454 permission_set_issues_private: Rendre les demandes publiques ou privΓ©es
454 permission_set_own_issues_private: Rendre ses propres demandes publiques ou privΓ©es
455 permission_set_own_issues_private: Rendre ses propres demandes publiques ou privΓ©es
@@ -100,6 +100,7 Redmine::AccessControl.map do |map|
100 :read => true
100 :read => true
101 map.permission :add_issues, {:issues => [:new, :create, :update_form], :attachments => :upload}
101 map.permission :add_issues, {:issues => [:new, :create, :update_form], :attachments => :upload}
102 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form], :journals => [:new], :attachments => :upload}
102 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form], :journals => [:new], :attachments => :upload}
103 map.permission :copy_issues, {:issues => [:new, :create, :bulk_edit, :bulk_update, :update_form], :attachments => :upload}
103 map.permission :manage_issue_relations, {:issue_relations => [:index, :show, :create, :destroy]}
104 map.permission :manage_issue_relations, {:issue_relations => [:index, :show, :create, :destroy]}
104 map.permission :manage_subtasks, {}
105 map.permission :manage_subtasks, {}
105 map.permission :set_issues_private, {}
106 map.permission :set_issues_private, {}
@@ -17,6 +17,7 roles_001:
17 - :view_issues
17 - :view_issues
18 - :add_issues
18 - :add_issues
19 - :edit_issues
19 - :edit_issues
20 - :copy_issues
20 - :manage_issue_relations
21 - :manage_issue_relations
21 - :manage_subtasks
22 - :manage_subtasks
22 - :add_issue_notes
23 - :add_issue_notes
@@ -77,6 +78,7 roles_002:
77 - :view_issues
78 - :view_issues
78 - :add_issues
79 - :add_issues
79 - :edit_issues
80 - :edit_issues
81 - :copy_issues
80 - :manage_issue_relations
82 - :manage_issue_relations
81 - :manage_subtasks
83 - :manage_subtasks
82 - :add_issue_notes
84 - :add_issue_notes
@@ -2473,6 +2473,20 class IssuesControllerTest < ActionController::TestCase
2473 assert_select '#main-menu a.new-issue[href="/projects/ecookbook/issues/new"]'
2473 assert_select '#main-menu a.new-issue[href="/projects/ecookbook/issues/new"]'
2474 end
2474 end
2475
2475
2476 def test_new_as_copy_without_add_issues_permission_should_not_propose_current_project_as_target
2477 user = setup_user_with_copy_but_not_add_permission
2478
2479 @request.session[:user_id] = user.id
2480 get :new, :project_id => 1, :copy_from => 1
2481
2482 assert_response :success
2483 assert_template 'new'
2484 assert_select 'select[name=?]', 'issue[project_id]' do
2485 assert_select 'option[value="1"]', 0
2486 assert_select 'option[value="2"]', :text => 'OnlineStore'
2487 end
2488 end
2489
2476 def test_new_as_copy_with_attachments_should_show_copy_attachments_checkbox
2490 def test_new_as_copy_with_attachments_should_show_copy_attachments_checkbox
2477 @request.session[:user_id] = 2
2491 @request.session[:user_id] = 2
2478 issue = Issue.find(3)
2492 issue = Issue.find(3)
@@ -3770,9 +3784,26 class IssuesControllerTest < ActionController::TestCase
3770 assert_not_nil issues
3784 assert_not_nil issues
3771 assert_equal [1, 2, 3], issues.map(&:id).sort
3785 assert_equal [1, 2, 3], issues.map(&:id).sort
3772
3786
3787 assert_select 'select[name=?]', 'issue[project_id]' do
3788 assert_select 'option[value=""]'
3789 end
3773 assert_select 'input[name=copy_attachments]'
3790 assert_select 'input[name=copy_attachments]'
3774 end
3791 end
3775
3792
3793 def test_get_bulk_copy_without_add_issues_permission_should_not_propose_current_project_as_target
3794 user = setup_user_with_copy_but_not_add_permission
3795 @request.session[:user_id] = user.id
3796
3797 get :bulk_edit, :ids => [1, 2, 3], :copy => '1'
3798 assert_response :success
3799 assert_template 'bulk_edit'
3800
3801 assert_select 'select[name=?]', 'issue[project_id]' do
3802 assert_select 'option[value=""]', 0
3803 assert_select 'option[value="2"]'
3804 end
3805 end
3806
3776 def test_bulk_copy_to_another_project
3807 def test_bulk_copy_to_another_project
3777 @request.session[:user_id] = 2
3808 @request.session[:user_id] = 2
3778 assert_difference 'Issue.count', 2 do
3809 assert_difference 'Issue.count', 2 do
@@ -3788,6 +3819,32 class IssuesControllerTest < ActionController::TestCase
3788 end
3819 end
3789 end
3820 end
3790
3821
3822 def test_bulk_copy_without_add_issues_permission_should_be_allowed_on_project_with_permission
3823 user = setup_user_with_copy_but_not_add_permission
3824 @request.session[:user_id] = user.id
3825
3826 assert_difference 'Issue.count', 3 do
3827 post :bulk_update, :ids => [1, 2, 3], :issue => {:project_id => '2'}, :copy => '1'
3828 assert_response 302
3829 end
3830 end
3831
3832 def test_bulk_copy_on_same_project_without_add_issues_permission_should_be_denied
3833 user = setup_user_with_copy_but_not_add_permission
3834 @request.session[:user_id] = user.id
3835
3836 post :bulk_update, :ids => [1, 2, 3], :issue => {:project_id => ''}, :copy => '1'
3837 assert_response 403
3838 end
3839
3840 def test_bulk_copy_on_different_project_without_add_issues_permission_should_be_denied
3841 user = setup_user_with_copy_but_not_add_permission
3842 @request.session[:user_id] = user.id
3843
3844 post :bulk_update, :ids => [1, 2, 3], :issue => {:project_id => '1'}, :copy => '1'
3845 assert_response 403
3846 end
3847
3791 def test_bulk_copy_should_allow_not_changing_the_issue_attributes
3848 def test_bulk_copy_should_allow_not_changing_the_issue_attributes
3792 @request.session[:user_id] = 2
3849 @request.session[:user_id] = 2
3793 issues = [
3850 issues = [
@@ -4079,4 +4136,13 class IssuesControllerTest < ActionController::TestCase
4079 assert_select 'input[name=issues][value="1"][type=hidden]'
4136 assert_select 'input[name=issues][value="1"][type=hidden]'
4080 end
4137 end
4081 end
4138 end
4139
4140 def setup_user_with_copy_but_not_add_permission
4141 Role.all.each {|r| r.remove_permission! :add_issues}
4142 Role.find_by_name('Manager').add_permission! :add_issues
4143 user = User.generate!
4144 User.add_to_project(user, Project.find(1), Role.find_by_name('Developer'))
4145 User.add_to_project(user, Project.find(2), Role.find_by_name('Manager'))
4146 user
4147 end
4082 end
4148 end
General Comments 0
You need to be logged in to leave comments. Login now