@@ -57,11 +57,7 class ImportsController < ApplicationController | |||||
57 | end |
|
57 | end | |
58 |
|
58 | |||
59 | def mapping |
|
59 | def mapping | |
60 | issue = Issue.new |
|
60 | @custom_fields = @import.mappable_custom_fields | |
61 | issue.project = @import.project |
|
|||
62 | issue.tracker = @import.tracker |
|
|||
63 | @attributes = issue.safe_attribute_names |
|
|||
64 | @custom_fields = issue.editable_custom_field_values.map(&:custom_field) |
|
|||
65 |
|
61 | |||
66 | if request.post? |
|
62 | if request.post? | |
67 | respond_to do |format| |
|
63 | respond_to do |format| |
@@ -23,12 +23,16 module ImportsHelper | |||||
23 | blank_text = options[:required] ? "-- #{l(:actionview_instancetag_blank_option)} --" : " ".html_safe |
|
23 | blank_text = options[:required] ? "-- #{l(:actionview_instancetag_blank_option)} --" : " ".html_safe | |
24 | tags << content_tag('option', blank_text, :value => '') |
|
24 | tags << content_tag('option', blank_text, :value => '') | |
25 | tags << options_for_select(import.columns_options, import.mapping[field]) |
|
25 | tags << options_for_select(import.columns_options, import.mapping[field]) | |
|
26 | if values = options[:values] | |||
|
27 | tags << content_tag('option', '--', :disabled => true) | |||
|
28 | tags << options_for_select(values.map {|text, value| [text, "value:#{value}"]}, import.mapping[field]) | |||
|
29 | end | |||
26 | tags |
|
30 | tags | |
27 | end |
|
31 | end | |
28 |
|
32 | |||
29 | def mapping_select_tag(import, field, options={}) |
|
33 | def mapping_select_tag(import, field, options={}) | |
30 | name = "import_settings[mapping][#{field}]" |
|
34 | name = "import_settings[mapping][#{field}]" | |
31 | select_tag name, options_for_mapping_select(import, field, options) |
|
35 | select_tag name, options_for_mapping_select(import, field, options), :id => "import_mapping_#{field}" | |
32 | end |
|
36 | end | |
33 |
|
37 | |||
34 | # Returns the options for the date_format setting |
|
38 | # Returns the options for the date_format setting |
@@ -691,7 +691,7 class Issue < ActiveRecord::Base | |||||
691 |
|
691 | |||
692 | # Checks that the issue can not be added/moved to a disabled tracker |
|
692 | # Checks that the issue can not be added/moved to a disabled tracker | |
693 | if project && (tracker_id_changed? || project_id_changed?) |
|
693 | if project && (tracker_id_changed? || project_id_changed?) | |
694 |
|
|
694 | if tracker && !project.trackers.include?(tracker) | |
695 | errors.add :tracker_id, :inclusion |
|
695 | errors.add :tracker_id, :inclusion | |
696 | end |
|
696 | end | |
697 | end |
|
697 | end |
@@ -41,8 +41,10 class IssueImport < Import | |||||
41 | end |
|
41 | end | |
42 |
|
42 | |||
43 | def tracker |
|
43 | def tracker | |
44 | tracker_id = mapping['tracker_id'].to_i |
|
44 | if mapping['tracker'].to_s =~ /\Avalue:(\d+)\z/ | |
45 | allowed_target_trackers.find_by_id(tracker_id) || allowed_target_trackers.first |
|
45 | tracker_id = $1.to_i | |
|
46 | allowed_target_trackers.find_by_id(tracker_id) | |||
|
47 | end | |||
46 | end |
|
48 | end | |
47 |
|
49 | |||
48 | # Returns true if missing categories should be created during the import |
|
50 | # Returns true if missing categories should be created during the import | |
@@ -57,6 +59,19 class IssueImport < Import | |||||
57 | mapping['create_versions'] == '1' |
|
59 | mapping['create_versions'] == '1' | |
58 | end |
|
60 | end | |
59 |
|
61 | |||
|
62 | def mappable_custom_fields | |||
|
63 | if tracker | |||
|
64 | issue = Issue.new | |||
|
65 | issue.project = project | |||
|
66 | issue.tracker = tracker | |||
|
67 | issue.editable_custom_field_values(user).map(&:custom_field) | |||
|
68 | elsif project | |||
|
69 | project.all_issue_custom_fields | |||
|
70 | else | |||
|
71 | [] | |||
|
72 | end | |||
|
73 | end | |||
|
74 | ||||
60 | private |
|
75 | private | |
61 |
|
76 | |||
62 | def build_object(row) |
|
77 | def build_object(row) | |
@@ -64,12 +79,24 class IssueImport < Import | |||||
64 | issue.author = user |
|
79 | issue.author = user | |
65 | issue.notify = false |
|
80 | issue.notify = false | |
66 |
|
81 | |||
|
82 | tracker_id = nil | |||
|
83 | if tracker | |||
|
84 | tracker_id = tracker.id | |||
|
85 | elsif tracker_name = row_value(row, 'tracker') | |||
|
86 | tracker_id = allowed_target_trackers.named(tracker_name).first.try(:id) | |||
|
87 | end | |||
|
88 | ||||
67 | attributes = { |
|
89 | attributes = { | |
68 | 'project_id' => mapping['project_id'], |
|
90 | 'project_id' => mapping['project_id'], | |
69 |
'tracker_id' => |
|
91 | 'tracker_id' => tracker_id, | |
70 | 'subject' => row_value(row, 'subject'), |
|
92 | 'subject' => row_value(row, 'subject'), | |
71 | 'description' => row_value(row, 'description') |
|
93 | 'description' => row_value(row, 'description') | |
72 | } |
|
94 | } | |
|
95 | if status_name = row_value(row, 'status') | |||
|
96 | if status_id = IssueStatus.named(status_name).first.try(:id) | |||
|
97 | attributes['status_id'] = status_id | |||
|
98 | end | |||
|
99 | end | |||
73 | issue.send :safe_attributes=, attributes, user |
|
100 | issue.send :safe_attributes=, attributes, user | |
74 |
|
101 | |||
75 | attributes = {} |
|
102 | attributes = {} | |
@@ -149,6 +176,11 class IssueImport < Import | |||||
149 | end |
|
176 | end | |
150 |
|
177 | |||
151 | issue.send :safe_attributes=, attributes, user |
|
178 | issue.send :safe_attributes=, attributes, user | |
|
179 | ||||
|
180 | if issue.tracker_id != tracker_id | |||
|
181 | issue.tracker_id = nil | |||
|
182 | end | |||
|
183 | ||||
152 | issue |
|
184 | issue | |
153 | end |
|
185 | end | |
154 | end |
|
186 | end |
@@ -1,17 +1,21 | |||||
1 | <div class="splitcontent"> |
|
|||
2 | <div class="splitcontentleft"> |
|
|||
3 | <p> |
|
1 | <p> | |
4 | <label><%= l(:label_project) %></label> |
|
2 | <label><%= l(:label_project) %></label> | |
5 | <%= select_tag 'import_settings[mapping][project_id]', |
|
3 | <%= select_tag 'import_settings[mapping][project_id]', | |
6 | options_for_select(project_tree_options_for_select(@import.allowed_target_projects, :selected => @import.project)), |
|
4 | options_for_select(project_tree_options_for_select(@import.allowed_target_projects, :selected => @import.project)), | |
7 |
:id => 'i |
|
5 | :id => 'import_mapping_project_id' %> | |
8 | </p> |
|
6 | </p> | |
9 | <p> |
|
7 | <p> | |
10 | <label><%= l(:label_tracker) %></label> |
|
8 | <label><%= l(:label_tracker) %></label> | |
11 | <%= select_tag 'import_settings[mapping][tracker_id]', |
|
9 | <%= mapping_select_tag @import, 'tracker', :required => true, | |
12 |
|
|
10 | :values => @import.allowed_target_trackers.sorted.map {|t| [t.name, t.id]} %> | |
13 | :id => 'issue_tracker_id' %> |
|
11 | </p> | |
|
12 | <p> | |||
|
13 | <label><%= l(:field_status) %></label> | |||
|
14 | <%= mapping_select_tag @import, 'status' %> | |||
14 | </p> |
|
15 | </p> | |
|
16 | ||||
|
17 | <div class="splitcontent"> | |||
|
18 | <div class="splitcontentleft"> | |||
15 | <p> |
|
19 | <p> | |
16 | <label><%= l(:field_subject) %></label> |
|
20 | <label><%= l(:field_subject) %></label> | |
17 | <%= mapping_select_tag @import, 'subject', :required => true %> |
|
21 | <%= mapping_select_tag @import, 'subject', :required => true %> |
@@ -35,7 +35,7 | |||||
35 |
|
35 | |||
36 | <%= javascript_tag do %> |
|
36 | <%= javascript_tag do %> | |
37 | $(document).ready(function() { |
|
37 | $(document).ready(function() { | |
38 |
$('#fields-mapping').on('change', '#i |
|
38 | $('#fields-mapping').on('change', '#import_mapping_project_id, #import_mapping_tracker', function(){ | |
39 | $.ajax({ |
|
39 | $.ajax({ | |
40 | url: '<%= import_mapping_path(@import, :format => 'js') %>', |
|
40 | url: '<%= import_mapping_path(@import, :format => 'js') %>', | |
41 | type: 'post', |
|
41 | type: 'post', |
@@ -1,27 +1,33 | |||||
1 | <h2><%= l(:label_import_issues) %></h2> |
|
1 | <h2><%= l(:label_import_issues) %></h2> | |
2 |
|
2 | |||
3 |
<% if @import. |
|
3 | <% if @import.saved_items.count > 0 %> | |
4 | <p><%= l(:notice_import_finished, :count => @import.saved_items.count) %></p> |
|
4 | <p><%= l(:notice_import_finished, :count => @import.saved_items.count) %></p> | |
5 |
|
5 | |||
6 | <ul> |
|
6 | <ul id="saved-items"> | |
7 | <% @import.saved_objects.each do |issue| %> |
|
7 | <% @import.saved_objects.each do |issue| %> | |
8 | <li><%= link_to_issue issue %></li> |
|
8 | <li><%= link_to_issue issue %></li> | |
9 | <% end %> |
|
9 | <% end %> | |
10 | </ul> |
|
10 | </ul> | |
11 |
<% e |
|
11 | <% end %> | |
|
12 | ||||
|
13 | <% if @import.unsaved_items.count > 0 %> | |||
12 | <p><%= l(:notice_import_finished_with_errors, :count => @import.unsaved_items.count, :total => @import.total_items) %></p> |
|
14 | <p><%= l(:notice_import_finished_with_errors, :count => @import.unsaved_items.count, :total => @import.total_items) %></p> | |
13 |
|
15 | |||
14 | <table id="unsaved-items" class="list"> |
|
16 | <table id="unsaved-items" class="list"> | |
|
17 | <thead> | |||
15 | <tr> |
|
18 | <tr> | |
16 | <th>Position</th> |
|
19 | <th>Position</th> | |
17 | <th>Message</th> |
|
20 | <th>Message</th> | |
18 | </tr> |
|
21 | </tr> | |
19 | <% @import.unsaved_items.each do |item| %> |
|
22 | </thead> | |
|
23 | <tbody> | |||
|
24 | <% @import.unsaved_items.each do |item| %> | |||
20 | <tr> |
|
25 | <tr> | |
21 | <td><%= item.position %></td> |
|
26 | <td><%= item.position %></td> | |
22 | <td><%= simple_format_without_paragraph item.message %></td> |
|
27 | <td><%= simple_format_without_paragraph item.message %></td> | |
23 | </tr> |
|
28 | </tr> | |
24 | <% end %> |
|
29 | <% end %> | |
|
30 | </tbody> | |||
25 | </table> |
|
31 | </table> | |
26 | <% end %> |
|
32 | <% end %> | |
27 |
|
33 |
@@ -1,4 +1,4 | |||||
1 | priority;subject;description;start_date;due_date;parent;private;progress;custom;version;category;user;estimated_hours |
|
1 | priority;subject;description;start_date;due_date;parent;private;progress;custom;version;category;user;estimated_hours;tracker;status | |
2 | High;First;First description;2015-07-08;2015-08-25;;no;;PostgreSQL;;New category;dlopper;1 |
|
2 | High;First;First description;2015-07-08;2015-08-25;;no;;PostgreSQL;;New category;dlopper;1;bug;new | |
3 | Normal;Child 1;Child description;;;1;yes;10;MySQL;2.0;New category;;2 |
|
3 | Normal;Child 1;Child description;;;1;yes;10;MySQL;2.0;New category;;2;feature request;new | |
4 | Normal;Child of existing issue;Child description;;;#2;no;20;;2.1;Printing;;3 |
|
4 | Normal;Child of existing issue;Child description;;;#2;no;20;;2.1;Printing;;3;bug;assigned |
@@ -184,6 +184,8 class ImportsControllerTest < ActionController::TestCase | |||||
184 | get :show, :id => import.to_param |
|
184 | get :show, :id => import.to_param | |
185 | assert_response :success |
|
185 | assert_response :success | |
186 | assert_template 'show' |
|
186 | assert_template 'show' | |
|
187 | assert_select 'ul#saved-items' | |||
|
188 | assert_select 'ul#saved-items li', import.saved_items.count | |||
187 | assert_select 'table#unsaved-items', 0 |
|
189 | assert_select 'table#unsaved-items', 0 | |
188 | end |
|
190 | end | |
189 |
|
191 | |||
@@ -197,5 +199,6 class ImportsControllerTest < ActionController::TestCase | |||||
197 | assert_response :success |
|
199 | assert_response :success | |
198 | assert_template 'show' |
|
200 | assert_template 'show' | |
199 | assert_select 'table#unsaved-items' |
|
201 | assert_select 'table#unsaved-items' | |
|
202 | assert_select 'table#unsaved-items tbody tr', import.unsaved_items.count | |||
200 | end |
|
203 | end | |
201 | end |
|
204 | end |
@@ -235,7 +235,7 module ObjectHelpers | |||||
235 |
|
235 | |||
236 | import.settings = { |
|
236 | import.settings = { | |
237 | 'separator' => ";", 'wrapper' => '"', 'encoding' => "UTF-8", |
|
237 | 'separator' => ";", 'wrapper' => '"', 'encoding' => "UTF-8", | |
238 |
'mapping' => {'project_id' => '1', 'tracker |
|
238 | 'mapping' => {'project_id' => '1', 'tracker' => '13', 'subject' => '1'} | |
239 | } |
|
239 | } | |
240 | import.save! |
|
240 | import.save! | |
241 | import |
|
241 | import |
@@ -58,6 +58,46 class IssueImportTest < ActiveSupport::TestCase | |||||
58 | assert_equal 'New category', category.name |
|
58 | assert_equal 'New category', category.name | |
59 | end |
|
59 | end | |
60 |
|
60 | |||
|
61 | def test_mapping_with_fixed_tracker | |||
|
62 | import = generate_import_with_mapping | |||
|
63 | import.mapping.merge!('tracker' => 'value:2') | |||
|
64 | import.save! | |||
|
65 | ||||
|
66 | issues = new_records(Issue, 3) { import.run } | |||
|
67 | assert_equal [2], issues.map(&:tracker_id).uniq | |||
|
68 | end | |||
|
69 | ||||
|
70 | def test_mapping_with_mapped_tracker | |||
|
71 | import = generate_import_with_mapping | |||
|
72 | import.mapping.merge!('tracker' => '13') | |||
|
73 | import.save! | |||
|
74 | ||||
|
75 | issues = new_records(Issue, 3) { import.run } | |||
|
76 | assert_equal [1, 2, 1], issues.map(&:tracker_id) | |||
|
77 | end | |||
|
78 | ||||
|
79 | def test_should_not_import_with_default_tracker_when_tracker_is_invalid | |||
|
80 | Tracker.find_by_name('Feature request').update!(:name => 'Feature') | |||
|
81 | ||||
|
82 | import = generate_import_with_mapping | |||
|
83 | import.mapping.merge!('tracker' => '13') | |||
|
84 | import.save! | |||
|
85 | import.run | |||
|
86 | ||||
|
87 | assert_equal 1, import.unsaved_items.count | |||
|
88 | item = import.unsaved_items.first | |||
|
89 | assert_include "Tracker cannot be blank", item.message | |||
|
90 | end | |||
|
91 | ||||
|
92 | def test_status_should_be_set | |||
|
93 | import = generate_import_with_mapping | |||
|
94 | import.mapping.merge!('status' => '14') | |||
|
95 | import.save! | |||
|
96 | ||||
|
97 | issues = new_records(Issue, 3) { import.run } | |||
|
98 | assert_equal ['New', 'New', 'Assigned'], issues.map(&:status).map(&:name) | |||
|
99 | end | |||
|
100 | ||||
61 | def test_parent_should_be_set |
|
101 | def test_parent_should_be_set | |
62 | import = generate_import_with_mapping |
|
102 | import = generate_import_with_mapping | |
63 | import.mapping.merge!('parent_issue_id' => '5') |
|
103 | import.mapping.merge!('parent_issue_id' => '5') | |
@@ -101,7 +141,7 class IssueImportTest < ActiveSupport::TestCase | |||||
101 | field = IssueCustomField.generate!(:field_format => 'date', :is_for_all => true, :trackers => Tracker.all) |
|
141 | field = IssueCustomField.generate!(:field_format => 'date', :is_for_all => true, :trackers => Tracker.all) | |
102 | import = generate_import_with_mapping('import_dates.csv') |
|
142 | import = generate_import_with_mapping('import_dates.csv') | |
103 | import.settings.merge!('date_format' => Import::DATE_FORMATS[1]) |
|
143 | import.settings.merge!('date_format' => Import::DATE_FORMATS[1]) | |
104 | import.mapping.merge!('subject' => '0', 'start_date' => '1', 'due_date' => '2', "cf_#{field.id}" => '3') |
|
144 | import.mapping.merge!('tracker' => 'value:1', 'subject' => '0', 'start_date' => '1', 'due_date' => '2', "cf_#{field.id}" => '3') | |
105 | import.save! |
|
145 | import.save! | |
106 |
|
146 | |||
107 | issue = new_record(Issue) { import.run } # only 1 valid issue |
|
147 | issue = new_record(Issue) { import.run } # only 1 valid issue |
General Comments 0
You need to be logged in to leave comments.
Login now