Project

General

Profile

Feature #22913 » 0002-Auto-select-fields-mapping-in-import-based-on-the-in.patch

Marius BĂLTEANU, 2020-02-18 18:00

View differences:

app/controllers/imports_controller.rb
66 66
  def mapping
67 67
    @custom_fields = @import.mappable_custom_fields
68 68

  
69
    if request.post?
69
    if request.get?
70
      auto_map_fields
71
    elsif request.post?
70 72
      respond_to do |format|
71 73
        format.html {
72 74
          if params[:previous]
......
159 161
        type && type < Import ? type : nil
160 162
      end
161 163
  end
164

  
165
  def auto_map_fields
166
    # Try to auto map fields only when settings['enconding'] is present
167
    # otherwhise, the import fails for non UTF-8 files because the headers
168
    # cannot be retrieved (Invalid byte sequence in UTF-8)
169
    return if @import.settings['encoding'].blank?
170

  
171
    mappings = @import.settings['mapping'] ||= {}
172
    headers = @import.headers.map(&:downcase)
173

  
174
    # Core fields
175
    import_type::AUTO_MAPPABLE_FIELDS.each do |field_nm, label_nm|
176
      next if mappings.include?(field_nm)
177
      index = headers.index(field_nm) || headers.index(l(label_nm).downcase)
178
      if index
179
        mappings[field_nm] = index
180
      end
181
    end
182

  
183
    # Custom fields
184
    @custom_fields.each do |field|
185
      field_nm = "cf_#{field.id}"
186
      next if mappings.include?(field_nm)
187
      index = headers.index(field_nm) || headers.index(field.name.downcase)
188
      if index
189
        mappings[field_nm] = index
190
      end
191
    end
192
    mappings
193
  end
162 194
end
app/models/import.rb
37 37
    '%d.%m.%Y',
38 38
    '%d-%m-%Y'
39 39
  ]
40
  AUTO_MAPPABLE_FIELDS = {}
40 41

  
41 42
  def self.menu_item
42 43
    nil
app/models/issue_import.rb
18 18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 19

  
20 20
class IssueImport < Import
21
  AUTO_MAPPABLE_FIELDS = {
22
    'tracker' => 'field_tracker',
23
    'subject' => 'field_subject',
24
    'description' => 'field_description',
25
    'status' => 'field_status',
26
    'priority' => 'field_priority',
27
    'category' => 'field_category',
28
    'assigned_to' => 'field_assigned_to',
29
    'fixed_version' => 'field_fixed_version',
30
    'is_private' => 'field_is_private',
31
    'parent_issue_id' => 'field_parent_issue',
32
    'start_date' => 'field_start_date',
33
    'due_date' => 'field_due_date',
34
    'estimated_hours' => 'field_estimated_hours',
35
    'done_ratio' => 'field_done_ratio'
36
  }
37

  
21 38
  def self.menu_item
22 39
    :issues
23 40
  end
app/models/time_entry_import.rb
18 18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 19

  
20 20
class TimeEntryImport < Import
21
  AUTO_MAPPABLE_FIELDS = {
22
    'activity' => 'field_activity',
23
    'user' => 'field_user',
24
    'issue_id' => 'field_issue',
25
    'spent_on' => 'field_spent_on',
26
    'hours' => 'field_hours',
27
    'comments' => 'field_comments'
28
  }
29

  
21 30
  def self.menu_item
22 31
    :time_entries
23 32
  end
app/views/imports/_issues_fields_mapping.html.erb
7 7
        :id => 'import_mapping_project_id' %>
8 8
</p>
9 9
<p>
10
  <label for="import_mapping_tracker"><%= l(:label_tracker) %></label>
10
  <label for="import_mapping_tracker"><%= l(:field_tracker) %></label>
11 11
  <%= mapping_select_tag @import, 'tracker', :required => true,
12 12
        :values => @import.allowed_target_trackers.sorted.map {|t| [t.name, t.id]} %>
13 13
</p>
......
99 99
</p>
100 100
</div>
101 101
</div>
102

  
test/fixtures/files/import_issues_auto_mapping.csv
1
priority;Subject;start_date;parent;private;progress;custom;"target version";category;user;estimated_hours;tracker;status;database;cf_6
2
High;First;2015-07-08;;no;;PostgreSQL;;New category;dlopper;1;bug;new;"PostgreSQL, Oracle";2
test/functional/imports_controller_test.rb
167 167
    end
168 168
  end
169 169

  
170
  def test_get_mapping_should_auto_map_fields_by_internal_field_name_or_by_label
171
    import = generate_import('import_issues_auto_mapping.csv')
172
    import.settings = {'separator' => ';', 'wrapper'=> '"', 'encoding' => 'ISO-8859-1'}
173
    import.save!
174

  
175
    get :mapping, :params => {
176
        :id => import.to_param
177
      }
178
    assert_response :success
179

  
180
    # 'subject' should be auto selected because
181
    #  - 'Subject' exists in the import file
182
    #  - mapping is case insensitive
183
    assert_select 'select[name=?]', 'import_settings[mapping][subject]' do
184
      assert_select 'option[value="1"][selected="selected"]', :text => 'Subject'
185
    end
186

  
187
    # 'estimated_hours' should be auto selected because
188
    #  - 'estimated_hours' exists in the import file
189
    assert_select 'select[name=?]', 'import_settings[mapping][estimated_hours]' do
190
      assert_select 'option[value="10"][selected="selected"]', :text => 'estimated_hours'
191
    end
192

  
193
    # 'fixed_version' should be auto selected because
194
    #  - the translation 'Target version' exists in the import file
195
    assert_select 'select[name=?]', 'import_settings[mapping][fixed_version]' do
196
      assert_select 'option[value="7"][selected="selected"]', :text => 'target version'
197
    end
198

  
199
    # 'assigned_to' should not be auto selected because
200
    #  - 'assigned_to' does not exist in the import file
201
    assert_select 'select[name=?]', 'import_settings[mapping][assigned_to]' do
202
      assert_select 'option[selected="selected"]', 0
203
    end
204

  
205
    # Custom field 'Float field' should be auto selected because
206
    #  - the internal field name ('cf_6') exists in the import file
207
    assert_select 'select[name=?]', 'import_settings[mapping][cf_6]' do
208
      assert_select 'option[value="14"][selected="selected"]', :text => 'cf_6'
209
    end
210

  
211
    # Custom field 'Database' should be auto selected because
212
    #  - field name 'database' exists in the import file
213
    #  - mapping is case insensitive
214
    assert_select 'select[name=?]', 'import_settings[mapping][cf_1]' do
215
      assert_select 'option[value="13"][selected="selected"]', :text => 'database'
216
    end
217
  end
218

  
170 219
  def test_post_mapping_should_update_mapping
171 220
    import = generate_import('import_iso8859-1.csv')
172 221

  
......
200 249

  
201 250
    assert_response :success
202 251

  
203
    # 'user_id' field should be available because User#2 has both
252
    # Assert auto mapped fields
253
    assert_select 'select[name=?]', 'import_settings[mapping][activity]' do
254
      assert_select 'option[value="5"][selected="selected"]', :text => 'activity'
255
    end
256
    # 'user' should be mapped to column 'user' from import file
257
    # and not to current user because the auto map has priority
258
    assert_select 'select[name=?]', 'import_settings[mapping][user]' do
259
      assert_select 'option[value="7"][selected="selected"]', :text => 'user'
260
    end
261
    assert_select 'select[name=?]', 'import_settings[mapping][cf_10]' do
262
      assert_select 'option[value="6"][selected="selected"]', :text => 'overtime'
263
    end
264
  end
265

  
266
  def test_get_mapping_time_entry_for_user_with_log_time_for_other_users_permission
267
    Role.find(1).add_permission! :log_time_for_other_users
268
    import = generate_time_entry_import
269
    import.settings = {
270
      'separator' => ";", 'wrapper' => '"', 'encoding' => "ISO-8859-1",
271
      # Do not auto map user in order to allow current user to be auto selected
272
      'mapping' => {'user' => nil}
273
    }
274
    import.save!
275

  
276
    get :mapping, :params => {
277
        :id => import.to_param
278
      }
279

  
280
    # 'user' field should be available because User#2 has both
204 281
    # 'import_time_entries' and 'log_time_for_other_users' permissions
205 282
    assert_select 'select[name=?]', 'import_settings[mapping][user]' do
206
      # Current user should be the default value
283
      # Current user should be the default value if there is not auto map present
207 284
      assert_select 'option[value="value:2"][selected]', :text => User.find(2).name
208 285
      assert_select 'option[value="value:3"]', :text => User.find(3).name
209 286
    end
(7-7/7)