@@ -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 => |
|
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 => |
|
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 => [ |
|
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( |
|
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? |
|
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(@ |
|
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(@ |
|
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&ids%5B%5D=2&ids%5B%5D=6" |
|
87 | ids = "ids%5B%5D=1&ids%5B%5D=2&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}&issue%5Bstatus_id%5D=5", | |||
|
93 | :class => '' } | |||
|
94 | assert_tag :tag => 'a', :content => 'Immediate', | |||
|
95 | :attributes => { :href => "/issues/bulk_edit?#{ids}&issue%5Bpriority_id%5D=8", | |||
|
96 | :class => '' } | |||
|
97 | assert_tag :tag => 'a', :content => 'John Smith', | |||
|
98 | :attributes => { :href => "/issues/bulk_edit?#{ids}&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