diff options
Diffstat (limited to 'app/services/import_csv/base_service.rb')
-rw-r--r-- | app/services/import_csv/base_service.rb | 40 |
1 files changed, 34 insertions, 6 deletions
diff --git a/app/services/import_csv/base_service.rb b/app/services/import_csv/base_service.rb index feb76425fb4..70834b8a85a 100644 --- a/app/services/import_csv/base_service.rb +++ b/app/services/import_csv/base_service.rb @@ -2,6 +2,8 @@ module ImportCsv class BaseService + include Gitlab::Utils::StrongMemoize + def initialize(user, project, csv_io) @user = user @project = project @@ -9,6 +11,8 @@ module ImportCsv @results = { success: 0, error_lines: [], parse_error: false } end + PreprocessError = Class.new(StandardError) + def execute process_csv email_results_to_user @@ -36,7 +40,23 @@ module ImportCsv raise NotImplementedError end + def validate_structure! + header_line = csv_data.lines.first + raise CSV::MalformedCSVError.new('File is empty, no headers found', 1) if header_line.blank? + + validate_headers_presence!(header_line) + detect_col_sep + end + + def preprocess! + # any logic can be added in subclasses if needed + # hence just a no-op rather than NotImplementedError + end + def process_csv + validate_structure! + preprocess! + with_csv_lines.each do |row, line_no| attributes = attributes_for(row) @@ -46,23 +66,30 @@ module ImportCsv results[:error_lines].push(line_no) end end - rescue ArgumentError, CSV::MalformedCSVError + rescue ArgumentError, CSV::MalformedCSVError => e results[:parse_error] = true + results[:error_lines].push(e.line_number) if e.respond_to?(:line_number) + rescue PreprocessError + results[:parse_error] = false end def with_csv_lines - csv_data = @csv_io.open(&:read).force_encoding(Encoding::UTF_8) - validate_headers_presence!(csv_data.lines.first) - CSV.new( csv_data, - col_sep: detect_col_sep(csv_data.lines.first), + col_sep: detect_col_sep, headers: true, header_converters: :symbol ).each.with_index(2) end - def detect_col_sep(header) + def csv_data + @csv_io.open(&:read).force_encoding(Encoding::UTF_8) + end + strong_memoize_attr :csv_data + + def detect_col_sep + header = csv_data.lines.first + if header.include?(",") "," elsif header.include?(";") @@ -73,6 +100,7 @@ module ImportCsv raise CSV::MalformedCSVError.new('Invalid CSV format', 1) end end + strong_memoize_attr :detect_col_sep def create_object(attributes) # NOTE: CSV imports are performed by workers, so we do not have a request context in order |