##// END OF EJS Templates
Makes new issue initial status settable in workflow (#5816)....
Jean-Philippe Lang -
r14076:2bc5b60f9de7
parent child
Show More
@@ -0,0 +1,23
1 class InsertAllowedStatusesForNewIssues < ActiveRecord::Migration
2 def self.up
3 # Adds the default status for all trackers and roles
4 sql = "INSERT INTO #{WorkflowTransition.table_name} (tracker_id, old_status_id, new_status_id, role_id, type)" +
5 " SELECT t.id, 0, t.default_status_id, r.id, 'WorkflowTransition'" +
6 " FROM #{Tracker.table_name} t, #{Role.table_name} r"
7 WorkflowTransition.connection.execute(sql)
8
9 # Adds other statuses that are reachable with one transition
10 # to preserve previous behaviour as default
11 sql = "INSERT INTO #{WorkflowTransition.table_name} (tracker_id, old_status_id, new_status_id, role_id, type)" +
12 " SELECT t.id, 0, w.new_status_id, w.role_id, 'WorkflowTransition'" +
13 " FROM #{Tracker.table_name} t" +
14 " JOIN #{IssueStatus.table_name} s on s.id = t.default_status_id" +
15 " JOIN #{WorkflowTransition.table_name} w on w.tracker_id = t.id and w.old_status_id = s.id and w.type = 'WorkflowTransition'" +
16 " WHERE w.new_status_id <> t.default_status_id"
17 WorkflowTransition.connection.execute(sql)
18 end
19
20 def self.down
21 WorkflowTransition.where(:old_status_id => 0).delete_all
22 end
23 end
@@ -427,12 +427,12 class IssuesController < ApplicationController
427 427 @issue.author ||= User.current
428 428 @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date?
429 429
430 if attrs = params[:issue].deep_dup
431 if action_name == 'new' && params[:was_default_status] == attrs[:status_id]
432 attrs.delete(:status_id)
433 end
434 @issue.safe_attributes = attrs
430 attrs = (params[:issue] || {}).deep_dup
431 if action_name == 'new' && params[:was_default_status] == attrs[:status_id]
432 attrs.delete(:status_id)
435 433 end
434 @issue.safe_attributes = attrs
435
436 436 if @issue.project
437 437 @issue.tracker ||= @issue.project.trackers.first
438 438 if @issue.tracker.nil?
@@ -446,7 +446,7 class IssuesController < ApplicationController
446 446 end
447 447
448 448 @priorities = IssuePriority.active
449 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, @issue.new_record?)
449 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
450 450 end
451 451
452 452 def parse_params_for_bulk_issue_attributes(params)
@@ -43,7 +43,9 class WorkflowsController < ApplicationController
43 43 end
44 44
45 45 if @trackers && @roles && @statuses.any?
46 workflows = WorkflowTransition.where(:role_id => @roles.map(&:id), :tracker_id => @trackers.map(&:id))
46 workflows = WorkflowTransition.
47 where(:role_id => @roles.map(&:id), :tracker_id => @trackers.map(&:id)).
48 preload(:old_status, :new_status)
47 49 @workflows = {}
48 50 @workflows['always'] = workflows.select {|w| !w.author && !w.assignee}
49 51 @workflows['author'] = workflows.select {|w| w.author}
@@ -75,14 +75,14 module WorkflowsHelper
75 75 end
76 76
77 77 def transition_tag(workflows, old_status, new_status, name)
78 w = workflows.select {|w| w.old_status_id == old_status.id && w.new_status_id == new_status.id}.size
78 w = workflows.select {|w| w.old_status == old_status && w.new_status == new_status}.size
79 79
80 tag_name = "transitions[#{ old_status.id }][#{new_status.id}][#{name}]"
80 tag_name = "transitions[#{ old_status.try(:id) || 0 }][#{new_status.id}][#{name}]"
81 81 if w == 0 || w == @roles.size * @trackers.size
82 82
83 83 hidden_field_tag(tag_name, "0", :id => nil) +
84 84 check_box_tag(tag_name, "1", w != 0,
85 :class => "old-status-#{old_status.id} new-status-#{new_status.id}")
85 :class => "old-status-#{old_status.try(:id) || 0} new-status-#{new_status.id}")
86 86 else
87 87 select_tag tag_name,
88 88 options_for_select([
@@ -465,11 +465,15 class Issue < ActiveRecord::Base
465 465 self.tracker ||= project.trackers.first
466 466 end
467 467
468 statuses_allowed = new_statuses_allowed_to(user)
468 469 if (s = attrs.delete('status_id')) && safe_attribute?('status_id')
469 if new_statuses_allowed_to(user).collect(&:id).include?(s.to_i)
470 if statuses_allowed.collect(&:id).include?(s.to_i)
470 471 self.status_id = s
471 472 end
472 473 end
474 if new_record? && !statuses_allowed.include?(status)
475 self.status = statuses_allowed.first || default_status
476 end
473 477
474 478 attrs = delete_unsafe_attributes(attrs, user)
475 479 return if attrs.empty?
@@ -825,7 +829,7 class Issue < ActiveRecord::Base
825 829 else
826 830 initial_status = nil
827 831 if new_record?
828 initial_status = default_status
832 # nop
829 833 elsif tracker_id_changed?
830 834 if Tracker.where(:id => tracker_id_was, :default_status_id => status_id_was).any?
831 835 initial_status = default_status
@@ -843,16 +847,15 class Issue < ActiveRecord::Base
843 847 (user.id == initial_assigned_to_id || user.group_ids.include?(initial_assigned_to_id))
844 848
845 849 statuses = []
846 if initial_status
847 statuses += initial_status.find_new_statuses_allowed_to(
848 user.admin ? Role.all.to_a : user.roles_for_project(project),
849 tracker,
850 author == user,
851 assignee_transitions_allowed
852 )
853 end
850 statuses += IssueStatus.new_statuses_allowed(
851 initial_status,
852 user.admin ? Role.all.to_a : user.roles_for_project(project),
853 tracker,
854 author == user,
855 assignee_transitions_allowed
856 )
854 857 statuses << initial_status unless statuses.empty?
855 statuses << default_status if include_default
858 statuses << default_status if include_default || (new_record? && statuses.empty?)
856 859 statuses = statuses.compact.uniq.sort
857 860 if blocked?
858 861 statuses.reject!(&:is_closed?)
@@ -45,28 +45,18 class IssueStatus < ActiveRecord::Base
45 45 end
46 46
47 47 # Returns an array of all statuses the given role can switch to
48 # Uses association cache when called more than one time
49 48 def new_statuses_allowed_to(roles, tracker, author=false, assignee=false)
50 if roles && tracker
51 role_ids = roles.collect(&:id)
52 transitions = workflows.select do |w|
53 role_ids.include?(w.role_id) &&
54 w.tracker_id == tracker.id &&
55 ((!w.author && !w.assignee) || (author && w.author) || (assignee && w.assignee))
56 end
57 transitions.map(&:new_status).compact.sort
58 else
59 []
60 end
49 self.class.new_statuses_allowed(self, roles, tracker, author, assignee)
61 50 end
51 alias :find_new_statuses_allowed_to :new_statuses_allowed_to
62 52
63 # Same thing as above but uses a database query
64 # More efficient than the previous method if called just once
65 def find_new_statuses_allowed_to(roles, tracker, author=false, assignee=false)
53 def self.new_statuses_allowed(status, roles, tracker, author=false, assignee=false)
66 54 if roles.present? && tracker
55 status_id = status.try(:id) || 0
56
67 57 scope = IssueStatus.
68 58 joins(:workflow_transitions_as_new_status).
69 where(:workflows => {:old_status_id => id, :role_id => roles.map(&:id), :tracker_id => tracker.id})
59 where(:workflows => {:old_status_id => status_id, :role_id => roles.map(&:id), :tracker_id => tracker.id})
70 60
71 61 unless author && assignee
72 62 if author || assignee
@@ -17,6 +17,7
17 17
18 18 class WorkflowPermission < WorkflowRule
19 19 validates_inclusion_of :rule, :in => %w(readonly required)
20 validates_presence_of :old_status
20 21 validate :validate_field_name
21 22
22 23 # Returns the workflow permissions for the given trackers and roles
@@ -23,7 +23,7 class WorkflowRule < ActiveRecord::Base
23 23 belongs_to :old_status, :class_name => 'IssueStatus'
24 24 belongs_to :new_status, :class_name => 'IssueStatus'
25 25
26 validates_presence_of :role, :tracker, :old_status
26 validates_presence_of :role, :tracker
27 27 attr_protected :id
28 28
29 29 # Copies workflows from source to targets
@@ -20,16 +20,17
20 20 </tr>
21 21 </thead>
22 22 <tbody>
23 <% for old_status in @statuses %>
23 <% for old_status in [nil] + @statuses %>
24 <% next if old_status.nil? && name != 'always' %>
24 25 <tr class="<%= cycle("odd", "even") %>">
25 26 <td class="name">
26 <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input.old-status-#{old_status.id}')",
27 <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input.old-status-#{old_status.try(:id) || 0}')",
27 28 :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %>
28 29
29 <%= old_status.name %>
30 <%= old_status ? old_status.name : content_tag('em', l(:label_issue_new)) %>
30 31 </td>
31 32 <% for new_status in @statuses -%>
32 <% checked = workflows.detect {|w| w.old_status_id == old_status.id && w.new_status_id == new_status.id} %>
33 <% checked = workflows.detect {|w| w.old_status == old_status && w.new_status == new_status} %>
33 34 <td class="<%= checked ? 'enabled' : '' %>">
34 35 <%= transition_tag workflows, old_status, new_status, name %>
35 36 </td>
@@ -1882,3 +1882,45 WorkflowTransitions_188:
1882 1882 id: 188
1883 1883 tracker_id: 3
1884 1884 type: WorkflowTransition
1885 WorkflowTransitions_271:
1886 new_status_id: 3
1887 role_id: 1
1888 old_status_id: 0
1889 id: 271
1890 tracker_id: 2
1891 type: WorkflowTransition
1892 WorkflowTransitions_272:
1893 new_status_id: 3
1894 role_id: 2
1895 old_status_id: 0
1896 id: 272
1897 tracker_id: 1
1898 type: WorkflowTransition
1899 WorkflowTransitions_273:
1900 new_status_id: 2
1901 role_id: 1
1902 old_status_id: 0
1903 id: 273
1904 tracker_id: 3
1905 type: WorkflowTransition
1906 WorkflowTransitions_274:
1907 new_status_id: 2
1908 role_id: 1
1909 old_status_id: 0
1910 id: 274
1911 tracker_id: 1
1912 type: WorkflowTransition
1913 WorkflowTransitions_275:
1914 new_status_id: 1
1915 role_id: 1
1916 old_status_id: 0
1917 id: 275
1918 tracker_id: 1
1919 type: WorkflowTransition
1920 WorkflowTransitions_276:
1921 new_status_id: 1
1922 role_id: 1
1923 old_status_id: 0
1924 id: 276
1925 tracker_id: 2
1926 type: WorkflowTransition
@@ -1602,6 +1602,37 class IssuesControllerTest < ActionController::TestCase
1602 1602 assert_select 'input[name=was_default_status][value="1"]'
1603 1603 end
1604 1604
1605 def test_new_should_propose_allowed_statuses
1606 WorkflowTransition.delete_all
1607 WorkflowTransition.create!(:tracker_id => 1, :role_id => 1, :old_status_id => 0, :new_status_id => 1)
1608 WorkflowTransition.create!(:tracker_id => 1, :role_id => 1, :old_status_id => 0, :new_status_id => 3)
1609 @request.session[:user_id] = 2
1610
1611 get :new, :project_id => 1
1612 assert_response :success
1613 assert_select 'select[name=?]', 'issue[status_id]' do
1614 assert_select 'option[value="1"]'
1615 assert_select 'option[value="3"]'
1616 assert_select 'option', 2
1617 assert_select 'option[value="1"][selected=selected]'
1618 end
1619 end
1620
1621 def test_new_should_propose_allowed_statuses_without_default_status_allowed
1622 WorkflowTransition.delete_all
1623 WorkflowTransition.create!(:tracker_id => 1, :role_id => 1, :old_status_id => 0, :new_status_id => 2)
1624 assert_equal 1, Tracker.find(1).default_status_id
1625 @request.session[:user_id] = 2
1626
1627 get :new, :project_id => 1
1628 assert_response :success
1629 assert_select 'select[name=?]', 'issue[status_id]' do
1630 assert_select 'option[value="2"]'
1631 assert_select 'option', 1
1632 assert_select 'option[value="2"][selected=selected]'
1633 end
1634 end
1635
1605 1636 def test_get_new_with_list_custom_field
1606 1637 @request.session[:user_id] = 2
1607 1638 get :new, :project_id => 1, :tracker_id => 1
@@ -1827,8 +1858,8 class IssuesControllerTest < ActionController::TestCase
1827 1858 def test_update_form_for_new_issue_should_propose_transitions_based_on_initial_status
1828 1859 @request.session[:user_id] = 2
1829 1860 WorkflowTransition.delete_all
1830 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2)
1831 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5)
1861 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 2)
1862 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 5)
1832 1863 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4)
1833 1864
1834 1865 xhr :post, :new, :project_id => 1,
@@ -1837,7 +1868,7 class IssuesControllerTest < ActionController::TestCase
1837 1868 :subject => 'This is an issue'}
1838 1869
1839 1870 assert_equal 5, assigns(:issue).status_id
1840 assert_equal [1,2,5], assigns(:allowed_statuses).map(&:id).sort
1871 assert_equal [2,5], assigns(:allowed_statuses).map(&:id).sort
1841 1872 end
1842 1873
1843 1874 def test_update_form_with_default_status_should_ignore_submitted_status_id_if_equals
@@ -61,6 +61,16 class WorkflowsControllerTest < ActionController::TestCase
61 61 assert_select 'input[type=checkbox][name=?]', 'transitions[1][1][always]', 0
62 62 end
63 63
64 def test_get_edit_should_include_allowed_statuses_for_new_issues
65 WorkflowTransition.delete_all
66 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 1)
67
68 get :edit, :role_id => 1, :tracker_id => 1
69 assert_response :success
70 assert_select 'td', 'New issue'
71 assert_select 'input[type=checkbox][name=?][value="1"][checked=checked]', 'transitions[0][1][always]'
72 end
73
64 74 def test_get_edit_with_all_roles_and_all_trackers
65 75 get :edit, :role_id => 'all', :tracker_id => 'all'
66 76 assert_response :success
@@ -96,6 +106,20 class WorkflowsControllerTest < ActionController::TestCase
96 106 assert_nil WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4).first
97 107 end
98 108
109 def test_post_edit_with_allowed_statuses_for_new_issues
110 WorkflowTransition.delete_all
111
112 post :edit, :role_id => 2, :tracker_id => 1,
113 :transitions => {
114 '0' => {'1' => {'always' => '1'}, '2' => {'always' => '1'}}
115 }
116 assert_response 302
117
118 assert WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 0, :new_status_id => 1).any?
119 assert WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 0, :new_status_id => 2).any?
120 assert_equal 2, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
121 end
122
99 123 def test_post_edit_with_additional_transitions
100 124 WorkflowTransition.delete_all
101 125
@@ -47,13 +47,14 class RoleTest < ActiveSupport::TestCase
47 47
48 48 def test_copy_workflows
49 49 source = Role.find(1)
50 assert_equal 90, source.workflow_rules.size
50 rule_count = source.workflow_rules.count
51 assert rule_count > 0
51 52
52 53 target = Role.new(:name => 'Target')
53 54 assert target.save
54 55 target.workflow_rules.copy(source)
55 56 target.reload
56 assert_equal 90, target.workflow_rules.size
57 assert_equal rule_count, target.workflow_rules.size
57 58 end
58 59
59 60 def test_permissions_should_be_unserialized_with_its_coder
@@ -30,13 +30,14 class TrackerTest < ActiveSupport::TestCase
30 30
31 31 def test_copy_workflows
32 32 source = Tracker.find(1)
33 assert_equal 89, source.workflow_rules.size
33 rules_count = source.workflow_rules.count
34 assert rules_count > 0
34 35
35 36 target = Tracker.new(:name => 'Target', :default_status_id => 1)
36 37 assert target.save
37 38 target.workflow_rules.copy(source)
38 39 target.reload
39 assert_equal 89, target.workflow_rules.size
40 assert_equal rules_count, target.workflow_rules.size
40 41 end
41 42
42 43 def test_issue_statuses
General Comments 0
You need to be logged in to leave comments. Login now