diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 092e1dd00..289b34e24 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -299,29 +299,22 @@ class ProjectsController < ApplicationController # admin is allowed to move issues to any active (visible) project @projects = Project.find(:all, :conditions => Project.visible_by(User.current), :order => 'name') else - User.current.memberships.each {|m| @projects << m.project if m.role.allowed_to?(:controller => 'projects', :action => 'move_issues')} + User.current.memberships.each {|m| @projects << m.project if m.role.allowed_to?(:move_issues)} end # issue can be moved to any tracker @trackers = Tracker.find(:all) if request.post? && params[:new_project_id] && @projects.collect(&:id).include?(params[:new_project_id].to_i) && params[:new_tracker_id] new_project = Project.find_by_id(params[:new_project_id]) - new_tracker = Tracker.find_by_id(params[:new_tracker_id]) - @issues.each do |i| - if new_project && i.project_id != new_project.id - # issue is moved to another project - i.category = nil - i.fixed_version = nil - # delete issue relations - i.relations_from.clear - i.relations_to.clear - i.project = new_project - end - if new_tracker - i.tracker = new_tracker - end - i.save + new_tracker = params[:new_tracker_id].blank? ? nil : Tracker.find_by_id(params[:new_tracker_id]) + unsaved_issue_ids = [] + @issues.each do |issue| + unsaved_issue_ids << issue.id unless issue.move_to(new_project, new_tracker) + end + if unsaved_issue_ids.empty? + flash[:notice] = l(:notice_successful_update) unless @issues.empty? + else + flash[:error] = l(:notice_failed_to_save_issues, unsaved_issue_ids.size, @issues.size, '#' + unsaved_issue_ids.join(', #')) end - flash[:notice] = l(:notice_successful_update) redirect_to :controller => 'issues', :action => 'index', :project_id => @project end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 0d2d6fc0d..60cca4051 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -61,6 +61,32 @@ class Issue < ActiveRecord::Base self end + # Move an issue to a new project and tracker + def move_to(new_project, new_tracker = nil) + transaction do + if new_project && project_id != new_project.id + # delete issue relations + self.relations_from.clear + self.relations_to.clear + # issue is moved to another project + self.category = nil + self.fixed_version = nil + self.project = new_project + end + if new_tracker + self.tracker = new_tracker + end + if save + # Manually update project_id on related time entries + TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id}) + else + rollback_db_transaction + return false + end + end + return true + end + def priority_id=(pid) self.priority = nil write_attribute(:priority_id, pid) diff --git a/app/views/issues/index.rhtml b/app/views/issues/index.rhtml index fa77cb78c..de0fd4add 100644 --- a/app/views/issues/index.rhtml +++ b/app/views/issues/index.rhtml @@ -10,7 +10,7 @@ { :url => { :set_filter => 1 }, :update => "content", :with => "Form.serialize('query_form')" - }, :class => 'icon icon-edit' %> + }, :class => 'icon icon-checked' %> <%= link_to_remote l(:button_clear), { :url => { :set_filter => 1 }, diff --git a/public/images/true.png b/public/images/true.png index 929c605ff..7cac1eb8c 100644 Binary files a/public/images/true.png and b/public/images/true.png differ diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb index 5ddd4bde4..6ffbe0a8b 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -18,7 +18,7 @@ require File.dirname(__FILE__) + '/../test_helper' class IssueTest < Test::Unit::TestCase - fixtures :projects, :users, :members, :trackers, :issue_statuses, :issue_categories, :enumerations, :issues, :custom_fields, :custom_values + fixtures :projects, :users, :members, :trackers, :issue_statuses, :issue_categories, :enumerations, :issues, :custom_fields, :custom_values, :time_entries def test_category_based_assignment issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => Enumeration.get_values('IPRI').first, :subject => 'Assignment test', :description => 'Assignment test', :category_id => 1) @@ -59,4 +59,15 @@ class IssueTest < Test::Unit::TestCase assert issue2.reload.closed? assert issue3.reload.closed? end + + def test_move_to_another_project + issue = Issue.find(1) + assert issue.move_to(Project.find(2)) + issue.reload + assert_equal 2, issue.project_id + # Category removed + assert_nil issue.category + # Make sure time entries were move to the target project + assert_equal 2, issue.time_entries.first.project_id + end end