From 048a7a39d9f6cb84f11aaea93c031919ed6f920b Mon Sep 17 00:00:00 2001 From: Mitch Saltykov Date: Wed, 23 Oct 2024 09:56:31 -0400 Subject: [PATCH 1/4] convert sentry logs to messages for ease of tracking --- .../concerns/form_attachment_create.rb | 24 ++++++++++++++++--- spec/concerns/form_attachment_create_spec.rb | 24 ++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/app/controllers/concerns/form_attachment_create.rb b/app/controllers/concerns/form_attachment_create.rb index 13b0c08c69e..484aff2fee5 100644 --- a/app/controllers/concerns/form_attachment_create.rb +++ b/app/controllers/concerns/form_attachment_create.rb @@ -41,21 +41,39 @@ def validate_file_upload_class! raise Common::Exceptions::InvalidFieldValue.new('file_data', filtered_params[:file_data].class.name) end rescue => e - log_exception_to_sentry(e, { context: 'FAC_validate', class: filtered_params[:file_data].class.name }) + log_message_to_sentry( + 'form attachment error 1', + :info, + phase: 'FAC_validate', + klass: filtered_params[:file_data].class.name, + exception: e.message + ) raise e end def save_attachment_to_cloud! form_attachment.set_file_data!(filtered_params[:file_data], filtered_params[:password]) rescue => e - log_exception_to_sentry(e, { context: 'FAC_cloud' }) + log_message_to_sentry( + 'form attachment error 2', + :info, + phase: 'FAC_cloud', + exception: e.message + ) raise e end def save_attachment_to_db! form_attachment.save! rescue => e - log_exception_to_sentry(e, { context: 'FAC_db', errors: form_attachment.errors }) + log_message_to_sentry( + 'form attachment error 3', + :info, + phase: 'FAC_db', + errors: form_attachment.errors, + exception: e.message + ) + raise e end diff --git a/spec/concerns/form_attachment_create_spec.rb b/spec/concerns/form_attachment_create_spec.rb index 499362f8c03..864381a8c31 100644 --- a/spec/concerns/form_attachment_create_spec.rb +++ b/spec/concerns/form_attachment_create_spec.rb @@ -79,7 +79,13 @@ def serializer_klass klass: 'String', debug_timestamp: anything ) - expect(@controller).to receive(:log_exception_to_sentry).twice + expect(@controller).to receive(:log_message_to_sentry).with( + 'form attachment error 1', + :info, + phase: 'FAC_validate', + klass: 'String', + exception: 'Invalid field value' + ) post(:create, params: { hca_attachment: { file_data: } }) end @@ -95,7 +101,12 @@ def serializer_klass klass: 'ActionDispatch::Http::UploadedFile', debug_timestamp: anything ) - expect(@controller).to receive(:log_exception_to_sentry).twice + expect(@controller).to receive(:log_message_to_sentry).with( + 'form attachment error 2', + :info, + phase: 'FAC_cloud', + exception: 'Unprocessable Entity' + ) form_attachment = double(HCAAttachment) expect(HCAAttachment).to receive(:new) { form_attachment } @@ -116,12 +127,19 @@ def serializer_klass klass: 'ActionDispatch::Http::UploadedFile', debug_timestamp: anything ) - expect(@controller).to receive(:log_exception_to_sentry) + expect(@controller).to receive(:log_message_to_sentry).with( + 'form attachment error 3', + :info, + phase: 'FAC_db', + errors: 'error text', + exception: 'Record invalid' + ) form_attachment = double(HCAAttachment) expect(HCAAttachment).to receive(:new) { form_attachment } expect(form_attachment).to receive(:set_file_data!) expect(form_attachment).to receive(:save!).and_raise(ActiveRecord::RecordInvalid) + expect(form_attachment).to receive(:errors).and_return('error text') post(:create, params: { hca_attachment: { file_data: } }) end From f401602f63122729f0f7f5062e91a2010c0481bf Mon Sep 17 00:00:00 2001 From: mattwrightva <107576133+mattwrightva@users.noreply.github.com> Date: Fri, 25 Oct 2024 08:53:36 -0600 Subject: [PATCH 2/4] Mhv 63375 ccd generate and download (#19059) * MHV-42363 Initial cut at radiology imaging * MHV-42363 More work on imaging * MHV-42363 Imaging work mostly complete * MHV-42363 Capture headers for DICOM * MHV-42363 Refactored controller * MHV-42363 Added spec tests for new client functions * MHV-42363 BBInternal now expects ICN * MHV-42363 Fixed header pass-through * MHV-42363 Fixed data for broken spec test * MHV-42363 Removed "new_episodes" * MHV-63375: generate and download ccd work done * MHV-63375: Shortened comment * MHV-63375: Added new routes and moved controller --------- Co-authored-by: Mike Moyer Co-authored-by: Mike Moyer <87040148+mmoyer-va@users.noreply.github.com> Co-authored-by: Matthew Wright --- lib/medical_records/bb_internal/client.rb | 20 + .../v1/medical_records/ccd_controller.rb | 24 + modules/my_health/config/routes.rb | 6 + .../bb_internal/client_spec.rb | 30 ++ .../mr_client/bb_internal/download_ccd.yml | 411 ++++++++++++++++++ .../mr_client/bb_internal/generate_ccd.yml | 36 ++ 6 files changed, 527 insertions(+) create mode 100644 modules/my_health/app/controllers/my_health/v1/medical_records/ccd_controller.rb create mode 100644 spec/support/vcr_cassettes/mr_client/bb_internal/download_ccd.yml create mode 100644 spec/support/vcr_cassettes/mr_client/bb_internal/generate_ccd.yml diff --git a/lib/medical_records/bb_internal/client.rb b/lib/medical_records/bb_internal/client.rb index ca80ab2060e..95478a5490e 100644 --- a/lib/medical_records/bb_internal/client.rb +++ b/lib/medical_records/bb_internal/client.rb @@ -98,6 +98,26 @@ def get_dicom(study_id, header_callback, yielder) end ## + # @param icn - user icn + # @param last_name - user last name + # @return JSON [{ dateGenerated, status, patientId }] + # + def get_generate_ccd(icn, last_name) + response = perform(:get, "bluebutton/healthsummary/#{icn}/#{last_name}/xml", nil, token_headers) + response.body + end + + ## + # @param date - receieved from get_generate_ccd call property dateGenerated (e.g. 2024-10-18T09:55:58.000-0400) + # @return - Continuity of Care Document in XML format + # + def get_download_ccd(date) + token_headers['Accept'] = 'application/xml' + + response = perform(:get, "bluebutton/healthsummary/#{date}/fileFormat/XML/ccdType/XML", nil, token_headers) + response.body + end + # check the status of a study job # @return [Array] - [{ status: "COMPLETE", studyIdUrn: "111-1234567" percentComplete: 100, fileSize: "1.01 MB", # startDate: 1729777818853, endDate}] diff --git a/modules/my_health/app/controllers/my_health/v1/medical_records/ccd_controller.rb b/modules/my_health/app/controllers/my_health/v1/medical_records/ccd_controller.rb new file mode 100644 index 00000000000..94edee21206 --- /dev/null +++ b/modules/my_health/app/controllers/my_health/v1/medical_records/ccd_controller.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module MyHealth + module V1 + module MedicalRecords + class CcdController < MrController + # Generates a CCD + # @return [Array] of objects with CCDs generated date and status (COMPLETE or not) + def generate + resource = bb_client.get_generate_ccd(@current_user.icn, @current_user.last_name) + render json: resource.to_json + end + + # Downloads the CCD once it has been generated + # @param generated_datetime [String] date receieved from get_generate_ccd call property dateGenerated + # @return [XML] Continuity of Care Document + def download + resource = bb_client.get_download_ccd(generated_datetime) + send_data resource, type: 'application/xml' + end + end + end + end +end diff --git a/modules/my_health/config/routes.rb b/modules/my_health/config/routes.rb index 74c9fa004e4..7f83bb5bc49 100644 --- a/modules/my_health/config/routes.rb +++ b/modules/my_health/config/routes.rb @@ -17,6 +17,12 @@ resources :session, only: %i[create], controller: 'mr_session', defaults: { format: :json } do get :status, on: :collection end + resources :ccd, only: [] do + collection do + get :generate, to: 'ccd#generate' + get :download, to: 'ccd#download' + end + end resources :imaging, only: %i[index], defaults: { format: :json } do get 'request', on: :member, action: :request_download get :status, on: :collection, action: :request_status diff --git a/spec/lib/medical_records/bb_internal/client_spec.rb b/spec/lib/medical_records/bb_internal/client_spec.rb index 0b69fcefad7..d5329777510 100644 --- a/spec/lib/medical_records/bb_internal/client_spec.rb +++ b/spec/lib/medical_records/bb_internal/client_spec.rb @@ -88,6 +88,36 @@ end end + describe '#get_generate_ccd' do + it 'requests a CCD be generated and returns the correct structure' do + VCR.use_cassette 'mr_client/bb_internal/generate_ccd' do + ccd_list = client.get_generate_ccd(client.session.icn, 'DOE') + + expect(ccd_list).to be_an(Array) + expect(ccd_list).not_to be_empty + + first_ccd = ccd_list.first + expect(first_ccd).to be_a(Hash) + expect(first_ccd).to have_key('dateGenerated') + expect(first_ccd['dateGenerated']).to be_a(String) + + expect(first_ccd).to have_key('status') + expect(first_ccd['status']).to be_a(String) + end + end + end + + describe '#get_download_ccd' do + it 'retrieves a previously generated CCD as XML' do + VCR.use_cassette 'mr_client/bb_internal/download_ccd' do + ccd = client.get_download_ccd('2024-10-23T12:42:48.000-0400') + + expect(ccd).to be_a(String) + expect(ccd).to include('/mhvapi/v1/bluebutton/healthsummary/2024-10-23T12:42:48.000-0400/fileFormat/XML/ccdType/XML" + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/xml + Content-Type: + - application/json + User-Agent: + - Vets.gov Agent + Token: "" + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: '' + headers: + Date: + - Wed, 23 Oct 2024 20:20:59 GMT + Content-Type: + - text/xml + Content-Length: + - '32663' + Expires: + - "-1" + Cache-Control: + - no-cache + Content-Disposition: + - attachment; filename=mhv_VA_CCD_IPOACEVEDA_20241023_1242.xml + Strict-Transport-Security: + - max-age=16000000; includeSubDomains; preload; + body: + encoding: UTF-8 + string: "\n\nVA Continuity of Care Document (CCD)4002 + Crutchfield StRichmondVA23225-4755IPOACEVEDADEWAYNEDEANMMarriedNazareneDeclined to AnswerNot Hispanic or LatinoDepartment of + Veterans Affairs (VA)Department + of Veterans Affairs (VA)810 + Vermont Avenue NWWashingtonDC20420USPrimary Care ProviderWVDIXSON, + JESSIPOTEST 1
Insurance Providers: All on record + at VANo Data Provided for This Section
Advance Directives: All on record + at VANo Data Provided + for This Section
Allergies and Adverse Reactions (ADRs): + All on record at VANo Data + Provided for This Section
Encounters: + Outpatient Encounters with NotesNo Data Provided for This Section
Functional Status: Functional Independence + Measurement (FIM) ScoresNo Data Provided for This Section
Medications: VA Dispensed and Non-VA Documented + (Obtained Outside VA)No + Data Provided for This Section
Immunizations: All on record at VANo Data Provided + for This Section
Procedures: + Surgical Procedures with NotesNo + Data Provided for This Section
Plan of + Treatment: Future Appointments and Active/Pending OrdersNo Data + Provided for This Section
Problems (Conditions): All on record at VANo Data Provided for This Section
Results: Chemistry and HematologyNo Data Provided + for This Section
Social History: All on record at VANo + Data Provided for This Section
Vital Signs\n The + included list of inpatient and outpatient Vital Signs is from the last 12 + months and includes a maximum of the 5 most recent sets of vital sign values. + If more than one set of vitals was taken on the same date, only the most recent + set is populated for that date. The data comes from all VA treatment facilities. + Vital Sign information from the new VA electronic health record is not included.\n\t\t\t\t\t\t\t\t\t\t\t
Date/TimeTemperaturePulseBlood + PressureRespiratory RateSP02PainHeightWeightBody + Mass IndexSource
Aug 29, 2024 12:57 + PM99 77 22 CHEYENNE VAMC
Vital + Sign Observation Text Not Available
TEMPERATUREPULSERESPIRATION
Consult NotesConsult + Notes\n The + included Consult Notes are from the last 18 months, are available thirty-six + (36) hours after completion, and include a maximum of the 5 most recent notes. + The data comes from all VA treatment facilities. Note that Compensation & + Pension Notes are available 30 days after completion. Consult Notes (including + Compensation and Pension exam notes) from the new VA electronic health record + are not included.\n\t\t\t\t\t\t\t\t\t\t
Date/TimeConsult + Note with TextProviderSource
Aug 21, 2024 12:00 PMEDUCATION:
LOCAL TITLE: NUTRITION CLASS - SATP EDUCATION CONSULT REPORT
STANDARD + TITLE: NUTRITION EDUCATION NOTE
DATE OF NOTE: + AUG 21, 2024@12:00 ENTRY DATE: AUG 21, 2024@14:38:20
AUTHOR: + GOODMAN,KEOLA EXP COSIGNER:
URGENCY: + \ STATUS: COMPLETED

VistA Imaging - Scanned Document


*** + SCANNED DOCUMENT ***
SIGNATURE NOT REQUIRED


Electronically Filed: 08/21/2024
by: + KEOLA GOODMAN




GOODMAN,KEOLACHEYENNE + VAMC
History and Physical + NotesNo Data Provided for This Section
Discharge + SummariesNo Data Provided for This Section
Radiology + ReportsNo Data Provided for This Section
Pathology + ReportsNo Data Provided for This Section
Clinical + Procedure NotesNo Data Provided for This Section
\n" + recorded_at: Wed, 23 Oct 2024 20:20:59 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/support/vcr_cassettes/mr_client/bb_internal/generate_ccd.yml b/spec/support/vcr_cassettes/mr_client/bb_internal/generate_ccd.yml new file mode 100644 index 00000000000..96bb7c54d51 --- /dev/null +++ b/spec/support/vcr_cassettes/mr_client/bb_internal/generate_ccd.yml @@ -0,0 +1,36 @@ +--- +http_interactions: +- request: + method: get + uri: "/mhvapi/v1/bluebutton/healthsummary/1012740022V620959/DOE/xml" + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Vets.gov Agent + Token: "" + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: '' + headers: + Date: + - Wed, 23 Oct 2024 20:04:00 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Strict-Transport-Security: + - max-age=16000000; includeSubDomains; preload; + body: + encoding: UTF-8 + string: '[{"dateGenerated":"2024-10-23T12:42:48.000-0400","status":"COMPLETE","patientId":"1012740022V620959"},{"dateGenerated":"2024-10-22T15:10:37.000-0400","status":"COMPLETE","patientId":"1012740022V620959"}]' + recorded_at: Wed, 23 Oct 2024 20:04:00 GMT +recorded_with: VCR 6.3.1 From e2e4a758f52142b3dbd4b540df0bf537626d0a31 Mon Sep 17 00:00:00 2001 From: Rebecca Tolmach <10993987+rmtolmach@users.noreply.github.com> Date: Fri, 25 Oct 2024 11:05:36 -0400 Subject: [PATCH 3/4] Fix code scanning alert no. 859: Deserialization of user-controlled data (#19080) Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- modules/check_in/app/services/travel_claim/service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/check_in/app/services/travel_claim/service.rb b/modules/check_in/app/services/travel_claim/service.rb index 7fa01e25333..963ea007f9b 100644 --- a/modules/check_in/app/services/travel_claim/service.rb +++ b/modules/check_in/app/services/travel_claim/service.rb @@ -49,7 +49,7 @@ def token resp = client.token - Oj.load(resp.body)&.fetch('access_token').tap do |access_token| + Oj.safe_load(resp.body)&.fetch('access_token').tap do |access_token| redis_client.save_token(token: access_token) end end From ab8262972fe4de27829bc23f80ad07a5636a1dfd Mon Sep 17 00:00:00 2001 From: Eric Boehs Date: Fri, 25 Oct 2024 10:11:37 -0500 Subject: [PATCH 4/4] chore: Bump Code Checks to 32 core (#19089) --- .github/workflows/code_checks.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/code_checks.yml b/.github/workflows/code_checks.yml index 2c333da3b67..bce18493148 100644 --- a/.github/workflows/code_checks.yml +++ b/.github/workflows/code_checks.yml @@ -13,7 +13,7 @@ jobs: env: BUNDLE_ENTERPRISE__CONTRIBSYS__COM: ${{ secrets.BUNDLE_ENTERPRISE__CONTRIBSYS__COM }} permissions: write-all - runs-on: ubuntu-16-cores-latest + runs-on: ubuntu-32-cores-latest steps: - uses: actions/checkout@v4 @@ -63,7 +63,7 @@ jobs: DOCKER_BUILDKIT: 1 COMPOSE_DOCKER_CLI_BUILD: 1 permissions: write-all - runs-on: ubuntu-16-cores-latest + runs-on: ubuntu-32-cores-latest steps: - uses: actions/checkout@v4 @@ -131,13 +131,13 @@ jobs: max_attempts: 3 command: | docker compose -f docker-compose.test.yml run web bash \ - -c "CI=true RAILS_ENV=test DISABLE_BOOTSNAP=true bundle exec parallel_test -n 13 -e 'bin/rails db:reset'" + -c "CI=true RAILS_ENV=test DISABLE_BOOTSNAP=true bundle exec parallel_test -n 24 -e 'bin/rails db:reset'" - name: Run Specs timeout-minutes: 20 run: | docker compose -f docker-compose.test.yml run web bash \ - -c "CI=true DISABLE_BOOTSNAP=true bundle exec parallel_rspec spec/ modules/ -n 13 -o '--color --tty'" + -c "CI=true DISABLE_BOOTSNAP=true bundle exec parallel_rspec spec/ modules/ -n 24 -o '--color --tty'" - name: Upload Coverage Report uses: actions/upload-artifact@v4