mirror of https://github.com/docusealco/docuseal
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
62 lines
1.4 KiB
62 lines
1.4 KiB
# frozen_string_literal: true
|
|
|
|
require 'csv'
|
|
|
|
# Decorate the built in CSV library
|
|
# Override << to sanitize incoming rows
|
|
# Override initialize to add a converter that will sanitize fields being read
|
|
class CSVSafe < CSV
|
|
def initialize(data, converters: nil, **options)
|
|
updated_converters = converters || []
|
|
updated_converters << lambda(&method(:sanitize_field))
|
|
super(data, **options.merge(converters: updated_converters))
|
|
end
|
|
|
|
def <<(row)
|
|
super(sanitize_row(row))
|
|
end
|
|
alias_method :add_row, :<<
|
|
alias_method :puts, :<<
|
|
|
|
private
|
|
|
|
def starts_with_special_character?(str)
|
|
str.start_with?("-", "=", "+", "@", "%", "|", "\r", "\t")
|
|
end
|
|
|
|
def prefix(field)
|
|
encoded = field.encode(CSV::ConverterEncoding)
|
|
"'" + encoded
|
|
rescue StandardError
|
|
"'" + field
|
|
end
|
|
|
|
def prefix_if_necessary(field)
|
|
as_string = field.to_s
|
|
if starts_with_special_character?(as_string)
|
|
prefix(as_string)
|
|
else
|
|
field
|
|
end
|
|
end
|
|
|
|
def sanitize_field(field)
|
|
if field.nil? || field.is_a?(Numeric)
|
|
field
|
|
else
|
|
prefix_if_necessary(field)
|
|
end
|
|
end
|
|
|
|
def sanitize_row(row)
|
|
case row
|
|
when self.class::Row
|
|
then row.fields.map { |field| sanitize_field(field) }
|
|
when Hash
|
|
then @headers.map { |header| sanitize_field(row[header]) }
|
|
else
|
|
row.map { |field| sanitize_field(field) }
|
|
end
|
|
end
|
|
end
|