Class: BenefitsIntakeService::Service

Inherits:
Common::Client::Base show all
Includes:
Common::Client::Concerns::Monitoring, SentryLogging
Defined in:
lib/benefits_intake_service/service.rb

Overview

Proxy Service for the Lighthouse Claims Intake API Service. We are using it here to submit claims that cannot be auto-established, via paper submission (electronic PDF submission to CMP)

Direct Known Subclasses

Form526BackupSubmission::Service

Defined Under Namespace

Classes: InvalidDocumentError

Constant Summary collapse

REQUIRED_CREATE_HEADERS =
%w[X-VA-First-Name X-VA-Last-Name X-VA-SSN X-VA-Birth-Date].freeze
PDF_VALIDATOR_OPTIONS =
{
  size_limit_in_bytes: 100_000_000, # 100 MB
  check_page_dimensions: true,
  check_encryption: true,
  width_limit_in_inches: 78,
  height_limit_in_inches: 101
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Common::Client::Concerns::Monitoring

#increment, #increment_failure, #increment_total, #with_monitoring

Methods included from SentryLogging

#log_exception_to_sentry, #log_message_to_sentry, #non_nil_hash?, #normalize_level, #rails_logger, #set_sentry_metadata

Methods inherited from Common::Client::Base

#config, configuration, #connection, #delete, #get, #perform, #post, #put, #raise_backend_exception, #raise_not_authenticated, #request, #sanitize_headers!, #service_name

Constructor Details

#initialize(with_upload_location: false) ⇒ Service

TODO: Remove param and clean up Form526BackupSubmissionProcess::Processor to use instance vars



69
70
71
72
73
74
75
76
# File 'lib/benefits_intake_service/service.rb', line 69

def initialize(with_upload_location: false)
  super()
  if with_upload_location
    upload_return = get_location_and_uuid
    @uuid = upload_return[:uuid]
    @location = upload_return[:location]
  end
end

Instance Attribute Details

#locationObject (readonly)

Returns the value of attribute location.



25
26
27
# File 'lib/benefits_intake_service/service.rb', line 25

def location
  @location
end

#uuidObject (readonly)

Returns the value of attribute uuid.



25
26
27
# File 'lib/benefits_intake_service/service.rb', line 25

def uuid
  @uuid
end

Instance Method Details

#generate_metadata(metadata) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/benefits_intake_service/service.rb', line 123

def ()
   = {
    veteranFirstName: [:veteran_first_name],
    veteranLastName: [:veteran_last_name],
    fileNumber: [:file_number],
    zipCode: [:zip],
    source: [:source] || 'va.gov submission',
    docType: [:doc_type],
    businessLine: [:business_line] || 'CMP',
    claimDate: [:claim_date]
  }
  BenefitsIntake::Metadata.validate(.stringify_keys)
end

#generate_tmp_metadata_file(metadata) ⇒ Object



137
138
139
# File 'lib/benefits_intake_service/service.rb', line 137

def ()
  Common::FileHelpers.generate_clamav_temp_file(.to_s, "#{SecureRandom.hex}.benefits_intake.metadata.json")
end

#get_bulk_status_of_uploads(ids) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/benefits_intake_service/service.rb', line 96

def get_bulk_status_of_uploads(ids)
  body = { ids: }.to_json
  response = perform(
    :post,
    'uploads/report',
    body,
    { 'Content-Type' => 'application/json', 'accept' => 'application/json' }
  )

  raise response.body unless response.success?

  response
end

#get_file_path_from_objs(file) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/benefits_intake_service/service.rb', line 110

def get_file_path_from_objs(file)
  case file
  when EVSS::DisabilityCompensationForm::Form8940Document
    file.pdf_path
  when CarrierWave::SanitizedFile
    file.file
  when Hash
    get_file_path_from_objs(file[:file])
  else
    file
  end
end

#get_location_and_uuidObject

Instantiates a new location and uuid via lighthouse



142
143
144
145
146
147
148
# File 'lib/benefits_intake_service/service.rb', line 142

def get_location_and_uuid
  upload_return = get_upload_location
  {
    uuid: upload_return.body.dig('data', 'id'),
    location: upload_return.body.dig('data', 'attributes', 'location')
  }
end

#get_upload_docs(file_with_full_path:, metadata:, attachments: []) ⇒ Object

Combines instantiating a new location/uuid and returning the important bits



151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/benefits_intake_service/service.rb', line 151

def get_upload_docs(file_with_full_path:, metadata:, attachments: [])
  json_tmpfile = ()
  file_name = File.basename(file_with_full_path)
  params = { metadata: Faraday::UploadIO.new(json_tmpfile, Mime[:json].to_s, 'metadata.json'),
             content: Faraday::UploadIO.new(file_with_full_path, Mime[:pdf].to_s, file_name) }
  attachments.each.with_index do |attachment, i|
    file_path = get_file_path_from_objs(attachment[:file])
    file_name = attachment[:file_name] || attachment['name']
    params[:"attachment#{i + 1}"] = Faraday::UploadIO.new(file_path, Mime[:pdf].to_s, file_name)
  end
  [params, json_tmpfile]
end

#get_upload_locationObject



90
91
92
93
94
# File 'lib/benefits_intake_service/service.rb', line 90

def get_upload_location
  headers = {}
  request_body = {}
  perform :post, 'uploads', request_body, headers
end

#permanent_file?(_file) ⇒ Boolean

Overload in other services to define files not meant to be deleted

Returns:

  • (Boolean)


195
196
197
# File 'lib/benefits_intake_service/service.rb', line 195

def permanent_file?(_file)
  false
end

#upload_deletion_logic(file_with_full_path:, attachments:) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/benefits_intake_service/service.rb', line 177

def upload_deletion_logic(file_with_full_path:, attachments:)
  if Rails.env.production?
    Common::FileHelpers.delete_file_if_exists(file_with_full_path) unless permanent_file?(file_with_full_path)
    attachments.each do |evidence_file|
      to_del = get_file_path_from_objs(evidence_file)
      # dont delete the instructions pdf we keep on the fs and send along for bdd claims
      Common::FileHelpers.delete_file_if_exists(to_del) unless permanent_file?(to_del)
    end
  else
    Rails.logger.info("Would have deleted file #{file_with_full_path} if in production env.")
    attachments.each do |evidence_file|
      to_del = get_file_path_from_objs(evidence_file)
      Rails.logger.info("Would have deleted file #{to_del} if in production env.") unless permanent_file?(to_del)
    end
  end
end

#upload_doc(upload_url:, file:, metadata:, attachments: []) ⇒ Object



164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/benefits_intake_service/service.rb', line 164

def upload_doc(upload_url:, file:, metadata:, attachments: [])
  file_with_full_path = get_file_path_from_objs(file)
  params, _json_tmpfile = get_upload_docs(file_with_full_path:, metadata:,
                                          attachments:)
  response = perform :put, upload_url, params, { 'Content-Type' => 'multipart/form-data' }

  raise response.body unless response.success?

  upload_deletion_logic(file_with_full_path:, attachments:)

  response
end

#upload_form(main_document:, attachments:, form_metadata:) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
# File 'lib/benefits_intake_service/service.rb', line 78

def upload_form(main_document:, attachments:, form_metadata:)
  raise 'Ran Method without Instance Variables' if @location.blank?

   = ()
  upload_doc(
    upload_url: @location,
    file: main_document,
    metadata: .to_json,
    attachments:
  )
end

#valid_document?(document:) ⇒ Boolean

Validate a file satisfies BenefitsIntake specifications. ** File must be a PDF.

Parameters:

  • document: (String)

    path to file

Returns:

  • (Boolean)

Raises:

See Also:



58
59
60
61
62
63
64
65
66
# File 'lib/benefits_intake_service/service.rb', line 58

def valid_document?(document:)
  result = PDFUtilities::PDFValidator::Validator.new(document, PDF_VALIDATOR_OPTIONS).validate
  raise InvalidDocumentError, "Invalid Document: #{result.errors}" unless result.valid_pdf?

  response = validate_document(doc_path: document)
  raise InvalidDocumentError, "Invalid Document: #{response}" unless response.success?

  document
end

#validate_document(doc_path:) ⇒ Object

Validate a file satisfies Benefits Intake specifications. File must be a PDF.

Parameters:

  • doc_path (String)


40
41
42
43
44
45
# File 'lib/benefits_intake_service/service.rb', line 40

def validate_document(doc_path:)
  # TODO: allow headers: to be passed to function if/when other file types are allowed
  headers = { 'Content-Type': 'application/pdf' }
  request_body = File.read(doc_path, mode: 'rb')
  perform :post, 'uploads/validate_document', request_body, headers
end