mirror of
https://github.com/meineerde/redmine.git
synced 2025-10-17 17:01:01 +00:00
* mappings are case insensitive * a field is auto mapped only if there is no mapping setting present for that field * "Current user" default value for User field when the user has permission to log time for other users is override by the auto mapped column Patch by Haihan Ji, Yuichi HARADA, and Marius BALTEANU. git-svn-id: http://svn.redmine.org/redmine/trunk@19524 e93f8b46-1217-0410-a6f0-8f06a7374b81
195 lines
5.0 KiB
Ruby
195 lines
5.0 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Redmine - project management software
|
|
# Copyright (C) 2006-2019 Jean-Philippe Lang
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
require 'csv'
|
|
|
|
class ImportsController < ApplicationController
|
|
before_action :find_import, :only => [:show, :settings, :mapping, :run]
|
|
before_action :authorize_import
|
|
|
|
layout :import_layout
|
|
|
|
helper :issues
|
|
helper :queries
|
|
|
|
def new
|
|
@import = import_type.new
|
|
end
|
|
|
|
def create
|
|
@import = import_type.new
|
|
@import.user = User.current
|
|
@import.file = params[:file]
|
|
@import.set_default_settings(:project_id => params[:project_id])
|
|
|
|
if @import.save
|
|
redirect_to import_settings_path(@import)
|
|
else
|
|
render :action => 'new'
|
|
end
|
|
end
|
|
|
|
def show
|
|
end
|
|
|
|
def settings
|
|
if request.post? && @import.parse_file
|
|
redirect_to import_mapping_path(@import)
|
|
end
|
|
|
|
rescue CSV::MalformedCSVError, EncodingError => e
|
|
if e.is_a?(CSV::MalformedCSVError) && e.message !~ /Invalid byte sequence/
|
|
flash.now[:error] = l(:error_invalid_csv_file_or_settings)
|
|
else
|
|
flash.now[:error] = l(:error_invalid_file_encoding, :encoding => ERB::Util.h(@import.settings['encoding']))
|
|
end
|
|
rescue SystemCallError => e
|
|
flash.now[:error] = l(:error_can_not_read_import_file)
|
|
end
|
|
|
|
def mapping
|
|
@custom_fields = @import.mappable_custom_fields
|
|
|
|
if request.get?
|
|
auto_map_fields
|
|
elsif request.post?
|
|
respond_to do |format|
|
|
format.html {
|
|
if params[:previous]
|
|
redirect_to import_settings_path(@import)
|
|
else
|
|
redirect_to import_run_path(@import)
|
|
end
|
|
}
|
|
format.js # updates mapping form on project or tracker change
|
|
end
|
|
end
|
|
end
|
|
|
|
def run
|
|
if request.post?
|
|
@current = @import.run(
|
|
:max_items => max_items_per_request,
|
|
:max_time => 10.seconds
|
|
)
|
|
respond_to do |format|
|
|
format.html {
|
|
if @import.finished?
|
|
redirect_to import_path(@import)
|
|
else
|
|
redirect_to import_run_path(@import)
|
|
end
|
|
}
|
|
format.js
|
|
end
|
|
end
|
|
end
|
|
|
|
def current_menu(project)
|
|
if import_layout == 'admin'
|
|
nil
|
|
else
|
|
:application_menu
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def find_import
|
|
@import = Import.where(:user_id => User.current.id, :filename => params[:id]).first
|
|
if @import.nil?
|
|
render_404
|
|
return
|
|
elsif @import.finished? && action_name != 'show'
|
|
redirect_to import_path(@import)
|
|
return
|
|
end
|
|
update_from_params if request.post?
|
|
end
|
|
|
|
def update_from_params
|
|
if params[:import_settings].present?
|
|
@import.settings ||= {}
|
|
@import.settings.merge!(params[:import_settings].to_unsafe_hash)
|
|
@import.save!
|
|
end
|
|
end
|
|
|
|
def max_items_per_request
|
|
5
|
|
end
|
|
|
|
def import_layout
|
|
import_type && import_type.layout || 'base'
|
|
end
|
|
|
|
def menu_items
|
|
menu_item = import_type ? import_type.menu_item : nil
|
|
|
|
{ self.controller_name.to_sym => { :actions => {}, :default => menu_item } }
|
|
end
|
|
|
|
def authorize_import
|
|
return render_404 unless import_type
|
|
return render_403 unless import_type.authorized?(User.current)
|
|
end
|
|
|
|
def import_type
|
|
return @import_type if defined? @import_type
|
|
|
|
@import_type =
|
|
if @import
|
|
@import.class
|
|
else
|
|
type = Object.const_get(params[:type]) rescue nil
|
|
type && type < Import ? type : nil
|
|
end
|
|
end
|
|
|
|
def auto_map_fields
|
|
# Try to auto map fields only when settings['enconding'] is present
|
|
# otherwhise, the import fails for non UTF-8 files because the headers
|
|
# cannot be retrieved (Invalid byte sequence in UTF-8)
|
|
return if @import.settings['encoding'].blank?
|
|
|
|
mappings = @import.settings['mapping'] ||= {}
|
|
headers = @import.headers.map(&:downcase)
|
|
|
|
# Core fields
|
|
import_type::AUTO_MAPPABLE_FIELDS.each do |field_nm, label_nm|
|
|
next if mappings.include?(field_nm)
|
|
index = headers.index(field_nm) || headers.index(l(label_nm).downcase)
|
|
if index
|
|
mappings[field_nm] = index
|
|
end
|
|
end
|
|
|
|
# Custom fields
|
|
@custom_fields.each do |field|
|
|
field_nm = "cf_#{field.id}"
|
|
next if mappings.include?(field_nm)
|
|
index = headers.index(field_nm) || headers.index(field.name.downcase)
|
|
if index
|
|
mappings[field_nm] = index
|
|
end
|
|
end
|
|
mappings
|
|
end
|
|
end
|