##// END OF EJS Templates
Copy issues via bulk update action....
Jean-Philippe Lang -
r8418:065376c160b0
parent child
Show More
@@ -206,9 +206,11 class IssuesController < ApplicationController
206 end
206 end
207 end
207 end
208
208
209 # Bulk edit a set of issues
209 # Bulk edit/copy a set of issues
210 def bulk_edit
210 def bulk_edit
211 @issues.sort!
211 @issues.sort!
212 @copy = params[:copy].present?
213 @notes = params[:notes]
212
214
213 if User.current.allowed_to?(:move_issues, @projects)
215 if User.current.allowed_to?(:move_issues, @projects)
214 @allowed_projects = Issue.allowed_target_projects_on_move
216 @allowed_projects = Issue.allowed_target_projects_on_move
@@ -226,18 +228,21 class IssuesController < ApplicationController
226 @assignables = target_projects.map(&:assignable_users).inject{|memo,a| memo & a}
228 @assignables = target_projects.map(&:assignable_users).inject{|memo,a| memo & a}
227 @trackers = target_projects.map(&:trackers).inject{|memo,t| memo & t}
229 @trackers = target_projects.map(&:trackers).inject{|memo,t| memo & t}
228
230
229 @notes = params[:notes]
230 render :layout => false if request.xhr?
231 render :layout => false if request.xhr?
231 end
232 end
232
233
233 def bulk_update
234 def bulk_update
234 @issues.sort!
235 @issues.sort!
236 @copy = params[:copy].present?
235 attributes = parse_params_for_bulk_issue_attributes(params)
237 attributes = parse_params_for_bulk_issue_attributes(params)
236
238
237 unsaved_issue_ids = []
239 unsaved_issue_ids = []
238 moved_issues = []
240 moved_issues = []
239 @issues.each do |issue|
241 @issues.each do |issue|
240 issue.reload
242 issue.reload
243 if @copy
244 issue = Issue.new.copy_from(issue)
245 end
241 journal = issue.init_journal(User.current, params[:notes])
246 journal = issue.init_journal(User.current, params[:notes])
242 issue.safe_attributes = attributes
247 issue.safe_attributes = attributes
243 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
248 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
@@ -110,7 +110,7
110 <li><%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
110 <li><%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
111 :class => 'icon-duplicate', :disabled => !@can[:copy] %></li>
111 :class => 'icon-duplicate', :disabled => !@can[:copy] %></li>
112 <% end %>
112 <% end %>
113 <li><%= context_menu_link l(:button_copy), new_issue_move_path(:ids => @issues.collect(&:id), :copy_options => {:copy => 't'}),
113 <li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :copy => '1'},
114 :class => 'icon-copy', :disabled => !@can[:move] %></li>
114 :class => 'icon-copy', :disabled => !@can[:move] %></li>
115 <li><%= context_menu_link l(:button_delete), issues_path(:ids => @issues.collect(&:id), :back_url => @back),
115 <li><%= context_menu_link l(:button_delete), issues_path(:ids => @issues.collect(&:id), :back_url => @back),
116 :method => :delete, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %></li>
116 :method => :delete, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %></li>
@@ -3,6 +3,6
3 <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %>
3 <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %>
4 <%= watcher_tag(@issue, User.current) %>
4 <%= watcher_tag(@issue, User.current) %>
5 <%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %>
5 <%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %>
6 <%= link_to_if_authorized l(:button_copy), {:controller => 'issue_moves', :action => 'new', :id => @issue, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy' %>
6 <%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'bulk_edit', :id => @issue, :copy => '1'}, :class => 'icon icon-copy' %>
7 <%= link_to l(:button_delete), issue_path(@issue), :confirm => issues_destroy_confirmation_message(@issue), :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %>
7 <%= link_to l(:button_delete), issue_path(@issue), :confirm => issues_destroy_confirmation_message(@issue), :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %>
8 </div>
8 </div>
@@ -1,4 +1,4
1 <h2><%= l(:label_bulk_edit_selected_issues) %></h2>
1 <h2><%= @copy ? l(:button_copy) : l(:label_bulk_edit_selected_issues) %></h2>
2
2
3 <ul><%= @issues.collect {|i|
3 <ul><%= @issues.collect {|i|
4 content_tag('li',
4 content_tag('li',
@@ -102,7 +102,11
102 </div>
102 </div>
103
103
104 <p>
104 <p>
105 <% if @target_project %>
105 <% if @copy %>
106 <%= hidden_field_tag 'copy', '1' %>
107 <%= submit_tag l(:button_copy) %>
108 <%= submit_tag l(:button_copy_and_follow), :name => 'follow' %>
109 <% elsif @target_project %>
106 <%= submit_tag l(:button_move) %>
110 <%= submit_tag l(:button_move) %>
107 <%= submit_tag l(:button_move_and_follow), :name => 'follow' %>
111 <%= submit_tag l(:button_move_and_follow), :name => 'follow' %>
108 <% else %>
112 <% else %>
@@ -40,9 +40,6 ActionController::Routing::Routes.draw do |map|
40 end
40 end
41 end
41 end
42
42
43 map.resources :issue_moves, :only => [:new, :create],
44 :path_prefix => '/issues', :as => 'move'
45
46 # Misc issue routes. TODO: move into resources
43 # Misc issue routes. TODO: move into resources
47 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes',
44 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes',
48 :action => 'issues', :conditions => { :method => :get }
45 :action => 'issues', :conditions => { :method => :get }
@@ -76,7 +76,7 Redmine::AccessControl.map do |map|
76 map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]}
76 map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]}
77 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
77 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
78 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
78 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
79 map.permission :move_issues, {:issue_moves => [:new, :create]}, :require => :loggedin
79 map.permission :move_issues, {:issues => [:bulk_edit, :bulk_update]}, :require => :loggedin
80 map.permission :delete_issues, {:issues => :destroy}, :require => :member
80 map.permission :delete_issues, {:issues => :destroy}, :require => :member
81 # Queries
81 # Queries
82 map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member
82 map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member
@@ -47,7 +47,7 class ContextMenusControllerTest < ActionController::TestCase
47 :attributes => { :href => '/projects/ecookbook/issues/1/copy',
47 :attributes => { :href => '/projects/ecookbook/issues/1/copy',
48 :class => 'icon-duplicate' }
48 :class => 'icon-duplicate' }
49 assert_tag :tag => 'a', :content => 'Copy',
49 assert_tag :tag => 'a', :content => 'Copy',
50 :attributes => { :href => '/issues/move/new?copy_options%5Bcopy%5D=t&amp;ids%5B%5D=1',
50 :attributes => { :href => '/issues/bulk_edit?copy=1&amp;ids%5B%5D=1',
51 :class => 'icon-copy' }
51 :class => 'icon-copy' }
52 assert_no_tag :tag => 'a', :content => 'Move'
52 assert_no_tag :tag => 'a', :content => 'Move'
53 assert_tag :tag => 'a', :content => 'Delete',
53 assert_tag :tag => 'a', :content => 'Delete',
@@ -86,7 +86,7 class ContextMenusControllerTest < ActionController::TestCase
86 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bassigned_to_id%5D=3",
86 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bassigned_to_id%5D=3",
87 :class => '' }
87 :class => '' }
88 assert_tag :tag => 'a', :content => 'Copy',
88 assert_tag :tag => 'a', :content => 'Copy',
89 :attributes => { :href => "/issues/move/new?copy_options%5Bcopy%5D=t&amp;#{ids}",
89 :attributes => { :href => "/issues/bulk_edit?copy=1&amp;#{ids}",
90 :class => 'icon-copy' }
90 :class => 'icon-copy' }
91 assert_no_tag :tag => 'a', :content => 'Move'
91 assert_no_tag :tag => 'a', :content => 'Move'
92 assert_tag :tag => 'a', :content => 'Delete',
92 assert_tag :tag => 'a', :content => 'Delete',
@@ -2319,6 +2319,87 class IssuesControllerTest < ActionController::TestCase
2319 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
2319 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
2320 end
2320 end
2321
2321
2322 def test_bulk_copy_to_another_project
2323 @request.session[:user_id] = 2
2324 assert_difference 'Issue.count', 2 do
2325 assert_no_difference 'Project.find(1).issues.count' do
2326 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}, :copy => '1'
2327 end
2328 end
2329 assert_redirected_to '/projects/ecookbook/issues'
2330 end
2331
2332 def test_bulk_copy_should_allow_not_changing_the issue_attributes
2333 @request.session[:user_id] = 2
2334 issue_before_move = Issue.find(1)
2335 assert_difference 'Issue.count', 1 do
2336 assert_no_difference 'Project.find(1).issues.count' do
2337 post :bulk_update, :ids => [1], :copy => '1',
2338 :issue => {
2339 :project_id => '2', :tracker_id => '', :assigned_to_id => '',
2340 :status_id => '', :start_date => '', :due_date => ''
2341 }
2342 end
2343 end
2344 issue_after_move = Issue.first(:order => 'id desc', :conditions => {:project_id => 2})
2345 assert_equal issue_before_move.tracker_id, issue_after_move.tracker_id
2346 assert_equal issue_before_move.status_id, issue_after_move.status_id
2347 assert_equal issue_before_move.assigned_to_id, issue_after_move.assigned_to_id
2348 end
2349
2350 def test_bulk_copy_should_allow_changing_the_issue_attributes
2351 # Fixes random test failure with Mysql
2352 # where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2})
2353 # doesn't return the expected results
2354 Issue.delete_all("project_id=2")
2355
2356 @request.session[:user_id] = 2
2357 assert_difference 'Issue.count', 2 do
2358 assert_no_difference 'Project.find(1).issues.count' do
2359 post :bulk_update, :ids => [1, 2], :copy => '1',
2360 :issue => {
2361 :project_id => '2', :tracker_id => '', :assigned_to_id => '4',
2362 :status_id => '3', :start_date => '2009-12-01', :due_date => '2009-12-31'
2363 }
2364 end
2365 end
2366
2367 copied_issues = Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2})
2368 assert_equal 2, copied_issues.size
2369 copied_issues.each do |issue|
2370 assert_equal 2, issue.project_id, "Project is incorrect"
2371 assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect"
2372 assert_equal 3, issue.status_id, "Status is incorrect"
2373 assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
2374 assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
2375 end
2376 end
2377
2378 def test_bulk_copy_should_allow_adding_a_note
2379 @request.session[:user_id] = 2
2380 assert_difference 'Issue.count', 1 do
2381 post :bulk_update, :ids => [1], :copy => '1',
2382 :notes => 'Copying one issue',
2383 :issue => {
2384 :project_id => '', :tracker_id => '', :assigned_to_id => '4',
2385 :status_id => '3', :start_date => '2009-12-01', :due_date => '2009-12-31'
2386 }
2387 end
2388
2389 issue = Issue.first(:order => 'id DESC')
2390 assert_equal 1, issue.journals.size
2391 journal = issue.journals.first
2392 assert_equal 0, journal.details.size
2393 assert_equal 'Copying one issue', journal.notes
2394 end
2395
2396 def test_bulk_copy_to_another_project_should_follow_when_needed
2397 @request.session[:user_id] = 2
2398 post :bulk_update, :ids => [1], :copy => '1', :issue => {:project_id => 2}, :follow => '1'
2399 issue = Issue.first(:order => 'id DESC')
2400 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
2401 end
2402
2322 def test_destroy_issue_with_no_time_entries
2403 def test_destroy_issue_with_no_time_entries
2323 assert_nil TimeEntry.find_by_issue_id(2)
2404 assert_nil TimeEntry.find_by_issue_id(2)
2324 @request.session[:user_id] = 2
2405 @request.session[:user_id] = 2
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now