@@ -65,7 +65,7 module IssuesHelper | |||
|
65 | 65 | s = '' |
|
66 | 66 | ancestors = issue.root? ? [] : issue.ancestors.visible.all |
|
67 | 67 | ancestors.each do |ancestor| |
|
68 | s << '<div>' + content_tag('p', link_to_issue(ancestor)) | |
|
68 | s << '<div>' + content_tag('p', link_to_issue(ancestor, :project => (issue.project_id != ancestor.project_id))) | |
|
69 | 69 | end |
|
70 | 70 | s << '<div>' |
|
71 | 71 | subject = h(issue.subject) |
@@ -82,7 +82,7 module IssuesHelper | |||
|
82 | 82 | issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level| |
|
83 | 83 | s << content_tag('tr', |
|
84 | 84 | content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') + |
|
85 | content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') + | |
|
85 | content_tag('td', link_to_issue(child, :truncate => 60, :project => (issue.project_id != child.project_id)), :class => 'subject') + | |
|
86 | 86 | content_tag('td', h(child.status)) + |
|
87 | 87 | content_tag('td', link_to_user(child.assigned_to)) + |
|
88 | 88 | content_tag('td', progress_bar(child.done_ratio, :width => '80px')), |
@@ -91,4 +91,16 module SettingsHelper | |||
|
91 | 91 | l_or_humanize(notifiable.name, :prefix => 'label_').html_safe, |
|
92 | 92 | :class => notifiable.parent.present? ? "parent" : '').html_safe |
|
93 | 93 | end |
|
94 | ||
|
95 | def cross_project_subtasks_options | |
|
96 | options = [ | |
|
97 | [:label_disabled, ''], | |
|
98 | [:label_cross_project_system, 'system'], | |
|
99 | [:label_cross_project_tree, 'tree'], | |
|
100 | [:label_cross_project_hierarchy, 'hierarchy'], | |
|
101 | [:label_cross_project_descendants, 'descendants'] | |
|
102 | ] | |
|
103 | ||
|
104 | options.map {|label, value| [l(label), value.to_s]} | |
|
105 | end | |
|
94 | 106 | end |
@@ -285,7 +285,8 class Issue < ActiveRecord::Base | |||
|
285 | 285 | if fixed_version && fixed_version.project != project && !project.shared_versions.include?(fixed_version) |
|
286 | 286 | self.fixed_version = nil |
|
287 | 287 | end |
|
288 | if parent && parent.project_id != project_id | |
|
288 | # Clear the parent task if it's no longer valid | |
|
289 | unless valid_parent_project? | |
|
289 | 290 | self.parent_issue_id = nil |
|
290 | 291 | end |
|
291 | 292 | @custom_field_values = nil |
@@ -550,8 +551,8 class Issue < ActiveRecord::Base | |||
|
550 | 551 | |
|
551 | 552 | # Checks parent issue assignment |
|
552 | 553 | if @parent_issue |
|
553 | if @parent_issue.project_id != project_id | |
|
554 |
errors.add :parent_issue_id, : |
|
|
554 | if !valid_parent_project?(@parent_issue) | |
|
555 | errors.add :parent_issue_id, :invalid | |
|
555 | 556 | elsif !new_record? |
|
556 | 557 | # moving an existing issue |
|
557 | 558 | if @parent_issue.root_id != root_id |
@@ -559,7 +560,7 class Issue < ActiveRecord::Base | |||
|
559 | 560 | elsif move_possible?(@parent_issue) |
|
560 | 561 | # move accepted inside tree |
|
561 | 562 | else |
|
562 |
errors.add :parent_issue_id, :n |
|
|
563 | errors.add :parent_issue_id, :invalid | |
|
563 | 564 | end |
|
564 | 565 | end |
|
565 | 566 | end |
@@ -963,6 +964,25 class Issue < ActiveRecord::Base | |||
|
963 | 964 | end |
|
964 | 965 | end |
|
965 | 966 | |
|
967 | # Returns true if issue's project is a valid | |
|
968 | # parent issue project | |
|
969 | def valid_parent_project?(issue=parent) | |
|
970 | return true if issue.nil? || issue.project_id == project_id | |
|
971 | ||
|
972 | case Setting.cross_project_subtasks | |
|
973 | when 'system' | |
|
974 | true | |
|
975 | when 'tree' | |
|
976 | issue.project.root == project.root | |
|
977 | when 'hierarchy' | |
|
978 | issue.project.is_or_is_ancestor_of?(project) || issue.project.is_descendant_of?(project) | |
|
979 | when 'descendants' | |
|
980 | issue.project.is_or_is_ancestor_of?(project) | |
|
981 | else | |
|
982 | false | |
|
983 | end | |
|
984 | end | |
|
985 | ||
|
966 | 986 | # Extracted from the ReportsController. |
|
967 | 987 | def self.by_tracker(project) |
|
968 | 988 | count_and_group_by(:project => project, |
@@ -1042,8 +1062,9 class Issue < ActiveRecord::Base | |||
|
1042 | 1062 | relations_to.clear |
|
1043 | 1063 | end |
|
1044 | 1064 | |
|
1045 | # Move subtasks | |
|
1065 | # Move subtasks that were in the same project | |
|
1046 | 1066 | children.each do |child| |
|
1067 | next unless child.project_id == project_id_was | |
|
1047 | 1068 | # Change project and keep project |
|
1048 | 1069 | child.send :project=, project, true |
|
1049 | 1070 | unless child.save |
@@ -43,7 +43,7 | |||
|
43 | 43 | <div class="splitcontentright"> |
|
44 | 44 | <% if @issue.safe_attribute? 'parent_issue_id' %> |
|
45 | 45 | <p id="parent_issue"><%= f.text_field :parent_issue_id, :size => 10, :required => @issue.required_attribute?('parent_issue_id') %></p> |
|
46 |
<%= javascript_tag "observeAutocompleteField('issue_parent_issue_id', '#{escape_javascript auto_complete_issues_path |
|
|
46 | <%= javascript_tag "observeAutocompleteField('issue_parent_issue_id', '#{escape_javascript auto_complete_issues_path}')" %> | |
|
47 | 47 | <% end %> |
|
48 | 48 | |
|
49 | 49 | <% if @issue.safe_attribute? 'start_date' %> |
@@ -3,6 +3,8 | |||
|
3 | 3 | <div class="box tabular settings"> |
|
4 | 4 | <p><%= setting_check_box :cross_project_issue_relations %></p> |
|
5 | 5 | |
|
6 | <p><%= setting_select :cross_project_subtasks, cross_project_subtasks_options %></p> | |
|
7 | ||
|
6 | 8 | <p><%= setting_check_box :issue_group_assignment %></p> |
|
7 | 9 | |
|
8 | 10 | <p><%= setting_check_box :default_issue_start_date_to_creation_date %></p> |
@@ -357,6 +357,7 en: | |||
|
357 | 357 | setting_date_format: Date format |
|
358 | 358 | setting_time_format: Time format |
|
359 | 359 | setting_cross_project_issue_relations: Allow cross-project issue relations |
|
360 | setting_cross_project_subtasks: Allow cross-project subtasks | |
|
360 | 361 | setting_issue_list_default_columns: Default columns displayed on the issue list |
|
361 | 362 | setting_repositories_encodings: Attachments and repositories encodings |
|
362 | 363 | setting_emails_header: Emails header |
@@ -356,6 +356,7 fr: | |||
|
356 | 356 | setting_date_format: Format de date |
|
357 | 357 | setting_time_format: Format d'heure |
|
358 | 358 | setting_cross_project_issue_relations: Autoriser les relations entre demandes de diffΓ©rents projets |
|
359 | setting_cross_project_subtasks: Autoriser les sous-tΓ’ches dans des projets diffΓ©rents | |
|
359 | 360 | setting_issue_list_default_columns: Colonnes affichΓ©es par dΓ©faut sur la liste des demandes |
|
360 | 361 | setting_emails_footer: Pied-de-page des emails |
|
361 | 362 | setting_protocol: Protocole |
@@ -133,6 +133,9 user_format: | |||
|
133 | 133 | format: symbol |
|
134 | 134 | cross_project_issue_relations: |
|
135 | 135 | default: 0 |
|
136 | # Enables subtasks to be in other projects | |
|
137 | cross_project_subtasks: | |
|
138 | default: 'tree' | |
|
136 | 139 | issue_group_assignment: |
|
137 | 140 | default: 0 |
|
138 | 141 | default_issue_start_date_to_creation_date: |
@@ -41,4 +41,7 projects_trackers_013: | |||
|
41 | 41 | projects_trackers_014: |
|
42 | 42 | project_id: 1 |
|
43 | 43 | tracker_id: 3 |
|
44 | projects_trackers_015: | |
|
45 | project_id: 6 | |
|
46 | tracker_id: 1 | |
|
44 | 47 | No newline at end of file |
@@ -156,6 +156,14 class ActiveSupport::TestCase | |||
|
156 | 156 | hs |
|
157 | 157 | end |
|
158 | 158 | |
|
159 | def assert_save(object) | |
|
160 | saved = object.save | |
|
161 | message = "#{object.class} could not be saved" | |
|
162 | errors = object.errors.full_messages.map {|m| "- #{m}"} | |
|
163 | message << ":\n#{errors.join("\n")}" if errors.any? | |
|
164 | assert_equal true, saved, message | |
|
165 | end | |
|
166 | ||
|
159 | 167 | def assert_error_tag(options={}) |
|
160 | 168 | assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options)) |
|
161 | 169 | end |
@@ -49,7 +49,15 class IssueNestedSetTest < ActiveSupport::TestCase | |||
|
49 | 49 | assert_equal [parent.id, parent.id, 2, 3], [child.root_id, child.parent_id, child.lft, child.rgt] |
|
50 | 50 | end |
|
51 | 51 | |
|
52 |
def test_creating_a_child_in_ |
|
|
52 | def test_creating_a_child_in_a_subproject_should_validate | |
|
53 | issue = create_issue! | |
|
54 | child = Issue.new(:project_id => 3, :tracker_id => 2, :author_id => 1, | |
|
55 | :subject => 'child', :parent_issue_id => issue.id) | |
|
56 | assert_save child | |
|
57 | assert_equal issue, child.reload.parent | |
|
58 | end | |
|
59 | ||
|
60 | def test_creating_a_child_in_an_invalid_project_should_not_validate | |
|
53 | 61 | issue = create_issue! |
|
54 | 62 | child = Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1, |
|
55 | 63 | :subject => 'child', :parent_issue_id => issue.id) |
@@ -906,6 +906,24 class IssueTest < ActiveSupport::TestCase | |||
|
906 | 906 | assert_equal 7, issue.fixed_version_id |
|
907 | 907 | end |
|
908 | 908 | |
|
909 | def test_move_to_another_project_should_keep_parent_if_valid | |
|
910 | issue = Issue.find(1) | |
|
911 | issue.update_attribute(:parent_issue_id, 2) | |
|
912 | issue.project = Project.find(3) | |
|
913 | assert issue.save | |
|
914 | issue.reload | |
|
915 | assert_equal 2, issue.parent_id | |
|
916 | end | |
|
917 | ||
|
918 | def test_move_to_another_project_should_clear_parent_if_not_valid | |
|
919 | issue = Issue.find(1) | |
|
920 | issue.update_attribute(:parent_issue_id, 2) | |
|
921 | issue.project = Project.find(2) | |
|
922 | assert issue.save | |
|
923 | issue.reload | |
|
924 | assert_nil issue.parent_id | |
|
925 | end | |
|
926 | ||
|
909 | 927 | def test_move_to_another_project_with_disabled_tracker |
|
910 | 928 | issue = Issue.find(1) |
|
911 | 929 | target = Project.find(2) |
@@ -996,6 +1014,48 class IssueTest < ActiveSupport::TestCase | |||
|
996 | 1014 | end |
|
997 | 1015 | end |
|
998 | 1016 | |
|
1017 | def test_valid_parent_project | |
|
1018 | issue = Issue.find(1) | |
|
1019 | issue_in_same_project = Issue.find(2) | |
|
1020 | issue_in_child_project = Issue.find(5) | |
|
1021 | issue_in_grandchild_project = Issue.generate!(:project_id => 6, :tracker_id => 1) | |
|
1022 | issue_in_other_child_project = Issue.find(6) | |
|
1023 | issue_in_different_tree = Issue.find(4) | |
|
1024 | ||
|
1025 | with_settings :cross_project_subtasks => '' do | |
|
1026 | assert_equal true, issue.valid_parent_project?(issue_in_same_project) | |
|
1027 | assert_equal false, issue.valid_parent_project?(issue_in_child_project) | |
|
1028 | assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project) | |
|
1029 | assert_equal false, issue.valid_parent_project?(issue_in_different_tree) | |
|
1030 | end | |
|
1031 | ||
|
1032 | with_settings :cross_project_subtasks => 'system' do | |
|
1033 | assert_equal true, issue.valid_parent_project?(issue_in_same_project) | |
|
1034 | assert_equal true, issue.valid_parent_project?(issue_in_child_project) | |
|
1035 | assert_equal true, issue.valid_parent_project?(issue_in_different_tree) | |
|
1036 | end | |
|
1037 | ||
|
1038 | with_settings :cross_project_subtasks => 'tree' do | |
|
1039 | assert_equal true, issue.valid_parent_project?(issue_in_same_project) | |
|
1040 | assert_equal true, issue.valid_parent_project?(issue_in_child_project) | |
|
1041 | assert_equal true, issue.valid_parent_project?(issue_in_grandchild_project) | |
|
1042 | assert_equal false, issue.valid_parent_project?(issue_in_different_tree) | |
|
1043 | ||
|
1044 | assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_same_project) | |
|
1045 | assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_other_child_project) | |
|
1046 | end | |
|
1047 | ||
|
1048 | with_settings :cross_project_subtasks => 'descendants' do | |
|
1049 | assert_equal true, issue.valid_parent_project?(issue_in_same_project) | |
|
1050 | assert_equal false, issue.valid_parent_project?(issue_in_child_project) | |
|
1051 | assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project) | |
|
1052 | assert_equal false, issue.valid_parent_project?(issue_in_different_tree) | |
|
1053 | ||
|
1054 | assert_equal true, issue_in_child_project.valid_parent_project?(issue) | |
|
1055 | assert_equal false, issue_in_child_project.valid_parent_project?(issue_in_other_child_project) | |
|
1056 | end | |
|
1057 | end | |
|
1058 | ||
|
999 | 1059 | def test_recipients_should_include_previous_assignee |
|
1000 | 1060 | user = User.find(3) |
|
1001 | 1061 | user.members.update_all ["mail_notification = ?", false] |
General Comments 0
You need to be logged in to leave comments.
Login now