]> source.dussan.org Git - redmine.git/commitdiff
Show only valid projects on issue form when the issue is a subtask (#33419).
authorGo MAEDA <maeda@farend.jp>
Fri, 1 Jan 2021 00:59:07 +0000 (00:59 +0000)
committerGo MAEDA <maeda@farend.jp>
Fri, 1 Jan 2021 00:59:07 +0000 (00:59 +0000)
Patch by Marius BALTEANU.

git-svn-id: http://svn.redmine.org/redmine/trunk@20701 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/helpers/issues_helper.rb
app/models/issue.rb
app/views/issues/_attributes.html.erb
app/views/issues/_form.html.erb
test/functional/issues_controller_test.rb
test/unit/issue_test.rb

index 808842325c71fdf0c688abe82c98082d65bbd967..4a9e7a2aa8f38a0794c6e0f6773b2861d4c7c77a 100644 (file)
@@ -696,4 +696,14 @@ module IssuesHelper
       user_default_tab
     end
   end
+
+  def projects_for_select(issue)
+    if issue.parent_issue_id.present?
+      issue.allowed_target_projects_for_subtask(User.current)
+    elsif issue.new_record? && !issue.copy?
+      issue.allowed_target_projects(User.current, 'descendants')
+    else
+      issue.allowed_target_projects(User.current)
+    end
+  end
 end
index 8ba261bb1f6730c5b0c3a7dc5ce5a54c6b28baa1..2c64373112fc0fe393a4b798d46167389399c28f 100644 (file)
@@ -1596,29 +1596,38 @@ class Issue < ActiveRecord::Base
       end
   end
 
+  # Returns a scope of projects that user can assign the subtask
+  def allowed_target_projects_for_subtask(user=User.current)
+    if parent_issue_id.present?
+      scope = filter_projects_scope(Setting.cross_project_subtasks)
+    end
+
+    self.class.allowed_target_projects(user, project, scope)
+  end
+
   # Returns a scope of projects that user can assign the issue to
-  def allowed_target_projects(user=User.current, context=nil)
-    if new_record? && context.is_a?(Project) && !copy?
-      current_project = context.self_and_descendants
-    elsif new_record?
-      current_project = nil
-    else
-      current_project = project
+  def allowed_target_projects(user=User.current, scope=nil)
+    current_project = new_record? ? nil : project
+    if scope
+      scope = filter_projects_scope(scope)
     end
 
-    self.class.allowed_target_projects(user, current_project)
+    self.class.allowed_target_projects(user, current_project, scope)
   end
 
   # Returns a scope of projects that user can assign issues to
   # If current_project is given, it will be included in the scope
-  def self.allowed_target_projects(user=User.current, current_project=nil)
+  def self.allowed_target_projects(user=User.current, current_project=nil, scope=nil)
     condition = Project.allowed_to_condition(user, :add_issues)
-    if current_project.is_a?(Project)
+    if current_project
       condition = ["(#{condition}) OR #{Project.table_name}.id = ?", current_project.id]
-    elsif current_project
-      condition = ["(#{condition}) AND #{Project.table_name}.id IN (?)", current_project.map(&:id)]
     end
-    Project.where(condition).having_trackers
+
+    if scope.nil?
+      scope = Project
+    end
+
+    scope.where(condition).having_trackers
   end
 
   # Returns a scope of trackers that user can assign the issue to
@@ -1988,4 +1997,21 @@ class Issue < ActiveRecord::Base
       self.done_ratio ||= 0
     end
   end
+
+  def filter_projects_scope(scope=nil)
+    case scope
+    when 'system'
+      Project
+    when 'tree'
+      project.root.self_and_descendants
+    when 'hierarchy'
+      project.hierarchy
+    when 'descendants'
+      project.self_and_descendants
+    when ''
+      Project.where(:id => project.id)
+    else
+      Project
+    end
+  end
 end
index ee4ae109c9cbb3afd20a32147b88372dbf76b037..b5003c436b53c79abec9f59fb46a9e504800859a 100644 (file)
@@ -61,7 +61,8 @@
 <div class="splitcontentright">
 <% if @issue.safe_attribute? 'parent_issue_id' %>
 <p id="parent_issue"><%= f.text_field :parent_issue_id, :size => 10,
-                                      :required => @issue.required_attribute?('parent_issue_id') %></p>
+                                      :required => @issue.required_attribute?('parent_issue_id'),
+                                      :onchange => "updateIssueFrom('#{escape_javascript update_issue_form_path(@project, @issue)}', this)" %></p>
 <%= javascript_tag "observeAutocompleteField('issue_parent_issue_id', '#{escape_javascript(auto_complete_issues_path(:project_id => @issue.project, :scope => Setting.cross_project_subtasks, :status => @issue.closed? ? 'c' : 'o', :issue_id => @issue.id))}')" %>
 <% end %>
 
index 0d3ca5e2218b0f8cf96107bd48a00cbedbb71d08..9654d631d6132ad72349891fe749cd346dc8256c 100644 (file)
@@ -9,7 +9,7 @@
 </p>
 <% end %>
 
-<% projects = @issue.allowed_target_projects(User.current, @project) %>
+<% projects = projects_for_select(@issue) %>
 <% if (@issue.safe_attribute?('project_id') || @issue.project_id_changed?) && (@project.nil? || projects.length > 1 || @issue.copy?) %>
 <p><%= f.select :project_id, project_tree_options_for_select(projects, :selected => @issue.project), {:required => true},
                 :onchange => "updateIssueFrom('#{escape_javascript update_issue_form_path(@project, @issue)}', this)" %></p>
index dda71f829f5ffdf0a0be57bbf2a4c48953223b98..cb04adad6d1186a967b27c16939d0b1c8bf043df 100644 (file)
@@ -3141,6 +3141,30 @@ class IssuesControllerTest < Redmine::ControllerTest
     assert_select 'select[name="issue[project_id]"]', 0
   end
 
+  def test_get_new_should_not_show_invalid_projects_when_issue_is_a_subtask
+    @request.session[:user_id] = 2
+    issue = Issue.find(1)
+    issue.parent_id = 3
+    issue.save
+
+    with_settings :cross_project_subtasks => 'tree' do
+      get(
+        :new,
+        :params => {
+          :project_id => 1,
+          :parent_issue_id => 1
+        }
+      )
+    end
+    assert_response :success
+    assert_select 'select[name="issue[project_id]"]' do
+      assert_select 'option', 3
+
+      # Onlinestore project should not be included
+      assert_select 'option[value=?]', '2', 0
+    end
+  end
+
   def test_get_new_with_minimal_permissions
     Role.find(1).update_attribute :permissions, [:add_issues]
     WorkflowTransition.where(:role_id => 1).delete_all
index 95812376a4bf67f124774613090b2754e27e9778..4a7c663b54a63260a71af8a8cbcd85bee8d0b4cc 100644 (file)
@@ -1708,6 +1708,17 @@ class IssueTest < ActiveSupport::TestCase
     assert_not_include project, Issue.allowed_target_projects(User.find(1))
   end
 
+  def test_allowed_target_projects_for_subtask_should_not_include_invalid_projects
+    User.current = User.find(1)
+    issue = Issue.find(1)
+    issue.parent_id = 3
+
+    with_settings :cross_project_subtasks => 'tree' do
+      # Should include only the project tree
+      assert_equal [1, 3, 5], issue.allowed_target_projects_for_subtask.ids.sort
+    end
+  end
+
   def test_allowed_target_trackers_with_one_role_allowed_on_all_trackers
     user = User.generate!
     role = Role.generate!
@@ -3343,4 +3354,27 @@ class IssueTest < ActiveSupport::TestCase
     assert !child.reopenable?
     assert_equal l(:notice_issue_not_reopenable_by_closed_parent_issue), child.transition_warning
   end
+
+  def test_filter_projects_scope
+    Issue.send(:public, :filter_projects_scope)
+    # Project eCookbook
+    issue = Issue.find(1)
+
+    assert_equal Project, issue.filter_projects_scope
+    assert_equal Project, issue.filter_projects_scope('system')
+
+    # Project Onlinestore (id 2) is not part of the tree
+    assert_equal [1, 3, 4, 5, 6], Issue.find(5).filter_projects_scope('tree').ids.sort
+
+    # Project "Private child of eCookbook"
+    issue2 = Issue.find(9)
+
+    # Projects "eCookbook Subproject 1" (id 3) and "eCookbook Subproject 1" (id 4) are not part of hierarchy
+    assert_equal [1, 5, 6], issue2.filter_projects_scope('hierarchy').ids.sort
+
+    # Project "Child of private child" is descendant of "Private child of eCookbook"
+    assert_equal [5, 6], issue2.filter_projects_scope('descendants').ids.sort
+
+    assert_equal [5], issue2.filter_projects_scope('').ids.sort
+  end
 end