@@ -206,9 +206,11 class IssuesController < ApplicationController | |||
|
206 | 206 | end |
|
207 | 207 | end |
|
208 | 208 | |
|
209 | # Bulk edit a set of issues | |
|
209 | # Bulk edit/copy a set of issues | |
|
210 | 210 | def bulk_edit |
|
211 | 211 | @issues.sort! |
|
212 | @copy = params[:copy].present? | |
|
213 | @notes = params[:notes] | |
|
212 | 214 | |
|
213 | 215 | if User.current.allowed_to?(:move_issues, @projects) |
|
214 | 216 | @allowed_projects = Issue.allowed_target_projects_on_move |
@@ -226,18 +228,21 class IssuesController < ApplicationController | |||
|
226 | 228 | @assignables = target_projects.map(&:assignable_users).inject{|memo,a| memo & a} |
|
227 | 229 | @trackers = target_projects.map(&:trackers).inject{|memo,t| memo & t} |
|
228 | 230 | |
|
229 | @notes = params[:notes] | |
|
230 | 231 | render :layout => false if request.xhr? |
|
231 | 232 | end |
|
232 | 233 | |
|
233 | 234 | def bulk_update |
|
234 | 235 | @issues.sort! |
|
236 | @copy = params[:copy].present? | |
|
235 | 237 | attributes = parse_params_for_bulk_issue_attributes(params) |
|
236 | 238 | |
|
237 | 239 | unsaved_issue_ids = [] |
|
238 | 240 | moved_issues = [] |
|
239 | 241 | @issues.each do |issue| |
|
240 | 242 | issue.reload |
|
243 | if @copy | |
|
244 | issue = Issue.new.copy_from(issue) | |
|
245 | end | |
|
241 | 246 | journal = issue.init_journal(User.current, params[:notes]) |
|
242 | 247 | issue.safe_attributes = attributes |
|
243 | 248 | call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue }) |
@@ -110,7 +110,7 | |||
|
110 | 110 | <li><%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue}, |
|
111 | 111 | :class => 'icon-duplicate', :disabled => !@can[:copy] %></li> |
|
112 | 112 | <% end %> |
|
113 |
<li><%= context_menu_link l(:button_copy), |
|
|
113 | <li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :copy => '1'}, | |
|
114 | 114 | :class => 'icon-copy', :disabled => !@can[:move] %></li> |
|
115 | 115 | <li><%= context_menu_link l(:button_delete), issues_path(:ids => @issues.collect(&:id), :back_url => @back), |
|
116 | 116 | :method => :delete, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %></li> |
@@ -3,6 +3,6 | |||
|
3 | 3 | <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %> |
|
4 | 4 | <%= watcher_tag(@issue, User.current) %> |
|
5 | 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 |
|
|
6 | <%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'bulk_edit', :id => @issue, :copy => '1'}, :class => 'icon icon-copy' %> | |
|
7 | 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 | 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 | 3 | <ul><%= @issues.collect {|i| |
|
4 | 4 | content_tag('li', |
@@ -102,7 +102,11 | |||
|
102 | 102 | </div> |
|
103 | 103 | |
|
104 | 104 | <p> |
|
105 |
<% if @ |
|
|
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 | 110 | <%= submit_tag l(:button_move) %> |
|
107 | 111 | <%= submit_tag l(:button_move_and_follow), :name => 'follow' %> |
|
108 | 112 | <% else %> |
@@ -40,9 +40,6 ActionController::Routing::Routes.draw do |map| | |||
|
40 | 40 | end |
|
41 | 41 | end |
|
42 | 42 | |
|
43 | map.resources :issue_moves, :only => [:new, :create], | |
|
44 | :path_prefix => '/issues', :as => 'move' | |
|
45 | ||
|
46 | 43 | # Misc issue routes. TODO: move into resources |
|
47 | 44 | map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', |
|
48 | 45 | :action => 'issues', :conditions => { :method => :get } |
@@ -76,7 +76,7 Redmine::AccessControl.map do |map| | |||
|
76 | 76 | map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]} |
|
77 | 77 | map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin |
|
78 | 78 | map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin |
|
79 |
map.permission :move_issues, {:issue |
|
|
79 | map.permission :move_issues, {:issues => [:bulk_edit, :bulk_update]}, :require => :loggedin | |
|
80 | 80 | map.permission :delete_issues, {:issues => :destroy}, :require => :member |
|
81 | 81 | # Queries |
|
82 | 82 | map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member |
@@ -47,7 +47,7 class ContextMenusControllerTest < ActionController::TestCase | |||
|
47 | 47 | :attributes => { :href => '/projects/ecookbook/issues/1/copy', |
|
48 | 48 | :class => 'icon-duplicate' } |
|
49 | 49 | assert_tag :tag => 'a', :content => 'Copy', |
|
50 |
:attributes => { :href => '/issues/ |
|
|
50 | :attributes => { :href => '/issues/bulk_edit?copy=1&ids%5B%5D=1', | |
|
51 | 51 | :class => 'icon-copy' } |
|
52 | 52 | assert_no_tag :tag => 'a', :content => 'Move' |
|
53 | 53 | assert_tag :tag => 'a', :content => 'Delete', |
@@ -86,7 +86,7 class ContextMenusControllerTest < ActionController::TestCase | |||
|
86 | 86 | :attributes => { :href => "/issues/bulk_update?#{ids}&issue%5Bassigned_to_id%5D=3", |
|
87 | 87 | :class => '' } |
|
88 | 88 | assert_tag :tag => 'a', :content => 'Copy', |
|
89 |
:attributes => { :href => "/issues/ |
|
|
89 | :attributes => { :href => "/issues/bulk_edit?copy=1&#{ids}", | |
|
90 | 90 | :class => 'icon-copy' } |
|
91 | 91 | assert_no_tag :tag => 'a', :content => 'Move' |
|
92 | 92 | assert_tag :tag => 'a', :content => 'Delete', |
@@ -2319,6 +2319,87 class IssuesControllerTest < ActionController::TestCase | |||
|
2319 | 2319 | assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier |
|
2320 | 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 | 2403 | def test_destroy_issue_with_no_time_entries |
|
2323 | 2404 | assert_nil TimeEntry.find_by_issue_id(2) |
|
2324 | 2405 | @request.session[:user_id] = 2 |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now