Defect #33415 » 0001-POC-fix-for-33415.patch
| app/models/issue.rb | ||
|---|---|---|
| 56 | 56 | |
| 57 | 57 | DONE_RATIO_OPTIONS = %w(issue_field issue_status) | 
| 58 | 58 | |
| 59 | attr_reader :transition_warning | |
| 60 | 59 | attr_writer :deleted_attachment_ids | 
| 61 | 60 | delegate :notes, :notes=, :private_notes, :private_notes=, :to => :current_journal, :allow_nil => true | 
| 62 | 61 | |
| ... | ... | |
| 971 | 970 | end | 
| 972 | 971 | |
| 973 | 972 | # Returns true if this issue can be closed and if not, returns false and populates the reason | 
| 973 | # This does not take the workflow transitions into account | |
| 974 | 974 | def closable? | 
| 975 | @transition_warnings ||= [] | |
| 975 | 976 | if descendants.open.any? | 
| 976 |       @transition_warning = l(:notice_issue_not_closable_by_open_tasks) | |
| 977 |       return false | |
| 977 |       @transition_warnings << 'not_closable_by_open_sub_tasks' unless @transition_warnings.include?('not_closable_by_open_sub_tasks') | |
| 978 |       open_sub_tasks = true | |
| 978 | 979 | end | 
| 979 | 980 | if blocked? | 
| 980 |       @transition_warning = l(:notice_issue_not_closable_by_blocking_issue) | |
| 981 |       return false | |
| 981 |       @transition_warnings << 'not_closable_by_blocking_issues' unless @transition_warnings.include?('not_closable_by_blocking_issues') | |
| 982 |       open_blocking_issues = true | |
| 982 | 983 | end | 
| 983 |     return true | |
| 984 |     open_sub_tasks == true || open_blocking_issues == true ? (return false) : (return true) | |
| 984 | 985 | end | 
| 985 | 986 | |
| 986 | # Returns true if this issue can be reopen and if not, returns false and populates the reason | |
| 987 | # Returns true if this issue can be reopened and if not, returns false and populates the reason | |
| 988 | # This does not take the workflow transitions into account | |
| 987 | 989 | def reopenable? | 
| 990 | @transition_warnings ||= [] | |
| 988 | 991 | if ancestors.open(false).any? | 
| 989 | @transition_warning = l(:notice_issue_not_reopenable_by_closed_parent_issue) | |
| 990 | return false | |
| 992 |       @transition_warnings << 'not_reopenable_by_closed_parent_issue' unless @transition_warnings.include?('not_reopenable_by_closed_parent_issue') | |
| 993 | closed_parent_issue = true | |
| 994 | end | |
| 995 | closed_parent_issue == true ? (return false) : (return true) | |
| 996 | end | |
| 997 | ||
| 998 | # Returns the transition warning message | |
| 999 | # Returns nil if @transition_warnings is nil | |
| 1000 | def transition_warning_message | |
| 1001 | tw = @transition_warnings | |
| 1002 | if !tw.nil? | |
| 1003 |       if tw.include?('not_closable_by_open_sub_tasks') && tw.include?('not_closable_by_blocking_issues') | |
| 1004 | s = l(:notice_issue_not_closable_by_open_tasks_and_blocking_issue) | |
| 1005 |       elsif tw.include?('not_closable_by_open_sub_tasks') | |
| 1006 | s = l(:notice_issue_not_closable_by_open_tasks) | |
| 1007 |       elsif tw.include?('not_closable_by_blocking_issues') | |
| 1008 | s = l(:notice_issue_not_closable_by_blocking_issue) | |
| 1009 |       elsif tw.include?('not_reopenable_by_closed_parent_issue') | |
| 1010 | s = l(:notice_issue_not_reopenable_by_closed_parent_issue) | |
| 1011 | end | |
| 1012 | return s | |
| 991 | 1013 | end | 
| 992 | return true | |
| 993 | 1014 | end | 
| 994 | 1015 | |
| 995 | 1016 | # Returns the default status of the issue based on its tracker | 
| app/views/issues/_attributes.html.erb | ||
|---|---|---|
| 6 | 6 | <p> | 
| 7 | 7 |   <%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), {:required => true}, | 
| 8 | 8 |                 :onchange => "updateIssueFrom('#{escape_javascript(update_issue_form_path(@project, @issue))}', this)" %> | 
| 9 | <% if @issue.transition_warning %> | |
| 10 |     <span class="icon-only icon-warning" title="<%= @issue.transition_warning %>"><%= @issue.transition_warning %></span> | |
| 9 |   <% if @issue.transition_warning_message %> | |
| 10 |     <span class="icon-only icon-warning" title="<%= @issue.transition_warning_message %>"><%= @issue.transition_warning_message %></span> | |
| 11 | 11 | <% end %> | 
| 12 | 12 | </p> | 
| 13 | 13 | <%= hidden_field_tag 'was_default_status', @issue.status_id, :id => nil if @issue.status == @issue.default_status %> | 
| config/locales/en.yml | ||
|---|---|---|
| 193 | 193 | notice_issue_not_closable_by_open_tasks: "This issue cannot be closed because it has at least one open subtask." | 
| 194 | 194 | notice_issue_not_closable_by_blocking_issue: "This issue cannot be closed because it is blocked by at least one open issue." | 
| 195 | 195 | notice_issue_not_reopenable_by_closed_parent_issue: "This issue cannot be reopened because its parent issue is closed." | 
| 196 | notice_issue_not_closable_by_open_tasks_and_blocking_issue: "This issue cannot be closed because it has at least one open subtask and it is blocked by at least one open issue." | |
| 196 | 197 | |
| 197 | 198 |   error_can_t_load_default_data: "Default configuration could not be loaded: %{value}" | 
| 198 | 199 | error_scm_not_found: "The entry or revision was not found in the repository." | 
| test/functional/issues_controller_test.rb | ||
|---|---|---|
| 5439 | 5439 | end | 
| 5440 | 5440 | |
| 5441 | 5441 | def test_get_edit_for_issue_with_transition_warning_should_show_the_warning | 
| 5442 | # Transition warning message for open issue blocked by another open issue | |
| 5442 | 5443 | @request.session[:user_id] = 2 | 
| 5444 | get( | |
| 5445 | :edit, | |
| 5446 |       :params => { | |
| 5447 | :id => 9, | |
| 5448 | } | |
| 5449 | ) | |
| 5450 | assert_response :success | |
| 5451 | reason = "This issue cannot be closed because it is blocked by at least one open issue." | |
| 5452 | assert_select 'span.icon-warning[title=?]', reason, :text => reason | |
| 5453 | ||
| 5454 | # Transition warning message for open issue with open subtask and blocked by another open issue | |
| 5455 | subissue1 = Issue.generate!(:project_id => 5, :author_id => 2, :tracker_id => 1, :parent_issue_id => 9, :subject => 'Open Child Issue') | |
| 5443 | 5456 | |
| 5444 | 5457 | get( | 
| 5445 | 5458 | :edit, | 
| ... | ... | |
| 5447 | 5460 | :id => 9, | 
| 5448 | 5461 | } | 
| 5449 | 5462 | ) | 
| 5463 | assert_response :success | |
| 5464 | reason = "This issue cannot be closed because it has at least one open subtask and it is blocked by at least one open issue." | |
| 5465 | assert_select 'span.icon-warning[title=?]', reason, :text => reason | |
| 5450 | 5466 | |
| 5467 | # Transition warning message for open issue with open subtask | |
| 5468 | subissue2 = Issue.generate!(:project_id => 5, :author_id => 2, :tracker_id => 1, :parent_issue_id => subissue1.id, :subject => 'Open Child Issue') | |
| 5469 |  | |
| 5470 | get( | |
| 5471 | :edit, | |
| 5472 |       :params => { | |
| 5473 | :id => subissue1.id, | |
| 5474 | } | |
| 5475 | ) | |
| 5476 | assert_response :success | |
| 5477 | reason = "This issue cannot be closed because it has at least one open subtask." | |
| 5478 | assert_select 'span.icon-warning[title=?]', reason, :text => reason | |
| 5479 | ||
| 5480 | # Transition warning message for closed subtask with closed parent issue | |
| 5481 | subissue1.update_attribute :status_id, 5 | |
| 5482 | assert subissue1.closed? | |
| 5483 | subissue3 = Issue.generate!(:project_id => 5, :author_id => 2, :tracker_id => 1, :status_id => 5, :parent_issue_id => subissue1.id, :subject => 'Closed Child Issue') | |
| 5484 | assert subissue3.closed? | |
| 5485 | ||
| 5486 | get( | |
| 5487 | :edit, | |
| 5488 |       :params => { | |
| 5489 | :id => subissue3.id, | |
| 5490 | } | |
| 5491 | ) | |
| 5451 | 5492 | assert_response :success | 
| 5452 |     reason = l(:notice_issue_not_closable_by_blocking_issue) | |
| 5493 |     reason = "This issue cannot be reopened because its parent issue is closed." | |
| 5453 | 5494 | assert_select 'span.icon-warning[title=?]', reason, :text => reason | 
| 5454 | 5495 | end | 
| 5455 | 5496 | |
| test/unit/issue_test.rb | ||
|---|---|---|
| 2106 | 2106 | allowed_statuses = parent.reload.new_statuses_allowed_to(users(:users_002)) | 
| 2107 | 2107 | |
| 2108 | 2108 | assert !parent.closable? | 
| 2109 | assert_equal l(:notice_issue_not_closable_by_open_tasks), parent.transition_warning | |
| 2109 |     assert_equal l(:notice_issue_not_closable_by_open_tasks), parent.transition_warning_message | |
| 2110 | 2110 | |
| 2111 | 2111 | assert allowed_statuses.any? | 
| 2112 | 2112 | assert_equal [], allowed_statuses.select(&:is_closed?) | 
| ... | ... | |
| 2119 | 2119 | allowed_statuses = parent.reload.new_statuses_allowed_to(users(:users_002)) | 
| 2120 | 2120 | |
| 2121 | 2121 | assert parent.closable? | 
| 2122 | assert_nil parent.transition_warning | |
| 2122 | assert_nil parent.transition_warning_message | |
| 2123 | ||
| 2123 | 2124 | assert allowed_statuses.any? | 
| 2124 | 2125 | assert allowed_statuses.select(&:is_closed?).any? | 
| 2125 | 2126 | end | 
| ... | ... | |
| 3296 | 3297 | def test_closable | 
| 3297 | 3298 | issue10 = Issue.find(10) | 
| 3298 | 3299 | assert issue10.closable? | 
| 3299 | assert_nil issue10.transition_warning | |
| 3300 |     assert_nil issue10.transition_warning_message | |
| 3300 | 3301 | |
| 3301 | # Issue blocked by another issue | |
| 3302 |     # Issue blocked by another open issue | |
| 3302 | 3303 | issue9 = Issue.find(9) | 
| 3303 | 3304 | assert !issue9.closable? | 
| 3304 | assert_equal l(:notice_issue_not_closable_by_blocking_issue), issue9.transition_warning | |
| 3305 | assert_equal l(:notice_issue_not_closable_by_blocking_issue), issue9.transition_warning_message | |
| 3306 | ||
| 3307 | # Issue with an open subtask and blocked by another open issue | |
| 3308 | child = issue9.generate_child!(:status_id => 1) | |
| 3309 | issue9.reload | |
| 3310 | assert !issue9.closable? | |
| 3311 | assert_equal l(:notice_issue_not_closable_by_open_tasks_and_blocking_issue), issue9.transition_warning_message | |
| 3312 | ||
| 3313 | # Issue with an open subtask | |
| 3314 | assert child.closable? | |
| 3315 | open_parent_issue = child.generate_child! | |
| 3316 | child.reload | |
| 3317 | assert !child.closable? | |
| 3318 | assert_equal l(:notice_issue_not_closable_by_open_tasks), child.transition_warning_message | |
| 3319 | ||
| 3320 | # Closed issue should be closable without a transition warning message | |
| 3321 | closed_issue = Issue.generate!(:status_id => 5) | |
| 3322 | assert closed_issue.closable? | |
| 3323 | assert_nil closed_issue.transition_warning_message | |
| 3305 | 3324 | end | 
| 3306 | 3325 | |
| 3307 | 3326 | def test_reopenable | 
| 3308 | parent = Issue.generate!(:status_id => 5) | |
| 3309 | child = parent.generate_child!(:status_id => 5) | |
| 3310 | ||
| 3311 | assert !child.reopenable? | |
| 3312 | assert_equal l(:notice_issue_not_reopenable_by_closed_parent_issue), child.transition_warning | |
| 3327 | closed_parent = Issue.generate!(:status_id => 5) | |
| 3328 | closed_child = closed_parent.generate_child!(:status_id => 5) | |
| 3329 | assert !closed_child.reopenable? | |
| 3330 | assert_equal l(:notice_issue_not_reopenable_by_closed_parent_issue), closed_child.transition_warning_message | |
| 3331 | ||
| 3332 | # Open issue should be reopenable without a transition warning message | |
| 3333 | open_issue = Issue.generate!(:status_id => 1) | |
| 3334 | assert open_issue.reopenable? | |
| 3335 | assert_nil open_issue.transition_warning_message | |
| 3313 | 3336 | end | 
| 3314 | 3337 | end |