##// END OF EJS Templates
Default status per tracker (#5991)....
Jean-Philippe Lang -
r13153:dfc594c33702
parent child
Show More
@@ -0,0 +1,15
1 class AddTrackersDefaultStatusId < ActiveRecord::Migration
2 def up
3 add_column :trackers, :default_status_id, :integer
4
5 status_id = IssueStatus.where(:is_default => true).pluck(:id).first
6 status_id ||= IssueStatus.order(:position).pluck(:id).first
7 if status_id
8 Tracker.update_all :default_status_id => status_id
9 end
10 end
11
12 def down
13 remove_column :trackers, :default_status_id
14 end
15 end
@@ -0,0 +1,12
1 class RemoveIssueStatusesIsDefault < ActiveRecord::Migration
2 def up
3 remove_column :issue_statuses, :is_default
4 end
5
6 def down
7 add_column :issue_statuses, :is_default, :boolean, :null => false, :default => false
8 # Restores the first status as default
9 default_status_id = IssueStatus.order("position").first.pluck(:id)
10 IssueStatus.where(:id => default_status_id).update_all(:is_default => true)
11 end
12 end
@@ -24,7 +24,6 class IssuesController < ApplicationController
24 before_filter :find_project, :only => [:new, :create, :update_form]
24 before_filter :find_project, :only => [:new, :create, :update_form]
25 before_filter :authorize, :except => [:index]
25 before_filter :authorize, :except => [:index]
26 before_filter :find_optional_project, :only => [:index]
26 before_filter :find_optional_project, :only => [:index]
27 before_filter :check_for_default_issue_status, :only => [:new, :create]
28 before_filter :build_new_issue_from_params, :only => [:new, :create, :update_form]
27 before_filter :build_new_issue_from_params, :only => [:new, :create, :update_form]
29 accept_rss_auth :index, :show
28 accept_rss_auth :index, :show
30 accept_api_auth :index, :show, :create, :update, :destroy
29 accept_api_auth :index, :show, :create, :update, :destroy
@@ -234,7 +233,8 class IssuesController < ApplicationController
234 target_projects ||= @projects
233 target_projects ||= @projects
235
234
236 if @copy
235 if @copy
237 @available_statuses = [IssueStatus.default]
236 # Copied issues will get their default statuses
237 @available_statuses = []
238 else
238 else
239 @available_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&)
239 @available_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&)
240 end
240 end
@@ -425,12 +425,21 class IssuesController < ApplicationController
425 @issue = @project.issues.visible.find(params[:id])
425 @issue = @project.issues.visible.find(params[:id])
426 end
426 end
427
427
428 @issue.safe_attributes = params[:issue]
428 if attrs = params[:issue].deep_dup
429 if params[:was_default_status] == attrs[:status_id]
430 attrs.delete(:status_id)
431 end
432 @issue.safe_attributes = attrs
433 end
429 @issue.tracker ||= @project.trackers.first
434 @issue.tracker ||= @project.trackers.first
430 if @issue.tracker.nil?
435 if @issue.tracker.nil?
431 render_error l(:error_no_tracker_in_project)
436 render_error l(:error_no_tracker_in_project)
432 return false
437 return false
433 end
438 end
439 if @issue.status.nil?
440 render_error l(:error_no_default_issue_status)
441 return false
442 end
434
443
435 @priorities = IssuePriority.active
444 @priorities = IssuePriority.active
436 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, @issue.new_record?)
445 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, @issue.new_record?)
@@ -440,13 +449,6 class IssuesController < ApplicationController
440 end
449 end
441 end
450 end
442
451
443 def check_for_default_issue_status
444 if IssueStatus.default.nil?
445 render_error l(:error_no_default_issue_status)
446 return false
447 end
448 end
449
450 def parse_params_for_bulk_issue_attributes(params)
452 def parse_params_for_bulk_issue_attributes(params)
451 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
453 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
452 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
454 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
@@ -162,7 +162,6 class Issue < ActiveRecord::Base
162 super
162 super
163 if new_record?
163 if new_record?
164 # set default values for new records only
164 # set default values for new records only
165 self.status ||= IssueStatus.default
166 self.priority ||= IssuePriority.default
165 self.priority ||= IssuePriority.default
167 self.watcher_user_ids = []
166 self.watcher_user_ids = []
168 end
167 end
@@ -273,11 +272,19 class Issue < ActiveRecord::Base
273 issue.save ? issue : false
272 issue.save ? issue : false
274 end
273 end
275
274
276 def status_id=(sid)
275 def status_id=(status_id)
277 self.status = nil
276 if status_id.to_s != self.status_id.to_s
278 result = write_attribute(:status_id, sid)
277 self.status = (status_id.present? ? IssueStatus.find_by_id(status_id) : nil)
279 @workflow_rule_by_attribute = nil
278 end
280 result
279 self.status_id
280 end
281
282 # Sets the status.
283 def self.status=(status)
284 if status != self.status
285 @workflow_rule_by_attribute = nil
286 end
287 association(:status).writer(status)
281 end
288 end
282
289
283 def priority_id=(pid)
290 def priority_id=(pid)
@@ -302,12 +309,24 class Issue < ActiveRecord::Base
302 self.tracker_id
309 self.tracker_id
303 end
310 end
304
311
312 # Sets the tracker.
313 # This will set the status to the default status of the new tracker if:
314 # * the status was the default for the previous tracker
315 # * or if the status was not part of the new tracker statuses
316 # * or the status was nil
305 def tracker=(tracker)
317 def tracker=(tracker)
306 if tracker != self.tracker
318 if tracker != self.tracker
319 if status == default_status
320 self.status = nil
321 elsif status && tracker && !tracker.issue_status_ids.include?(status.id)
322 self.status = nil
323 end
307 @custom_field_values = nil
324 @custom_field_values = nil
308 @workflow_rule_by_attribute = nil
325 @workflow_rule_by_attribute = nil
309 end
326 end
310 association(:tracker).writer(tracker)
327 association(:tracker).writer(tracker)
328 self.status ||= default_status
329 self.tracker
311 end
330 end
312
331
313 def project_id=(project_id)
332 def project_id=(project_id)
@@ -317,6 +336,14 class Issue < ActiveRecord::Base
317 self.project_id
336 self.project_id
318 end
337 end
319
338
339 # Sets the project.
340 # Unless keep_tracker argument is set to true, this will change the tracker
341 # to the first tracker of the new project if the previous tracker is not part
342 # of the new project trackers.
343 # This will clear the fixed_version is it's no longer valid for the new project.
344 # This will clear the parent issue if it's no longer valid for the new project.
345 # This will set the category to the category with the same name in the new
346 # project if it exists, or clear it if it doesn't.
320 def project=(project, keep_tracker=false)
347 def project=(project, keep_tracker=false)
321 project_was = self.project
348 project_was = self.project
322 association(:project).writer(project)
349 association(:project).writer(project)
@@ -339,7 +366,9 class Issue < ActiveRecord::Base
339 self.parent_issue_id = nil
366 self.parent_issue_id = nil
340 end
367 end
341 @custom_field_values = nil
368 @custom_field_values = nil
369 @workflow_rule_by_attribute = nil
342 end
370 end
371 self.project
343 end
372 end
344
373
345 def description=(arg)
374 def description=(arg)
@@ -776,14 +805,28 class Issue < ActiveRecord::Base
776 !relations_to.detect {|ir| ir.relation_type == 'blocks' && !ir.issue_from.closed?}.nil?
805 !relations_to.detect {|ir| ir.relation_type == 'blocks' && !ir.issue_from.closed?}.nil?
777 end
806 end
778
807
808 # Returns the default status of the issue based on its tracker
809 # Returns nil if tracker is nil
810 def default_status
811 tracker.try(:default_status)
812 end
813
779 # Returns an array of statuses that user is able to apply
814 # Returns an array of statuses that user is able to apply
780 def new_statuses_allowed_to(user=User.current, include_default=false)
815 def new_statuses_allowed_to(user=User.current, include_default=false)
781 if new_record? && @copied_from
816 if new_record? && @copied_from
782 [IssueStatus.default, @copied_from.status].compact.uniq.sort
817 [default_status, @copied_from.status].compact.uniq.sort
783 else
818 else
784 initial_status = nil
819 initial_status = nil
785 if new_record?
820 if new_record?
786 initial_status = IssueStatus.default
821 initial_status = default_status
822 elsif tracker_id_changed?
823 if Tracker.where(:id => tracker_id_was, :default_status_id => status_id_was).any?
824 initial_status = default_status
825 elsif tracker.issue_status_ids.include?(status_id_was)
826 initial_status = IssueStatus.find_by_id(status_id_was)
827 else
828 initial_status = default_status
829 end
787 else
830 else
788 initial_status = status_was
831 initial_status = status_was
789 end
832 end
@@ -802,7 +845,7 class Issue < ActiveRecord::Base
802 )
845 )
803 end
846 end
804 statuses << initial_status unless statuses.empty?
847 statuses << initial_status unless statuses.empty?
805 statuses << IssueStatus.default if include_default
848 statuses << default_status if include_default
806 statuses = statuses.compact.uniq.sort
849 statuses = statuses.compact.uniq.sort
807 if blocked?
850 if blocked?
808 statuses.reject!(&:is_closed?)
851 statuses.reject!(&:is_closed?)
@@ -22,7 +22,6 class IssueStatus < ActiveRecord::Base
22 acts_as_list
22 acts_as_list
23
23
24 before_destroy :delete_workflow_rules
24 before_destroy :delete_workflow_rules
25 after_save :update_default
26
25
27 validates_presence_of :name
26 validates_presence_of :name
28 validates_uniqueness_of :name
27 validates_uniqueness_of :name
@@ -33,15 +32,6 class IssueStatus < ActiveRecord::Base
33 scope :sorted, lambda { order(:position) }
32 scope :sorted, lambda { order(:position) }
34 scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
33 scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
35
34
36 def update_default
37 IssueStatus.where(['id <> ?', id]).update_all({:is_default => false}) if self.is_default?
38 end
39
40 # Returns the default status for new issues
41 def self.default
42 where(:is_default => true).first
43 end
44
45 # Update all the +Issues+ setting their done_ratio to the value of their +IssueStatus+
35 # Update all the +Issues+ setting their done_ratio to the value of their +IssueStatus+
46 def self.update_issue_done_ratios
36 def self.update_issue_done_ratios
47 if Issue.use_status_for_done_ratio?
37 if Issue.use_status_for_done_ratio?
@@ -100,7 +90,11 class IssueStatus < ActiveRecord::Base
100 private
90 private
101
91
102 def check_integrity
92 def check_integrity
103 raise "Can't delete status" if Issue.where(:status_id => id).any?
93 if Issue.where(:status_id => id).any?
94 raise "This status is used by some issues"
95 elsif Tracker.where(:default_status_id => id).any?
96 raise "This status is used as the default status by some trackers"
97 end
104 end
98 end
105
99
106 # Deletes associated workflows
100 # Deletes associated workflows
@@ -24,6 +24,7 class Tracker < ActiveRecord::Base
24 CORE_FIELDS_ALL = (CORE_FIELDS_UNDISABLABLE + CORE_FIELDS).freeze
24 CORE_FIELDS_ALL = (CORE_FIELDS_UNDISABLABLE + CORE_FIELDS).freeze
25
25
26 before_destroy :check_integrity
26 before_destroy :check_integrity
27 belongs_to :default_status, :class_name => 'IssueStatus'
27 has_many :issues
28 has_many :issues
28 has_many :workflow_rules, :dependent => :delete_all do
29 has_many :workflow_rules, :dependent => :delete_all do
29 def copy(source_tracker)
30 def copy(source_tracker)
@@ -37,6 +38,7 class Tracker < ActiveRecord::Base
37
38
38 attr_protected :fields_bits
39 attr_protected :fields_bits
39
40
41 validates_presence_of :default_status
40 validates_presence_of :name
42 validates_presence_of :name
41 validates_uniqueness_of :name
43 validates_uniqueness_of :name
42 validates_length_of :name, :maximum => 30
44 validates_length_of :name, :maximum => 30
@@ -53,14 +55,15 class Tracker < ActiveRecord::Base
53 # Returns an array of IssueStatus that are used
55 # Returns an array of IssueStatus that are used
54 # in the tracker's workflows
56 # in the tracker's workflows
55 def issue_statuses
57 def issue_statuses
56 if @issue_statuses
58 @issue_statuses ||= IssueStatus.where(:id => issue_status_ids).to_a.sort
57 return @issue_statuses
59 end
58 elsif new_record?
59 return []
60 end
61
60
62 status_ids = WorkflowTransition.where(:tracker_id => id).uniq.pluck(:old_status_id, :new_status_id).flatten.uniq
61 def issue_status_ids
63 @issue_statuses = IssueStatus.where(:id => status_ids).to_a.sort
62 if new_record?
63 []
64 else
65 @issue_status_ids ||= WorkflowTransition.where(:tracker_id => id).uniq.pluck(:old_status_id, :new_status_id).flatten.uniq
66 end
64 end
67 end
65
68
66 def disabled_core_fields
69 def disabled_core_fields
@@ -6,7 +6,6
6 <p><%= f.select :default_done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :include_blank => true, :label => :field_done_ratio %></p>
6 <p><%= f.select :default_done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :include_blank => true, :label => :field_done_ratio %></p>
7 <% end %>
7 <% end %>
8 <p><%= f.check_box :is_closed %></p>
8 <p><%= f.check_box :is_closed %></p>
9 <p><%= f.check_box :is_default %></p>
10
9
11 <%= call_hook(:view_issue_statuses_form, :issue_status => @issue_status) %>
10 <%= call_hook(:view_issue_statuses_form, :issue_status => @issue_status) %>
12 </div>
11 </div>
@@ -3,7 +3,6 api.array :issue_statuses do
3 api.issue_status do
3 api.issue_status do
4 api.id status.id
4 api.id status.id
5 api.name status.name
5 api.name status.name
6 api.is_default status.is_default
7 api.is_closed status.is_closed
6 api.is_closed status.is_closed
8 end
7 end
9 end
8 end
@@ -11,7 +11,6
11 <% if Issue.use_status_for_done_ratio? %>
11 <% if Issue.use_status_for_done_ratio? %>
12 <th><%=l(:field_done_ratio)%></th>
12 <th><%=l(:field_done_ratio)%></th>
13 <% end %>
13 <% end %>
14 <th><%=l(:field_is_default)%></th>
15 <th><%=l(:field_is_closed)%></th>
14 <th><%=l(:field_is_closed)%></th>
16 <th><%=l(:button_sort)%></th>
15 <th><%=l(:button_sort)%></th>
17 <th></th>
16 <th></th>
@@ -23,7 +22,6
23 <% if Issue.use_status_for_done_ratio? %>
22 <% if Issue.use_status_for_done_ratio? %>
24 <td><%= h status.default_done_ratio %></td>
23 <td><%= h status.default_done_ratio %></td>
25 <% end %>
24 <% end %>
26 <td><%= checked_image status.is_default? %></td>
27 <td><%= checked_image status.is_closed? %></td>
25 <td><%= checked_image status.is_closed? %></td>
28 <td class="reorder"><%= reorder_links('issue_status', {:action => 'update', :id => status}, :put) %></td>
26 <td class="reorder"><%= reorder_links('issue_status', {:action => 'update', :id => status}, :put) %></td>
29 <td class="buttons">
27 <td class="buttons">
@@ -5,9 +5,9
5 <% if @issue.safe_attribute?('status_id') && @allowed_statuses.present? %>
5 <% if @issue.safe_attribute?('status_id') && @allowed_statuses.present? %>
6 <p><%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), {:required => true},
6 <p><%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), {:required => true},
7 :onchange => "updateIssueFrom('#{escape_javascript project_issue_form_path(@project, :id => @issue, :format => 'js')}')" %></p>
7 :onchange => "updateIssueFrom('#{escape_javascript project_issue_form_path(@project, :id => @issue, :format => 'js')}')" %></p>
8
8 <%= hidden_field_tag 'was_default_status', @issue.status_id, :id => nil if @issue.status == @issue.default_status %>
9 <% else %>
9 <% else %>
10 <p><label><%= l(:field_status) %></label> <%= h(@issue.status.name) %></p>
10 <p><label><%= l(:field_status) %></label> <%= @issue.status %></p>
11 <% end %>
11 <% end %>
12
12
13 <% if @issue.safe_attribute? 'priority_id' %>
13 <% if @issue.safe_attribute? 'priority_id' %>
@@ -4,8 +4,12
4 <div class="box tabular">
4 <div class="box tabular">
5 <!--[form:tracker]-->
5 <!--[form:tracker]-->
6 <p><%= f.text_field :name, :required => true %></p>
6 <p><%= f.text_field :name, :required => true %></p>
7 <p><%= f.select :default_status_id,
8 IssueStatus.sorted.map {|s| [s.name, s.id]},
9 :include_blank => @tracker.default_status.nil?,
10 :required => true %>
11 </p>
7 <p><%= f.check_box :is_in_roadmap %></p>
12 <p><%= f.check_box :is_in_roadmap %></p>
8
9 <p>
13 <p>
10 <label><%= l(:field_core_fields) %></label>
14 <label><%= l(:field_core_fields) %></label>
11 <% Tracker::CORE_FIELDS.each do |field| %>
15 <% Tracker::CORE_FIELDS.each do |field| %>
@@ -3,6 +3,7 api.array :trackers do
3 api.tracker do
3 api.tracker do
4 api.id tracker.id
4 api.id tracker.id
5 api.name tracker.name
5 api.name tracker.name
6 api.default_status(:id => tracker.default_status.id, :name => tracker.default_status.name) unless tracker.default_status.nil?
6 end
7 end
7 end
8 end
8 end
9 end
@@ -337,6 +337,7 en:
337 field_inherit_members: Inherit members
337 field_inherit_members: Inherit members
338 field_generate_password: Generate password
338 field_generate_password: Generate password
339 field_must_change_passwd: Must change password at next logon
339 field_must_change_passwd: Must change password at next logon
340 field_default_status: Default status
340
341
341 setting_app_title: Application title
342 setting_app_title: Application title
342 setting_app_subtitle: Application subtitle
343 setting_app_subtitle: Application subtitle
@@ -357,6 +357,7 fr:
357 field_inherit_members: Hériter les membres
357 field_inherit_members: Hériter les membres
358 field_generate_password: Générer un mot de passe
358 field_generate_password: Générer un mot de passe
359 field_must_change_passwd: Doit changer de mot de passe à la prochaine connexion
359 field_must_change_passwd: Doit changer de mot de passe à la prochaine connexion
360 field_default_status: Statut par défaut
360
361
361 setting_app_title: Titre de l'application
362 setting_app_title: Titre de l'application
362 setting_app_subtitle: Sous-titre de l'application
363 setting_app_subtitle: Sous-titre de l'application
@@ -125,18 +125,18 module Redmine
125 :browse_repository,
125 :browse_repository,
126 :view_changesets]
126 :view_changesets]
127
127
128 # Trackers
129 Tracker.create!(:name => l(:default_tracker_bug), :is_in_chlog => true, :is_in_roadmap => false, :position => 1)
130 Tracker.create!(:name => l(:default_tracker_feature), :is_in_chlog => true, :is_in_roadmap => true, :position => 2)
131 Tracker.create!(:name => l(:default_tracker_support), :is_in_chlog => false, :is_in_roadmap => false, :position => 3)
132
133 # Issue statuses
128 # Issue statuses
134 new = IssueStatus.create!(:name => l(:default_issue_status_new), :is_closed => false, :is_default => true, :position => 1)
129 new = IssueStatus.create!(:name => l(:default_issue_status_new), :is_closed => false, :position => 1)
135 in_progress = IssueStatus.create!(:name => l(:default_issue_status_in_progress), :is_closed => false, :is_default => false, :position => 2)
130 in_progress = IssueStatus.create!(:name => l(:default_issue_status_in_progress), :is_closed => false, :position => 2)
136 resolved = IssueStatus.create!(:name => l(:default_issue_status_resolved), :is_closed => false, :is_default => false, :position => 3)
131 resolved = IssueStatus.create!(:name => l(:default_issue_status_resolved), :is_closed => false, :position => 3)
137 feedback = IssueStatus.create!(:name => l(:default_issue_status_feedback), :is_closed => false, :is_default => false, :position => 4)
132 feedback = IssueStatus.create!(:name => l(:default_issue_status_feedback), :is_closed => false, :position => 4)
138 closed = IssueStatus.create!(:name => l(:default_issue_status_closed), :is_closed => true, :is_default => false, :position => 5)
133 closed = IssueStatus.create!(:name => l(:default_issue_status_closed), :is_closed => true, :position => 5)
139 rejected = IssueStatus.create!(:name => l(:default_issue_status_rejected), :is_closed => true, :is_default => false, :position => 6)
134 rejected = IssueStatus.create!(:name => l(:default_issue_status_rejected), :is_closed => true, :position => 6)
135
136 # Trackers
137 Tracker.create!(:name => l(:default_tracker_bug), :default_status_id => new.id, :is_in_chlog => true, :is_in_roadmap => false, :position => 1)
138 Tracker.create!(:name => l(:default_tracker_feature), :default_status_id => new.id, :is_in_chlog => true, :is_in_roadmap => true, :position => 2)
139 Tracker.create!(:name => l(:default_tracker_support), :default_status_id => new.id, :is_in_chlog => false, :is_in_roadmap => false, :position => 3)
140
140
141 # Workflow
141 # Workflow
142 Tracker.all.each { |t|
142 Tracker.all.each { |t|
@@ -25,15 +25,15 task :migrate_from_mantis => :environment do
25
25
26 module MantisMigrate
26 module MantisMigrate
27
27
28 DEFAULT_STATUS = IssueStatus.default
28 new_status = IssueStatus.find_by_position(1)
29 assigned_status = IssueStatus.find_by_position(2)
29 assigned_status = IssueStatus.find_by_position(2)
30 resolved_status = IssueStatus.find_by_position(3)
30 resolved_status = IssueStatus.find_by_position(3)
31 feedback_status = IssueStatus.find_by_position(4)
31 feedback_status = IssueStatus.find_by_position(4)
32 closed_status = IssueStatus.where(:is_closed => true).first
32 closed_status = IssueStatus.where(:is_closed => true).first
33 STATUS_MAPPING = {10 => DEFAULT_STATUS, # new
33 STATUS_MAPPING = {10 => new_status, # new
34 20 => feedback_status, # feedback
34 20 => feedback_status, # feedback
35 30 => DEFAULT_STATUS, # acknowledged
35 30 => new_status, # acknowledged
36 40 => DEFAULT_STATUS, # confirmed
36 40 => new_status, # confirmed
37 50 => assigned_status, # assigned
37 50 => assigned_status, # assigned
38 80 => resolved_status, # resolved
38 80 => resolved_status, # resolved
39 90 => closed_status # closed
39 90 => closed_status # closed
@@ -317,8 +317,8 task :migrate_from_mantis => :environment do
317 i.author = User.find_by_id(users_map[bug.reporter_id])
317 i.author = User.find_by_id(users_map[bug.reporter_id])
318 i.category = IssueCategory.find_by_project_id_and_name(i.project_id, bug.category[0,30]) unless bug.category.blank?
318 i.category = IssueCategory.find_by_project_id_and_name(i.project_id, bug.category[0,30]) unless bug.category.blank?
319 i.fixed_version = Version.find_by_project_id_and_name(i.project_id, bug.fixed_in_version) unless bug.fixed_in_version.blank?
319 i.fixed_version = Version.find_by_project_id_and_name(i.project_id, bug.fixed_in_version) unless bug.fixed_in_version.blank?
320 i.status = STATUS_MAPPING[bug.status] || DEFAULT_STATUS
321 i.tracker = (bug.severity == 10 ? TRACKER_FEATURE : TRACKER_BUG)
320 i.tracker = (bug.severity == 10 ? TRACKER_FEATURE : TRACKER_BUG)
321 i.status = STATUS_MAPPING[bug.status] || i.status
322 i.id = bug.id if keep_bug_ids
322 i.id = bug.id if keep_bug_ids
323 next unless i.save
323 next unless i.save
324 issues_map[bug.id] = i.id
324 issues_map[bug.id] = i.id
@@ -25,12 +25,12 namespace :redmine do
25 module TracMigrate
25 module TracMigrate
26 TICKET_MAP = []
26 TICKET_MAP = []
27
27
28 DEFAULT_STATUS = IssueStatus.default
28 new_status = IssueStatus.find_by_position(1)
29 assigned_status = IssueStatus.find_by_position(2)
29 assigned_status = IssueStatus.find_by_position(2)
30 resolved_status = IssueStatus.find_by_position(3)
30 resolved_status = IssueStatus.find_by_position(3)
31 feedback_status = IssueStatus.find_by_position(4)
31 feedback_status = IssueStatus.find_by_position(4)
32 closed_status = IssueStatus.where(:is_closed => true).first
32 closed_status = IssueStatus.where(:is_closed => true).first
33 STATUS_MAPPING = {'new' => DEFAULT_STATUS,
33 STATUS_MAPPING = {'new' => new_status,
34 'reopened' => feedback_status,
34 'reopened' => feedback_status,
35 'assigned' => assigned_status,
35 'assigned' => assigned_status,
36 'closed' => closed_status
36 'closed' => closed_status
@@ -476,8 +476,8 namespace :redmine do
476 i.author = find_or_create_user(ticket.reporter)
476 i.author = find_or_create_user(ticket.reporter)
477 i.category = issues_category_map[ticket.component] unless ticket.component.blank?
477 i.category = issues_category_map[ticket.component] unless ticket.component.blank?
478 i.fixed_version = version_map[ticket.milestone] unless ticket.milestone.blank?
478 i.fixed_version = version_map[ticket.milestone] unless ticket.milestone.blank?
479 i.status = STATUS_MAPPING[ticket.status] || DEFAULT_STATUS
480 i.tracker = TRACKER_MAPPING[ticket.ticket_type] || DEFAULT_TRACKER
479 i.tracker = TRACKER_MAPPING[ticket.ticket_type] || DEFAULT_TRACKER
480 i.status = STATUS_MAPPING[ticket.status] || i.default_status
481 i.id = ticket.id unless Issue.exists?(ticket.id)
481 i.id = ticket.id unless Issue.exists?(ticket.id)
482 next unless Time.fake(ticket.changetime) { i.save }
482 next unless Time.fake(ticket.changetime) { i.save }
483 TICKET_MAP[ticket.id] = i.id
483 TICKET_MAP[ticket.id] = i.id
@@ -2,36 +2,30
2 issue_statuses_001:
2 issue_statuses_001:
3 id: 1
3 id: 1
4 name: New
4 name: New
5 is_default: true
6 is_closed: false
5 is_closed: false
7 position: 1
6 position: 1
8 issue_statuses_002:
7 issue_statuses_002:
9 id: 2
8 id: 2
10 name: Assigned
9 name: Assigned
11 is_default: false
12 is_closed: false
10 is_closed: false
13 position: 2
11 position: 2
14 issue_statuses_003:
12 issue_statuses_003:
15 id: 3
13 id: 3
16 name: Resolved
14 name: Resolved
17 is_default: false
18 is_closed: false
15 is_closed: false
19 position: 3
16 position: 3
20 issue_statuses_004:
17 issue_statuses_004:
21 name: Feedback
18 name: Feedback
22 id: 4
19 id: 4
23 is_default: false
24 is_closed: false
20 is_closed: false
25 position: 4
21 position: 4
26 issue_statuses_005:
22 issue_statuses_005:
27 id: 5
23 id: 5
28 name: Closed
24 name: Closed
29 is_default: false
30 is_closed: true
25 is_closed: true
31 position: 5
26 position: 5
32 issue_statuses_006:
27 issue_statuses_006:
33 id: 6
28 id: 6
34 name: Rejected
29 name: Rejected
35 is_default: false
36 is_closed: true
30 is_closed: true
37 position: 6
31 position: 6
@@ -3,14 +3,17 trackers_001:
3 name: Bug
3 name: Bug
4 id: 1
4 id: 1
5 is_in_chlog: true
5 is_in_chlog: true
6 default_status_id: 1
6 position: 1
7 position: 1
7 trackers_002:
8 trackers_002:
8 name: Feature request
9 name: Feature request
9 id: 2
10 id: 2
10 is_in_chlog: true
11 is_in_chlog: true
12 default_status_id: 1
11 position: 2
13 position: 2
12 trackers_003:
14 trackers_003:
13 name: Support request
15 name: Support request
14 id: 3
16 id: 3
15 is_in_chlog: false
17 is_in_chlog: false
18 default_status_id: 1
16 position: 3
19 position: 3
@@ -86,7 +86,8 class IssueStatusesControllerTest < ActionController::TestCase
86 end
86 end
87
87
88 def test_destroy
88 def test_destroy
89 Issue.delete_all("status_id = 1")
89 Issue.where(:status_id => 1).delete_all
90 Tracker.where(:default_status_id => 1).delete_all
90
91
91 assert_difference 'IssueStatus.count', -1 do
92 assert_difference 'IssueStatus.count', -1 do
92 delete :destroy, :id => '1'
93 delete :destroy, :id => '1'
@@ -96,7 +97,19 class IssueStatusesControllerTest < ActionController::TestCase
96 end
97 end
97
98
98 def test_destroy_should_block_if_status_in_use
99 def test_destroy_should_block_if_status_in_use
99 assert_not_nil Issue.find_by_status_id(1)
100 assert Issue.where(:status_id => 1).any?
101 Tracker.where(:default_status_id => 1).delete_all
102
103 assert_no_difference 'IssueStatus.count' do
104 delete :destroy, :id => '1'
105 end
106 assert_redirected_to :action => 'index'
107 assert_not_nil IssueStatus.find_by_id(1)
108 end
109
110 def test_destroy_should_block_if_status_in_use
111 Issue.where(:status_id => 1).delete_all
112 assert Tracker.where(:default_status_id => 1).any?
100
113
101 assert_no_difference 'IssueStatus.count' do
114 assert_no_difference 'IssueStatus.count' do
102 delete :destroy, :id => '1'
115 delete :destroy, :id => '1'
@@ -1511,6 +1511,30 class IssuesControllerTest < ActionController::TestCase
1511 end
1511 end
1512 end
1512 end
1513
1513
1514 def test_new_should_select_default_status
1515 @request.session[:user_id] = 2
1516
1517 get :new, :project_id => 1
1518 assert_response :success
1519 assert_template 'new'
1520 assert_select 'select[name=?]', 'issue[status_id]' do
1521 assert_select 'option[value=1][selected=selected]'
1522 end
1523 assert_select 'input[name=was_default_status][value=1]'
1524 end
1525
1526 def test_new_should_select_default_status
1527 @request.session[:user_id] = 2
1528
1529 get :new, :project_id => 1
1530 assert_response :success
1531 assert_template 'new'
1532 assert_select 'select[name=?]', 'issue[status_id]' do
1533 assert_select 'option[value=1][selected=selected]'
1534 end
1535 assert_select 'input[name=was_default_status][value=1]'
1536 end
1537
1514 def test_get_new_with_list_custom_field
1538 def test_get_new_with_list_custom_field
1515 @request.session[:user_id] = 2
1539 @request.session[:user_id] = 2
1516 get :new, :project_id => 1, :tracker_id => 1
1540 get :new, :project_id => 1, :tracker_id => 1
@@ -1731,6 +1755,20 class IssuesControllerTest < ActionController::TestCase
1731 assert_equal [1,2,5], assigns(:allowed_statuses).map(&:id).sort
1755 assert_equal [1,2,5], assigns(:allowed_statuses).map(&:id).sort
1732 end
1756 end
1733
1757
1758 def test_update_form_with_default_status_should_ignore_submitted_status_id_if_equals
1759 @request.session[:user_id] = 2
1760 tracker = Tracker.find(2)
1761 tracker.update! :default_status_id => 2
1762 tracker.generate_transitions! 2, 1, :clear => true
1763
1764 xhr :post, :update_form, :project_id => 1,
1765 :issue => {:tracker_id => 2,
1766 :status_id => 1},
1767 :was_default_status => 1
1768
1769 assert_equal 2, assigns(:issue).status_id
1770 end
1771
1734 def test_post_create
1772 def test_post_create
1735 @request.session[:user_id] = 2
1773 @request.session[:user_id] = 2
1736 assert_difference 'Issue.count' do
1774 assert_difference 'Issue.count' do
@@ -2266,13 +2304,17 class IssuesControllerTest < ActionController::TestCase
2266 get :new, :project_id => 1
2304 get :new, :project_id => 1
2267 assert_response :success
2305 assert_response :success
2268 assert_template 'new'
2306 assert_template 'new'
2307
2308 issue = assigns(:issue)
2309 assert_not_nil issue.default_status
2310
2269 assert_select 'select[name=?]', 'issue[status_id]' do
2311 assert_select 'select[name=?]', 'issue[status_id]' do
2270 assert_select 'option', 1
2312 assert_select 'option', 1
2271 assert_select 'option[value=?]', IssueStatus.default.id.to_s
2313 assert_select 'option[value=?]', issue.default_status.id.to_s
2272 end
2314 end
2273 end
2315 end
2274
2316
2275 test "without workflow privilege #new should accept default status" do
2317 test "without workflow privilege #create should accept default status" do
2276 setup_without_workflow_privilege
2318 setup_without_workflow_privilege
2277 assert_difference 'Issue.count' do
2319 assert_difference 'Issue.count' do
2278 post :create, :project_id => 1,
2320 post :create, :project_id => 1,
@@ -2281,10 +2323,11 class IssuesControllerTest < ActionController::TestCase
2281 :status_id => 1}
2323 :status_id => 1}
2282 end
2324 end
2283 issue = Issue.order('id').last
2325 issue = Issue.order('id').last
2284 assert_equal IssueStatus.default, issue.status
2326 assert_not_nil issue.default_status
2327 assert_equal issue.default_status, issue.status
2285 end
2328 end
2286
2329
2287 test "without workflow privilege #new should ignore unauthorized status" do
2330 test "without workflow privilege #create should ignore unauthorized status" do
2288 setup_without_workflow_privilege
2331 setup_without_workflow_privilege
2289 assert_difference 'Issue.count' do
2332 assert_difference 'Issue.count' do
2290 post :create, :project_id => 1,
2333 post :create, :project_id => 1,
@@ -2293,7 +2336,8 class IssuesControllerTest < ActionController::TestCase
2293 :status_id => 3}
2336 :status_id => 3}
2294 end
2337 end
2295 issue = Issue.order('id').last
2338 issue = Issue.order('id').last
2296 assert_equal IssueStatus.default, issue.status
2339 assert_not_nil issue.default_status
2340 assert_equal issue.default_status, issue.status
2297 end
2341 end
2298
2342
2299 test "without workflow privilege #update should ignore status change" do
2343 test "without workflow privilege #update should ignore status change" do
@@ -18,7 +18,7
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class TrackersControllerTest < ActionController::TestCase
20 class TrackersControllerTest < ActionController::TestCase
21 fixtures :trackers, :projects, :projects_trackers, :users, :issues, :custom_fields
21 fixtures :trackers, :projects, :projects_trackers, :users, :issues, :custom_fields, :issue_statuses
22
22
23 def setup
23 def setup
24 User.current = nil
24 User.current = nil
@@ -51,7 +51,7 class TrackersControllerTest < ActionController::TestCase
51
51
52 def test_create
52 def test_create
53 assert_difference 'Tracker.count' do
53 assert_difference 'Tracker.count' do
54 post :create, :tracker => { :name => 'New tracker', :project_ids => ['1', '', ''], :custom_field_ids => ['1', '6', ''] }
54 post :create, :tracker => { :name => 'New tracker', :default_status_id => 1, :project_ids => ['1', '', ''], :custom_field_ids => ['1', '6', ''] }
55 end
55 end
56 assert_redirected_to :action => 'index'
56 assert_redirected_to :action => 'index'
57 tracker = Tracker.order('id DESC').first
57 tracker = Tracker.order('id DESC').first
@@ -62,9 +62,9 class TrackersControllerTest < ActionController::TestCase
62 assert_equal 0, tracker.workflow_rules.count
62 assert_equal 0, tracker.workflow_rules.count
63 end
63 end
64
64
65 def create_with_disabled_core_fields
65 def test_create_with_disabled_core_fields
66 assert_difference 'Tracker.count' do
66 assert_difference 'Tracker.count' do
67 post :create, :tracker => { :name => 'New tracker', :core_fields => ['assigned_to_id', 'fixed_version_id', ''] }
67 post :create, :tracker => { :name => 'New tracker', :default_status_id => 1, :core_fields => ['assigned_to_id', 'fixed_version_id', ''] }
68 end
68 end
69 assert_redirected_to :action => 'index'
69 assert_redirected_to :action => 'index'
70 tracker = Tracker.order('id DESC').first
70 tracker = Tracker.order('id DESC').first
@@ -74,7 +74,7 class TrackersControllerTest < ActionController::TestCase
74
74
75 def test_create_new_with_workflow_copy
75 def test_create_new_with_workflow_copy
76 assert_difference 'Tracker.count' do
76 assert_difference 'Tracker.count' do
77 post :create, :tracker => { :name => 'New tracker' }, :copy_workflow_from => 1
77 post :create, :tracker => { :name => 'New tracker', :default_status_id => 1 }, :copy_workflow_from => 1
78 end
78 end
79 assert_redirected_to :action => 'index'
79 assert_redirected_to :action => 'index'
80 tracker = Tracker.find_by_name('New tracker')
80 tracker = Tracker.find_by_name('New tracker')
@@ -164,7 +164,7 class TrackersControllerTest < ActionController::TestCase
164 end
164 end
165
165
166 def test_destroy
166 def test_destroy
167 tracker = Tracker.create!(:name => 'Destroyable')
167 tracker = Tracker.generate!(:name => 'Destroyable')
168 assert_difference 'Tracker.count', -1 do
168 assert_difference 'Tracker.count', -1 do
169 delete :destroy, :id => tracker.id
169 delete :destroy, :id => tracker.id
170 end
170 end
@@ -45,11 +45,22 module ObjectHelpers
45 project
45 project
46 end
46 end
47
47
48 def IssueStatus.generate!(attributes={})
49 @generated_status_name ||= 'Status 0'
50 @generated_status_name.succ!
51 status = IssueStatus.new(attributes)
52 status.name = @generated_status_name.dup if status.name.blank?
53 yield status if block_given?
54 status.save!
55 status
56 end
57
48 def Tracker.generate!(attributes={})
58 def Tracker.generate!(attributes={})
49 @generated_tracker_name ||= 'Tracker 0'
59 @generated_tracker_name ||= 'Tracker 0'
50 @generated_tracker_name.succ!
60 @generated_tracker_name.succ!
51 tracker = Tracker.new(attributes)
61 tracker = Tracker.new(attributes)
52 tracker.name = @generated_tracker_name.dup if tracker.name.blank?
62 tracker.name = @generated_tracker_name.dup if tracker.name.blank?
63 tracker.default_status ||= IssueStatus.order('position').first || IssueStatus.generate!
53 yield tracker if block_given?
64 yield tracker if block_given?
54 tracker.save!
65 tracker.save!
55 tracker
66 tracker
@@ -188,6 +199,27 module ObjectHelpers
188 end
199 end
189 end
200 end
190
201
202 module TrackerObjectHelpers
203 def generate_transitions!(*args)
204 options = args.last.is_a?(Hash) ? args.pop : {}
205 if args.size == 1
206 args << args.first
207 end
208 if options[:clear]
209 WorkflowTransition.where(:tracker_id => id).delete_all
210 end
211 args.each_cons(2) do |old_status_id, new_status_id|
212 WorkflowTransition.create!(
213 :tracker => self,
214 :role_id => (options[:role_id] || 1),
215 :old_status_id => old_status_id,
216 :new_status_id => new_status_id
217 )
218 end
219 end
220 end
221 Tracker.send :include, TrackerObjectHelpers
222
191 module IssueObjectHelpers
223 module IssueObjectHelpers
192 def close!
224 def close!
193 self.status = IssueStatus.where(:is_closed => true).first
225 self.status = IssueStatus.where(:is_closed => true).first
@@ -198,5 +230,4 module IssueObjectHelpers
198 Issue.generate!(attributes.merge(:parent_issue_id => self.id))
230 Issue.generate!(attributes.merge(:parent_issue_id => self.id))
199 end
231 end
200 end
232 end
201
202 Issue.send :include, IssueObjectHelpers
233 Issue.send :include, IssueObjectHelpers
@@ -28,7 +28,6 class IssueStatusTest < ActiveSupport::TestCase
28
28
29 status.name = "Test Status"
29 status.name = "Test Status"
30 assert status.save
30 assert status.save
31 assert !status.is_default
32 end
31 end
33
32
34 def test_destroy
33 def test_destroy
@@ -46,29 +45,6 class IssueStatusTest < ActiveSupport::TestCase
46 assert_raise(RuntimeError, "Can't delete status") { status.destroy }
45 assert_raise(RuntimeError, "Can't delete status") { status.destroy }
47 end
46 end
48
47
49 def test_default
50 status = IssueStatus.default
51 assert_kind_of IssueStatus, status
52 end
53
54 def test_change_default
55 status = IssueStatus.find(2)
56 assert !status.is_default
57 status.is_default = true
58 assert status.save
59 status.reload
60
61 assert_equal status, IssueStatus.default
62 assert !IssueStatus.find(1).is_default
63 end
64
65 def test_reorder_should_not_clear_default_status
66 status = IssueStatus.default
67 status.move_to_bottom
68 status.reload
69 assert status.is_default?
70 end
71
72 def test_new_statuses_allowed_to
48 def test_new_statuses_allowed_to
73 WorkflowTransition.delete_all
49 WorkflowTransition.delete_all
74
50
@@ -40,11 +40,11 class IssueTest < ActiveSupport::TestCase
40
40
41 assert_nil issue.project_id
41 assert_nil issue.project_id
42 assert_nil issue.tracker_id
42 assert_nil issue.tracker_id
43 assert_nil issue.status_id
43 assert_nil issue.author_id
44 assert_nil issue.author_id
44 assert_nil issue.assigned_to_id
45 assert_nil issue.assigned_to_id
45 assert_nil issue.category_id
46 assert_nil issue.category_id
46
47
47 assert_equal IssueStatus.default, issue.status
48 assert_equal IssuePriority.default, issue.priority
48 assert_equal IssuePriority.default, issue.priority
49 end
49 end
50
50
@@ -59,10 +59,9 class IssueTest < ActiveSupport::TestCase
59 end
59 end
60
60
61 def test_create_minimal
61 def test_create_minimal
62 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
62 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :subject => 'test_create')
63 :status_id => 1, :priority => IssuePriority.all.first,
64 :subject => 'test_create')
65 assert issue.save
63 assert issue.save
64 assert_equal issue.tracker.default_status, issue.status
66 assert issue.description.nil?
65 assert issue.description.nil?
67 assert_nil issue.estimated_hours
66 assert_nil issue.estimated_hours
68 end
67 end
@@ -908,7 +907,7 class IssueTest < ActiveSupport::TestCase
908
907
909 def test_copy_should_copy_status
908 def test_copy_should_copy_status
910 orig = Issue.find(8)
909 orig = Issue.find(8)
911 assert orig.status != IssueStatus.default
910 assert orig.status != orig.default_status
912
911
913 issue = Issue.new.copy_from(orig)
912 issue = Issue.new.copy_from(orig)
914 assert issue.save
913 assert issue.save
@@ -2480,4 +2479,67 class IssueTest < ActiveSupport::TestCase
2480 issue.save!
2479 issue.save!
2481 assert_equal false, issue.reopening?
2480 assert_equal false, issue.reopening?
2482 end
2481 end
2482
2483 def test_default_status_without_tracker_should_be_nil
2484 issue = Issue.new
2485 assert_nil issue.tracker
2486 assert_nil issue.default_status
2487 end
2488
2489 def test_default_status_should_be_tracker_default_status
2490 issue = Issue.new(:tracker_id => 1)
2491 assert_not_nil issue.status
2492 assert_equal issue.tracker.default_status, issue.default_status
2493 end
2494
2495 def test_initializing_with_tracker_should_set_default_status
2496 issue = Issue.new(:tracker => Tracker.find(1))
2497 assert_not_nil issue.status
2498 assert_equal issue.default_status, issue.status
2499 end
2500
2501 def test_initializing_with_tracker_id_should_set_default_status
2502 issue = Issue.new(:tracker_id => 1)
2503 assert_not_nil issue.status
2504 assert_equal issue.default_status, issue.status
2505 end
2506
2507 def test_setting_tracker_should_set_default_status
2508 issue = Issue.new
2509 issue.tracker = Tracker.find(1)
2510 assert_not_nil issue.status
2511 assert_equal issue.default_status, issue.status
2512 end
2513
2514 def test_changing_tracker_should_set_default_status_if_status_was_default
2515 WorkflowTransition.delete_all
2516 WorkflowTransition.create! :role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1
2517 Tracker.find(2).update! :default_status_id => 2
2518
2519 issue = Issue.new(:tracker_id => 1, :status_id => 1)
2520 assert_equal IssueStatus.find(1), issue.status
2521 issue.tracker = Tracker.find(2)
2522 assert_equal IssueStatus.find(2), issue.status
2523 end
2524
2525 def test_changing_tracker_should_set_default_status_if_status_is_not_used_by_tracker
2526 WorkflowTransition.delete_all
2527 Tracker.find(2).update! :default_status_id => 2
2528
2529 issue = Issue.new(:tracker_id => 1, :status_id => 3)
2530 assert_equal IssueStatus.find(3), issue.status
2531 issue.tracker = Tracker.find(2)
2532 assert_equal IssueStatus.find(2), issue.status
2533 end
2534
2535 def test_changing_tracker_should_keep_status_if_status_was_not_default_and_is_used_by_tracker
2536 WorkflowTransition.delete_all
2537 WorkflowTransition.create! :role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 3
2538 Tracker.find(2).update! :default_status_id => 2
2539
2540 issue = Issue.new(:tracker_id => 1, :status_id => 3)
2541 assert_equal IssueStatus.find(3), issue.status
2542 issue.tracker = Tracker.find(2)
2543 assert_equal IssueStatus.find(3), issue.status
2544 end
2483 end
2545 end
@@ -412,7 +412,7 class MailHandlerTest < ActiveSupport::TestCase
412
412
413 def test_add_issue_with_japanese_keywords
413 def test_add_issue_with_japanese_keywords
414 ja_dev = "\xe9\x96\x8b\xe7\x99\xba".force_encoding('UTF-8')
414 ja_dev = "\xe9\x96\x8b\xe7\x99\xba".force_encoding('UTF-8')
415 tracker = Tracker.create!(:name => ja_dev)
415 tracker = Tracker.generate!(:name => ja_dev)
416 Project.find(1).trackers << tracker
416 Project.find(1).trackers << tracker
417 issue = submit_email(
417 issue = submit_email(
418 'japanese_keywords_iso_2022_jp.eml',
418 'japanese_keywords_iso_2022_jp.eml',
@@ -32,7 +32,7 class TrackerTest < ActiveSupport::TestCase
32 source = Tracker.find(1)
32 source = Tracker.find(1)
33 assert_equal 89, source.workflow_rules.size
33 assert_equal 89, source.workflow_rules.size
34
34
35 target = Tracker.new(:name => 'Target')
35 target = Tracker.new(:name => 'Target', :default_status_id => 1)
36 assert target.save
36 assert target.save
37 target.workflow_rules.copy(source)
37 target.workflow_rules.copy(source)
38 target.reload
38 target.reload
General Comments 0
You need to be logged in to leave comments. Login now