##// END OF EJS Templates
Allows project to be changed from the regular issue update action (#4769, #9803)....
Jean-Philippe Lang -
r8411:81cf6b234397
parent child
Show More
@@ -135,7 +135,17 class IssuesController < ApplicationController
135 135 def new
136 136 respond_to do |format|
137 137 format.html { render :action => 'new', :layout => !request.xhr? }
138 format.js { render :partial => 'attributes' }
138 format.js {
139 render(:update) { |page|
140 if params[:project_change]
141 page.replace_html 'all_attributes', :partial => 'form'
142 else
143 page.replace_html 'attributes', :partial => 'attributes'
144 end
145 m = User.current.allowed_to?(:log_time, @issue.project) ? 'show' : 'hide'
146 page << "if ($('log_time')) {Element.#{m}('log_time');}"
147 }
148 }
139 149 end
140 150 end
141 151
@@ -274,7 +284,7 private
274 284 end
275 285
276 286 def find_project
277 project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id]
287 project_id = params[:project_id] || (params[:issue] && params[:issue][:project_id])
278 288 @project = Project.find(project_id)
279 289 rescue ActiveRecord::RecordNotFound
280 290 render_404
@@ -147,7 +147,9 class Issue < ActiveRecord::Base
147 147
148 148 issue.init_journal(User.current, options[:notes])
149 149
150 issue.project = new_project
150 # Preserve previous behaviour
151 # #move_to_project doesn't change tracker automatically
152 issue.send :project=, new_project, true
151 153 if new_tracker
152 154 issue.tracker = new_tracker
153 155 end
@@ -169,6 +171,16 class Issue < ActiveRecord::Base
169 171 write_attribute(:priority_id, pid)
170 172 end
171 173
174 def category_id=(cid)
175 self.category = nil
176 write_attribute(:category_id, cid)
177 end
178
179 def fixed_version_id=(vid)
180 self.fixed_version = nil
181 write_attribute(:fixed_version_id, vid)
182 end
183
172 184 def tracker_id=(tid)
173 185 self.tracker = nil
174 186 result = write_attribute(:tracker_id, tid)
@@ -182,11 +194,14 class Issue < ActiveRecord::Base
182 194 end
183 195 end
184 196
185 def project=(project)
197 def project=(project, keep_tracker=false)
186 198 project_was = self.project
187 199 write_attribute(:project_id, project ? project.id : nil)
188 200 association_instance_set('project', project)
189 201 if project_was && project && project_was != project
202 unless keep_tracker || project.trackers.include?(tracker)
203 self.tracker = project.trackers.first
204 end
190 205 # Reassign to the category with same name if any
191 206 if category
192 207 self.category = project.issue_categories.find_by_name(category.name)
@@ -229,6 +244,12 class Issue < ActiveRecord::Base
229 244 write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h)
230 245 end
231 246
247 safe_attributes 'project_id',
248 :if => lambda {|issue, user|
249 projects = Issue.allowed_target_projects_on_move(user)
250 projects.include?(issue.project) && projects.size > 1
251 }
252
232 253 safe_attributes 'tracker_id',
233 254 'status_id',
234 255 'category_id',
@@ -278,7 +299,11 class Issue < ActiveRecord::Base
278 299 attrs = delete_unsafe_attributes(attrs, user)
279 300 return if attrs.empty?
280 301
281 # Tracker must be set before since new_statuses_allowed_to depends on it.
302 # Project and Tracker must be set before since new_statuses_allowed_to depends on it.
303 if p = attrs.delete('project_id')
304 self.project_id = p
305 end
306
282 307 if t = attrs.delete('tracker_id')
283 308 self.tracker_id = t
284 309 end
@@ -725,16 +750,16 class Issue < ActiveRecord::Base
725 750 # End ReportsController extraction
726 751
727 752 # Returns an array of projects that current user can move issues to
728 def self.allowed_target_projects_on_move
753 def self.allowed_target_projects_on_move(user=User.current)
729 754 projects = []
730 if User.current.admin?
755 if user.admin?
731 756 # admin is allowed to move issues to any active (visible) project
732 projects = Project.visible.all
733 elsif User.current.logged?
757 projects = Project.visible(user).all
758 elsif user.logged?
734 759 if Role.non_member.allowed_to?(:move_issues)
735 projects = Project.visible.all
760 projects = Project.visible(user).all
736 761 else
737 User.current.memberships.each {|m| projects << m.project if m.roles.detect {|r| r.allowed_to?(:move_issues)}}
762 user.memberships.each {|m| projects << m.project if m.roles.detect {|r| r.allowed_to?(:move_issues)}}
738 763 end
739 764 end
740 765 projects
@@ -754,7 +779,8 class Issue < ActiveRecord::Base
754 779
755 780 # Move subtasks
756 781 children.each do |child|
757 child.project = project
782 # Change project and keep project
783 child.send :project=, project, true
758 784 unless child.save
759 785 raise ActiveRecord::Rollback
760 786 end
@@ -15,14 +15,14
15 15 <p><%= f.select :assigned_to_id, principals_options_for_select(@issue.assignable_users, @issue.assigned_to), :include_blank => true %></p>
16 16 <% end %>
17 17
18 <% if @issue.safe_attribute?('category_id') && @project.issue_categories.any? %>
19 <p><%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>
18 <% if @issue.safe_attribute?('category_id') && @issue.project.issue_categories.any? %>
19 <p><%= f.select :category_id, (@issue.project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>
20 20 <%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'),
21 21 l(:label_issue_category_new),
22 22 'issue_category[name]',
23 {:controller => 'issue_categories', :action => 'create', :project_id => @project},
23 {:controller => 'issue_categories', :action => 'create', :project_id => @issue.project},
24 24 :title => l(:label_issue_category_new),
25 :tabindex => 199) if authorize_for('issue_categories', 'new') %></p>
25 :tabindex => 199) if User.current.allowed_to?(:manage_categories, @issue.project) %></p>
26 26 <% end %>
27 27
28 28 <% if @issue.safe_attribute?('fixed_version_id') && @issue.assignable_versions.any? %>
@@ -30,9 +30,9
30 30 <%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'),
31 31 l(:label_version_new),
32 32 'version[name]',
33 {:controller => 'versions', :action => 'create', :project_id => @project},
33 {:controller => 'versions', :action => 'create', :project_id => @issue.project},
34 34 :title => l(:label_version_new),
35 :tabindex => 200) if authorize_for('versions', 'new') %>
35 :tabindex => 200) if User.current.allowed_to?(:manage_versions, @issue.project) %>
36 36 </p>
37 37 <% end %>
38 38 </div>
@@ -41,7 +41,7
41 41 <% if @issue.safe_attribute? 'parent_issue_id' %>
42 42 <p id="parent_issue"><%= f.text_field :parent_issue_id, :size => 10 %></p>
43 43 <div id="parent_issue_candidates" class="autocomplete"></div>
44 <%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:id => @issue, :project_id => @project) }')" %>
44 <%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:id => @issue, :project_id => @issue.project) }')" %>
45 45 <% end %>
46 46
47 47 <% if @issue.safe_attribute? 'start_date' %>
@@ -3,7 +3,9
3 3 <div class="box">
4 4 <% if @edit_allowed || !@allowed_statuses.empty? %>
5 5 <fieldset class="tabular"><legend><%= l(:label_change_properties) %></legend>
6 <div id="all_attributes">
6 7 <%= render :partial => 'form', :locals => {:f => f} %>
8 </div>
7 9 </fieldset>
8 10 <% end %>
9 11 <% if User.current.allowed_to?(:log_time, @project) %>
@@ -1,3 +1,4
1 <% labelled_fields_for :issue, @issue do |f| %>
1 2 <%= call_hook(:view_issues_form_details_top, { :issue => @issue, :form => f }) %>
2 3
3 4 <% if @issue.safe_attribute? 'is_private' %>
@@ -6,10 +7,15
6 7 </p>
7 8 <% end %>
8 9
10 <% if !@issue.new_record? && @issue.safe_attribute?('project_id') %>
11 <p><%= f.select :project_id, Issue.allowed_target_projects_on_move.collect {|t| [t.name, t.id]}, :required => true %></p>
12 <%= observe_field :issue_project_id, :url => project_issue_form_path(@project, :id => @issue, :project_change => '1'),
13 :with => "Form.serialize('issue-form')" %>
14 <% end %>
15
9 16 <% if @issue.safe_attribute? 'tracker_id' %>
10 <p><%= f.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %></p>
17 <p><%= f.select :tracker_id, @issue.project.trackers.collect {|t| [t.name, t.id]}, :required => true %></p>
11 18 <%= observe_field :issue_tracker_id, :url => project_issue_form_path(@project, :id => @issue),
12 :update => :attributes,
13 19 :with => "Form.serialize('issue-form')" %>
14 20 <% end %>
15 21
@@ -39,3 +45,4
39 45 </div>
40 46
41 47 <%= call_hook(:view_issues_form_details_bottom, { :issue => @issue, :form => f }) %>
48 <% end %>
@@ -152,7 +152,6 roles_004:
152 152 - :edit_issues
153 153 - :manage_issue_relations
154 154 - :add_issue_notes
155 - :move_issues
156 155 - :save_queries
157 156 - :view_gantt
158 157 - :view_calendar
@@ -721,6 +721,7 class IssuesControllerTest < ActionController::TestCase
721 721
722 722 assert_tag 'form', :attributes => {:id => 'issue-form'}
723 723 assert_tag 'input', :attributes => {:name => 'issue[is_private]'}
724 assert_tag 'select', :attributes => {:name => 'issue[project_id]'}
724 725 assert_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
725 726 assert_tag 'input', :attributes => {:name => 'issue[subject]'}
726 727 assert_tag 'textarea', :attributes => {:name => 'issue[description]'}
@@ -748,6 +749,7 class IssuesControllerTest < ActionController::TestCase
748 749
749 750 assert_tag 'form', :attributes => {:id => 'issue-form'}
750 751 assert_no_tag 'input', :attributes => {:name => 'issue[is_private]'}
752 assert_no_tag 'select', :attributes => {:name => 'issue[project_id]'}
751 753 assert_no_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
752 754 assert_no_tag 'input', :attributes => {:name => 'issue[subject]'}
753 755 assert_no_tag 'textarea', :attributes => {:name => 'issue[description]'}
@@ -774,6 +776,7 class IssuesControllerTest < ActionController::TestCase
774 776
775 777 assert_tag 'form', :attributes => {:id => 'issue-form'}
776 778 assert_no_tag 'input', :attributes => {:name => 'issue[is_private]'}
779 assert_no_tag 'select', :attributes => {:name => 'issue[project_id]'}
777 780 assert_no_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
778 781 assert_no_tag 'input', :attributes => {:name => 'issue[subject]'}
779 782 assert_no_tag 'textarea', :attributes => {:name => 'issue[description]'}
@@ -1014,6 +1017,7 class IssuesControllerTest < ActionController::TestCase
1014 1017 assert_template 'new'
1015 1018
1016 1019 assert_tag 'input', :attributes => {:name => 'issue[is_private]'}
1020 assert_no_tag 'select', :attributes => {:name => 'issue[project_id]'}
1017 1021 assert_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
1018 1022 assert_tag 'input', :attributes => {:name => 'issue[subject]'}
1019 1023 assert_tag 'textarea', :attributes => {:name => 'issue[description]'}
@@ -1045,6 +1049,7 class IssuesControllerTest < ActionController::TestCase
1045 1049 assert_template 'new'
1046 1050
1047 1051 assert_no_tag 'input', :attributes => {:name => 'issue[is_private]'}
1052 assert_no_tag 'select', :attributes => {:name => 'issue[project_id]'}
1048 1053 assert_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
1049 1054 assert_tag 'input', :attributes => {:name => 'issue[subject]'}
1050 1055 assert_tag 'textarea', :attributes => {:name => 'issue[description]'}
@@ -1636,7 +1641,7 class IssuesControllerTest < ActionController::TestCase
1636 1641
1637 1642 def test_update_edit_form
1638 1643 @request.session[:user_id] = 2
1639 xhr :post, :new, :project_id => 1,
1644 xhr :put, :new, :project_id => 1,
1640 1645 :id => 1,
1641 1646 :issue => {:tracker_id => 2,
1642 1647 :subject => 'This is the test_new issue',
@@ -1653,6 +1658,27 class IssuesControllerTest < ActionController::TestCase
1653 1658 assert_equal 'This is the test_new issue', issue.subject
1654 1659 end
1655 1660
1661 def test_update_edit_form_with_project_change
1662 @request.session[:user_id] = 2
1663 xhr :put, :new, :project_id => 1,
1664 :id => 1,
1665 :project_change => '1',
1666 :issue => {:project_id => 2,
1667 :tracker_id => 2,
1668 :subject => 'This is the test_new issue',
1669 :description => 'This is the description',
1670 :priority_id => 5}
1671 assert_response :success
1672 assert_template 'form'
1673
1674 issue = assigns(:issue)
1675 assert_kind_of Issue, issue
1676 assert_equal 1, issue.id
1677 assert_equal 2, issue.project_id
1678 assert_equal 2, issue.tracker_id
1679 assert_equal 'This is the test_new issue', issue.subject
1680 end
1681
1656 1682 def test_update_using_invalid_http_verbs
1657 1683 @request.session[:user_id] = 2
1658 1684 subject = 'Updated by an invalid http verb'
@@ -1696,6 +1722,57 class IssuesControllerTest < ActionController::TestCase
1696 1722 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
1697 1723 end
1698 1724
1725 def test_put_update_with_project_change
1726 @request.session[:user_id] = 2
1727 ActionMailer::Base.deliveries.clear
1728
1729 assert_difference('Journal.count') do
1730 assert_difference('JournalDetail.count', 3) do
1731 put :update, :id => 1, :issue => {:project_id => '2',
1732 :tracker_id => '1', # no change
1733 :priority_id => '6',
1734 :category_id => '3'
1735 }
1736 end
1737 end
1738 assert_redirected_to :action => 'show', :id => '1'
1739 issue = Issue.find(1)
1740 assert_equal 2, issue.project_id
1741 assert_equal 1, issue.tracker_id
1742 assert_equal 6, issue.priority_id
1743 assert_equal 3, issue.category_id
1744
1745 mail = ActionMailer::Base.deliveries.last
1746 assert_not_nil mail
1747 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
1748 assert mail.body.include?("Project changed from eCookbook to OnlineStore")
1749 end
1750
1751 def test_put_update_with_tracker_change
1752 @request.session[:user_id] = 2
1753 ActionMailer::Base.deliveries.clear
1754
1755 assert_difference('Journal.count') do
1756 assert_difference('JournalDetail.count', 2) do
1757 put :update, :id => 1, :issue => {:project_id => '1',
1758 :tracker_id => '2',
1759 :priority_id => '6'
1760 }
1761 end
1762 end
1763 assert_redirected_to :action => 'show', :id => '1'
1764 issue = Issue.find(1)
1765 assert_equal 1, issue.project_id
1766 assert_equal 2, issue.tracker_id
1767 assert_equal 6, issue.priority_id
1768 assert_equal 1, issue.category_id
1769
1770 mail = ActionMailer::Base.deliveries.last
1771 assert_not_nil mail
1772 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
1773 assert mail.body.include?("Tracker changed from Bug to Feature request")
1774 end
1775
1699 1776 def test_put_update_with_custom_field_change
1700 1777 @request.session[:user_id] = 2
1701 1778 issue = Issue.find(1)
@@ -455,6 +455,22 class ApiTest::IssuesTest < ActionController::IntegrationTest
455 455 end
456 456 end
457 457
458 context "PUT /issues/3.xml with project change" do
459 setup do
460 @parameters = {:issue => {:project_id => 2, :subject => 'Project changed'}}
461 end
462
463 should "update project" do
464 assert_no_difference('Issue.count') do
465 put '/issues/3.xml', @parameters, credentials('jsmith')
466 end
467
468 issue = Issue.find(3)
469 assert_equal 2, issue.project_id
470 assert_equal 'Project changed', issue.subject
471 end
472 end
473
458 474 context "PUT /issues/6.xml with failed update" do
459 475 setup do
460 476 @parameters = {:issue => {:subject => ''}}
General Comments 0
You need to be logged in to leave comments. Login now