Project

General

Profile

Defect #33415 » 0001-Fix-33415-by-re-implementing-31589.patch

Replaces 0001-POC-fix-for-33415.patch - Mischa The Evil, 2020-05-16 07:53

View differences:

app/helpers/issues_helper.rb
640 640
    end
641 641
  end
642 642

  
643
  # Returns the transition warning message
644
  # Returns nil if @transition_warnings is nil
645
  def transition_warning_message(issue)
646
    tw = issue.transition_warnings
647
    if !tw.nil?
648
      if tw.include?(:not_closable_by_open_sub_tasks_and_blocking_issues)
649
        s = l(:notice_issue_not_closable_by_open_tasks_and_blocking_issue)
650
      elsif tw.include?(:not_closable_by_open_sub_tasks)
651
        s = l(:notice_issue_not_closable_by_open_tasks)
652
      elsif tw.include?(:not_closable_by_open_blocking_issues)
653
        s = l(:notice_issue_not_closable_by_blocking_issue)
654
      elsif tw.include?(:not_reopenable_by_closed_parent_issue)
655
        s = l(:notice_issue_not_reopenable_by_closed_parent_issue)
656
      end
657
      return s
658
    end
659
  end
660

  
643 661
end
app/models/issue.rb
56 56

  
57 57
  DONE_RATIO_OPTIONS = %w(issue_field issue_status)
58 58

  
59
  attr_reader :transition_warning
59
  attr_reader :transition_warnings
60 60
  attr_writer :deleted_attachment_ids
61 61
  delegate :notes, :notes=, :private_notes, :private_notes=, :to => :current_journal, :allow_nil => true
62 62

  
......
971 971
  end
972 972

  
973 973
  # Returns true if this issue can be closed and if not, returns false and populates the reason
974
  # This does not take the workflow transitions into account
974 975
  def closable?
976
    @transition_warnings ||= []
975 977
    if descendants.open.any?
976
      @transition_warning = l(:notice_issue_not_closable_by_open_tasks)
977
      return false
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
      open_blocking_issues = true
982 982
    end
983
    return true
983

  
984
    if (open_sub_tasks && open_blocking_issues) && !@transition_warnings.include?(:not_closable_by_open_sub_tasks_and_blocking_issues)
985
      @transition_warnings << :not_closable_by_open_sub_tasks_and_blocking_issues
986
    elsif open_sub_tasks && !@transition_warnings.include?(:not_closable_by_open_sub_tasks)
987
      @transition_warnings << :not_closable_by_open_sub_tasks
988
    elsif open_blocking_issues && !@transition_warnings.include?(:not_closable_by_open_blocking_issues)
989
      @transition_warnings << :not_closable_by_open_blocking_issues
990
    end
991

  
992
    open_sub_tasks || open_blocking_issues ? (return false) : (return true)
984 993
  end
985 994

  
986
  # Returns true if this issue can be reopen and if not, returns false and populates the reason
995
  # Returns true if this issue can be reopened and if not, returns false and populates the reason
996
  # This does not take the workflow transitions into account
987 997
  def reopenable?
998
    @transition_warnings ||= []
988 999
    if ancestors.open(false).any?
989
      @transition_warning = l(:notice_issue_not_reopenable_by_closed_parent_issue)
990
      return false
1000
      closed_parent_issue = true
991 1001
    end
992
    return true
1002

  
1003
    if closed_parent_issue && !@transition_warnings.include?(:not_reopenable_by_closed_parent_issue)
1004
      @transition_warnings << :not_reopenable_by_closed_parent_issue
1005
    end
1006

  
1007
    closed_parent_issue ? (return false) : (return true)
993 1008
  end
994 1009

  
995 1010
  # 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_warnings %>
10
    <span class="icon-only icon-warning" title="<%= transition_warning_message(@issue) %>"><%= transition_warning_message(@issue) %></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 = l(:notice_issue_not_closable_by_blocking_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 = l(:notice_issue_not_closable_by_open_tasks_and_blocking_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
    )
5451 5476
    assert_response :success
5452
    reason = l(:notice_issue_not_closable_by_blocking_issue)
5477
    reason = l(:notice_issue_not_closable_by_open_tasks)
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
    )
5492
    assert_response :success
5493
    reason = l(:notice_issue_not_reopenable_by_closed_parent_issue)
5453 5494
    assert_select 'span.icon-warning[title=?]', reason, :text => reason
5454 5495
  end
5455 5496

  
test/unit/issue_test.rb
2105 2105

  
2106 2106
    allowed_statuses = parent.reload.new_statuses_allowed_to(users(:users_002))
2107 2107

  
2108
    assert !parent.closable?
2109
    assert_equal l(:notice_issue_not_closable_by_open_tasks), parent.transition_warning
2110

  
2111 2108
    assert allowed_statuses.any?
2112 2109
    assert_equal [], allowed_statuses.select(&:is_closed?)
2113 2110
  end
......
2118 2115

  
2119 2116
    allowed_statuses = parent.reload.new_statuses_allowed_to(users(:users_002))
2120 2117

  
2121
    assert parent.closable?
2122
    assert_nil parent.transition_warning
2123 2118
    assert allowed_statuses.any?
2124 2119
    assert allowed_statuses.select(&:is_closed?).any?
2125 2120
  end
......
3296 3291
  def test_closable
3297 3292
    issue10 = Issue.find(10)
3298 3293
    assert issue10.closable?
3299
    assert_nil issue10.transition_warning
3294
    assert_empty(issue10.transition_warnings)
3300 3295

  
3301
    # Issue blocked by another issue
3296
    # Issue blocked by another open issue
3302 3297
    issue9 = Issue.find(9)
3303 3298
    assert !issue9.closable?
3304
    assert_equal l(:notice_issue_not_closable_by_blocking_issue), issue9.transition_warning
3299
    assert_includes(issue9.transition_warnings, :not_closable_by_open_blocking_issues)
3300

  
3301
    # Issue with an open subtask and blocked by another open issue
3302
    child = issue9.generate_child!(:status_id => 1)
3303
    issue9.reload
3304
    assert !issue9.closable?
3305
    assert_includes(issue9.transition_warnings, :not_closable_by_open_sub_tasks_and_blocking_issues)
3306

  
3307
    # Issue with an open subtask
3308
    assert child.closable?
3309
    open_parent_issue = child.generate_child!
3310
    child.reload
3311
    assert !child.closable?
3312
    assert_includes(child.transition_warnings, :not_closable_by_open_sub_tasks)
3313

  
3314
    # Closed issue should be closable without a transition warning message
3315
    closed_issue = Issue.generate!(:status_id => 5)
3316
    assert closed_issue.closable?
3317
    assert_empty(closed_issue.transition_warnings)
3305 3318
  end
3306 3319

  
3307 3320
  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
3321
    closed_parent = Issue.generate!(:status_id => 5)
3322
    closed_child = closed_parent.generate_child!(:status_id => 5)
3323
    assert !closed_child.reopenable?
3324
    assert_includes(closed_child.transition_warnings, :not_reopenable_by_closed_parent_issue)
3325

  
3326
    # Open issue should be reopenable without a transition warning message
3327
    open_issue = Issue.generate!(:status_id => 1)
3328
    assert open_issue.reopenable?
3329
    assert_empty(open_issue.transition_warnings)
3313 3330
  end
3314 3331
end
(2-2/3)