##// END OF EJS Templates
Added ability to edit issues from different project through contextual menu (#5332)...
Jean-Baptiste Barth -
r4128:156eca4d223e
parent child
Show More
@@ -16,9 +16,9 class ContextMenusController < ApplicationController
16 @projects = @issues.collect(&:project).compact.uniq
16 @projects = @issues.collect(&:project).compact.uniq
17 @project = @projects.first if @projects.size == 1
17 @project = @projects.first if @projects.size == 1
18
18
19 @can = {:edit => (@project && User.current.allowed_to?(:edit_issues, @project)),
19 @can = {:edit => User.current.allowed_to?(:edit_issues, @projects),
20 :log_time => (@project && User.current.allowed_to?(:log_time, @project)),
20 :log_time => (@project && User.current.allowed_to?(:log_time, @project)),
21 :update => (@project && (User.current.allowed_to?(:edit_issues, @project) || (User.current.allowed_to?(:change_status, @project) && @allowed_statuses && !@allowed_statuses.empty?))),
21 :update => (User.current.allowed_to?(:edit_issues, @projects) || (User.current.allowed_to?(:change_status, @projects) && !@allowed_statuses.blank?)),
22 :move => (@project && User.current.allowed_to?(:move_issues, @project)),
22 :move => (@project && User.current.allowed_to?(:move_issues, @project)),
23 :copy => (@issue && @project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)),
23 :copy => (@issue && @project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)),
24 :delete => User.current.allowed_to?(:delete_issues, @projects)
24 :delete => User.current.allowed_to?(:delete_issues, @projects)
@@ -27,6 +27,10 class ContextMenusController < ApplicationController
27 @assignables = @project.assignable_users
27 @assignables = @project.assignable_users
28 @assignables << @issue.assigned_to if @issue && @issue.assigned_to && !@assignables.include?(@issue.assigned_to)
28 @assignables << @issue.assigned_to if @issue && @issue.assigned_to && !@assignables.include?(@issue.assigned_to)
29 @trackers = @project.trackers
29 @trackers = @project.trackers
30 else
31 #when multiple projects, we only keep the intersection of each set
32 @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a}
33 @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t}
30 end
34 end
31
35
32 @priorities = IssuePriority.all.reverse
36 @priorities = IssuePriority.all.reverse
@@ -21,7 +21,7 class IssuesController < ApplicationController
21
21
22 before_filter :find_issue, :only => [:show, :edit, :update]
22 before_filter :find_issue, :only => [:show, :edit, :update]
23 before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :move, :perform_move, :destroy]
23 before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :move, :perform_move, :destroy]
24 before_filter :check_project_uniqueness, :only => [:bulk_edit, :bulk_update, :move, :perform_move]
24 before_filter :check_project_uniqueness, :only => [:move, :perform_move]
25 before_filter :find_project, :only => [:new, :create]
25 before_filter :find_project, :only => [:new, :create]
26 before_filter :authorize, :except => [:index]
26 before_filter :authorize, :except => [:index]
27 before_filter :find_optional_project, :only => [:index]
27 before_filter :find_optional_project, :only => [:index]
@@ -194,8 +194,10 class IssuesController < ApplicationController
194 # Bulk edit a set of issues
194 # Bulk edit a set of issues
195 def bulk_edit
195 def bulk_edit
196 @issues.sort!
196 @issues.sort!
197 @available_statuses = Workflow.available_statuses(@project)
197 @available_statuses = @projects.map{|p|Workflow.available_statuses(p)}.inject{|memo,w|memo & w}
198 @custom_fields = @project.all_issue_custom_fields
198 @custom_fields = @projects.map{|p|p.all_issue_custom_fields}.inject{|memo,c|memo & c}
199 @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a}
200 @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t}
199 end
201 end
200
202
201 def bulk_update
203 def bulk_update
@@ -33,7 +33,6
33 </li>
33 </li>
34 <% end %>
34 <% end %>
35
35
36 <% if @projects.size == 1 %>
37 <li class="folder">
36 <li class="folder">
38 <a href="#" class="submenu"><%= l(:field_priority) %></a>
37 <a href="#" class="submenu"><%= l(:field_priority) %></a>
39 <ul>
38 <ul>
@@ -43,8 +42,8
43 <% end -%>
42 <% end -%>
44 </ul>
43 </ul>
45 </li>
44 </li>
46 <% end %>
47
45
46 <% #TODO: allow editing versions when multiple projects %>
48 <% unless @project.nil? || @project.shared_versions.open.empty? -%>
47 <% unless @project.nil? || @project.shared_versions.open.empty? -%>
49 <li class="folder">
48 <li class="folder">
50 <a href="#" class="submenu"><%= l(:field_fixed_version) %></a>
49 <a href="#" class="submenu"><%= l(:field_fixed_version) %></a>
@@ -85,7 +84,7
85 </li>
84 </li>
86 <% end -%>
85 <% end -%>
87
86
88 <% if Issue.use_field_for_done_ratio? && @projects.size == 1 %>
87 <% if Issue.use_field_for_done_ratio? %>
89 <li class="folder">
88 <li class="folder">
90 <a href="#" class="submenu"><%= l(:field_done_ratio) %></a>
89 <a href="#" class="submenu"><%= l(:field_done_ratio) %></a>
91 <ul>
90 <ul>
@@ -11,7 +11,7
11 <div class="splitcontentleft">
11 <div class="splitcontentleft">
12 <p>
12 <p>
13 <label><%= l(:field_tracker) %></label>
13 <label><%= l(:field_tracker) %></label>
14 <%= select_tag('issue[tracker_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@project.trackers, :id, :name)) %>
14 <%= select_tag('issue[tracker_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, :id, :name)) %>
15 </p>
15 </p>
16 <% if @available_statuses.any? %>
16 <% if @available_statuses.any? %>
17 <p>
17 <p>
@@ -27,20 +27,25
27 <label><%= l(:field_assigned_to) %></label>
27 <label><%= l(:field_assigned_to) %></label>
28 <%= select_tag('issue[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') +
28 <%= select_tag('issue[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') +
29 content_tag('option', l(:label_nobody), :value => 'none') +
29 content_tag('option', l(:label_nobody), :value => 'none') +
30 options_from_collection_for_select(@project.assignable_users, :id, :name)) %>
30 options_from_collection_for_select(@assignables, :id, :name)) %>
31 </p>
31 </p>
32 <% if @project %>
32 <p>
33 <p>
33 <label><%= l(:field_category) %></label>
34 <label><%= l(:field_category) %></label>
34 <%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') +
35 <%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') +
35 content_tag('option', l(:label_none), :value => 'none') +
36 content_tag('option', l(:label_none), :value => 'none') +
36 options_from_collection_for_select(@project.issue_categories, :id, :name)) %>
37 options_from_collection_for_select(@project.issue_categories, :id, :name)) %>
37 </p>
38 </p>
39 <% end %>
40 <% #TODO: allow editing versions when multiple projects %>
41 <% if @project %>
38 <p>
42 <p>
39 <label><%= l(:field_fixed_version) %></label>
43 <label><%= l(:field_fixed_version) %></label>
40 <%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') +
44 <%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') +
41 content_tag('option', l(:label_none), :value => 'none') +
45 content_tag('option', l(:label_none), :value => 'none') +
42 version_options_for_select(@project.shared_versions.open)) %>
46 version_options_for_select(@project.shared_versions.open)) %>
43 </p>
47 </p>
48 <% end %>
44
49
45 <% @custom_fields.each do |custom_field| %>
50 <% @custom_fields.each do |custom_field| %>
46 <p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('issue', custom_field) %></p>
51 <p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('issue', custom_field) %></p>
@@ -85,6 +85,18 class ContextMenusControllerTest < ActionController::TestCase
85 assert_response :success
85 assert_response :success
86 assert_template 'context_menu'
86 assert_template 'context_menu'
87 ids = "ids%5B%5D=1&amp;ids%5B%5D=2&amp;ids%5B%5D=6"
87 ids = "ids%5B%5D=1&amp;ids%5B%5D=2&amp;ids%5B%5D=6"
88 assert_tag :tag => 'a', :content => 'Edit',
89 :attributes => { :href => "/issues/bulk_edit?#{ids}",
90 :class => 'icon-edit' }
91 assert_tag :tag => 'a', :content => 'Closed',
92 :attributes => { :href => "/issues/bulk_edit?#{ids}&amp;issue%5Bstatus_id%5D=5",
93 :class => '' }
94 assert_tag :tag => 'a', :content => 'Immediate',
95 :attributes => { :href => "/issues/bulk_edit?#{ids}&amp;issue%5Bpriority_id%5D=8",
96 :class => '' }
97 assert_tag :tag => 'a', :content => 'John Smith',
98 :attributes => { :href => "/issues/bulk_edit?#{ids}&amp;issue%5Bassigned_to_id%5D=2",
99 :class => '' }
88 assert_tag :tag => 'a', :content => 'Delete',
100 assert_tag :tag => 'a', :content => 'Delete',
89 :attributes => { :href => "/issues/destroy?#{ids}",
101 :attributes => { :href => "/issues/destroy?#{ids}",
90 :class => 'icon-del' }
102 :class => 'icon-del' }
@@ -911,6 +911,19 class IssuesControllerTest < ActionController::TestCase
911 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
911 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
912 end
912 end
913
913
914 def test_get_bulk_edit_on_different_projects
915 @request.session[:user_id] = 2
916 get :bulk_edit, :ids => [1, 2, 6]
917 assert_response :success
918 assert_template 'bulk_edit'
919
920 # Project specific custom field, date type
921 field = CustomField.find(9)
922 assert !field.is_for_all?
923 assert !field.project_ids.include?(Issue.find(6).project_id)
924 assert_no_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
925 end
926
914 def test_bulk_update
927 def test_bulk_update
915 @request.session[:user_id] = 2
928 @request.session[:user_id] = 2
916 # update issues priority
929 # update issues priority
@@ -930,6 +943,39 class IssuesControllerTest < ActionController::TestCase
930 assert_equal 1, journal.details.size
943 assert_equal 1, journal.details.size
931 end
944 end
932
945
946 def test_bulk_update_on_different_projects
947 @request.session[:user_id] = 2
948 # update issues priority
949 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
950 :issue => {:priority_id => 7,
951 :assigned_to_id => '',
952 :custom_field_values => {'2' => ''}}
953
954 assert_response 302
955 # check that the issues were updated
956 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
957
958 issue = Issue.find(1)
959 journal = issue.journals.find(:first, :order => 'created_on DESC')
960 assert_equal '125', issue.custom_value_for(2).value
961 assert_equal 'Bulk editing', journal.notes
962 assert_equal 1, journal.details.size
963 end
964
965 def test_bulk_update_on_different_projects_without_rights
966 @request.session[:user_id] = 3
967 user = User.find(3)
968 action = { :controller => "issues", :action => "bulk_update" }
969 assert user.allowed_to?(action, Issue.find(1).project)
970 assert ! user.allowed_to?(action, Issue.find(6).project)
971 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
972 :issue => {:priority_id => 7,
973 :assigned_to_id => '',
974 :custom_field_values => {'2' => ''}}
975 assert_response 403
976 assert_not_equal "Bulk should fail", Journal.last.notes
977 end
978
933 def test_bullk_update_should_send_a_notification
979 def test_bullk_update_should_send_a_notification
934 @request.session[:user_id] = 2
980 @request.session[:user_id] = 2
935 ActionMailer::Base.deliveries.clear
981 ActionMailer::Base.deliveries.clear
General Comments 0
You need to be logged in to leave comments. Login now