diff --git a/modules/simple_forms_api/app/services/simple_forms_api/s3/dump_submission_to_pdf.rb b/modules/simple_forms_api/app/services/simple_forms_api/s3/dump_submission_to_pdf.rb index e409210fc21..c81b9425f35 100644 --- a/modules/simple_forms_api/app/services/simple_forms_api/s3/dump_submission_to_pdf.rb +++ b/modules/simple_forms_api/app/services/simple_forms_api/s3/dump_submission_to_pdf.rb @@ -20,14 +20,15 @@ # ids.each { |id| DumpSubmissionToPdf.new(submission_id: id, parent_dir:).run } # this will just put each submission in a folder by it's id under the parent dir class DumpSubmissionToPdf - attr_accessor :submission, :parent_dir, :failed_uploads, :include_text_dump, - :quiet_upload_failures, :quiet_pdf_failures, :include_json_dump, :run_quiet + attr_reader :failures, :form_id, :include_json_dump, :include_text_dump, + :parent_dir, :quiet_pdf_failures, :quiet_upload_failures, :submission - def initialize(submission_id: nil, submission: nil, **options) + def initialize(form_id: nil, submission_id: nil, submission: nil, **options) defaults = default_options.merge(options) @failures = [] - @submission = defaults[:submission] || FormSubmission.find(submission_id) + @form_id = form_id + @submission = submission || FormSubmission.find(submission_id) @parent_dir = defaults[:parent_dir] @include_text_dump = defaults[:include_text_dump] @include_json_dump = defaults[:include_json_dump] @@ -36,206 +37,166 @@ def initialize(submission_id: nil, submission: nil, **options) end def run - log_info(" - submission id: #{submission.id}") - write - write_as_json_dump if include_json_dump - write_as_text_dump if include_text_dump - write_user_uploads if user_uploads.present? - write_metadata + log_info("Processing submission ID: #{submission.id}") + process_submission_files output_directory_path - rescue => e - if run_quiet - @failures << { id: submission.id, error: e.try(:message) || e } - log_error("failed submission: #{submission.id}") - else - raise e - end + rescue StandardError => e + handle_run_error(e) end private def default_options { - parent_dir: 'wipn8923-test', - include_text_dump: true, # include the form data as a text file include_json_dump: true, # include the form data as a JSON object - quiet_upload_failures: true, # will skip problematic user uploads if true - quiet_pdf_failures: true, # will skip the PDF generating if it's not working + include_text_dump: true, # include the form data as a text file + parent_dir: 'wipn8923-test', + quiet_pdf_failures: true, # skip PDF generation silently + quiet_upload_failures: true, # skip problematic uploads silently run_quiet: true } end - def metadata - @metadata ||= generate_metadata - end - - def output_directory_path - @output_directory_path ||= "#{parent_dir}/#{submission.id}" + def process_submission_files + write_pdf + write_as_json_dump if include_json_dump + write_as_text_dump if include_text_dump + write_user_uploads if user_uploads.present? + write_metadata end - def s3_resource - @s3_resource ||= Reports::Uploader.new_s3_resource - end + def handle_run_error(error) + raise error unless default_options[:run_quiet] - def target_bucket - @target_bucket ||= Reports::Uploader.s3_bucket + failures << { id: submission.id, error: error.message } + log_error("Failed submission: #{submission.id}", error) end - def form_json - @form_json ||= JSON.parse(submission.form_json)['form'] + def write_pdf + encoded_pdf = generate_pdf_content + save_file_to_s3("#{output_directory_path}/form.pdf", Base64.decode64(encoded_pdf)) + rescue StandardError => e + quiet_pdf_failures ? write_pdf_error(e) : raise(e) end - # ## - # File Writing Helpers: - def write - submission_create_date = submission.created_at.iso8601 - form_json['form']['claimDate'] ||= submission_create_date - form_json['form']['applicationExpirationDate'] = 365.days.from_now.iso8601 + def generate_pdf_content service = EVSS::DisabilityCompensationForm::NonBreakeredService.new(submission.auth_headers) - response = service.get_form(form_json.to_json) - encoded_pdf = response.body['pdf'] - content = Base64.decode64(encoded_pdf) - object = s3_resource.bucket(target_bucket).object("#{output_directory_path}/form.pdf") - object.put(body: content) - rescue => e - if quiet_pdf_failures - write_pdf_error(e) - else - raise e - end + service.get_form(form_json.to_json).body['pdf'] end def write_pdf_error(error) - content = if error.present? - "#{error.try(:message)}\n\n#{error.try(:messages).try(:join, "\n\t - ")}" - else - 'unknown failure' - end - rescue - content = 'unknown failure' - ensure - object = s3_resource.bucket(target_bucket).object("#{output_directory_path}/pdf_generating_failure_explanation.txt") - object.put(body: content) + log_error("PDF generation failed for submission: #{submission.id}", error) + save_file_to_s3("#{output_directory_path}/pdf_generating_failure.txt", error_details(error)) + end + + def error_details(error) + "#{error.message}\n\n#{error.backtrace.join("\n")}" end def write_as_json_dump - object = s3_resource.bucket(target_bucket).object("#{output_directory_path}/form_text_dump.txt") - content = JSON.pretty_generate(submission.form) - object.put(body: content) + save_file_to_s3("#{output_directory_path}/form_text_dump.json", JSON.pretty_generate(form_json)) end - def write_alternative - new_target = s3_resource.bucket(target_bucket).object("#{output_directory_path}/form.pdf") - new_target.upload_file(form_initial_path) - Common::FileHelpers.delete_file_if_exists(form_initial_path) + def write_as_text_dump + save_file_to_s3("#{output_directory_path}/form_text_dump.txt", form_text_dump.to_json) end def write_metadata - path = "#{output_directory_path}/metadata.txt" - object = s3_resource.bucket(target_bucket).object(path) - object.put(body: metadata.to_json) + save_file_to_s3("#{output_directory_path}/metadata.json", metadata.to_json) end - def write_failure_report - path = "#{output_directory_path}/user_upload_failures.txt" - object = s3_resource.bucket(target_bucket).object(path) - content = JSON.pretty_generate(user_upload_failures) - object.put(body: content) + def write_user_uploads + log_info("Moving #{user_uploads.count} user uploads") + user_uploads.each { |upload| process_user_upload(upload) } + write_failure_report if user_upload_failures.present? + rescue StandardError => e + handle_upload_error(e) end - def write_as_text_dump - path = "#{output_directory_path}/form_text_dump.txt" - object = s3_resource.bucket(target_bucket).object(path) - object.put(body: form_text_dump.to_json) + def process_user_upload(upload) + log_info("Processing upload: #{upload['name']} - #{upload['confirmationCode']}") + local_file = SupportingEvidenceAttachment.find_by(guid: upload['confirmationCode']) + raise 'Local record not found' unless local_file + + copy_file_between_buckets(local_file) end - def form_text_dump - @form_text_dump ||= generate_form_text_dump + def copy_file_between_buckets(local_file) + source_obj = s3_resource.bucket(local_file.get_file.uploader.aws_bucket).object(local_file.get_file.path) + target_obj = s3_resource.bucket(target_bucket).object("#{user_upload_path}/#{local_file.get_file.filename}") + target_obj.copy_from(source_obj) end - def generate_form_text_dump - form = submission.form - return form if form['form'].blank? + def write_failure_report + save_file_to_s3("#{output_directory_path}/user_upload_failures.txt", JSON.pretty_generate(user_upload_failures)) + end - form['form']['claimDate'] ||= submission.created_at.iso8601 - form + def save_file_to_s3(path, content) + s3_resource.bucket(target_bucket).object(path).put(body: content) end - def user_upload_path - @user_upload_path ||= "#{output_directory_path}/user_uploads" + def s3_resource + @s3_resource ||= Reports::Uploader.new_s3_resource end - def user_uploads - @user_uploads ||= submission.form['form_uploads'] + def target_bucket + @target_bucket ||= Reports::Uploader.s3_bucket end - def user_upload_failures - @user_upload_failures ||= [] + def form_json + @form_json ||= JSON.parse(submission.form_json)[form_id] end - # ## - # User Upload Processing: - def write_user_uploads - log_info(" Moving #{user_uploads.count} user uploads:") - user_uploads.each do |upload| - write_user_upload upload - rescue => e - if quiet_upload_failures - user_upload_failures << { - filename: upload['name'], - confirmationCode: upload['attachmentId'], - attachmentId: upload['attachmentId'], - error: e.try(:message) || e || 'unknown error' - } - else - raise e - end - end - write_failure_report if user_upload_failures.present? + def form_text_dump + form = submission.form + form[form_id]['claimDate'] ||= submission.created_at.iso8601 + form end - def write_user_upload(upload_data) - log_info(" - processing upload: #{upload_data['name']} - #{upload_data['confirmationCode']}") - local = SupportingEvidenceAttachment.find_by(guid: upload_data['confirmationCode']) - raise 'No local record found' if local.blank? + def metadata + return {} unless submission.auth_headers.present? && submission.form[form_id].present? - read_bucket = local.get_file.uploader.aws_bucket - aws_path = local.get_file.path - old_obj = s3_resource.bucket(read_bucket).object(aws_path) - new_obj = s3_resource.bucket(target_bucket).object("#{user_upload_path}/#{upload_data['name']}") - new_obj.copy_from(old_obj) + extract_metadata_from_submission end - # ## - # Metadata Processing: - # create metadata json with - # - vet PII - # - formsIncluded value indicates to the reviewing admin that nothing is missing - # - GUIDs of failed document uploads - def generate_metadata - return {} unless submission.auth_headers.present? && submission.form['form'].present? - - zc = submission.form.dig('form', 'veteran', 'currentMailingAddress') - zipcode = zc.nil? ? '00000' : [zc['zipFirstFive'], zc['zipLastFour']].join('-') + def extract_metadata_from_submission + address = submission.form.dig(form_id, 'veteran', 'currentMailingAddress') + zip = [address['zipFirstFive'], address['zipLastFour']].join('-') if address.present? pii = JSON.parse(submission.auth_headers['va_eauth_authorization'])['authorizationResponse'] pii.merge({ - fileNumber: pii['va_eauth_pnid'], - birlsfilenumber: pii['va_eauth_birlsfilenumber'], - zipCode: zipcode, - claimDate: submission.created_at.iso8601, - formsIncluded: map_form_inclusion - }) + fileNumber: pii['va_eauth_pnid'], + zipCode: zip || '00000', + claimDate: submission.created_at.iso8601, + formsIncluded: map_form_inclusion + }) end def map_form_inclusion %w[form1 form2].select { |type| submission.form[type].present? } end - def log_info(message, **details) - Rails.logger.info(message, details) + def log_info(message) + Rails.logger.info(message) end - def log_error(message, error, **details) - Rails.logger.error(message, details.merge(error: error.message, backtrace: error.backtrace.first(5))) + def log_error(message, error) + Rails.logger.error("#{message}: #{error.message}") + end + + def output_directory_path + @output_directory_path ||= "#{parent_dir}/#{submission.id}" + end + + def user_uploads + @user_uploads ||= submission.form['form_uploads'] + end + + def user_upload_failures + @user_upload_failures ||= [] + end + + def user_upload_path + @user_upload_path ||= "#{output_directory_path}/user_uploads" end end +