mirror of
				https://github.com/redmine/redmine.git
				synced 2025-10-31 02:15:52 +01:00 
			
		
		
		
	Support external ID when importing issues (#28213).
Patch by Gregor Schmidt and Marius BALTEANU. git-svn-id: http://svn.redmine.org/redmine/trunk@18285 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
		| @@ -157,8 +157,8 @@ class Import < ActiveRecord::Base | |||||||
|   # Adds a callback that will be called after the item at given position is imported |   # Adds a callback that will be called after the item at given position is imported | ||||||
|   def add_callback(position, name, *args) |   def add_callback(position, name, *args) | ||||||
|     settings['callbacks'] ||= {} |     settings['callbacks'] ||= {} | ||||||
|     settings['callbacks'][position.to_i] ||= [] |     settings['callbacks'][position] ||= [] | ||||||
|     settings['callbacks'][position.to_i] << [name, args] |     settings['callbacks'][position] << [name, args] | ||||||
|     save! |     save! | ||||||
|   end |   end | ||||||
|  |  | ||||||
| @@ -190,6 +190,7 @@ class Import < ActiveRecord::Base | |||||||
|       if position > resume_after |       if position > resume_after | ||||||
|         item = items.build |         item = items.build | ||||||
|         item.position = position |         item.position = position | ||||||
|  |         item.unique_id = row_value(row, 'unique_id') if use_unique_id? | ||||||
|  |  | ||||||
|         if object = build_object(row, item) |         if object = build_object(row, item) | ||||||
|           if object.save |           if object.save | ||||||
| @@ -202,7 +203,7 @@ class Import < ActiveRecord::Base | |||||||
|         item.save! |         item.save! | ||||||
|         imported += 1 |         imported += 1 | ||||||
|  |  | ||||||
|         do_callbacks(item.position, object) |         do_callbacks(use_unique_id? ? item.unique_id : item.position, object) | ||||||
|       end |       end | ||||||
|       current = position |       current = position | ||||||
|     end |     end | ||||||
| @@ -283,4 +284,8 @@ class Import < ActiveRecord::Base | |||||||
|   def yes?(value) |   def yes?(value) | ||||||
|     value == lu(user, :general_text_yes) || value == '1' |     value == lu(user, :general_text_yes) || value == '1' | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  |   def use_unique_id? | ||||||
|  |     mapping['unique_id'].present? | ||||||
|  |   end | ||||||
| end | end | ||||||
|   | |||||||
| @@ -150,18 +150,30 @@ class IssueImport < Import | |||||||
|       end |       end | ||||||
|     end |     end | ||||||
|     if parent_issue_id = row_value(row, 'parent_issue_id') |     if parent_issue_id = row_value(row, 'parent_issue_id') | ||||||
|       if parent_issue_id =~ /\A(#)?(\d+)\z/ |       if parent_issue_id.start_with? '#' | ||||||
|         parent_issue_id = $2.to_i |         # refers to existing issue | ||||||
|         if $1 |         attributes['parent_issue_id'] = parent_issue_id[1..-1] | ||||||
|           attributes['parent_issue_id'] = parent_issue_id |       elsif use_unique_id? | ||||||
|  |         # refers to other row with unique id | ||||||
|  |         issue_id = items.where(:unique_id => parent_issue_id).first.try(:obj_id) | ||||||
|  |  | ||||||
|  |         if issue_id | ||||||
|  |           attributes['parent_issue_id'] = issue_id | ||||||
|         else |         else | ||||||
|           if parent_issue_id > item.position |           add_callback(parent_issue_id, 'set_as_parent', item.position) | ||||||
|             add_callback(parent_issue_id, 'set_as_parent', item.position) |  | ||||||
|           elsif issue_id = items.where(:position => parent_issue_id).first.try(:obj_id) |  | ||||||
|             attributes['parent_issue_id'] = issue_id |  | ||||||
|           end |  | ||||||
|         end |         end | ||||||
|  |       elsif parent_issue_id =~ /\A\d+\z/ | ||||||
|  |         # refers to other row by position | ||||||
|  |         parent_issue_id = parent_issue_id.to_i | ||||||
|  |  | ||||||
|  |         if parent_issue_id > item.position | ||||||
|  |           add_callback(parent_issue_id, 'set_as_parent', item.position) | ||||||
|  |         elsif issue_id = items.where(:position => parent_issue_id).first.try(:obj_id) | ||||||
|  |           attributes['parent_issue_id'] = issue_id | ||||||
|  |         end | ||||||
|  |  | ||||||
|       else |       else | ||||||
|  |         # Something is odd. Assign parent_issue_id to trigger validation error | ||||||
|         attributes['parent_issue_id'] = parent_issue_id |         attributes['parent_issue_id'] = parent_issue_id | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | <div class="splitcontent"> | ||||||
|  | <div class="splitcontentleft"> | ||||||
| <p> | <p> | ||||||
|   <label for="import_mapping_project_id"><%= l(:label_project) %></label> |   <label for="import_mapping_project_id"><%= l(:label_project) %></label> | ||||||
|   <%= select_tag 'import_settings[mapping][project_id]', |   <%= select_tag 'import_settings[mapping][project_id]', | ||||||
| @@ -13,6 +15,16 @@ | |||||||
|   <label for="import_mapping_status"><%= l(:field_status) %></label> |   <label for="import_mapping_status"><%= l(:field_status) %></label> | ||||||
|   <%= mapping_select_tag @import, 'status' %> |   <%= mapping_select_tag @import, 'status' %> | ||||||
| </p> | </p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <div class="splitcontentright"> | ||||||
|  | <p></p> | ||||||
|  | <p> | ||||||
|  |   <label for="import_mapping_unique_id"><%= l(:field_unique_id) %></label> | ||||||
|  |   <%= mapping_select_tag @import, 'unique_id' %> | ||||||
|  | </p> | ||||||
|  | </div> | ||||||
|  | </div> | ||||||
|  |  | ||||||
| <div class="splitcontent"> | <div class="splitcontent"> | ||||||
| <div class="splitcontentleft"> | <div class="splitcontentleft"> | ||||||
|   | |||||||
| @@ -392,6 +392,7 @@ de: | |||||||
|   field_warn_on_leaving_unsaved: Vor dem Verlassen einer Seite mit ungesichertem Text im Editor warnen |   field_warn_on_leaving_unsaved: Vor dem Verlassen einer Seite mit ungesichertem Text im Editor warnen | ||||||
|   field_watcher: Beobachter |   field_watcher: Beobachter | ||||||
|   field_default_assigned_to: Standardbearbeiter |   field_default_assigned_to: Standardbearbeiter | ||||||
|  |   field_unique_id: Eindeutige ID | ||||||
|  |  | ||||||
|   general_csv_decimal_separator: ',' |   general_csv_decimal_separator: ',' | ||||||
|   general_csv_encoding: ISO-8859-1 |   general_csv_encoding: ISO-8859-1 | ||||||
|   | |||||||
| @@ -384,6 +384,7 @@ en: | |||||||
|   field_default_assigned_to: Default assignee |   field_default_assigned_to: Default assignee | ||||||
|   field_recently_used_projects: Number of recently used projects in jump box |   field_recently_used_projects: Number of recently used projects in jump box | ||||||
|   field_history_default_tab: Issue's history default tab |   field_history_default_tab: Issue's history default tab | ||||||
|  |   field_unique_id: Unique ID | ||||||
|  |  | ||||||
|   setting_app_title: Application title |   setting_app_title: Application title | ||||||
|   setting_welcome_text: Welcome text |   setting_welcome_text: Welcome text | ||||||
|   | |||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | class AddUniqueIdToImportItems < ActiveRecord::Migration[5.2] | ||||||
|  |   def change | ||||||
|  |     change_table :import_items do |t| | ||||||
|  |       t.string "unique_id" | ||||||
|  |       t.index ["import_id", "unique_id"] | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										5
									
								
								test/fixtures/files/import_subtasks_with_unique_id.csv
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								test/fixtures/files/import_subtasks_with_unique_id.csv
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | id;tracker;subject;parent | ||||||
|  | RED-I;bug;Root; | ||||||
|  | RED-II;bug;Child 1;RED-I | ||||||
|  | RED-III;bug;Grand-child;RED-IV | ||||||
|  | RED-IV;bug;Child 2;RED-I | ||||||
| 
 | 
| @@ -146,6 +146,16 @@ class IssueImportTest < ActiveSupport::TestCase | |||||||
|     assert_equal child2, grandchild.parent |     assert_equal child2, grandchild.parent | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  |   def test_backward_and_forward_reference_with_unique_id | ||||||
|  |     import = generate_import_with_mapping('import_subtasks_with_unique_id.csv') | ||||||
|  |     import.settings['mapping'] = {'project_id' => '1', 'unique_id' => '0', 'tracker' => '1', 'subject' => '2', 'parent_issue_id' => '3'} | ||||||
|  |     import.save! | ||||||
|  |  | ||||||
|  |     root, child1, grandchild, child2 = new_records(Issue, 4) { import.run } | ||||||
|  |     assert_equal root, child1.parent | ||||||
|  |     assert_equal child2, grandchild.parent | ||||||
|  |   end | ||||||
|  |  | ||||||
|   def test_assignee_should_be_set |   def test_assignee_should_be_set | ||||||
|     import = generate_import_with_mapping |     import = generate_import_with_mapping | ||||||
|     import.mapping.merge!('assigned_to' => '11') |     import.mapping.merge!('assigned_to' => '11') | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user