Class: BBInternal::Client

Inherits:
Common::Client::Base show all
Includes:
Common::Client::Concerns::MHVSessionBasedClient, Common::Client::Concerns::StreamingClient
Defined in:
lib/medical_records/bb_internal/client.rb

Overview

Core class responsible for MHV internal Blue Button API interface operations

Constant Summary

Constants included from Common::Client::Concerns::MhvLockedSessionClient

Common::Client::Concerns::MhvLockedSessionClient::LOCK_RETRY_DELAY, Common::Client::Concerns::MhvLockedSessionClient::RETRY_ATTEMPTS

Instance Attribute Summary

Attributes included from Common::Client::Concerns::MHVSessionBasedClient

#session

Attributes included from Common::Client::Concerns::MhvLockedSessionClient

#session

Instance Method Summary collapse

Methods included from Common::Client::Concerns::StreamingClient

#streaming_get

Methods included from Common::Client::Concerns::MHVSessionBasedClient

#auth_headers, #invalid?, #token_headers, #user_key

Methods included from SentryLogging

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

Methods included from Common::Client::Concerns::MhvLockedSessionClient

#authenticate, #initialize, #invalid?, #lock_and_get_session, #obtain_redis_lock, #refresh_session, #release_redis_lock

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

Instance Method Details

#bb_redisObject (private)



282
283
284
285
# File 'lib/medical_records/bb_internal/client.rb', line 282

def bb_redis
  namespace = REDIS_CONFIG[:bb_internal_store][:namespace]
  Redis::Namespace.new(namespace, redis: $redis)
end

#get_bbmi_notification_settingHash

Retrieves the BBMI notification setting for the user.

Returns:

  • (Hash)

    containing:

    • flag [Boolean]: Indicates whether the BBMI notification setting is enabled (true) or disabled (false)



40
41
42
43
# File 'lib/medical_records/bb_internal/client.rb', line 40

def get_bbmi_notification_setting
  response = perform(:get, 'usermgmt/notification/bbmi', nil, token_headers)
  response.body
end

#get_demographic_infoHash

Retrieves the patient demographic information

Returns:

  • (Hash)

    A hash containing the patient’s demographic information



264
265
266
267
# File 'lib/medical_records/bb_internal/client.rb', line 264

def get_demographic_info
  response = perform(:get, 'bluebutton/external/phrdemographic', nil, token_headers)
  response.body
end

#get_dicom(study_id, header_callback, yielder) ⇒ void

This method returns an undefined value.

Pass-through to get a binary stream of a DICOM zip file. This file can be very large.

body via the provided yielder.

Parameters:

  • study_id (String)
    • The radiology study from which to retrieve images



157
158
159
160
# File 'lib/medical_records/bb_internal/client.rb', line 157

def get_dicom(study_id, header_callback, yielder)
  uri = URI.join(config.base_path, "bluebutton/studyjob/zip/stream/#{session.patient_id}/studyidUrn/#{study_id}")
  streaming_get(uri, token_headers, header_callback, yielder)
end

#get_download_ccd(date) ⇒ Object

Returns - Continuity of Care Document in XML format.

Parameters:

  • date
    • receieved from get_generate_ccd call property dateGenerated (e.g. 2024-10-18T09:55:58.000-0400)

Returns:

    • Continuity of Care Document in XML format



176
177
178
179
180
181
# File 'lib/medical_records/bb_internal/client.rb', line 176

def get_download_ccd(date)
  modified_headers = token_headers.dup
  modified_headers['Accept'] = 'application/xml'
  response = perform(:get, "bluebutton/healthsummary/#{date}/fileFormat/XML/ccdType/XML", nil, modified_headers)
  response.body
end

#get_generate_ccd(icn, last_name) ⇒ Object

Parameters:

  • icn
    • user icn

  • last_name
    • user last name



167
168
169
170
# File 'lib/medical_records/bb_internal/client.rb', line 167

def get_generate_ccd(icn, last_name)
  response = perform(:get, "bluebutton/healthsummary/#{icn}/#{last_name}/xml", nil, token_headers)
  response.body
end

#get_image(study_id, series, image, header_callback, yielder) ⇒ void

This method returns an undefined value.

Pass-through to get a binary stream of a radiology image JPG file.

body via the provided yielder.

Parameters:

  • study_id (String)
    • The radiology study from which to retrieve images

  • series (String)
    • The series number, e.g. “01”

  • image (String)
    • The image number, e.g. “01”

  • yielder (Enumerator::Yielder)
    • An enumerator yielder used to yield chunks of the response body.



143
144
145
146
147
# File 'lib/medical_records/bb_internal/client.rb', line 143

def get_image(study_id, series, image, header_callback, yielder)
  uri = URI.join(config.base_path,
                 "bluebutton/external/studyjob/image/studyidUrn/#{study_id}/series/#{series}/image/#{image}")
  streaming_get(uri, token_headers, header_callback, yielder)
end

#get_patientHash

Retrieves the patient information by user ID.

Returns:

  • (Hash)

    A hash containing the patient’s details

Raises:



27
28
29
30
31
32
33
34
# File 'lib/medical_records/bb_internal/client.rb', line 27

def get_patient
  response = perform(:get, "usermgmt/patient/uid/#{@session.user_id}", nil, token_headers)
  patient = response.body

  raise Common::Exceptions::ServiceError.new(detail: 'Patient not found') if patient.blank?

  patient
end

#get_sei_activity_journalObject



251
252
253
254
# File 'lib/medical_records/bb_internal/client.rb', line 251

def get_sei_activity_journal
  response = perform(:get, "journal/activityjournals/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sei_allergiesObject



201
202
203
204
# File 'lib/medical_records/bb_internal/client.rb', line 201

def get_sei_allergies
  response = perform(:get, "healthhistory/allergy/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sei_family_health_historyObject



206
207
208
209
# File 'lib/medical_records/bb_internal/client.rb', line 206

def get_sei_family_health_history
  response = perform(:get, "healthhistory/healthHistory/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sei_food_journalObject



246
247
248
249
# File 'lib/medical_records/bb_internal/client.rb', line 246

def get_sei_food_journal
  response = perform(:get, "journal/journals/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sei_health_insuranceObject



236
237
238
239
# File 'lib/medical_records/bb_internal/client.rb', line 236

def get_sei_health_insurance
  response = perform(:get, "getcare/healthInsurance/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sei_healthcare_providersObject



231
232
233
234
# File 'lib/medical_records/bb_internal/client.rb', line 231

def get_sei_healthcare_providers
  response = perform(:get, "getcare/healthCareProvider/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sei_immunizationsObject



211
212
213
214
# File 'lib/medical_records/bb_internal/client.rb', line 211

def get_sei_immunizations
  response = perform(:get, "healthhistory/immunization/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sei_medical_eventsObject



221
222
223
224
# File 'lib/medical_records/bb_internal/client.rb', line 221

def get_sei_medical_events
  response = perform(:get, "healthhistory/medicalEvent/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sei_medicationsObject



256
257
258
259
# File 'lib/medical_records/bb_internal/client.rb', line 256

def get_sei_medications
  response = perform(:get, "pharmacy/medications/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sei_military_historyObject



226
227
228
229
# File 'lib/medical_records/bb_internal/client.rb', line 226

def get_sei_military_history
  response = perform(:get, "healthhistory/militaryHistory/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sei_test_entriesObject



216
217
218
219
# File 'lib/medical_records/bb_internal/client.rb', line 216

def get_sei_test_entries
  response = perform(:get, "healthhistory/testEntry/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sei_treatment_facilitiesObject



241
242
243
244
# File 'lib/medical_records/bb_internal/client.rb', line 241

def get_sei_treatment_facilities
  response = perform(:get, "getcare/treatmentFacility/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sei_vital_signs_summaryObject

Self-Entered Information (SEI) APIs



196
197
198
199
# File 'lib/medical_records/bb_internal/client.rb', line 196

def get_sei_vital_signs_summary
  response = perform(:get, "vitals/summary/#{@session.user_id}", nil, token_headers)
  response.body
end

#get_sessionObject (private)

Overriding MHVSessionBasedClient’s method so we can get the patientId and store it as well.



309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/medical_records/bb_internal/client.rb', line 309

def get_session
  # Pull ICN out of the session var before it is overwritten in the super's save
  icn = session.icn

  # Call MHVSessionBasedClient.get_session
  @session = super

  # Supplement session with patientId
  patient = get_patient
  session.patient_id = patient['ipas']&.first&.dig('patientId')
  # Put ICN back into the session
  session.icn = icn

  session.save
  session
end

#get_session_taggedObject (private)

Overriding MHVSessionBasedClient’s method, because we need more control over the path.



329
330
331
# File 'lib/medical_records/bb_internal/client.rb', line 329

def get_session_tagged
  perform(:get, 'usermgmt/auth/session', nil, auth_headers)
end

#get_study_data_from_cacheObject (private)



287
288
289
# File 'lib/medical_records/bb_internal/client.rb', line 287

def get_study_data_from_cache
  bb_redis.get(study_data_key)
end

#get_study_id_from_cache(id) ⇒ Object (private)



291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/medical_records/bb_internal/client.rb', line 291

def get_study_id_from_cache(id)
  study_data = get_study_data_from_cache

  if study_data
    study_data_hash = JSON.parse(study_data)
    id = id.to_s
    study_id = study_data_hash[id]

    study_id || raise(Common::Exceptions::RecordNotFound, id)
  else
    # throw 400 for FE to know to refetch the list
    raise Common::Exceptions::InvalidResource, 'Study data map'
  end
end

#get_study_statusArray

check the status of a study job

Returns:

  • (Array)
    • [{ status: “COMPLETE”, studyIdUrn: “111-1234567” percentComplete: 100, fileSize: “1.01 MB”,

    startDate: 1729777818853, endDate}]



187
188
189
190
# File 'lib/medical_records/bb_internal/client.rb', line 187

def get_study_status
  response = perform(:get, "bluebutton/studyjob/#{session.patient_id}", nil, token_headers)
  response.body
end

#list_images(id) ⇒ Hash

Get a list of images for the provided CVIX radiology study

Parameters:

  • id (String)
    • The uuid of the radiology study from which to retrieve images

Returns:

  • (Hash)

    The list of images from MHV



125
126
127
128
129
130
# File 'lib/medical_records/bb_internal/client.rb', line 125

def list_images(id)
  study_id = get_study_id_from_cache(id)
  response = perform(:get, "bluebutton/studyjob/zip/preview/list/#{session.patient_id}/studyidUrn/#{study_id}", nil,
                     token_headers)
  response.body
end

#list_imaging_studiesHash

Get a list of MHV radiology reports from CVIX for the current user. These results do not include VIA reports.

study_id is mapped to a new UUID and stored in Redis for later retrieval. This is to prevent the study_id from being exposed to the client. The client will use the UUID to request the study. UUID map is stored in Redis with a TTL of 3 days. On method call, if the studyId soe not exist in the map, a new UUID is generated and stored in the map. Otherwise, the existing UUID is used.

Returns:

  • (Hash)

    The radiology study list from MHV



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/medical_records/bb_internal/client.rb', line 73

def list_imaging_studies
  response = perform(:get, "bluebutton/study/#{session.patient_id}", nil, token_headers)
  data = response.body

  study_data_cached = get_study_data_from_cache
  study_data_hash = JSON.parse(study_data_cached) if study_data_cached
  id_uuid_map = study_data_hash || {}

  modified_data = data.map do |obj|
    study_id = obj['studyIdUrn']

    # Find the key by value in the hash
    existing_uuid, = study_data_hash.find { |_, v| v == study_id.to_s } if study_data_hash

    if existing_uuid
      obj['studyIdUrn'] = existing_uuid
    else
      new_uuid = SecureRandom.uuid
      id_uuid_map[new_uuid] = study_id
      obj['studyIdUrn'] = new_uuid
    end
    obj
  end

  bb_redis.set(study_data_key, id_uuid_map.to_json, nx: false, ex: 259_200)

  modified_data
end

#list_radiologyHash

Get a list of MHV radiology reports from VIA for the current user. These results do not include CVIX reports.

Returns:

  • (Hash)

    The radiology report list from MHV



55
56
57
58
# File 'lib/medical_records/bb_internal/client.rb', line 55

def list_radiology
  response = perform(:get, "bluebutton/radiology/phrList/#{session.patient_id}", nil, token_headers)
  response.body
end

#request_study(id) ⇒ Hash

Request that MHV download an imaging study from CVIX. This will initiate the transfer of the images into MHV for later retrieval from vets-api as DICOM or JPGs.

Parameters:

  • icn (String)
    • The patient’s ICN

  • id (String)
    • The uuid of the radiology study to request

Returns:

  • (Hash)

    The status of the image request, including percent complete



111
112
113
114
115
116
# File 'lib/medical_records/bb_internal/client.rb', line 111

def request_study(id)
  study_id = get_study_id_from_cache(id)
  response = perform(:get, "bluebutton/studyjob/#{session.patient_id}/icn/#{session.icn}/studyid/#{study_id}", nil,
                     token_headers)
  response.body
end

#session_config_keyObject (private)

Overriding this to ensure a unique namespace for the redis lock.



274
275
276
# File 'lib/medical_records/bb_internal/client.rb', line 274

def session_config_key
  :mhv_mr_bb_session_lock
end

#study_data_keyObject (private)



278
279
280
# File 'lib/medical_records/bb_internal/client.rb', line 278

def study_data_key
  "study_data-#{session.patient_id}"
end