class KPM::Account
def b64_decode_if_needed(input)
def b64_decode_if_needed(input) # Exclude nil or non string return input if input.nil? || !input.is_a?(String) # Apply regex to check that string is built as a B64 string: the character set is [A-Z, a-z, 0-9, and + /] # and if the rest length is less than 4, the string is padded with '=' characters. return input if input.match(B64_REGEX).nil? # Decode result = Base64.decode64(input) # Verify encoded of the decoded value == input prior return result return input if Base64.strict_encode64(result) != input Blob.new(result, TMP_DIR) end
def config=(config_file = nil)
def config=(config_file = nil) @config = nil return if config_file.nil? @config = YAML.load_file(config_file) unless Dir[config_file][0].nil? end
def export(export_data)
def export(export_data) export_file = TMP_DIR + File::SEPARATOR + 'kbdump' File.open(export_file, 'w') do |io| table_name = nil cols_names = nil export_data.split("\n").each do |line| words = line.strip.split(' ') clean_line = line if !/--/.match(words[0]).nil? table_name = words[1] cols_names = words[2].strip.split(@delimiter) elsif !table_name.nil? clean_line = process_export_data(line, table_name, cols_names) end io.puts clean_line end end export_file end
def export_data(account_id = nil)
def export_data(account_id = nil) raise Interrupt, 'Need to specify an account id' if account_id == :export.to_s export_data = fetch_export_data(account_id) export_file = export(export_data) raise Interrupt, 'Account id not found' unless File.exist?(export_file) @logger.info "\e[32mData exported under #{export_file}\e[0m" export_file end
def fetch_export_data(account_id)
def fetch_export_data(account_id) KillBillClient.url = @killbill_url options = { username: @killbill_user, password: @killbill_password, api_key: @killbill_api_key, api_secret: @killbill_api_secret } begin account_data = KillBillClient::Model::Export.find_by_account_id(account_id, 'KPM', options) rescue StandardError raise Interrupt, 'Account id not found' end account_data end
def fill_empty_column(value)
def fill_empty_column(value) if value.to_s.strip.empty? :DEFAULT else value end end
def fix_dates(value)
def fix_dates(value) unless value.equal?(:DEFAULT) dt = DateTime.parse(value) return dt.strftime('%F %T').to_s end value end
def import(tables)
def import(tables) record_id = nil statements = @database.generate_insert_statement(tables) statements.each do |statement| response = @database.execute_insert_statement(statement[:table_name], statement[:query], statement[:qty_to_insert], statement[:table_data], record_id) record_id = { variable: '@account_record_id', value: response } if statement[:table_name] == 'accounts' && response.is_a?(String) break unless response end end
def import_data(source_file, tenant_record_id, skip_payment_methods, round_trip_export_import = false, generate_record_id = false)
def import_data(source_file, tenant_record_id, skip_payment_methods, round_trip_export_import = false, generate_record_id = false) source_file = File.expand_path(source_file) @generate_record_id = generate_record_id @tenant_record_id = tenant_record_id @round_trip_export_import = round_trip_export_import raise Interrupt, 'Need to specify a file' if source_file == :import.to_s raise Interrupt, "File #{source_file} does not exist" unless File.exist?(source_file) @delimiter = sniff_delimiter(source_file) || @delimiter sanitize_and_import(source_file, skip_payment_methods) end
def initialize(config_file = nil, killbill_api_credentials = nil, killbill_credentials = nil, killbill_url = nil,
def initialize(config_file = nil, killbill_api_credentials = nil, killbill_credentials = nil, killbill_url = nil, database_name = nil, database_credentials = nil, database_host = nil, database_port = nil, data_delimiter = nil, logger = nil) @killbill_api_key = KILLBILL_API_KEY @killbill_api_secret = KILLBILL_API_SECRET @killbill_url = KILLBILL_URL @killbill_user = KILLBILL_USER @killbill_password = KILLBILL_PASSWORD @delimiter = data_delimiter || DEFAULT_DELIMITER @logger = logger @tables_id = {} set_killbill_options(killbill_api_credentials, killbill_credentials, killbill_url) database_credentials ||= [nil, nil] @database = Database.new(database_name, database_host, database_port, database_credentials[0], database_credentials[1], logger) load_config_from_file(config_file) end
def load_config_from_file(config_file)
def load_config_from_file(config_file) self.config = config_file return if @config.nil? config_killbill = @config['killbill'] unless config_killbill.nil? set_killbill_options([config_killbill['api_key'], config_killbill['api_secret']], [config_killbill['user'], config_killbill['password']], "http://#{config_killbill['host']}:#{config_killbill['port']}") end config_db = @config['database'] @database = Database.new(config_db['name'], config_db['host'], config_db['port'], config_db['username'], config_db['password'], @logger) unless config_db.nil? end
def process_export_data(line_to_process, table_name, cols_names)
def process_export_data(line_to_process, table_name, cols_names) clean_line = line_to_process row = [] cols = clean_line.strip.split(@delimiter) cols_names.each_with_index do |col_name, index| sanitized_value = remove_export_data(table_name, col_name, cols[index]) row << sanitized_value end row.join(@delimiter) end
def process_import_data(line, table_name, cols_names, skip_payment_methods, _rows)
def process_import_data(line, table_name, cols_names, skip_payment_methods, _rows) # to make sure that the last column is not omitted if is empty cols = line.strip.split(@delimiter, line.count(@delimiter) + 1) if cols_names.size != cols.size @logger.warn "\e[32mWARNING!!! On #{table_name} table there is a mismatch on column count[#{cols.size}] versus header count[#{cols_names.size}]\e[0m" return nil end row = [] @logger.debug "Processing table_name=#{table_name}, line=#{line}" cols_names.each_with_index do |col_name, index| sanitized_value = sanitize(table_name, col_name, cols[index], skip_payment_methods) row << sanitized_value unless sanitized_value.nil? end row end
def remove_export_data(table_name, col_name, value)
def remove_export_data(table_name, col_name, value) unless REMOVE_DATA_FROM[table_name.to_sym].nil? return nil if REMOVE_DATA_FROM[table_name.to_sym].include? col_name.to_sym end value end
def replace_account_record_id(table_name, column_name, value)
def replace_account_record_id(table_name, column_name, value) return :@account_record_id if column_name == 'account_record_id' return nil if column_name == 'record_id' if column_name == 'target_record_id' return :@account_record_id if table_name == 'account_history' end return :@account_record_id if column_name == 'search_key1' && table_name == 'bus_ext_events_history' return :@account_record_id if column_name == 'search_key1' && table_name == 'bus_events_history' value end
def replace_boolean(value)
def replace_boolean(value) case value.to_s when 'true' 1 when 'false' 0 else value end end
def replace_tenant_record_id(_table_name, column_name, value)
def replace_tenant_record_id(_table_name, column_name, value) return @tenant_record_id if %w[tenant_record_id search_key2].include?(column_name) value end
def replace_uuid(table_name, column_name, value)
def replace_uuid(table_name, column_name, value) @tables_id["#{table_name}_id"] = SecureRandom.uuid if column_name == 'id' if ROUND_TRIP_EXPORT_IMPORT_MAP[table_name.to_sym] && ROUND_TRIP_EXPORT_IMPORT_MAP[table_name.to_sym][column_name.to_sym] key = ROUND_TRIP_EXPORT_IMPORT_MAP[table_name.to_sym][column_name.to_sym] new_value = if key.equal?(:generate) SecureRandom.uuid else @tables_id[key.to_s] end if new_value.nil? new_value = SecureRandom.uuid @tables_id[key.to_s] = new_value end return new_value end unless ROUND_TRIP_EXPORT_IMPORT_MAP[:all][column_name.to_sym].nil? key = ROUND_TRIP_EXPORT_IMPORT_MAP[:all][column_name.to_sym] new_value = @tables_id[key.to_s] return new_value end value end
def sanitize(table_name, column_name, value, skip_payment_methods)
def sanitize(table_name, column_name, value, skip_payment_methods) sanitized_value = replace_boolean(value) sanitized_value = fill_empty_column(sanitized_value) sanitized_value = SAFE_PAYMENT_METHOD if table_name == 'payment_methods' && skip_payment_methods && column_name == PLUGIN_NAME_COLUMN sanitized_value = fix_dates(sanitized_value) if DATE_COLUMNS_TO_FIX.include? column_name sanitized_value = replace_tenant_record_id(table_name, column_name, sanitized_value) unless @tenant_record_id.nil? sanitized_value = replace_account_record_id(table_name, column_name, sanitized_value) if @generate_record_id sanitized_value = replace_uuid(table_name, column_name, sanitized_value) if @round_trip_export_import sanitized_value = b64_decode_if_needed(sanitized_value) if column_name == 'billing_events' sanitized_value end
def sanitize_and_import(source_file, skip_payment_methods)
import helpers: sanitize_and_import; import; sanitize; replace_tenant_record_id; replace_account_record_id; replace_boolean;
def sanitize_and_import(source_file, skip_payment_methods) tables = {} error_importing_data = false File.open(source_file, 'r:UTF-8') do |data| rows = nil table_name = nil cols_names = nil data.each_line do |line| words = line.strip.split(' ') if /--/.match(words[0]) unless table_name.nil? cols_names.shift if @generate_record_id tables[table_name] = { col_names: cols_names, rows: rows } end table_name = words[1] cols_names = words[2].strip.split(@delimiter) rows = [] elsif !table_name.nil? row = process_import_data(line, table_name, cols_names, skip_payment_methods, rows) next if row.nil? rows.push(row) else error_importing_data = true break end end unless table_name.nil? || error_importing_data cols_names.shift if @generate_record_id tables[table_name] = { col_names: cols_names, rows: rows } end error_importing_data = true if tables.empty? end raise Interrupt, "Data on #{source_file} is invalid" if error_importing_data import(tables) end
def set_killbill_options(killbill_api_credentials, killbill_credentials, killbill_url)
def set_killbill_options(killbill_api_credentials, killbill_credentials, killbill_url) unless killbill_api_credentials.nil? @killbill_api_key = killbill_api_credentials[0] @killbill_api_secret = killbill_api_credentials[1] end unless killbill_credentials.nil? @killbill_user = killbill_credentials[0] @killbill_password = killbill_credentials[1] end @killbill_url = killbill_url unless killbill_url.nil? end
def sniff_delimiter(file)
def sniff_delimiter(file) return nil if File.size?(file).nil? first_line = File.open(file, &:readline) return nil if first_line.nil? sniff = {} DELIMITERS.each do |delimiter| sniff[delimiter] = first_line.count(delimiter) end sniff = sniff.sort { |a, b| b[1] <=> a[1] } !sniff.empty? ? sniff[0][0] : nil end