@@ -260,29 +260,16 class IssuesController < ApplicationController | |||||
260 | # Bulk edit a set of issues |
|
260 | # Bulk edit a set of issues | |
261 | def bulk_edit |
|
261 | def bulk_edit | |
262 | if request.post? |
|
262 | if request.post? | |
263 | tracker = params[:tracker_id].blank? ? nil : @project.trackers.find_by_id(params[:tracker_id]) |
|
263 | attributes = (params[:issue] || {}).reject {|k,v| v.blank?} | |
264 | status = params[:status_id].blank? ? nil : IssueStatus.find_by_id(params[:status_id]) |
|
264 | attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} | |
265 | priority = params[:priority_id].blank? ? nil : IssuePriority.find_by_id(params[:priority_id]) |
|
265 | attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values] | |
266 | assigned_to = (params[:assigned_to_id].blank? || params[:assigned_to_id] == 'none') ? nil : User.find_by_id(params[:assigned_to_id]) |
|
|||
267 | category = (params[:category_id].blank? || params[:category_id] == 'none') ? nil : @project.issue_categories.find_by_id(params[:category_id]) |
|
|||
268 | fixed_version = (params[:fixed_version_id].blank? || params[:fixed_version_id] == 'none') ? nil : @project.shared_versions.find_by_id(params[:fixed_version_id]) |
|
|||
269 | custom_field_values = params[:custom_field_values] ? params[:custom_field_values].reject {|k,v| v.blank?} : nil |
|
|||
270 |
|
||||
271 | # Need to merge in the records found above for Issue#bulk_edit. |
|
|||
272 | # Assuming this is done so the associations are only looked up once. |
|
|||
273 | merged_params = params.merge({ |
|
|||
274 | :tracker => tracker, |
|
|||
275 | :status => status, |
|
|||
276 | :priority => priority, |
|
|||
277 | :assigned_to => assigned_to, |
|
|||
278 | :category => category, |
|
|||
279 | :fixed_version => fixed_version, |
|
|||
280 | :custom_field_values => custom_field_values |
|
|||
281 | }) |
|
|||
282 |
|
266 | |||
283 |
unsaved_issue_ids = [] |
|
267 | unsaved_issue_ids = [] | |
284 | @issues.each do |issue| |
|
268 | @issues.each do |issue| | |
285 | unless issue.bulk_edit(merged_params) |
|
269 | journal = issue.init_journal(User.current, params[:notes]) | |
|
270 | issue.safe_attributes = attributes | |||
|
271 | call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue }) | |||
|
272 | unless issue.save | |||
286 | # Keep unsaved issue ids to display them in flash error |
|
273 | # Keep unsaved issue ids to display them in flash error | |
287 | unsaved_issue_ids << issue.id |
|
274 | unsaved_issue_ids << issue.id | |
288 | end |
|
275 | end |
@@ -67,9 +67,9 module CustomFieldsHelper | |||||
67 | custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value) |
|
67 | custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value) | |
68 | end |
|
68 | end | |
69 |
|
69 | |||
70 | def custom_field_tag_for_bulk_edit(custom_field) |
|
70 | def custom_field_tag_for_bulk_edit(name, custom_field) | |
71 | field_name = "custom_field_values[#{custom_field.id}]" |
|
71 | field_name = "#{name}[custom_field_values][#{custom_field.id}]" | |
72 | field_id = "custom_field_values_#{custom_field.id}" |
|
72 | field_id = "#{name}_custom_field_values_#{custom_field.id}" | |
73 | case custom_field.field_format |
|
73 | case custom_field.field_format | |
74 | when "date" |
|
74 | when "date" | |
75 | text_field_tag(field_name, '', :id => field_id, :size => 10) + |
|
75 | text_field_tag(field_name, '', :id => field_id, :size => 10) + |
@@ -136,24 +136,6 class Issue < ActiveRecord::Base | |||||
136 | end |
|
136 | end | |
137 | return issue |
|
137 | return issue | |
138 | end |
|
138 | end | |
139 |
|
||||
140 | def bulk_edit(params) |
|
|||
141 | journal = init_journal(User.current, params[:notes]) |
|
|||
142 | self.tracker = params[:tracker] if params[:tracker] |
|
|||
143 | self.priority = params[:priority] if params[:priority] |
|
|||
144 | self.assigned_to = params[:assigned_to] if params[:assigned_to] || params[:assigned_to_id] == 'none' |
|
|||
145 | self.category = params[:category] if params[:category] || params[:category_id] == 'none' |
|
|||
146 | self.fixed_version = params[:fixed_version] if params[:fixed_version] || params[:fixed_version_id] == 'none' |
|
|||
147 | self.start_date = params[:start_date] unless params[:start_date].blank? |
|
|||
148 | self.due_date = params[:due_date] unless params[:due_date].blank? |
|
|||
149 | self.done_ratio = params[:done_ratio] unless params[:done_ratio].blank? |
|
|||
150 | self.custom_field_values = params[:custom_field_values] if params[:custom_field_values] && !params[:custom_field_values].empty? |
|
|||
151 | # TODO: Edit hook name |
|
|||
152 | Redmine::Hook.call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => self }) |
|
|||
153 |
|
||||
154 | # Don't save any change to the issue if the user is not authorized to apply the requested status |
|
|||
155 | return (params[:status].nil? || (new_statuses_allowed_to(User.current).include?(params[:status]) && self.status = params[:status])) && save |
|
|||
156 | end |
|
|||
157 |
|
139 | |||
158 | def priority_id=(pid) |
|
140 | def priority_id=(pid) | |
159 | self.priority = nil |
|
141 | self.priority = nil | |
@@ -206,7 +188,13 class Issue < ActiveRecord::Base | |||||
206 | # TODO: move workflow/permission checks from controllers to here |
|
188 | # TODO: move workflow/permission checks from controllers to here | |
207 | def safe_attributes=(attrs, user=User.current) |
|
189 | def safe_attributes=(attrs, user=User.current) | |
208 | return if attrs.nil? |
|
190 | return if attrs.nil? | |
209 |
|
|
191 | attrs = attrs.reject {|k,v| !SAFE_ATTRIBUTES.include?(k)} | |
|
192 | if attrs['status_id'] | |||
|
193 | unless new_statuses_allowed_to(user).collect(&:id).include?(attrs['status_id'].to_i) | |||
|
194 | attrs.delete('status_id') | |||
|
195 | end | |||
|
196 | end | |||
|
197 | self.attributes = attrs | |||
210 | end |
|
198 | end | |
211 |
|
199 | |||
212 | def done_ratio |
|
200 | def done_ratio |
@@ -11,39 +11,39 | |||||
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('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(@project.trackers, :id, :name)) %> | |
15 | </p> |
|
15 | </p> | |
16 | <% if @available_statuses.any? %> |
|
16 | <% if @available_statuses.any? %> | |
17 | <p> |
|
17 | <p> | |
18 | <label><%= l(:field_status) %></label> |
|
18 | <label><%= l(:field_status) %></label> | |
19 | <%= select_tag('status_id', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@available_statuses, :id, :name)) %> |
|
19 | <%= select_tag('issue[status_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@available_statuses, :id, :name)) %> | |
20 | </p> |
|
20 | </p> | |
21 | <% end %> |
|
21 | <% end %> | |
22 | <p> |
|
22 | <p> | |
23 | <label><%= l(:field_priority) %></label> |
|
23 | <label><%= l(:field_priority) %></label> | |
24 | <%= select_tag('priority_id', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(IssuePriority.all, :id, :name)) %> |
|
24 | <%= select_tag('issue[priority_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(IssuePriority.all, :id, :name)) %> | |
25 | </p> |
|
25 | </p> | |
26 | <p> |
|
26 | <p> | |
27 | <label><%= l(:field_assigned_to) %></label> |
|
27 | <label><%= l(:field_assigned_to) %></label> | |
28 | <%= select_tag('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(@project.assignable_users, :id, :name)) %> | |
31 | </p> |
|
31 | </p> | |
32 | <p> |
|
32 | <p> | |
33 | <label><%= l(:field_category) %></label> |
|
33 | <label><%= l(:field_category) %></label> | |
34 | <%= select_tag('category_id', content_tag('option', l(:label_no_change_option), :value => '') + |
|
34 | <%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') + | |
35 | content_tag('option', l(:label_none), :value => 'none') + |
|
35 | content_tag('option', l(:label_none), :value => 'none') + | |
36 | options_from_collection_for_select(@project.issue_categories, :id, :name)) %> |
|
36 | options_from_collection_for_select(@project.issue_categories, :id, :name)) %> | |
37 | </p> |
|
37 | </p> | |
38 | <p> |
|
38 | <p> | |
39 | <label><%= l(:field_fixed_version) %></label> |
|
39 | <label><%= l(:field_fixed_version) %></label> | |
40 | <%= select_tag('fixed_version_id', content_tag('option', l(:label_no_change_option), :value => '') + |
|
40 | <%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') + | |
41 | content_tag('option', l(:label_none), :value => 'none') + |
|
41 | content_tag('option', l(:label_none), :value => 'none') + | |
42 | version_options_for_select(@project.shared_versions.open)) %> |
|
42 | version_options_for_select(@project.shared_versions.open)) %> | |
43 | </p> |
|
43 | </p> | |
44 |
|
44 | |||
45 | <% @custom_fields.each do |custom_field| %> |
|
45 | <% @custom_fields.each do |custom_field| %> | |
46 | <p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit(custom_field) %></p> |
|
46 | <p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('issue', custom_field) %></p> | |
47 | <% end %> |
|
47 | <% end %> | |
48 |
|
48 | |||
49 | <%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %> |
|
49 | <%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %> | |
@@ -52,16 +52,16 | |||||
52 | <div class="splitcontentright"> |
|
52 | <div class="splitcontentright"> | |
53 | <p> |
|
53 | <p> | |
54 | <label><%= l(:field_start_date) %></label> |
|
54 | <label><%= l(:field_start_date) %></label> | |
55 | <%= text_field_tag 'start_date', '', :size => 10 %><%= calendar_for('start_date') %> |
|
55 | <%= text_field_tag 'issue[start_date]', '', :size => 10 %><%= calendar_for('issue_start_date') %> | |
56 | </p> |
|
56 | </p> | |
57 | <p> |
|
57 | <p> | |
58 | <label><%= l(:field_due_date) %></label> |
|
58 | <label><%= l(:field_due_date) %></label> | |
59 | <%= text_field_tag 'due_date', '', :size => 10 %><%= calendar_for('due_date') %> |
|
59 | <%= text_field_tag 'issue[due_date]', '', :size => 10 %><%= calendar_for('issue_due_date') %> | |
60 | </p> |
|
60 | </p> | |
61 | <% if Issue.use_field_for_done_ratio? %> |
|
61 | <% if Issue.use_field_for_done_ratio? %> | |
62 | <p> |
|
62 | <p> | |
63 | <label><%= l(:field_done_ratio) %></label> |
|
63 | <label><%= l(:field_done_ratio) %></label> | |
64 | <%= select_tag 'done_ratio', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %> |
|
64 | <%= select_tag 'issue[done_ratio]', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %> | |
65 | </p> |
|
65 | </p> | |
66 | <% end %> |
|
66 | <% end %> | |
67 | </div> |
|
67 | </div> |
@@ -899,20 +899,21 class IssuesControllerTest < ActionController::TestCase | |||||
899 | field = CustomField.find(9) |
|
899 | field = CustomField.find(9) | |
900 | assert !field.is_for_all? |
|
900 | assert !field.is_for_all? | |
901 | assert_equal 'date', field.field_format |
|
901 | assert_equal 'date', field.field_format | |
902 | assert_tag :input, :attributes => {:name => 'custom_field_values[9]'} |
|
902 | assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'} | |
903 |
|
903 | |||
904 | # System wide custom field |
|
904 | # System wide custom field | |
905 | assert CustomField.find(1).is_for_all? |
|
905 | assert CustomField.find(1).is_for_all? | |
906 | assert_tag :select, :attributes => {:name => 'custom_field_values[1]'} |
|
906 | assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'} | |
907 | end |
|
907 | end | |
908 |
|
908 | |||
909 | def test_bulk_edit |
|
909 | def test_bulk_edit | |
910 | @request.session[:user_id] = 2 |
|
910 | @request.session[:user_id] = 2 | |
911 | # update issues priority |
|
911 | # update issues priority | |
912 |
post :bulk_edit, :ids => [1, 2], : |
|
912 | post :bulk_edit, :ids => [1, 2], :notes => 'Bulk editing', | |
913 |
: |
|
913 | :issue => {:priority_id => 7, | |
914 |
|
|
914 | :assigned_to_id => '', | |
915 |
|
|
915 | :custom_field_values => {'2' => ''}} | |
|
916 | ||||
916 | assert_response 302 |
|
917 | assert_response 302 | |
917 | # check that the issues were updated |
|
918 | # check that the issues were updated | |
918 | assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id} |
|
919 | assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id} | |
@@ -930,10 +931,12 class IssuesControllerTest < ActionController::TestCase | |||||
930 | post(:bulk_edit, |
|
931 | post(:bulk_edit, | |
931 | { |
|
932 | { | |
932 | :ids => [1, 2], |
|
933 | :ids => [1, 2], | |
933 | :priority_id => 7, |
|
934 | :notes => 'Bulk editing', | |
934 |
: |
|
935 | :issue => { | |
935 | :custom_field_values => {'2' => ''}, |
|
936 | :priority_id => 7, | |
936 | :notes => 'Bulk editing' |
|
937 | :assigned_to_id => '', | |
|
938 | :custom_field_values => {'2' => ''} | |||
|
939 | } | |||
937 | }) |
|
940 | }) | |
938 |
|
941 | |||
939 | assert_response 302 |
|
942 | assert_response 302 | |
@@ -943,10 +946,11 class IssuesControllerTest < ActionController::TestCase | |||||
943 | def test_bulk_edit_status |
|
946 | def test_bulk_edit_status | |
944 | @request.session[:user_id] = 2 |
|
947 | @request.session[:user_id] = 2 | |
945 | # update issues priority |
|
948 | # update issues priority | |
946 |
post :bulk_edit, :ids => [1, 2], : |
|
949 | post :bulk_edit, :ids => [1, 2], :notes => 'Bulk editing status', | |
947 |
: |
|
950 | :issue => {:priority_id => '', | |
948 |
: |
|
951 | :assigned_to_id => '', | |
949 |
|
|
952 | :status_id => '5'} | |
|
953 | ||||
950 | assert_response 302 |
|
954 | assert_response 302 | |
951 | issue = Issue.find(1) |
|
955 | issue = Issue.find(1) | |
952 | assert issue.closed? |
|
956 | assert issue.closed? | |
@@ -955,10 +959,11 class IssuesControllerTest < ActionController::TestCase | |||||
955 | def test_bulk_edit_custom_field |
|
959 | def test_bulk_edit_custom_field | |
956 | @request.session[:user_id] = 2 |
|
960 | @request.session[:user_id] = 2 | |
957 | # update issues priority |
|
961 | # update issues priority | |
958 |
post :bulk_edit, :ids => [1, 2], : |
|
962 | post :bulk_edit, :ids => [1, 2], :notes => 'Bulk editing custom field', | |
959 |
: |
|
963 | :issue => {:priority_id => '', | |
960 |
|
|
964 | :assigned_to_id => '', | |
961 |
|
|
965 | :custom_field_values => {'2' => '777'}} | |
|
966 | ||||
962 | assert_response 302 |
|
967 | assert_response 302 | |
963 |
|
968 | |||
964 | issue = Issue.find(1) |
|
969 | issue = Issue.find(1) | |
@@ -973,7 +978,7 class IssuesControllerTest < ActionController::TestCase | |||||
973 | assert_not_nil Issue.find(2).assigned_to |
|
978 | assert_not_nil Issue.find(2).assigned_to | |
974 | @request.session[:user_id] = 2 |
|
979 | @request.session[:user_id] = 2 | |
975 | # unassign issues |
|
980 | # unassign issues | |
976 |
|
|
981 | post :bulk_edit, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'} | |
977 | assert_response 302 |
|
982 | assert_response 302 | |
978 | # check that the issues were updated |
|
983 | # check that the issues were updated | |
979 | assert_nil Issue.find(2).assigned_to |
|
984 | assert_nil Issue.find(2).assigned_to | |
@@ -982,9 +987,7 class IssuesControllerTest < ActionController::TestCase | |||||
982 | def test_post_bulk_edit_should_allow_fixed_version_to_be_set_to_a_subproject |
|
987 | def test_post_bulk_edit_should_allow_fixed_version_to_be_set_to_a_subproject | |
983 | @request.session[:user_id] = 2 |
|
988 | @request.session[:user_id] = 2 | |
984 |
|
989 | |||
985 | post :bulk_edit, |
|
990 | post :bulk_edit, :ids => [1,2], :issue => {:fixed_version_id => 4} | |
986 | :ids => [1,2], |
|
|||
987 | :fixed_version_id => 4 |
|
|||
988 |
|
991 | |||
989 | assert_response :redirect |
|
992 | assert_response :redirect | |
990 | issues = Issue.find([1,2]) |
|
993 | issues = Issue.find([1,2]) |
General Comments 0
You need to be logged in to leave comments.
Login now