@@ -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]) |
|
|
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 |
|
|
755 | if user.admin? | |
|
731 | 756 | # admin is allowed to move issues to any active (visible) project |
|
732 | projects = Project.visible.all | |
|
733 |
elsif |
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
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 |
|
|
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 :p |
|
|
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