Feature #6033 » 6033_subtasks_show_in_parent_history.patch
app/helpers/issues_helper.rb | ||
---|---|---|
547 | 547 |
value = "##{detail.value}" unless detail.value.blank? |
548 | 548 |
old_value = "##{detail.old_value}" unless detail.old_value.blank? |
549 | 549 | |
550 |
when 'child_id' |
|
551 |
label = l(:label_subtask) |
|
552 |
value = "##{detail.value}" unless detail.value.blank? |
|
553 |
old_value = "##{detail.old_value}" unless detail.old_value.blank? |
|
554 |
multiple = true |
|
555 | ||
550 | 556 |
when 'is_private' |
551 | 557 |
value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank? |
552 | 558 |
old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank? |
app/models/issue.rb | ||
---|---|---|
118 | 118 |
after_save :reschedule_following_issues, :update_nested_set_attributes, |
119 | 119 |
:update_parent_attributes, :delete_selected_attachments, :create_journal |
120 | 120 |
# Should be after_create but would be called before previous after_save callbacks |
121 |
after_save :after_create_from_copy |
|
122 |
after_destroy :update_parent_attributes |
|
121 |
after_save :after_create_from_copy, :create_parent_issue_journal
|
|
122 |
after_destroy :update_parent_attributes, :create_parent_issue_journal
|
|
123 | 123 |
after_create_commit :send_notification |
124 | 124 | |
125 | 125 |
# Returns a SQL conditions string used to find all issues visible by the specified user |
... | ... | |
1988 | 1988 |
end |
1989 | 1989 |
end |
1990 | 1990 | |
1991 |
def create_parent_issue_journal |
|
1992 |
return if persisted? && !saved_change_to_parent_id? |
|
1993 |
return if destroyed? && @without_nested_set_update |
|
1994 | ||
1995 |
child_id = self.id |
|
1996 |
old_parent_id, new_parent_id = |
|
1997 |
if persisted? |
|
1998 |
[parent_id_before_last_save, parent_id] |
|
1999 |
elsif destroyed? |
|
2000 |
[parent_id, nil] |
|
2001 |
else |
|
2002 |
[nil, parent_id] |
|
2003 |
end |
|
2004 | ||
2005 |
if old_parent_id.present? && old_parent_issue = Issue.visible.find_by_id(old_parent_id) |
|
2006 |
old_parent_issue.init_journal(User.current) |
|
2007 |
old_parent_issue.current_journal.__send__(:add_attribute_detail, 'child_id', child_id, nil) |
|
2008 |
old_parent_issue.save |
|
2009 |
end |
|
2010 |
if new_parent_id.present? && new_parent_issue = Issue.visible.find_by_id(new_parent_id) |
|
2011 |
new_parent_issue.init_journal(User.current) |
|
2012 |
new_parent_issue.current_journal.__send__(:add_attribute_detail, 'child_id', nil, child_id) |
|
2013 |
new_parent_issue.save |
|
2014 |
end |
|
2015 |
end |
|
2016 | ||
1991 | 2017 |
def send_notification |
1992 | 2018 |
if notify? && Setting.notified_events.include?('issue_added') |
1993 | 2019 |
Mailer.deliver_issue_add(self) |
config/locales/en.yml | ||
---|---|---|
995 | 995 |
label_missing_api_access_key: Missing an API access key |
996 | 996 |
label_api_access_key_created_on: "API access key created %{value} ago" |
997 | 997 |
label_profile: Profile |
998 |
label_subtask: Subtask |
|
998 | 999 |
label_subtask_plural: Subtasks |
999 | 1000 |
label_project_copy_notifications: Send email notifications during the project copy |
1000 | 1001 |
label_import_notifications: Send email notifications during the import |
test/functional/issues_controller_test.rb | ||
---|---|---|
2344 | 2344 |
end |
2345 | 2345 | |
2346 | 2346 |
def test_show_should_list_subtasks |
2347 |
Issue. |
|
2347 |
issue = Issue.
|
|
2348 | 2348 |
create!( |
2349 | 2349 |
:project_id => 1, :author_id => 1, :tracker_id => 1, |
2350 | 2350 |
:parent_issue_id => 1, :subject => 'Child Issue' |
... | ... | |
2354 | 2354 |
assert_select 'div#issue_tree' do |
2355 | 2355 |
assert_select 'td.subject', :text => /Child Issue/ |
2356 | 2356 |
end |
2357 |
assert_select 'div#tab-content-history' do |
|
2358 |
assert_select 'div[id=?]', "change-#{Issue.find(1).journals.last.id}" do |
|
2359 |
assert_select 'ul.details', :text => "Subtask ##{issue.id} added" |
|
2360 |
end |
|
2361 |
end |
|
2357 | 2362 |
end |
2358 | 2363 | |
2359 | 2364 |
def test_show_should_show_subtasks_stats |
... | ... | |
8199 | 8204 |
assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6)) |
8200 | 8205 |
end |
8201 | 8206 | |
8207 |
def test_destroy_child_issue |
|
8208 |
parent = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Parent Issue') |
|
8209 |
child = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Child Issue', :parent_issue_id => parent.id) |
|
8210 |
assert child.is_descendant_of?(parent.reload) |
|
8211 | ||
8212 |
@request.session[:user_id] = 2 |
|
8213 |
assert_difference 'Issue.count', -1 do |
|
8214 |
delete :destroy, :params => {:id => child.id} |
|
8215 |
end |
|
8216 |
assert_response :found |
|
8217 |
assert_redirected_to :action => 'index', :project_id => 'ecookbook' |
|
8218 | ||
8219 |
parent.reload |
|
8220 |
assert_equal 2, parent.journals.count |
|
8221 | ||
8222 |
get :show, :params => {:id => parent.id} |
|
8223 |
assert_response :success |
|
8224 | ||
8225 |
assert_select 'div#tab-content-history' do |
|
8226 |
assert_select 'div[id=?]', "change-#{parent.journals.last.id}" do |
|
8227 |
assert_select 'ul.details', :text => "Subtask deleted (##{child.id})" |
|
8228 |
end |
|
8229 |
end |
|
8230 |
end |
|
8231 | ||
8202 | 8232 |
def test_destroy_parent_and_child_issues |
8203 | 8233 |
parent = Issue.create!(:project_id => 1, :author_id => 1, |
8204 | 8234 |
:tracker_id => 1, :subject => 'Parent Issue') |
test/unit/issue_nested_set_test.rb | ||
---|---|---|
49 | 49 |
def test_create_child_issue |
50 | 50 |
lft = new_issue_lft |
51 | 51 |
parent = Issue.generate! |
52 |
child = parent.generate_child! |
|
52 |
child = nil |
|
53 |
assert_difference 'Journal.count', 1 do |
|
54 |
child = parent.generate_child! |
|
55 |
end |
|
53 | 56 |
parent.reload |
54 | 57 |
child.reload |
55 | 58 |
assert_equal [parent.id, nil, lft, lft + 3], [parent.root_id, parent.parent_id, parent.lft, parent.rgt] |
... | ... | |
58 | 61 | |
59 | 62 |
def test_creating_a_child_in_a_subproject_should_validate |
60 | 63 |
issue = Issue.generate! |
61 |
child = Issue.new(:project_id => 3, :tracker_id => 2, :author_id => 1, |
|
62 |
:subject => 'child', :parent_issue_id => issue.id) |
|
63 |
assert_save child |
|
64 |
child = nil |
|
65 |
assert_difference 'Journal.count', 1 do |
|
66 |
child = Issue.new(:project_id => 3, :tracker_id => 2, :author_id => 1, |
|
67 |
:subject => 'child', :parent_issue_id => issue.id) |
|
68 |
assert_save child |
|
69 |
end |
|
64 | 70 |
assert_equal issue, child.reload.parent |
65 | 71 |
end |
66 | 72 | |
67 | 73 |
def test_creating_a_child_in_an_invalid_project_should_not_validate |
68 | 74 |
issue = Issue.generate! |
69 |
child = Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1, |
|
70 |
:subject => 'child', :parent_issue_id => issue.id) |
|
71 |
assert !child.save |
|
75 |
child = nil |
|
76 |
assert_no_difference 'Journal.count' do |
|
77 |
child = Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1, |
|
78 |
:subject => 'child', :parent_issue_id => issue.id) |
|
79 |
assert !child.save |
|
80 |
end |
|
72 | 81 |
assert_not_equal [], child.errors[:parent_issue_id] |
73 | 82 |
end |
74 | 83 | |
... | ... | |
77 | 86 |
parent1 = Issue.generate! |
78 | 87 |
parent2 = Issue.generate! |
79 | 88 |
child = parent1.generate_child! |
80 |
parent2.parent_issue_id = parent1.id |
|
81 |
parent2.save! |
|
89 |
assert_difference 'Journal.count', 2 do |
|
90 |
parent2.init_journal(User.find(2)) |
|
91 |
parent2.parent_issue_id = parent1.id |
|
92 |
parent2.save! |
|
93 |
end |
|
82 | 94 |
child.reload |
83 | 95 |
parent1.reload |
84 | 96 |
parent2.reload |
... | ... | |
94 | 106 |
parent2 = Issue.generate! |
95 | 107 |
lft3 = new_issue_lft |
96 | 108 |
child = parent1.generate_child! |
97 |
child.parent_issue_id = nil |
|
98 |
child.save! |
|
109 |
assert_difference 'Journal.count', 2 do |
|
110 |
child.init_journal(User.find(2)) |
|
111 |
child.parent_issue_id = nil |
|
112 |
child.save! |
|
113 |
end |
|
99 | 114 |
child.reload |
100 | 115 |
parent1.reload |
101 | 116 |
parent2.reload |
... | ... | |
110 | 125 |
lft2 = new_issue_lft |
111 | 126 |
parent2 = Issue.generate! |
112 | 127 |
child = parent1.generate_child! |
113 |
child.parent_issue_id = parent2.id |
|
114 |
child.save! |
|
128 |
assert_difference 'Journal.count', 3 do |
|
129 |
child.init_journal(User.find(2)) |
|
130 |
child.parent_issue_id = parent2.id |
|
131 |
child.save! |
|
132 |
end |
|
115 | 133 |
child.reload |
116 | 134 |
parent1.reload |
117 | 135 |
parent2.reload |
... | ... | |
154 | 172 |
grandchild = child.generate_child! |
155 | 173 |
lft4 = new_issue_lft |
156 | 174 |
child.reload |
157 |
child.project = Project.find(2) |
|
158 |
assert child.save |
|
175 |
assert_difference 'Journal.count', 2 do |
|
176 |
assert_difference 'JournalDetail.count', 3 do |
|
177 |
child.init_journal(User.find(2)) |
|
178 |
child.project = Project.find(2) |
|
179 |
assert child.save |
|
180 |
end |
|
181 |
end |
|
159 | 182 |
child.reload |
160 | 183 |
grandchild.reload |
161 | 184 |
parent1.reload |
... | ... | |
173 | 196 |
grandchild = child.generate_child! |
174 | 197 | |
175 | 198 |
child.reload |
176 |
child.parent_issue_id = grandchild.id |
|
177 |
assert !child.save |
|
199 |
assert_no_difference 'Journal.count' do |
|
200 |
child.init_journal(User.find(2)) |
|
201 |
child.parent_issue_id = grandchild.id |
|
202 |
assert !child.save |
|
203 |
end |
|
178 | 204 |
assert_not_equal [], child.errors[:parent_issue_id] |
179 | 205 |
end |
180 | 206 | |
... | ... | |
223 | 249 |
issue3.subject = 'child with journal' |
224 | 250 |
issue3.save! |
225 | 251 |
assert_difference 'Issue.count', -2 do |
226 |
assert_difference 'Journal.count', -1 do
|
|
227 |
assert_difference 'JournalDetail.count', -1 do
|
|
252 |
assert_difference 'Journal.count', -2 do
|
|
253 |
assert_difference 'JournalDetail.count', -2 do
|
|
228 | 254 |
Issue.find(issue2.id).destroy |
229 | 255 |
end |
230 | 256 |
end |
... | ... | |
244 | 270 |
child2 = issue.generate_child! |
245 | 271 |
issue.reload |
246 | 272 |
assert_equal [issue.id, lft1, lft1 + 5], [issue.root_id, issue.lft, issue.rgt] |
247 |
child2.reload.destroy |
|
273 |
assert_difference 'Journal.count', 1 do |
|
274 |
child2.reload.destroy |
|
275 |
end |
|
248 | 276 |
issue.reload |
249 | 277 |
assert_equal [issue.id, lft1, lft1 + 3], [issue.root_id, issue.lft, issue.rgt] |
250 | 278 |
end |
... | ... | |
255 | 283 |
parent.generate_child!(:start_date => 2.days.from_now) |
256 | 284 | |
257 | 285 |
assert_difference 'Issue.count', -3 do |
258 |
Issue.find(parent.id).destroy |
|
286 |
assert_difference 'Journal.count', -2 do |
|
287 |
Issue.find(parent.id).destroy |
|
288 |
end |
|
259 | 289 |
end |
260 | 290 |
end |
261 | 291 | |
... | ... | |
287 | 317 |
grandchild1 = child.generate_child! |
288 | 318 |
grandchild2 = child.generate_child! |
289 | 319 |
assert_difference 'Issue.count', -4 do |
290 |
Issue.find(issue.id).destroy |
|
320 |
assert_difference 'Journal.count', -2 do |
|
321 |
Issue.find(issue.id).destroy |
|
322 |
end |
|
291 | 323 |
parent.reload |
292 | 324 |
assert_equal [lft1, lft1 + 1], [parent.lft, parent.rgt] |
293 | 325 |
end |
test/unit/issue_subtasking_test.rb | ||
---|---|---|
277 | 277 |
with_settings :issue_done_ratio => 'issue_status' do |
278 | 278 |
status = IssueStatus.find(4) |
279 | 279 |
status.update_attribute :default_done_ratio, 50 |
280 |
child1.reload |
|
280 | 281 |
child1.update_attribute :status, status |
281 | 282 | |
282 | 283 |
assert_equal 50, child1.done_ratio |