@@ -260,29 +260,16 class IssuesController < ApplicationController | |||
|
260 | 260 | # Bulk edit a set of issues |
|
261 | 261 | def bulk_edit |
|
262 | 262 | if request.post? |
|
263 | tracker = params[:tracker_id].blank? ? nil : @project.trackers.find_by_id(params[:tracker_id]) | |
|
264 | status = params[:status_id].blank? ? nil : IssueStatus.find_by_id(params[:status_id]) | |
|
265 | priority = params[:priority_id].blank? ? nil : IssuePriority.find_by_id(params[:priority_id]) | |
|
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 | }) | |
|
263 | attributes = (params[:issue] || {}).reject {|k,v| v.blank?} | |
|
264 | attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} | |
|
265 | attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values] | |
|
282 | 266 | |
|
283 |
unsaved_issue_ids = [] |
|
|
267 | unsaved_issue_ids = [] | |
|
284 | 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 | 273 | # Keep unsaved issue ids to display them in flash error |
|
287 | 274 | unsaved_issue_ids << issue.id |
|
288 | 275 | end |
@@ -67,9 +67,9 module CustomFieldsHelper | |||
|
67 | 67 | custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value) |
|
68 | 68 | end |
|
69 | 69 | |
|
70 | def custom_field_tag_for_bulk_edit(custom_field) | |
|
71 | field_name = "custom_field_values[#{custom_field.id}]" | |
|
72 | field_id = "custom_field_values_#{custom_field.id}" | |
|
70 | def custom_field_tag_for_bulk_edit(name, custom_field) | |
|
71 | field_name = "#{name}[custom_field_values][#{custom_field.id}]" | |
|
72 | field_id = "#{name}_custom_field_values_#{custom_field.id}" | |
|
73 | 73 | case custom_field.field_format |
|
74 | 74 | when "date" |
|
75 | 75 | text_field_tag(field_name, '', :id => field_id, :size => 10) + |
@@ -136,24 +136,6 class Issue < ActiveRecord::Base | |||
|
136 | 136 | end |
|
137 | 137 | return issue |
|
138 | 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 | 140 | def priority_id=(pid) |
|
159 | 141 | self.priority = nil |
@@ -206,7 +188,13 class Issue < ActiveRecord::Base | |||
|
206 | 188 | # TODO: move workflow/permission checks from controllers to here |
|
207 | 189 | def safe_attributes=(attrs, user=User.current) |
|
208 | 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 | 198 | end |
|
211 | 199 | |
|
212 | 200 | def done_ratio |
@@ -11,39 +11,39 | |||
|
11 | 11 | <div class="splitcontentleft"> |
|
12 | 12 | <p> |
|
13 | 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 | 15 | </p> |
|
16 | 16 | <% if @available_statuses.any? %> |
|
17 | 17 | <p> |
|
18 | 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 | 20 | </p> |
|
21 | 21 | <% end %> |
|
22 | 22 | <p> |
|
23 | 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 | 25 | </p> |
|
26 | 26 | <p> |
|
27 | 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 | 29 | content_tag('option', l(:label_nobody), :value => 'none') + |
|
30 | 30 | options_from_collection_for_select(@project.assignable_users, :id, :name)) %> |
|
31 | 31 | </p> |
|
32 | 32 | <p> |
|
33 | 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 | 35 | content_tag('option', l(:label_none), :value => 'none') + |
|
36 | 36 | options_from_collection_for_select(@project.issue_categories, :id, :name)) %> |
|
37 | 37 | </p> |
|
38 | 38 | <p> |
|
39 | 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 | 41 | content_tag('option', l(:label_none), :value => 'none') + |
|
42 | 42 | version_options_for_select(@project.shared_versions.open)) %> |
|
43 | 43 | </p> |
|
44 | 44 | |
|
45 | 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 | 47 | <% end %> |
|
48 | 48 | |
|
49 | 49 | <%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %> |
@@ -52,16 +52,16 | |||
|
52 | 52 | <div class="splitcontentright"> |
|
53 | 53 | <p> |
|
54 | 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 | 56 | </p> |
|
57 | 57 | <p> |
|
58 | 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 | 60 | </p> |
|
61 | 61 | <% if Issue.use_field_for_done_ratio? %> |
|
62 | 62 | <p> |
|
63 | 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 | 65 | </p> |
|
66 | 66 | <% end %> |
|
67 | 67 | </div> |
@@ -899,20 +899,21 class IssuesControllerTest < ActionController::TestCase | |||
|
899 | 899 | field = CustomField.find(9) |
|
900 | 900 | assert !field.is_for_all? |
|
901 | 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 | 904 | # System wide custom field |
|
905 | 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 | 907 | end |
|
908 | 908 | |
|
909 | 909 | def test_bulk_edit |
|
910 | 910 | @request.session[:user_id] = 2 |
|
911 | 911 | # update issues priority |
|
912 |
post :bulk_edit, :ids => [1, 2], : |
|
|
913 |
: |
|
|
914 |
|
|
|
915 |
|
|
|
912 | post :bulk_edit, :ids => [1, 2], :notes => 'Bulk editing', | |
|
913 | :issue => {:priority_id => 7, | |
|
914 | :assigned_to_id => '', | |
|
915 | :custom_field_values => {'2' => ''}} | |
|
916 | ||
|
916 | 917 | assert_response 302 |
|
917 | 918 | # check that the issues were updated |
|
918 | 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 | 931 | post(:bulk_edit, |
|
931 | 932 | { |
|
932 | 933 | :ids => [1, 2], |
|
933 | :priority_id => 7, | |
|
934 |
: |
|
|
935 | :custom_field_values => {'2' => ''}, | |
|
936 | :notes => 'Bulk editing' | |
|
934 | :notes => 'Bulk editing', | |
|
935 | :issue => { | |
|
936 | :priority_id => 7, | |
|
937 | :assigned_to_id => '', | |
|
938 | :custom_field_values => {'2' => ''} | |
|
939 | } | |
|
937 | 940 | }) |
|
938 | 941 | |
|
939 | 942 | assert_response 302 |
@@ -943,10 +946,11 class IssuesControllerTest < ActionController::TestCase | |||
|
943 | 946 | def test_bulk_edit_status |
|
944 | 947 | @request.session[:user_id] = 2 |
|
945 | 948 | # update issues priority |
|
946 |
post :bulk_edit, :ids => [1, 2], : |
|
|
947 |
: |
|
|
948 |
: |
|
|
949 |
|
|
|
949 | post :bulk_edit, :ids => [1, 2], :notes => 'Bulk editing status', | |
|
950 | :issue => {:priority_id => '', | |
|
951 | :assigned_to_id => '', | |
|
952 | :status_id => '5'} | |
|
953 | ||
|
950 | 954 | assert_response 302 |
|
951 | 955 | issue = Issue.find(1) |
|
952 | 956 | assert issue.closed? |
@@ -955,10 +959,11 class IssuesControllerTest < ActionController::TestCase | |||
|
955 | 959 | def test_bulk_edit_custom_field |
|
956 | 960 | @request.session[:user_id] = 2 |
|
957 | 961 | # update issues priority |
|
958 |
post :bulk_edit, :ids => [1, 2], : |
|
|
959 |
: |
|
|
960 |
|
|
|
961 |
|
|
|
962 | post :bulk_edit, :ids => [1, 2], :notes => 'Bulk editing custom field', | |
|
963 | :issue => {:priority_id => '', | |
|
964 | :assigned_to_id => '', | |
|
965 | :custom_field_values => {'2' => '777'}} | |
|
966 | ||
|
962 | 967 | assert_response 302 |
|
963 | 968 | |
|
964 | 969 | issue = Issue.find(1) |
@@ -973,7 +978,7 class IssuesControllerTest < ActionController::TestCase | |||
|
973 | 978 | assert_not_nil Issue.find(2).assigned_to |
|
974 | 979 | @request.session[:user_id] = 2 |
|
975 | 980 | # unassign issues |
|
976 |
|
|
|
981 | post :bulk_edit, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'} | |
|
977 | 982 | assert_response 302 |
|
978 | 983 | # check that the issues were updated |
|
979 | 984 | assert_nil Issue.find(2).assigned_to |
@@ -982,9 +987,7 class IssuesControllerTest < ActionController::TestCase | |||
|
982 | 987 | def test_post_bulk_edit_should_allow_fixed_version_to_be_set_to_a_subproject |
|
983 | 988 | @request.session[:user_id] = 2 |
|
984 | 989 | |
|
985 | post :bulk_edit, | |
|
986 | :ids => [1,2], | |
|
987 | :fixed_version_id => 4 | |
|
990 | post :bulk_edit, :ids => [1,2], :issue => {:fixed_version_id => 4} | |
|
988 | 991 | |
|
989 | 992 | assert_response :redirect |
|
990 | 993 | issues = Issue.find([1,2]) |
General Comments 0
You need to be logged in to leave comments.
Login now