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
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
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
<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 %>
</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>
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
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!
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