##// END OF EJS Templates
Use the regular issue form to copy a single issue....
Jean-Philippe Lang -
r8432:121bc44cc504
parent child
Show More
@@ -158,7 +158,7 class IssuesController < ApplicationController
158 format.html {
158 format.html {
159 render_attachment_warning_if_needed(@issue)
159 render_attachment_warning_if_needed(@issue)
160 flash[:notice] = l(:notice_issue_successful_create, :id => "<a href='#{issue_path(@issue)}'>##{@issue.id}</a>")
160 flash[:notice] = l(:notice_issue_successful_create, :id => "<a href='#{issue_path(@issue)}'>##{@issue.id}</a>")
161 redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
161 redirect_to(params[:continue] ? { :action => 'new', :project_id => @issue.project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
162 { :action => 'show', :id => @issue })
162 { :action => 'show', :id => @issue })
163 }
163 }
164 format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
164 format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
@@ -127,12 +127,14 class Issue < ActiveRecord::Base
127 (project && tracker) ? (project.all_issue_custom_fields & tracker.custom_fields.all) : []
127 (project && tracker) ? (project.all_issue_custom_fields & tracker.custom_fields.all) : []
128 end
128 end
129
129
130 # Copies attributes from another issue, arg can be an id or an Issue
130 def copy_from(arg)
131 def copy_from(arg)
131 issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg)
132 issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg)
132 self.attributes = issue.attributes.dup.except("id", "root_id", "parent_id", "lft", "rgt", "created_on", "updated_on")
133 self.attributes = issue.attributes.dup.except("id", "root_id", "parent_id", "lft", "rgt", "created_on", "updated_on")
133 self.custom_field_values = issue.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h}
134 self.custom_field_values = issue.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h}
134 self.status = issue.status
135 self.status = issue.status
135 self.author = User.current
136 self.author = User.current
137 @copied_from = issue
136 self
138 self
137 end
139 end
138
140
@@ -143,6 +145,11 class Issue < ActiveRecord::Base
143 copy
145 copy
144 end
146 end
145
147
148 # Returns true if the issue is a copy
149 def copy?
150 @copied_from.present?
151 end
152
146 # Moves/copies an issue to a new project and tracker
153 # Moves/copies an issue to a new project and tracker
147 # Returns the moved/copied issue on success, false on failure
154 # Returns the moved/copied issue on success, false on failure
148 def move_to_project(new_project, new_tracker=nil, options={})
155 def move_to_project(new_project, new_tracker=nil, options={})
@@ -255,7 +262,9 class Issue < ActiveRecord::Base
255
262
256 safe_attributes 'project_id',
263 safe_attributes 'project_id',
257 :if => lambda {|issue, user|
264 :if => lambda {|issue, user|
258 if user.allowed_to?(:move_issues, issue.project)
265 if issue.new_record?
266 issue.copy?
267 elsif user.allowed_to?(:move_issues, issue.project)
259 projects = Issue.allowed_target_projects_on_move(user)
268 projects = Issue.allowed_target_projects_on_move(user)
260 projects.include?(issue.project) && projects.size > 1
269 projects.include?(issue.project) && projects.size > 1
261 end
270 end
@@ -107,11 +107,12
107 <% end %>
107 <% end %>
108
108
109 <% if @issue.present? %>
109 <% if @issue.present? %>
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_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
111 :class => 'icon-duplicate', :disabled => !@can[:copy] %></li>
111 :class => 'icon-copy', :disabled => !@can[:copy] %></li>
112 <% end %>
112 <% else %>
113 <li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :copy => '1'},
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 <% end %>
115 <li><%= context_menu_link l(:button_delete), issues_path(:ids => @issues.collect(&:id), :back_url => @back),
116 <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>
117 :method => :delete, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %></li>
117
118
@@ -2,7 +2,6
2 <%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
2 <%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
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_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue}, :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) %>
6 <%= 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>
7 </div>
@@ -7,7 +7,7
7 </p>
7 </p>
8 <% end %>
8 <% end %>
9
9
10 <% if !@issue.new_record? && @issue.safe_attribute?('project_id') %>
10 <% if @issue.safe_attribute? 'project_id' %>
11 <p><%= f.select :project_id, project_tree_options_for_select(Issue.allowed_target_projects_on_move, :selected => @issue.project), :required => true %></p>
11 <p><%= f.select :project_id, project_tree_options_for_select(Issue.allowed_target_projects_on_move, :selected => @issue.project), :required => true %></p>
12 <%= observe_field :issue_project_id, :url => project_issue_form_path(@project, :id => @issue, :project_change => '1'),
12 <%= observe_field :issue_project_id, :url => project_issue_form_path(@project, :id => @issue, :project_change => '1'),
13 :with => "Form.serialize('issue-form')" %>
13 :with => "Form.serialize('issue-form')" %>
@@ -5,8 +5,11
5 <% labelled_form_for @issue, :url => project_issues_path(@project),
5 <% labelled_form_for @issue, :url => project_issues_path(@project),
6 :html => {:id => 'issue-form', :multipart => true} do |f| %>
6 :html => {:id => 'issue-form', :multipart => true} do |f| %>
7 <%= error_messages_for 'issue' %>
7 <%= error_messages_for 'issue' %>
8 <%= hidden_field_tag 'copy_from', params[:copy_from] if params[:copy_from] %>
8 <div class="box tabular">
9 <div class="box tabular">
10 <div id="all_attributes">
9 <%= render :partial => 'issues/form', :locals => {:f => f} %>
11 <%= render :partial => 'issues/form', :locals => {:f => f} %>
12 </div>
10
13
11 <p id="attachments_form"><%= label_tag('attachments[1][file]', l(:label_attachment_plural))%><%= render :partial => 'attachments/form' %></p>
14 <p id="attachments_form"><%= label_tag('attachments[1][file]', l(:label_attachment_plural))%><%= render :partial => 'attachments/form' %></p>
12
15
@@ -43,11 +43,8 class ContextMenusControllerTest < ActionController::TestCase
43 assert_tag :tag => 'a', :content => 'Dave Lopper',
43 assert_tag :tag => 'a', :content => 'Dave Lopper',
44 :attributes => { :href => '/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bassigned_to_id%5D=3',
44 :attributes => { :href => '/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bassigned_to_id%5D=3',
45 :class => '' }
45 :class => '' }
46 assert_tag :tag => 'a', :content => 'Duplicate',
47 :attributes => { :href => '/projects/ecookbook/issues/1/copy',
48 :class => 'icon-duplicate' }
49 assert_tag :tag => 'a', :content => 'Copy',
46 assert_tag :tag => 'a', :content => 'Copy',
50 :attributes => { :href => '/issues/bulk_edit?copy=1&amp;ids%5B%5D=1',
47 :attributes => { :href => '/projects/ecookbook/issues/1/copy',
51 :class => 'icon-copy' }
48 :class => 'icon-copy' }
52 assert_no_tag :tag => 'a', :content => 'Move'
49 assert_no_tag :tag => 'a', :content => 'Move'
53 assert_tag :tag => 'a', :content => 'Delete',
50 assert_tag :tag => 'a', :content => 'Delete',
@@ -1571,13 +1571,63 class IssuesControllerTest < ActionController::TestCase
1571 end
1571 end
1572 end
1572 end
1573
1573
1574 def test_copy_issue
1574 def test_new_as_copy
1575 @request.session[:user_id] = 2
1575 @request.session[:user_id] = 2
1576 get :new, :project_id => 1, :copy_from => 1
1576 get :new, :project_id => 1, :copy_from => 1
1577
1578 assert_response :success
1577 assert_template 'new'
1579 assert_template 'new'
1580
1578 assert_not_nil assigns(:issue)
1581 assert_not_nil assigns(:issue)
1579 orig = Issue.find(1)
1582 orig = Issue.find(1)
1583 assert_equal 1, assigns(:issue).project_id
1580 assert_equal orig.subject, assigns(:issue).subject
1584 assert_equal orig.subject, assigns(:issue).subject
1585 assert assigns(:issue).copy?
1586
1587 assert_tag 'form', :attributes => {:id => 'issue-form', :action => '/projects/ecookbook/issues'}
1588 assert_tag 'select', :attributes => {:name => 'issue[project_id]'}
1589 assert_tag 'select', :attributes => {:name => 'issue[project_id]'},
1590 :child => {:tag => 'option', :attributes => {:value => '1', :selected => 'selected'}, :content => 'eCookbook'}
1591 assert_tag 'select', :attributes => {:name => 'issue[project_id]'},
1592 :child => {:tag => 'option', :attributes => {:value => '2', :selected => nil}, :content => 'OnlineStore'}
1593 assert_tag 'input', :attributes => {:name => 'copy_from', :value => '1'}
1594 end
1595
1596 def test_create_as_copy_on_different_project
1597 @request.session[:user_id] = 2
1598 assert_difference 'Issue.count' do
1599 post :create, :project_id => 1, :copy_from => 1,
1600 :issue => {:project_id => '2', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
1601
1602 assert_not_nil assigns(:issue)
1603 assert assigns(:issue).copy?
1604 end
1605 issue = Issue.first(:order => 'id DESC')
1606 assert_redirected_to "/issues/#{issue.id}"
1607
1608 assert_equal 2, issue.project_id
1609 assert_equal 3, issue.tracker_id
1610 assert_equal 'Copy', issue.subject
1611 end
1612
1613 def test_create_as_copy_with_failure
1614 @request.session[:user_id] = 2
1615 post :create, :project_id => 1, :copy_from => 1,
1616 :issue => {:project_id => '2', :tracker_id => '3', :status_id => '1', :subject => ''}
1617
1618 assert_response :success
1619 assert_template 'new'
1620
1621 assert_not_nil assigns(:issue)
1622 assert assigns(:issue).copy?
1623
1624 assert_tag 'form', :attributes => {:id => 'issue-form', :action => '/projects/ecookbook/issues'}
1625 assert_tag 'select', :attributes => {:name => 'issue[project_id]'}
1626 assert_tag 'select', :attributes => {:name => 'issue[project_id]'},
1627 :child => {:tag => 'option', :attributes => {:value => '1', :selected => nil}, :content => 'eCookbook'}
1628 assert_tag 'select', :attributes => {:name => 'issue[project_id]'},
1629 :child => {:tag => 'option', :attributes => {:value => '2', :selected => 'selected'}, :content => 'OnlineStore'}
1630 assert_tag 'input', :attributes => {:name => 'copy_from', :value => '1'}
1581 end
1631 end
1582
1632
1583 def test_get_edit
1633 def test_get_edit
@@ -388,6 +388,7 class IssueTest < ActiveSupport::TestCase
388
388
389 def test_copy
389 def test_copy
390 issue = Issue.new.copy_from(1)
390 issue = Issue.new.copy_from(1)
391 assert issue.copy?
391 assert issue.save
392 assert issue.save
392 issue.reload
393 issue.reload
393 orig = Issue.find(1)
394 orig = Issue.find(1)
General Comments 0
You need to be logged in to leave comments. Login now