# frozen_string_literal: true require_dependency "renalware/ukrdc" require "gpg_encrypt_folder" module Renalware module UKRDC class SendPatients attr_reader :patient_ids, :changed_since, :logger, :request_uuid def initialize(changed_since: nil, patient_ids: nil, logger: nil) @changed_since = Time.zone.parse(changed_since) if changed_since.present? @patient_ids = Array(patient_ids) @logger = logger || Rails.logger @request_uuid = SecureRandom.uuid # helps group logs together end def call logger.info "Request #{request_uuid}" ms = Benchmark.ms do send_patients end print_summary(ms) end private # rubocop:disable Metrics/AbcSize, Metrics/MethodLength def send_patients logger.info("Generating XML files for #{patient_ids&.any? ? patient_ids : 'all'} patients") query = Renalware::UKRDC::PatientsQuery.new.call(changed_since: changed_since) query = query.where(id: Array(patient_ids)) if patient_ids.present? if changed_since.present? logger.info("#{query.count} patients have changed since #{changed_since}") else logger.info("#{query.count} patients have changed since the last send") end folder_name = within_new_folder do |dir| xml_path = dir.join("xml") query.all.find_each do |patient| SendPatient.new( patient: patient, dir: xml_path, changes_since: changed_since, request_uuid: request_uuid, logger: logger ).call end encrypt_xml_files_in(dir) end logger.info("Files saved to #{folder_name}") end # rubocop:enable Metrics/AbcSize, Metrics/MethodLength def gpg_encrypt(filepath, output_filepath) path_to_key = File.open(Rails.root.join("key.gpg")) # only needed if the key has not been imported previously GPGME::Key.import(path_to_key) crypto = GPGME::Crypto.new(always_trust: true) File.open(filepath) do |in_file| File.open(output_filepath, "wb") do |out_file| crypto.encrypt in_file, output: out_file, recipients: "Patient View" end end end def timestamp Time.zone.now.strftime("%Y%m%d%H%M%S%L") end def within_new_folder dir = Pathname(File.join("/var", "ukrdc", timestamp)) FileUtils.mkdir_p File.join(dir, "xml") FileUtils.mkdir_p File.join(dir, "encrypted") yield dir if block_given? dir end def filepath_for(patient, dir, sub_folder) raise(ArgumentError, "Patient has no ukrdc_external_id") if patient.ukrdc_external_id.blank? filename = "#{patient.ukrdc_external_id}.xml" File.join(dir, sub_folder.to_s, filename) end def print_summary(ms) logger.info "*** Summary ***" logger.info "Took #{ms.to_i / 1000} seconds" results = TransmissionLog.where(request_uuid: request_uuid).group(:status).count(:status) results.to_h.map{ |key, value| logger.info("#{key}: #{value}") } end def encrypt_xml_files_in(dir) logger.info "Encrypting..." GpgEncryptFolder.new(folder: dir, options: gpg_options).call end def config Renalware.config end def gpg_options GpgOptions.new( recipient: config.ukrdc_gpg_recipient, keyring: config.ukrdc_gpg_keyring, homedir: config.ukrdc_gpg_homedir, filename_transform: lambda do |filename| filename.to_s.gsub("/xml/", "/encrypted/") + ".enc" end ) end end end end