diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f9481452e5f..8da827ed0ea 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -290,6 +290,7 @@ app/models/rate_limited_search.rb @department-of-veterans-affairs/va-api-enginee app/models/saml_request_tracker.rb @department-of-veterans-affairs/octo-identity app/models/saved_claim.rb @department-of-veterans-affairs/Benefits-Team-1 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/session.rb @department-of-veterans-affairs/octo-identity +app/models/saved_claim/burial.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pensions @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/saved_claim/pension.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group app/models/saved_claim/veteran_readiness_employment_claim.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/sign_in @department-of-veterans-affairs/octo-identity diff --git a/Gemfile.lock b/Gemfile.lock index 79d6edfca13..c2f6771ab7f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -73,10 +73,10 @@ GIT GIT remote: https://github.com/department-of-veterans-affairs/vets-json-schema - revision: 7892dc348677325cc57712ff4a12d6a78f024315 + revision: 0277d5bcddf48894d22b45f3618bca33e82a8ca4 branch: master specs: - vets_json_schema (21.5.5) + vets_json_schema (22.0.1) multi_json (~> 1.0) script_utils (= 0.0.4) @@ -890,7 +890,7 @@ GEM rswag-ui (2.13.0) actionpack (>= 3.1, < 7.2) railties (>= 3.1, < 7.2) - rubocop (1.62.1) + rubocop (1.63.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -1283,4 +1283,3 @@ RUBY VERSION BUNDLED WITH 2.4.9 - diff --git a/app/models/saved_claim/burial.rb b/app/models/saved_claim/burial.rb index 5bf7b4b7de8..fd9b1f858f2 100644 --- a/app/models/saved_claim/burial.rb +++ b/app/models/saved_claim/burial.rb @@ -32,7 +32,7 @@ def regional_office end def attachment_keys - %i[transportationReceipts deathCertificate].freeze + %i[transportationReceipts deathCertificate militarySeparationDocuments additionalEvidence].freeze end def email diff --git a/app/policies/mhv_messaging_policy.rb b/app/policies/mhv_messaging_policy.rb index 9e6d1a72d79..d1e8d83266c 100644 --- a/app/policies/mhv_messaging_policy.rb +++ b/app/policies/mhv_messaging_policy.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'sm/client' + MHVMessagingPolicy = Struct.new(:user, :mhv_messaging) do def access? return false unless user.mhv_correlation_id diff --git a/app/services/users/services.rb b/app/services/users/services.rb index 11b0ec35049..c07a5a0f36a 100644 --- a/app/services/users/services.rb +++ b/app/services/users/services.rb @@ -18,7 +18,7 @@ def initialize(user) # def authorizations @list << BackendServices::RX if user.authorize :mhv_prescriptions, :access? - @list << BackendServices::MESSAGING if user.authorize :legacy_mhv_messaging, :access? + @list << BackendServices::MESSAGING if user.authorize messaging_service, :access? @list << BackendServices::MEDICAL_RECORDS if user.authorize :mhv_medical_records, :access? @list << BackendServices::HEALTH_RECORDS if user.authorize :mhv_health_records, :access? @list << BackendServices::EVSS_CLAIMS if user.authorize :evss, :access? @@ -30,6 +30,7 @@ def authorizations @list << BackendServices::ID_CARD if user.can_access_id_card? @list << BackendServices::IDENTITY_PROOFED if user.loa3? @list << BackendServices::VET360 if user.can_access_vet360? + @list end @@ -44,5 +45,9 @@ def auth_free_services BackendServices::FORM_PREFILL ] end + + def messaging_service + Flipper.enabled?(:mhv_sm_session_policy, user) ? :mhv_messaging : :legacy_mhv_messaging + end end end diff --git a/app/sidekiq/lighthouse/submit_benefits_intake_claim.rb b/app/sidekiq/lighthouse/submit_benefits_intake_claim.rb index ff98683f62d..34553145270 100644 --- a/app/sidekiq/lighthouse/submit_benefits_intake_claim.rb +++ b/app/sidekiq/lighthouse/submit_benefits_intake_claim.rb @@ -77,13 +77,13 @@ def generate_metadata 'veteranFirstName' => veteran_full_name['first'], 'veteranLastName' => veteran_full_name['last'], 'fileNumber' => form['vaFileNumber'] || form['veteranSocialSecurityNumber'], - 'zipCode' => address['country'] == 'USA' ? address['postalCode'] : FOREIGN_POSTALCODE, + 'zipCode' => address['postalCode'], 'source' => "#{@claim.class} va.gov", 'docType' => @claim.form_id, 'businessLine' => @claim.business_line } - SimpleFormsApiSubmission::MetadataValidator.validate(metadata) + SimpleFormsApiSubmission::MetadataValidator.validate(metadata, zip_code_is_us_based: check_zipcode(address)) end # rubocop:disable Metrics/MethodLength @@ -149,5 +149,9 @@ def cleanup_file_paths Common::FileHelpers.delete_file_if_exists(@pdf_path) if @pdf_path @attachment_paths&.each { |p| Common::FileHelpers.delete_file_if_exists(p) } end + + def check_zipcode(address) + address['country'].upcase.in?(%w[USA US]) + end end end diff --git a/app/swagger/swagger/schemas/contacts.rb b/app/swagger/swagger/schemas/contacts.rb index d19585b9085..e6a01bf6276 100644 --- a/app/swagger/swagger/schemas/contacts.rb +++ b/app/swagger/swagger/schemas/contacts.rb @@ -10,7 +10,7 @@ class Contacts key :required, [:data] property :data, type: :array do items do - property :id, type: :string, example: 'dbbf9a58-41e5-40c0-bdb5-fc1407aa1f05' + property :id, type: :string property :type, type: :string property :attributes do key :$ref, :Contact @@ -21,7 +21,11 @@ class Contacts swagger_schema :Contact do key :required, %i[contact_type given_name family_name primary_phone] - property :contact_type, type: :string, enum: VAProfile::Models::AssociatedPerson::CONTACT_TYPES + property( + :contact_type, + type: :string, + enum: VAProfile::Models::AssociatedPerson::PERSONAL_HEALTH_CARE_CONTACT_TYPES + ) property :given_name, type: %i[string null] property :family_name, type: %i[string null] property :relationship, type: %i[string null] diff --git a/config/features.yml b/config/features.yml index bf37c613b8c..186c377c035 100644 --- a/config/features.yml +++ b/config/features.yml @@ -664,6 +664,10 @@ features: actor_type: user description: Enables/disables Secure Messaging Cerner Transition Pilot environment on VA.gov enable_in_development: true + mhv_sm_session_policy: + actor_type: user + description: changes secure messaging policy to use sm sessions endpoint for authorization + enable_in_development: true mhv_medical_records_allow_txt_downloads: actor_type: user description: Allows users to download Medical Records data in TXT format diff --git a/lib/lighthouse/benefits_claims/service.rb b/lib/lighthouse/benefits_claims/service.rb index 3e4313cf0e1..46f200a43ea 100644 --- a/lib/lighthouse/benefits_claims/service.rb +++ b/lib/lighthouse/benefits_claims/service.rb @@ -38,6 +38,14 @@ def get_claim(id, lighthouse_client_id = nil, lighthouse_rsa_key_path = nil, opt raise BenefitsClaims::ServiceException.new(e.response), 'Lighthouse Error' end + def get_power_of_attorney(lighthouse_client_id = nil, lighthouse_rsa_key_path = nil, options = {}) + config.get("#{@icn}/power-of-attorney", lighthouse_client_id, lighthouse_rsa_key_path, options).body + rescue Faraday::TimeoutError + raise BenefitsClaims::ServiceException.new({ status: 504 }), 'Lighthouse Error' + rescue Faraday::ClientError, Faraday::ServerError => e + raise BenefitsClaims::ServiceException.new(e.response), 'Lighthouse Error' + end + def submit5103(user, id, options = {}) params = {} is_dependent = SponsorResolver.dependent?(user) diff --git a/lib/va_profile/models/associated_person.rb b/lib/va_profile/models/associated_person.rb index 9f9f72c25bc..c100e0e1d33 100644 --- a/lib/va_profile/models/associated_person.rb +++ b/lib/va_profile/models/associated_person.rb @@ -10,19 +10,27 @@ class AssociatedPerson < Base OTHER_EMERGENCY_CONTACT = 'Other emergency contact' PRIMARY_NEXT_OF_KIN = 'Primary Next of Kin' OTHER_NEXT_OF_KIN = 'Other Next of Kin' + DESIGNEE = 'Designee' + POWER_OF_ATTORNEY = 'Power of Attorney' - CONTACT_TYPES = [ + PERSONAL_HEALTH_CARE_CONTACT_TYPES = [ EMERGENCY_CONTACT, OTHER_EMERGENCY_CONTACT, PRIMARY_NEXT_OF_KIN, OTHER_NEXT_OF_KIN ].freeze + CONTACT_TYPES = [ + *PERSONAL_HEALTH_CARE_CONTACT_TYPES, + DESIGNEE, + POWER_OF_ATTORNEY + ].freeze + attribute :contact_type, String attribute :given_name, Common::TitlecaseString attribute :middle_name, Common::TitlecaseString attribute :family_name, Common::TitlecaseString - attribute :relationship, Common::TitlecaseString + attribute :relationship, String attribute :address_line1, String attribute :address_line2, String attribute :address_line3, String diff --git a/lib/va_profile/profile/v3/health_benefit_bio_response.rb b/lib/va_profile/profile/v3/health_benefit_bio_response.rb index 1dde3fb9f89..1b333021400 100644 --- a/lib/va_profile/profile/v3/health_benefit_bio_response.rb +++ b/lib/va_profile/profile/v3/health_benefit_bio_response.rb @@ -8,33 +8,39 @@ module VAProfile module Profile module V3 class HealthBenefitBioResponse < VAProfile::Response - attr_reader :body - attribute :contacts, Array[VAProfile::Models::AssociatedPerson] attribute :messages, Array[VAProfile::Models::Message] + attribute :va_profile_tx_audit_id, String def initialize(response) - @body = response.body + body = response.body contacts = body.dig('profile', 'health_benefit', 'associated_persons') &.select { |p| valid_contact_types.include?(p['contact_type']) } &.sort_by { |p| valid_contact_types.index(p['contact_type']) } messages = body['messages'] - super(response.status, { contacts:, messages: }) + va_profile_tx_audit_id = response.response_headers['vaprofiletxauditid'] + super(response.status, { contacts:, messages:, va_profile_tx_audit_id: }) end - def metadata - { status:, messages: } + def debug_data + { + status:, + message:, + va_profile_tx_audit_id: + } end private def valid_contact_types - [ - VAProfile::Models::AssociatedPerson::EMERGENCY_CONTACT, - VAProfile::Models::AssociatedPerson::OTHER_EMERGENCY_CONTACT, - VAProfile::Models::AssociatedPerson::PRIMARY_NEXT_OF_KIN, - VAProfile::Models::AssociatedPerson::OTHER_NEXT_OF_KIN - ] + VAProfile::Models::AssociatedPerson::PERSONAL_HEALTH_CARE_CONTACT_TYPES + end + + def message + m = messages&.first + return '' unless m + + "#{m.code} #{m.key} #{m.text}" end end end diff --git a/lib/va_profile/profile/v3/service.rb b/lib/va_profile/profile/v3/service.rb index 8c26e61e49f..8b06ccc5f59 100644 --- a/lib/va_profile/profile/v3/service.rb +++ b/lib/va_profile/profile/v3/service.rb @@ -26,8 +26,10 @@ def initialize(user) def get_health_benefit_bio oid = MPI::Constants::VA_ROOT_OID path = "#{oid}/#{ERB::Util.url_encode(icn_with_aaid)}" - response = perform(:post, path, { bios: [{ bioPath: 'healthBenefit' }] }) - VAProfile::Profile::V3::HealthBenefitBioResponse.new(response) + service_response = perform(:post, path, { bios: [{ bioPath: 'healthBenefit' }] }) + response = VAProfile::Profile::V3::HealthBenefitBioResponse.new(service_response) + Sentry.set_extras(response.debug_data) unless response.ok? + response end def get_military_info diff --git a/modules/claims_api/app/sidekiq/claims_api/v2/poa_form_builder_job.rb b/modules/claims_api/app/sidekiq/claims_api/v2/poa_form_builder_job.rb index 4564b5b154b..2c0c25e9aa0 100644 --- a/modules/claims_api/app/sidekiq/claims_api/v2/poa_form_builder_job.rb +++ b/modules/claims_api/app/sidekiq/claims_api/v2/poa_form_builder_job.rb @@ -45,15 +45,8 @@ def pdf_constructor(form_number) # # @return [Hash] All data to be inserted into pdf def data(power_of_attorney, form_number, rep) - res = power_of_attorney - .form_data.deep_merge({ - 'veteran' => { - 'firstName' => power_of_attorney.auth_headers['va_eauth_firstName'], - 'lastName' => power_of_attorney.auth_headers['va_eauth_lastName'], - 'ssn' => power_of_attorney.auth_headers['va_eauth_pnid'], - 'birthdate' => power_of_attorney.auth_headers['va_eauth_birthdate'] - } - }) + res = power_of_attorney.form_data + res.deep_merge!(veteran_attributes(power_of_attorney)) signatures = if form_number == '2122A' individual_signatures(power_of_attorney, rep) @@ -65,10 +58,24 @@ def data(power_of_attorney, form_number, rep) 'firstName' => rep.first_name, 'lastName' => rep.last_name } }) + + res.deep_merge!(organization_name(power_of_attorney)) if form_number == '2122' + res.merge!({ 'text_signatures' => signatures }) res end + def veteran_attributes(power_of_attorney) + { + 'veteran' => { + 'firstName' => power_of_attorney.auth_headers['va_eauth_firstName'], + 'lastName' => power_of_attorney.auth_headers['va_eauth_lastName'], + 'ssn' => power_of_attorney.auth_headers['va_eauth_pnid'], + 'birthdate' => power_of_attorney.auth_headers['va_eauth_birthdate'] + } + } + end + def organization_signatures(power_of_attorney, rep) first_name, last_name = veteran_or_claimant_signature(power_of_attorney) { @@ -89,11 +96,11 @@ def organization_signatures(power_of_attorney, rep) end def individual_signatures(power_of_attorney, rep) + first_name, last_name = veteran_or_claimant_signature(power_of_attorney) { 'page2' => [ { - 'signature' => "#{power_of_attorney.auth_headers['va_eauth_firstName']} " \ - "#{power_of_attorney.auth_headers['va_eauth_lastName']} - signed via api.va.gov", + 'signature' => "#{first_name} #{last_name} - signed via api.va.gov", 'x' => 35, 'y' => 306 }, @@ -117,6 +124,18 @@ def veteran_or_claimant_signature(power_of_attorney) end [first_name, last_name] end + + def organization_name(power_of_attorney) + poa_code = power_of_attorney.form_data.dig('serviceOrganization', 'poaCode') + + name = ::Veteran::Service::Organization.find_by(poa: poa_code).name + + { + 'serviceOrganization' => { + 'organizationName' => name + } + } + end end end end diff --git a/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json b/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json index 6e76306fc95..dcc849f41f8 100644 --- a/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json +++ b/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json @@ -9198,11 +9198,6 @@ "example": "6789" } } - }, - "organizationName": { - "description": "Name of the service organization.", - "type": "string", - "example": "I help vets LLC." } } }, @@ -9832,11 +9827,6 @@ "type": "string", "example": "A1Q" }, - "organizationName": { - "description": "Name of the service organization.", - "type": "string", - "example": "I help vets LLC." - }, "registrationNumber": { "description": "Registration Number of representative.", "type": "string", @@ -10526,11 +10516,6 @@ "example": "6789" } } - }, - "organizationName": { - "description": "Name of the service organization.", - "type": "string", - "example": "I help vets LLC." } } }, @@ -11151,11 +11136,6 @@ "type": "string", "example": "A1Q" }, - "organizationName": { - "description": "Name of the service organization.", - "type": "string", - "example": "I help vets LLC." - }, "registrationNumber": { "description": "Registration Number of representative.", "type": "string", diff --git a/modules/claims_api/app/swagger/claims_api/v2/production/swagger.json b/modules/claims_api/app/swagger/claims_api/v2/production/swagger.json index 5095d8c17b5..0d7a7c009b1 100644 --- a/modules/claims_api/app/swagger/claims_api/v2/production/swagger.json +++ b/modules/claims_api/app/swagger/claims_api/v2/production/swagger.json @@ -9198,11 +9198,6 @@ "example": "6789" } } - }, - "organizationName": { - "description": "Name of the service organization.", - "type": "string", - "example": "I help vets LLC." } } }, @@ -9832,11 +9827,6 @@ "type": "string", "example": "A1Q" }, - "organizationName": { - "description": "Name of the service organization.", - "type": "string", - "example": "I help vets LLC." - }, "registrationNumber": { "description": "Registration Number of representative.", "type": "string", @@ -10526,11 +10516,6 @@ "example": "6789" } } - }, - "organizationName": { - "description": "Name of the service organization.", - "type": "string", - "example": "I help vets LLC." } } }, @@ -11151,11 +11136,6 @@ "type": "string", "example": "A1Q" }, - "organizationName": { - "description": "Name of the service organization.", - "type": "string", - "example": "I help vets LLC." - }, "registrationNumber": { "description": "Registration Number of representative.", "type": "string", diff --git a/modules/claims_api/config/schemas/v2/2122.json b/modules/claims_api/config/schemas/v2/2122.json index 258542e2b93..9ecceb725a2 100644 --- a/modules/claims_api/config/schemas/v2/2122.json +++ b/modules/claims_api/config/schemas/v2/2122.json @@ -219,11 +219,6 @@ "type": "string", "example": "A1Q" }, - "organizationName": { - "description": "Name of the service organization.", - "type": "string", - "example": "I help vets LLC." - }, "registrationNumber": { "description": "Registration Number of representative.", "type": "string", diff --git a/modules/claims_api/config/schemas/v2/2122a.json b/modules/claims_api/config/schemas/v2/2122a.json index 02cfe95b1a9..aae8b1469a4 100644 --- a/modules/claims_api/config/schemas/v2/2122a.json +++ b/modules/claims_api/config/schemas/v2/2122a.json @@ -288,11 +288,6 @@ "example": "6789" } } - }, - "organizationName": { - "description": "Name of the service organization.", - "type": "string", - "example": "I help vets LLC." } } }, diff --git a/modules/claims_api/spec/fixtures/21-22/v2/signed_filled_final.pdf b/modules/claims_api/spec/fixtures/21-22/v2/signed_filled_final.pdf index a7802967ec2..ee31a770503 100644 Binary files a/modules/claims_api/spec/fixtures/21-22/v2/signed_filled_final.pdf and b/modules/claims_api/spec/fixtures/21-22/v2/signed_filled_final.pdf differ diff --git a/modules/claims_api/spec/fixtures/21-22A/v2/signed_filled_final.pdf b/modules/claims_api/spec/fixtures/21-22A/v2/signed_filled_final.pdf index 859dd3cc56f..0f6615ce398 100644 Binary files a/modules/claims_api/spec/fixtures/21-22A/v2/signed_filled_final.pdf and b/modules/claims_api/spec/fixtures/21-22A/v2/signed_filled_final.pdf differ diff --git a/modules/claims_api/spec/fixtures/21-22A/v2/signed_filled_final_other_service_branch.pdf b/modules/claims_api/spec/fixtures/21-22A/v2/signed_filled_final_other_service_branch.pdf new file mode 100644 index 00000000000..166c29d891f Binary files /dev/null and b/modules/claims_api/spec/fixtures/21-22A/v2/signed_filled_final_other_service_branch.pdf differ diff --git a/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/individual_spec.rb b/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/individual_spec.rb index 0c906d3defa..aafa7a5aae3 100644 --- a/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/individual_spec.rb +++ b/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/individual_spec.rb @@ -47,9 +47,8 @@ }, representative: { poaCode: 'A1Q', + registrationNumber: '1234', type: 'ATTORNEY', - firstName: 'Bob', - lastName: 'Law', address: { addressLine1: '2719 Hyperion Ave', city: 'Los Angeles', @@ -68,7 +67,8 @@ other_service_branch_temp.form_data = { veteran: { serviceNumber: '987654321', - otherServiceBranch: 'Air National Guard', + serviceBranch: 'OTHER', + serviceBranchOther: 'Air National Guard', address: { addressLine1: '2719 Hyperion Ave', city: 'Los Angeles', @@ -103,8 +103,7 @@ representative: { poaCode: 'A1Q', type: 'ATTORNEY', - firstName: 'Bob', - lastName: 'Law', + registrationNumber: '1234', address: { addressLine1: '2719 Hyperion Ave', city: 'Los Angeles', @@ -138,8 +137,7 @@ 'text_signatures' => { 'page2' => [ { - 'signature' => "#{power_of_attorney.auth_headers['va_eauth_firstName']} " \ - "#{power_of_attorney.auth_headers['va_eauth_lastName']} - signed via api.va.gov", + 'signature' => 'Lillian Disney - signed via api.va.gov', 'x' => 35, 'y' => 306 }, @@ -149,6 +147,10 @@ 'y' => 200 } ] + }, + 'representative' => { + 'firstName' => 'Bob', + 'lastName' => 'Law' } } ) @@ -173,8 +175,7 @@ 'text_signatures' => { 'page2' => [ { - 'signature' => "#{power_of_attorney.auth_headers['va_eauth_firstName']} " \ - "#{power_of_attorney.auth_headers['va_eauth_lastName']} - signed via api.va.gov", + 'signature' => 'Lillian Disney - signed via api.va.gov', 'x' => 35, 'y' => 306 }, @@ -184,13 +185,17 @@ 'y' => 200 } ] + }, + 'representative' => { + 'firstName' => 'Bob', + 'lastName' => 'Law' } } ) constructor = ClaimsApi::V2::PoaPdfConstructor::Individual.new expected_pdf = Rails.root.join('modules', 'claims_api', 'spec', 'fixtures', '21-22A', 'v2', - 'signed_filled_final.pdf') + 'signed_filled_final_other_service_branch.pdf') generated_pdf = constructor.construct(data, id: power_of_attorney.id) expect(generated_pdf).to match_pdf_content_of(expected_pdf) end diff --git a/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/organization_spec.rb b/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/organization_spec.rb index 9007da1d420..1a4b7f60b7d 100644 --- a/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/organization_spec.rb +++ b/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/organization_spec.rb @@ -46,9 +46,7 @@ }, serviceOrganization: { poaCode: '456', - firstName: 'Bob', - lastName: 'Representative', - organizationName: 'I Help Vets LLC', + registrationNumber: '1234', address: { addressLine1: '2719 Hyperion Ave', city: 'Los Angeles', @@ -83,8 +81,7 @@ 'text_signatures' => { 'page2' => [ { - 'signature' => "#{power_of_attorney.auth_headers['va_eauth_firstName']} " \ - "#{power_of_attorney.auth_headers['va_eauth_lastName']} - signed via api.va.gov", + 'signature' => 'Lillian Disney - signed via api.va.gov', 'x' => 35, 'y' => 240 }, @@ -94,7 +91,13 @@ 'y' => 200 } ] - } + }, + 'serviceOrganization' => + { + 'firstName' => 'Bob', + 'lastName' => 'Representative', + 'organizationName' => 'I Help Vets LLC' + } } ) diff --git a/modules/claims_api/spec/sidekiq/v2/poa_form_builder_job_spec.rb b/modules/claims_api/spec/sidekiq/v2/poa_form_builder_job_spec.rb index 5e2bee573bb..29d84f0475e 100644 --- a/modules/claims_api/spec/sidekiq/v2/poa_form_builder_job_spec.rb +++ b/modules/claims_api/spec/sidekiq/v2/poa_form_builder_job_spec.rb @@ -8,7 +8,10 @@ let(:power_of_attorney) { create(:power_of_attorney, :with_full_headers) } let(:poa_code) { 'ABC' } - let(:rep) { create(:representative, first_name: 'Bob', last_name: 'Representative') } + let(:rep) do + create(:representative, representative_id: '1234', poa_codes: [poa_code], first_name: 'Bob', + last_name: 'Representative') + end before do Sidekiq::Job.clear_all @@ -23,45 +26,27 @@ consentLimits: %w[DRUG_ABUSE SICKLE_CELL], veteran: { address: { - numberAndStreet: '2719 Hyperion Ave', + addressLine1: '2719 Hyperion Ave', city: 'Los Angeles', - state: 'CA', + stateCode: 'CA', country: 'US', - zipFirstFive: '92264' + zipCode: '92264' }, phone: { areaCode: '555', phoneNumber: '5551337' } }, - claimant: { - claimantId: '1012830872V584140', - email: 'lillian@disney.com', - relationship: 'Spouse', - address: { - numberAndStreet: '2688 S Camino Real', - city: 'Palm Springs', - state: 'CA', - country: 'US', - zipFirstFive: '92264' - }, - phone: { - areaCode: '555', - phoneNumber: '5551337' - }, - firstName: 'JESSE', - lastName: 'GRAY' - }, representative: { poaCode: poa_code.to_s, + registrationNumber: '1234', type: 'ATTORNEY', - organizationName: 'I Help Vets LLC', address: { - numberAndStreet: '2719 Hyperion Ave', + addressLine1: '2719 Hyperion Ave', city: 'Los Angeles', - state: 'CA', + stateCode: 'CA', country: 'US', - zipFirstFive: '92264' + zipCode: '92264' } } } @@ -139,15 +124,15 @@ power_of_attorney.form_data = { recordConsent: true, consentAddressChange: true, - consentLimits: ['DRUG ABUSE', 'SICKLE CELL'], + consentLimits: %w[DRUG_ABUSE SICKLE_CELL], veteran: { serviceBranch: 'ARMY', address: { - numberAndStreet: '2719 Hyperion Ave', + addressLine1: '2719 Hyperion Ave', city: 'Los Angeles', - state: 'CA', + stateCode: 'CA', country: 'US', - zipFirstFive: '92264' + zipCode: '92264' }, phone: { areaCode: '555', @@ -159,11 +144,11 @@ email: 'lillian@disney.com', relationship: 'Spouse', address: { - numberAndStreet: '2688 S Camino Real', + addressLine1: '2688 S Camino Real', city: 'Palm Springs', - state: 'CA', + stateCode: 'CA', country: 'US', - zipFirstFive: '92264' + zipCode: '92264' }, phone: { areaCode: '555', @@ -174,16 +159,16 @@ }, representative: { poaCode: poa_code.to_s, + registrationNumber: '1234', type: 'SERVICE ORGANIZATION REPRESENTATIVE', firstName: 'Bob', lastName: 'Representative', - organizationName: 'I Help Vets LLC', address: { - numberAndStreet: '2719 Hyperion Ave', + addressLine1: '2719 Hyperion Ave', city: 'Los Angeles', - state: 'CA', + stateCode: 'CA', country: 'US', - zipFirstFive: '92264' + zipCode: '92264' } } } @@ -209,7 +194,7 @@ 'text_signatures' => { 'page2' => [ { - 'signature' => 'JESSE GRAY - signed via api.va.gov', + 'signature' => 'Mitchell Jenkins - signed via api.va.gov', 'x' => 35, 'y' => 306 }, @@ -239,6 +224,8 @@ end context '2122 veteran claimant' do + let!(:org) { create(:organization, name: 'I Help Vets LLC', poa: poa_code) } + before do power_of_attorney.form_data = { recordConsent: true, @@ -246,45 +233,26 @@ consentLimits: %w[DRUG_ABUSE SICKLE_CELL], veteran: { address: { - numberAndStreet: '2719 Hyperion Ave', + addressLine1: '2719 Hyperion Ave', city: 'Los Angeles', - state: 'CA', + stateCode: 'CA', country: 'US', - zipFirstFive: '92264' + zipCode: '92264' }, phone: { areaCode: '555', phoneNumber: '5551337' } }, - claimant: { - email: 'lillian@disney.com', - relationship: 'Spouse', - address: { - numberAndStreet: '2688 S Camino Real', - city: 'Palm Springs', - state: 'CA', - country: 'US', - zipFirstFive: '92264' - }, - phone: { - areaCode: '555', - phoneNumber: '5551337' - }, - firstName: 'JESSE', - lastName: 'GRAY' - }, serviceOrganization: { poaCode: poa_code.to_s, - firstName: 'Bob', - lastName: 'Representative', - organizationName: 'I Help Vets LLC', + registrationNumber: '1234', address: { - numberAndStreet: '2719 Hyperion Ave', + addressLine1: '2719 Hyperion Ave', city: 'Los Angeles', - state: 'CA', + stateCode: 'CA', country: 'US', - zipFirstFive: '92264' + zipCode: '92264' } } } @@ -320,7 +288,11 @@ } ] }, - 'serviceOrganization' => { 'firstName' => 'Bob', 'lastName' => 'Representative' } + 'serviceOrganization' => { + 'firstName' => 'Bob', + 'lastName' => 'Representative', + 'organizationName' => 'I Help Vets LLC' + } } ) @@ -354,18 +326,20 @@ end context '2122 non-veteran claimant' do + let!(:org) { create(:organization, name: 'I Help Vets LLC', poa: poa_code) } + before do power_of_attorney.form_data = { recordConsent: true, consentAddressChange: true, - consentLimits: ['DRUG ABUSE', 'SICKLE CELL'], + consentLimits: %w[DRUG_ABUSE SICKLE_CELL], veteran: { address: { - numberAndStreet: '2719 Hyperion Ave', + addressLine1: '2719 Hyperion Ave', city: 'Los Angeles', - state: 'CA', + stateCode: 'CA', country: 'US', - zipFirstFive: '92264' + zipCode: '92264' }, phone: { areaCode: '555', @@ -377,11 +351,11 @@ email: 'lillian@disney.com', relationship: 'Spouse', address: { - numberAndStreet: '2688 S Camino Real', + addressLine1: '2688 S Camino Real', city: 'Palm Springs', - state: 'CA', + stateCode: 'CA', country: 'US', - zipFirstFive: '92264' + zipCode: '92264' }, phone: { areaCode: '555', @@ -392,15 +366,13 @@ }, serviceOrganization: { poaCode: poa_code.to_s, - firstName: 'Bob', - lastName: 'Representative', - organizationName: 'I Help Vets LLC', + registrationNumber: '1234', address: { - numberAndStreet: '2719 Hyperion Ave', + addressLine1: '2719 Hyperion Ave', city: 'Los Angeles', - state: 'CA', + stateCode: 'CA', country: 'US', - zipFirstFive: '92264' + zipCode: '92264' } } } @@ -436,7 +408,11 @@ } ] }, - 'serviceOrganization' => { 'firstName' => 'Bob', 'lastName' => 'Representative' } + 'serviceOrganization' => { + 'firstName' => 'Bob', + 'lastName' => 'Representative', + 'organizationName' => 'I Help Vets LLC' + } } ) diff --git a/modules/meb_api/lib/dgi/forms/service/submission_service.rb b/modules/meb_api/lib/dgi/forms/service/submission_service.rb index 0f369b477b3..8adae906f53 100644 --- a/modules/meb_api/lib/dgi/forms/service/submission_service.rb +++ b/modules/meb_api/lib/dgi/forms/service/submission_service.rb @@ -53,9 +53,9 @@ def update_dd_params(params, dd_params) params[:form][:direct_deposit][:direct_deposit_account_number] = dd_params[:dposit_acnt_nbr] params[:form][:direct_deposit][:direct_deposit_routing_number] = dd_params[:routng_trnsit_nbr] elsif check_masking && Flipper.enabled?(:toe_light_house_dgi_direct_deposit, @current_user) - params[:form][:direct_deposit][:account_number] = + params[:form][:direct_deposit][:direct_deposit_account_number] = dd_params&.payment_account ? dd_params.payment_account[:account_number] : nil - params[:form][:direct_deposit][:routing_number] = + params[:form][:direct_deposit][:direct_deposit_routing_number] = dd_params&.payment_account ? dd_params.payment_account[:routing_number] : nil end params diff --git a/modules/meb_api/lib/dgi/submission/service.rb b/modules/meb_api/lib/dgi/submission/service.rb index 26c001c5a22..85b91d8482c 100644 --- a/modules/meb_api/lib/dgi/submission/service.rb +++ b/modules/meb_api/lib/dgi/submission/service.rb @@ -54,9 +54,9 @@ def update_dd_params(params, dd_params) check_masking = account_number&.include?('*') if check_masking && Flipper.enabled?(:show_dgi_direct_deposit_1990EZ, @current_user) - params[:direct_deposit][:account_number] = + params[:direct_deposit][:direct_deposit_account_number] = dd_params&.payment_account ? dd_params.payment_account[:account_number] : nil - params[:direct_deposit][:routing_number] = + params[:direct_deposit][:direct_deposit_routing_number] = dd_params&.payment_account ? dd_params.payment_account[:routing_number] : nil end diff --git a/modules/my_health/app/controllers/my_health/sm_controller.rb b/modules/my_health/app/controllers/my_health/sm_controller.rb index b98917299e4..1c2bcc9721e 100644 --- a/modules/my_health/app/controllers/my_health/sm_controller.rb +++ b/modules/my_health/app/controllers/my_health/sm_controller.rb @@ -15,7 +15,17 @@ def client end def authorize - raise_access_denied unless current_user.authorize(:legacy_mhv_messaging, :access?) + raise_access_denied unless mhv_messaging_authorized? + end + + def mhv_messaging_authorized? + if Flipper.enabled?(:mhv_sm_session_policy, current_user) + Rails.logger.info('SMController Using new SM session policy') + current_user.authorize(:mhv_messaging, :access?) + else + Rails.logger.info('SMController Using Legacy SM session policy') + current_user.authorize(:legacy_mhv_messaging, :access?) + end end def raise_access_denied diff --git a/modules/my_health/spec/request/v1/all_triage_teams_request_spec.rb b/modules/my_health/spec/request/v1/all_triage_teams_request_spec.rb index 2312df7f711..c1b870553d1 100644 --- a/modules/my_health/spec/request/v1/all_triage_teams_request_spec.rb +++ b/modules/my_health/spec/request/v1/all_triage_teams_request_spec.rb @@ -9,54 +9,106 @@ include SchemaMatchers let(:va_patient) { true } + let(:mhv_account_type) { 'Premium' } let(:current_user) { build(:user, :mhv, va_patient:, mhv_account_type:) } before do - allow(SM::Client).to receive(:new).and_return(authenticated_client) sign_in_as(current_user) end - context 'Basic User' do - let(:mhv_account_type) { 'Basic' } + context 'when sm session policy is enabled' do + before do + Flipper.enable(:mhv_sm_session_policy) + Timecop.freeze(Time.zone.parse('2017-05-01T19:25:00Z')) + end - before { get '/my_health/v1/messaging/allrecipients' } + after do + Flipper.disable(:mhv_sm_session_policy) + Timecop.return + end - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + context 'when NOT authorized' do + before do + VCR.insert_cassette('sm_client/session_error') + get '/my_health/v1/messaging/allrecipients' + end - context 'Premium User' do - let(:mhv_account_type) { 'Premium' } + after do + VCR.eject_cassette + end - context 'not a va patient' do - before { get '/my_health/v1/messaging/allrecipients' } + include_examples 'for user account level', message: 'You do not have access to messaging' + end - let(:va_patient) { false } - let(:current_user) do - build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) + context 'when authorized' do + before do + VCR.insert_cassette('sm_client/session') end - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + after do + VCR.eject_cassette + end - it 'responds to GET #index' do - VCR.use_cassette('sm_client/triage_teams/gets_a_collection_of_all_triage_team_recipients') do - get '/my_health/v1/messaging/allrecipients' + it 'responds to GET #index' do + VCR.use_cassette('sm_client/triage_teams/gets_a_collection_of_all_triage_team_recipients') do + get '/my_health/v1/messaging/allrecipients' + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_response_schema('all_triage_teams') end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_response_schema('all_triage_teams') + it 'responds to GET #index when camel-inflected' do + VCR.use_cassette('sm_client/triage_teams/gets_a_collection_of_all_triage_team_recipients') do + get '/my_health/v1/messaging/allrecipients', headers: { 'X-Key-Inflection' => 'camel' } + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_camelized_response_schema('all_triage_teams') + end end + end + + context 'when legacy sm policy' do + before do + Flipper.disable(:mhv_sm_session_policy) + allow(SM::Client).to receive(:new).and_return(authenticated_client) + end + + context 'Basic User' do + let(:mhv_account_type) { 'Basic' } + + before { get '/my_health/v1/messaging/allrecipients' } + + include_examples 'for user account level', message: 'You do not have access to messaging' + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' + end + + context 'Premium User' do + let(:mhv_account_type) { 'Premium' } + + context 'not a va patient' do + before { get '/my_health/v1/messaging/allrecipients' } - it 'responds to GET #index when camel-inflected' do - VCR.use_cassette('sm_client/triage_teams/gets_a_collection_of_all_triage_team_recipients') do - get '/my_health/v1/messaging/allrecipients', headers: { 'X-Key-Inflection' => 'camel' } + let(:va_patient) { false } + let(:current_user) do + build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) + end + + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_camelized_response_schema('all_triage_teams') + it 'responds to GET #index' do + VCR.use_cassette('sm_client/triage_teams/gets_a_collection_of_all_triage_team_recipients') do + get '/my_health/v1/messaging/allrecipients' + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_response_schema('all_triage_teams') + end end end end diff --git a/modules/my_health/spec/request/v1/attachments_request_spec.rb b/modules/my_health/spec/request/v1/attachments_request_spec.rb index 75cefcbc488..89b551f2a97 100644 --- a/modules/my_health/spec/request/v1/attachments_request_spec.rb +++ b/modules/my_health/spec/request/v1/attachments_request_spec.rb @@ -7,61 +7,109 @@ RSpec.describe 'Message Attachments Integration', type: :request do include SM::ClientHelpers + let(:mhv_account_type) { 'Premium' } let(:va_patient) { true } let(:current_user) { build(:user, :mhv, va_patient:, mhv_account_type:) } - let(:user_id) { '10616687' } let(:inbox_id) { 0 } let(:message_id) { 573_302 } before do - allow(SM::Client).to receive(:new).and_return(authenticated_client) sign_in_as(current_user) end - context 'Basic User' do - let(:mhv_account_type) { 'Basic' } + context 'when sm session policy is enabled' do + before do + Flipper.enable(:mhv_sm_session_policy) + Timecop.freeze(Time.zone.parse('2017-05-01T19:25:00Z')) + end - before { get '/my_health/v1/messaging/messages/629999/attachments/629993' } + after do + Flipper.disable(:mhv_sm_session_policy) + Timecop.return + end - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + context 'when NOT authorized' do + before do + VCR.insert_cassette('sm_client/session_error') + get '/my_health/v1/messaging/messages/629999/attachments/629993' + end - context 'Advanced User' do - let(:mhv_account_type) { 'Advanced' } + after do + VCR.eject_cassette + end - before { get '/my_health/v1/messaging/messages/629999/attachments/629993' } + include_examples 'for user account level', message: 'You do not have access to messaging' + end - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' + context 'when authorized' do + before do + VCR.insert_cassette('sm_client/session') + get '/my_health/v1/messaging/messages/629999/attachments/629993' + end + + after do + VCR.eject_cassette + end + + describe '#show' do + it 'responds sending data for an attachment' do + VCR.use_cassette('sm_client/messages/nested_resources/gets_a_single_attachment_by_id') do + get '/my_health/v1/messaging/messages/629999/attachments/629993' + end + + expect(response).to be_successful + expect(response.headers['Content-Disposition']) + .to eq("attachment; filename=\"noise300x200.png\"; filename*=UTF-8''noise300x200.png") + expect(response.headers['Content-Transfer-Encoding']).to eq('binary') + expect(response.headers['Content-Type']).to eq('image/png') + expect(response.body).to be_a(String) + end + end + end end - context 'Premium User' do - let(:mhv_account_type) { 'Premium' } + context 'when legacy sm policy' do + before do + Flipper.disable(:mhv_sm_session_policy) + allow(SM::Client).to receive(:new).and_return(authenticated_client) + end + + context 'Basic User' do + let(:mhv_account_type) { 'Basic' } - context 'not a va patient' do before { get '/my_health/v1/messaging/messages/629999/attachments/629993' } - let(:va_patient) { false } - let(:current_user) do - build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) - end - + include_examples 'for user account level', message: 'You do not have access to messaging' include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' end - describe '#show' do - it 'responds sending data for an attachment' do - VCR.use_cassette('sm_client/messages/nested_resources/gets_a_single_attachment_by_id') do - get '/my_health/v1/messaging/messages/629999/attachments/629993' + context 'Premium User' do + let(:mhv_account_type) { 'Premium' } + + context 'not a va patient' do + before { get '/my_health/v1/messaging/messages/629999/attachments/629993' } + + let(:va_patient) { false } + let(:current_user) do + build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) end - expect(response).to be_successful - expect(response.headers['Content-Disposition']) - .to eq("attachment; filename=\"noise300x200.png\"; filename*=UTF-8''noise300x200.png") - expect(response.headers['Content-Transfer-Encoding']).to eq('binary') - expect(response.headers['Content-Type']).to eq('image/png') - expect(response.body).to be_a(String) + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' + end + + describe '#show' do + it 'responds sending data for an attachment' do + VCR.use_cassette('sm_client/messages/nested_resources/gets_a_single_attachment_by_id') do + get '/my_health/v1/messaging/messages/629999/attachments/629993' + end + + expect(response).to be_successful + expect(response.headers['Content-Disposition']) + .to eq("attachment; filename=\"noise300x200.png\"; filename*=UTF-8''noise300x200.png") + expect(response.headers['Content-Transfer-Encoding']).to eq('binary') + expect(response.headers['Content-Type']).to eq('image/png') + expect(response.body).to be_a(String) + end end end end diff --git a/modules/my_health/spec/request/v1/folders_request_spec.rb b/modules/my_health/spec/request/v1/folders_request_spec.rb index c366f5fc4f8..6acf0e80e4e 100644 --- a/modules/my_health/spec/request/v1/folders_request_spec.rb +++ b/modules/my_health/spec/request/v1/folders_request_spec.rb @@ -9,6 +9,7 @@ include SchemaMatchers let(:user_id) { '10616687' } + let(:mhv_account_type) { 'Premium' } let(:inbox_id) { 0 } let(:message_id) { 573_059 } let(:va_patient) { true } @@ -16,223 +17,277 @@ let(:inflection_header) { { 'X-Key-Inflection' => 'camel' } } before do - allow(SM::Client).to receive(:new).and_return(authenticated_client) sign_in_as(current_user) end - context 'Basic User' do - let(:mhv_account_type) { 'Basic' } - - before { get '/my_health/v1/messaging/folders' } - - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end - - context 'Advanced User' do - let(:mhv_account_type) { 'Advanced' } - - before { get '/my_health/v1/messaging/folders' } - - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + context 'when sm session policy is enabled' do + before do + Flipper.enable(:mhv_sm_session_policy) + Timecop.freeze(Time.zone.parse('2017-05-01T19:25:00Z')) + end - context 'Premium User' do - let(:mhv_account_type) { 'Premium' } + after do + Flipper.disable(:mhv_sm_session_policy) + Timecop.return + end - context 'not a va patient' do - before { get '/my_health/v1/messaging/folders' } + context 'when NOT authorized' do + before do + VCR.insert_cassette('sm_client/session_error') + get '/my_health/v1/messaging/folders' + end - let(:va_patient) { false } - let(:current_user) do - build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) + after do + VCR.eject_cassette end - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' + include_examples 'for user account level', message: 'You do not have access to messaging' end - describe '#index' do - it 'responds to GET #index' do - VCR.use_cassette('sm_client/folders/gets_a_collection_of_folders') do - get '/my_health/v1/messaging/folders' - end - - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_response_schema('folders') + context 'when authorized' do + before do + VCR.insert_cassette('sm_client/session') end - it 'responds to GET #index when camel-inflected' do - VCR.use_cassette('sm_client/folders/gets_a_collection_of_folders') do - get '/my_health/v1/messaging/folders', headers: inflection_header - end - - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_camelized_response_schema('folders') + after do + VCR.eject_cassette end - end - describe '#show' do - context 'with valid id' do - it 'response to GET #show' do - VCR.use_cassette('sm_client/folders/gets_a_single_folder') do - get "/my_health/v1/messaging/folders/#{inbox_id}" + describe '#index' do + it 'responds to GET #index' do + VCR.use_cassette('sm_client/folders/gets_a_collection_of_folders') do + get '/my_health/v1/messaging/folders' end expect(response).to be_successful expect(response.body).to be_a(String) - expect(response).to match_response_schema('folder') + expect(response).to match_response_schema('folders') end - it 'response to GET #show when camel-inflected' do - VCR.use_cassette('sm_client/folders/gets_a_single_folder') do - get "/my_health/v1/messaging/folders/#{inbox_id}", headers: inflection_header + it 'responds to GET #index when camel-inflected' do + VCR.use_cassette('sm_client/folders/gets_a_collection_of_folders') do + get '/my_health/v1/messaging/folders', headers: inflection_header end expect(response).to be_successful expect(response.body).to be_a(String) - expect(response).to match_camelized_response_schema('folder') + expect(response).to match_camelized_response_schema('folders') end end - end - describe '#create' do - context 'with valid name' do - let(:params) { { folder: { name: 'test folder create name 160805101218' } } } + describe '#show' do + context 'with valid id' do + it 'response to GET #show' do + VCR.use_cassette('sm_client/folders/gets_a_single_folder') do + get "/my_health/v1/messaging/folders/#{inbox_id}" + end - it 'response to POST #create' do - VCR.use_cassette('sm_client/folders/creates_a_folder_and_deletes_a_folder') do - post '/my_health/v1/messaging/folders', params: + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_response_schema('folder') end - expect(response).to be_successful - expect(response).to have_http_status(:created) - expect(response).to match_response_schema('folder') + it 'response to GET #show when camel-inflected' do + VCR.use_cassette('sm_client/folders/gets_a_single_folder') do + get "/my_health/v1/messaging/folders/#{inbox_id}", headers: inflection_header + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_camelized_response_schema('folder') + end end + end + + describe '#create' do + context 'with valid name' do + let(:params) { { folder: { name: 'test folder create name 160805101218' } } } + + it 'response to POST #create' do + VCR.use_cassette('sm_client/folders/creates_a_folder_and_deletes_a_folder') do + post '/my_health/v1/messaging/folders', params: + end - it 'response to POST #create with camel-inflection' do - VCR.use_cassette('sm_client/folders/creates_a_folder_and_deletes_a_folder') do - post '/my_health/v1/messaging/folders', params:, headers: inflection_header + expect(response).to be_successful + expect(response).to have_http_status(:created) + expect(response).to match_response_schema('folder') end - expect(response).to be_successful - expect(response).to have_http_status(:created) - expect(response).to match_camelized_response_schema('folder') + it 'response to POST #create with camel-inflection' do + VCR.use_cassette('sm_client/folders/creates_a_folder_and_deletes_a_folder') do + post '/my_health/v1/messaging/folders', params:, headers: inflection_header + end + + expect(response).to be_successful + expect(response).to have_http_status(:created) + expect(response).to match_camelized_response_schema('folder') + end end end - end - describe '#update' do - context 'with valid folder id' do - let(:id) { 7_207_029 } - let(:params) { { folder: { name: 'Test222' } } } + describe '#update' do + context 'with valid folder id' do + let(:id) { 7_207_029 } + let(:params) { { folder: { name: 'Test222' } } } - it 'responds to RENAME #update' do - VCR.use_cassette('sm_client/folders/renames_a_folder') do - put "/my_health/v1/messaging/folders/#{id}", params: - end + it 'responds to RENAME #update' do + VCR.use_cassette('sm_client/folders/renames_a_folder') do + put "/my_health/v1/messaging/folders/#{id}", params: + end - expect(response).to be_successful - expect(response).to have_http_status(:created) - expect(response).to match_response_schema('folder') + expect(response).to be_successful + expect(response).to have_http_status(:created) + expect(response).to match_response_schema('folder') + end end end - end - describe '#destroy' do - context 'with valid folder id' do - let(:id) { 674_886 } + describe '#destroy' do + context 'with valid folder id' do + let(:id) { 674_886 } - it 'responds to DELETE #destroy' do - VCR.use_cassette('sm_client/folders/creates_a_folder_and_deletes_a_folder') do - delete "/my_health/v1/messaging/folders/#{id}" + it 'responds to DELETE #destroy' do + VCR.use_cassette('sm_client/folders/creates_a_folder_and_deletes_a_folder') do + delete "/my_health/v1/messaging/folders/#{id}" + end + + expect(response).to be_successful + expect(response).to have_http_status(:no_content) end + end + end - expect(response).to be_successful - expect(response).to have_http_status(:no_content) + describe '#search' do + context 'with valid search criteria' do + let(:id) { 0 } + + it 'responds to POST #search' do + VCR.use_cassette('sm_client/folders/searches_a_folder') do + post "/my_health/v1/messaging/folders/#{id}/search", params: { subject: 'test' } + end + + expect(response).to be_successful + expect(response).to have_http_status(:ok) + expect(response).to match_response_schema('folder_search') + end end end - end - describe '#search' do - context 'with valid search criteria' do - let(:id) { 0 } + describe 'nested resources' do + it 'gets messages#index' do + VCR.use_cassette('sm_client/folders/nested_resources/gets_a_collection_of_messages') do + get "/my_health/v1/messaging/folders/#{inbox_id}/messages" + end + + expect(response).to be_successful + expect(response).to have_http_status(:ok) + expect(response).to match_response_schema('messages') + end - it 'responds to POST #search' do - VCR.use_cassette('sm_client/folders/searches_a_folder') do - post "/my_health/v1/messaging/folders/#{id}/search", params: { subject: 'test' } + it 'gets messages#index with camel-inflection' do + VCR.use_cassette('sm_client/folders/nested_resources/gets_a_collection_of_messages') do + get "/my_health/v1/messaging/folders/#{inbox_id}/messages", headers: inflection_header end expect(response).to be_successful expect(response).to have_http_status(:ok) - expect(response).to match_response_schema('folder_search') + expect(response).to match_camelized_response_schema('messages') end end - end - describe 'nested resources' do - it 'gets messages#index' do - VCR.use_cassette('sm_client/folders/nested_resources/gets_a_collection_of_messages') do - get "/my_health/v1/messaging/folders/#{inbox_id}/messages" + describe 'pagination' do + it 'provides pagination indicators' do + VCR.use_cassette('sm_client/folders/nested_resources/gets_a_collection_of_messages') do + get "/my_health/v1/messaging/folders/#{inbox_id}/messages" + end + + payload = JSON.parse(response.body) + pagination = payload['meta']['pagination'] + expect(pagination['total_entries']).to eq(10) end - expect(response).to be_successful - expect(response).to have_http_status(:ok) - expect(response).to match_response_schema('messages') - end + it 'respects pagination parameters' do + VCR.use_cassette('sm_client/folders/nested_resources/gets_a_collection_of_messages') do + get "/my_health/v1/messaging/folders/#{inbox_id}/messages", params: { page: 2, per_page: 3 } + end - it 'gets messages#index with camel-inflection' do - VCR.use_cassette('sm_client/folders/nested_resources/gets_a_collection_of_messages') do - get "/my_health/v1/messaging/folders/#{inbox_id}/messages", headers: inflection_header + payload = JSON.parse(response.body) + pagination = payload['meta']['pagination'] + expect(pagination['current_page']).to eq(2) + expect(pagination['per_page']).to eq(3) + expect(pagination['total_pages']).to eq(4) + expect(pagination['total_entries']).to eq(10) end - expect(response).to be_successful - expect(response).to have_http_status(:ok) - expect(response).to match_camelized_response_schema('messages') - end - end + it 'does not paginate if per_page pagination parameter is -1' do + VCR.use_cassette('sm_client/folders/nested_resources/gets_a_collection_of_messages') do + get "/my_health/v1/messaging/folders/#{inbox_id}/messages", params: { per_page: -1 } + end - describe 'pagination' do - it 'provides pagination indicators' do - VCR.use_cassette('sm_client/folders/nested_resources/gets_a_collection_of_messages') do - get "/my_health/v1/messaging/folders/#{inbox_id}/messages" + payload = JSON.parse(response.body) + pagination = payload['meta']['pagination'] + expect(pagination).to be_nil end - payload = JSON.parse(response.body) - pagination = payload['meta']['pagination'] - expect(pagination['total_entries']).to eq(10) + it 'generates a 4xx error for out of bounds pagination' do + VCR.use_cassette('sm_client/folders/nested_resources/gets_a_collection_of_messages') do + get "/my_health/v1/messaging/folders/#{inbox_id}/messages", params: { page: 3, per_page: 10 } + end + expect(response).to have_http_status(:bad_request) + end end + end + end - it 'respects pagination parameters' do - VCR.use_cassette('sm_client/folders/nested_resources/gets_a_collection_of_messages') do - get "/my_health/v1/messaging/folders/#{inbox_id}/messages", params: { page: 2, per_page: 3 } + context 'when legacy sm policy' do + before do + Flipper.disable(:mhv_sm_session_policy) + allow(SM::Client).to receive(:new).and_return(authenticated_client) + end + + context 'Basic User' do + let(:mhv_account_type) { 'Basic' } + + before { get '/my_health/v1/messaging/folders' } + + include_examples 'for user account level', message: 'You do not have access to messaging' + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' + end + + context 'Premium User' do + let(:mhv_account_type) { 'Premium' } + + context 'not a va patient' do + before { get '/my_health/v1/messaging/folders' } + + let(:va_patient) { false } + let(:current_user) do + build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) end - payload = JSON.parse(response.body) - pagination = payload['meta']['pagination'] - expect(pagination['current_page']).to eq(2) - expect(pagination['per_page']).to eq(3) - expect(pagination['total_pages']).to eq(4) - expect(pagination['total_entries']).to eq(10) + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' end - it 'does not paginate if per_page pagination parameter is -1' do - VCR.use_cassette('sm_client/folders/nested_resources/gets_a_collection_of_messages') do - get "/my_health/v1/messaging/folders/#{inbox_id}/messages", params: { per_page: -1 } + describe '#index' do + it 'responds to GET #index' do + VCR.use_cassette('sm_client/folders/gets_a_collection_of_folders') do + get '/my_health/v1/messaging/folders' + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_response_schema('folders') end - payload = JSON.parse(response.body) - pagination = payload['meta']['pagination'] - expect(pagination).to be_nil - end + it 'responds to GET #index when camel-inflected' do + VCR.use_cassette('sm_client/folders/gets_a_collection_of_folders') do + get '/my_health/v1/messaging/folders', headers: inflection_header + end - it 'generates a 4xx error for out of bounds pagination' do - VCR.use_cassette('sm_client/folders/nested_resources/gets_a_collection_of_messages') do - get "/my_health/v1/messaging/folders/#{inbox_id}/messages", params: { page: 3, per_page: 10 } + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_camelized_response_schema('folders') end - expect(response).to have_http_status(:bad_request) end end end diff --git a/modules/my_health/spec/request/v1/message_drafts_request_spec.rb b/modules/my_health/spec/request/v1/message_drafts_request_spec.rb index eddf0211a19..4c65e5aae45 100644 --- a/modules/my_health/spec/request/v1/message_drafts_request_spec.rb +++ b/modules/my_health/spec/request/v1/message_drafts_request_spec.rb @@ -13,120 +13,168 @@ let(:created_draft_reply_id) { 674_944 } let(:draft) { attributes_for(:message, body: 'Body 1', subject: 'Subject 1') } let(:params) { draft.slice(:category, :subject, :body, :recipient_id) } + let(:mhv_account_type) { 'Premium' } let(:va_patient) { true } let(:current_user) { build(:user, :mhv, va_patient:, mhv_account_type:) } let(:inflection_header) { { 'X-Key-Inflection' => 'camel' } } before do - allow(SM::Client).to receive(:new).and_return(authenticated_client) sign_in_as(current_user) end - context 'Basic User' do - let(:mhv_account_type) { 'Basic' } - - before { post '/my_health/v1/messaging/message_drafts', params: } - - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + context 'when sm session policy is enabled' do + before do + Flipper.enable(:mhv_sm_session_policy) + Timecop.freeze(Time.zone.parse('2017-05-01T19:25:00Z')) + end - context 'Advanced User' do - let(:mhv_account_type) { 'Advanced' } + after do + Flipper.disable(:mhv_sm_session_policy) + Timecop.return + end - before { post '/my_health/v1/messaging/message_drafts', params: } + context 'when NOT authorized' do + before do + VCR.insert_cassette('sm_client/session_error') + post '/my_health/v1/messaging/message_drafts', params: + end - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + after do + VCR.eject_cassette + end - context 'Premium User' do - let(:mhv_account_type) { 'Premium' } + include_examples 'for user account level', message: 'You do not have access to messaging' + end - context 'not a va patient' do - before { post '/my_health/v1/messaging/message_drafts', params: } + context 'when authorized' do + before do + VCR.insert_cassette('sm_client/session') + end - let(:va_patient) { false } - let(:current_user) do - build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) + after do + VCR.eject_cassette end - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + describe 'drafts' do + let(:params) { { message_draft: draft.slice(:category, :subject, :body, :recipient_id) } } - describe 'drafts' do - let(:params) { { message_draft: draft.slice(:category, :subject, :body, :recipient_id) } } + it 'responds to POST #create' do + VCR.use_cassette('sm_client/message_drafts/creates_a_draft') do + post '/my_health/v1/messaging/message_drafts', params: + end - it 'responds to POST #create' do - VCR.use_cassette('sm_client/message_drafts/creates_a_draft') do - post '/my_health/v1/messaging/message_drafts', params: + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_response_schema('message') + expect(response).to have_http_status(:created) end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_response_schema('message') - expect(response).to have_http_status(:created) - end + it 'responds to POST #create when camel-inflected' do + VCR.use_cassette('sm_client/message_drafts/creates_a_draft') do + post '/my_health/v1/messaging/message_drafts', params:, headers: inflection_header + end - it 'responds to POST #create when camel-inflected' do - VCR.use_cassette('sm_client/message_drafts/creates_a_draft') do - post '/my_health/v1/messaging/message_drafts', params:, headers: inflection_header + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_camelized_response_schema('message') + expect(response).to have_http_status(:created) end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_camelized_response_schema('message') - expect(response).to have_http_status(:created) + it 'responds to PUT #update' do + VCR.use_cassette('sm_client/message_drafts/updates_a_draft') do + params[:subject] = 'Updated Subject' + params[:id] = created_draft_id + + put "/my_health/v1/messaging/message_drafts/#{created_draft_id}", params: + end + + expect(response).to be_successful + expect(response).to have_http_status(:no_content) + end end - it 'responds to PUT #update' do - VCR.use_cassette('sm_client/message_drafts/updates_a_draft') do - params[:subject] = 'Updated Subject' - params[:id] = created_draft_id + describe 'reply drafts' do + let(:params) { { message_draft: draft.slice(:body) } } + + it 'responds to POST #create' do + VCR.use_cassette('sm_client/message_drafts/creates_a_draft_reply') do + post "/my_health/v1/messaging/message_drafts/#{reply_id}/replydraft", params: + end - put "/my_health/v1/messaging/message_drafts/#{created_draft_id}", params: + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_response_schema('message') + expect(response).to have_http_status(:created) end - expect(response).to be_successful - expect(response).to have_http_status(:no_content) + it 'responds to POST #create when camel-inflected' do + VCR.use_cassette('sm_client/message_drafts/creates_a_draft_reply') do + post "/my_health/v1/messaging/message_drafts/#{reply_id}/replydraft", params:, + headers: inflection_header + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_camelized_response_schema('message') + expect(response).to have_http_status(:created) + end + + it 'responds to PUT #update' do + VCR.use_cassette('sm_client/message_drafts/updates_a_draft_reply') do + params[:body] = 'Updated Body' + params[:id] = created_draft_reply_id + put "/my_health/v1/messaging/message_drafts/#{reply_id}/replydraft/#{created_draft_reply_id}", params: + end + + expect(response).to be_successful + expect(response).to have_http_status(:no_content) + end end end + end - describe 'reply drafts' do - let(:params) { { message_draft: draft.slice(:body) } } + context 'when legacy sm policy' do + before do + Flipper.disable(:mhv_sm_session_policy) + allow(SM::Client).to receive(:new).and_return(authenticated_client) + end - it 'responds to POST #create' do - VCR.use_cassette('sm_client/message_drafts/creates_a_draft_reply') do - post "/my_health/v1/messaging/message_drafts/#{reply_id}/replydraft", params: - end + context 'Basic User' do + let(:mhv_account_type) { 'Basic' } - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_response_schema('message') - expect(response).to have_http_status(:created) - end + before { post '/my_health/v1/messaging/message_drafts', params: } + + include_examples 'for user account level', message: 'You do not have access to messaging' + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' + end + + context 'Premium User' do + let(:mhv_account_type) { 'Premium' } - it 'responds to POST #create when camel-inflected' do - VCR.use_cassette('sm_client/message_drafts/creates_a_draft_reply') do - post "/my_health/v1/messaging/message_drafts/#{reply_id}/replydraft", params:, - headers: inflection_header + context 'not a va patient' do + before { post '/my_health/v1/messaging/message_drafts', params: } + + let(:va_patient) { false } + let(:current_user) do + build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_camelized_response_schema('message') - expect(response).to have_http_status(:created) + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' end - it 'responds to PUT #update' do - VCR.use_cassette('sm_client/message_drafts/updates_a_draft_reply') do - params[:body] = 'Updated Body' - params[:id] = created_draft_reply_id - put "/my_health/v1/messaging/message_drafts/#{reply_id}/replydraft/#{created_draft_reply_id}", params: - end + describe 'drafts' do + let(:params) { { message_draft: draft.slice(:category, :subject, :body, :recipient_id) } } - expect(response).to be_successful - expect(response).to have_http_status(:no_content) + it 'responds to POST #create' do + VCR.use_cassette('sm_client/message_drafts/creates_a_draft') do + post '/my_health/v1/messaging/message_drafts', params: + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_response_schema('message') + expect(response).to have_http_status(:created) + end end end end diff --git a/modules/my_health/spec/request/v1/messages_request_spec.rb b/modules/my_health/spec/request/v1/messages_request_spec.rb index 3e7546cb4aa..096d72df942 100644 --- a/modules/my_health/spec/request/v1/messages_request_spec.rb +++ b/modules/my_health/spec/request/v1/messages_request_spec.rb @@ -9,6 +9,7 @@ include SchemaMatchers let(:user_id) { '10616687' } + let(:mhv_account_type) { 'Premium' } let(:inbox_id) { 0 } let(:message_id) { 573_059 } let(:va_patient) { true } @@ -16,320 +17,369 @@ let(:inflection_header) { { 'X-Key-Inflection' => 'camel' } } before do - allow(SM::Client).to receive(:new).and_return(authenticated_client) sign_in_as(current_user) end - context 'Basic User' do - let(:mhv_account_type) { 'Basic' } - - before { get '/my_health/v1/messaging/messages/categories' } - - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + context 'when sm session policy is enabled' do + before do + Flipper.enable(:mhv_sm_session_policy) + Timecop.freeze(Time.zone.parse('2017-05-01T19:25:00Z')) + end - context 'Advanced User' do - let(:mhv_account_type) { 'Advanced' } + after do + Flipper.disable(:mhv_sm_session_policy) + Timecop.return + end - before { get '/my_health/v1/messaging/messages/categories' } + context 'when NOT authorized' do + before do + VCR.insert_cassette('sm_client/session_error') + get "/my_health/v1/messaging/messages/#{message_id}" + end - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + after do + VCR.eject_cassette + end - context 'Premium User' do - let(:mhv_account_type) { 'Premium' } + include_examples 'for user account level', message: 'You do not have access to messaging' + end - context 'not a va patient' do - before { get '/my_health/v1/messaging/messages/categories' } + context 'when authorized' do + before do + VCR.insert_cassette('sm_client/session') + end - let(:va_patient) { false } - let(:current_user) do - build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) + after do + VCR.eject_cassette end - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + it 'responds to GET messages/categories' do + VCR.use_cassette('sm_client/messages/gets_message_categories') do + get '/my_health/v1/messaging/messages/categories' + end - it 'responds to GET messages/categories' do - VCR.use_cassette('sm_client/messages/gets_message_categories') do - get '/my_health/v1/messaging/messages/categories' + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_response_schema('category') end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_response_schema('category') - end + it 'responds to GET messages/categories when camel-inflected' do + VCR.use_cassette('sm_client/messages/gets_message_categories') do + get '/my_health/v1/messaging/messages/categories', headers: inflection_header + end - it 'responds to GET messages/categories when camel-inflected' do - VCR.use_cassette('sm_client/messages/gets_message_categories') do - get '/my_health/v1/messaging/messages/categories', headers: inflection_header + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_camelized_response_schema('category') end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_camelized_response_schema('category') - end + it 'returns message signature preferences' do + VCR.use_cassette('sm_client/messages/gets_message_signature') do + get '/my_health/v1/messaging/messages/signature', headers: inflection_header + end - it 'returns message signature preferences' do - VCR.use_cassette('sm_client/messages/gets_message_signature') do - get '/my_health/v1/messaging/messages/signature', headers: inflection_header + result = JSON.parse(response.body) + expect(result['data']['includeSignature']).to eq(true) + expect(result['data']['signatureTitle']).to eq('test-api title') + expect(result['data']['signatureName']).to eq('test-api Name') end - result = JSON.parse(response.body) - expect(result['data']['includeSignature']).to eq(true) - expect(result['data']['signatureTitle']).to eq('test-api title') - expect(result['data']['signatureName']).to eq('test-api Name') - end + it 'responds to GET #show' do + VCR.use_cassette('sm_client/messages/gets_a_message_with_id') do + get "/my_health/v1/messaging/messages/#{message_id}" + end - it 'responds to GET #show' do - VCR.use_cassette('sm_client/messages/gets_a_message_with_id') do - get "/my_health/v1/messaging/messages/#{message_id}" + expect(response).to be_successful + expect(response.body).to be_a(String) + # It should decode html entities + expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('Quote test: “test”') + # rubocop:disable Layout/LineLength + expect(JSON.parse(response.body)['data']['attributes']['body']).to eq("Einstein once said: “Profound quote contents here”. \n\nThat was supposed to show a regular quote but it didn’t display like it did in the compose form.\n\nLet’s try out more symbols here:\n\nSingle quote: ‘ contents’\nQuestion mark: ?\nColon: :\nDash: -\nLess than: <\nGreat then: >\nEquals: =\nAsterisk: *\nAnd symbol: &\nDollar symbol: $\nDivide symbol: %\nAt symbol: @\nParentheses: ( contents )\nBrackets: [ contents ]\nCurly braces: { contents }\nSemicolon: ;\nSlash: /\nPlus: +\nUp symbol: ^\nPound key: #\nExclamation: !") + # rubocop:enable Layout/LineLength + expect(response).to match_response_schema('message') end - expect(response).to be_successful - expect(response.body).to be_a(String) - # It should decode html entities - expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('Quote test: “test”') - # rubocop:disable Layout/LineLength - expect(JSON.parse(response.body)['data']['attributes']['body']).to eq("Einstein once said: “Profound quote contents here”. \n\nThat was supposed to show a regular quote but it didn’t display like it did in the compose form.\n\nLet’s try out more symbols here:\n\nSingle quote: ‘ contents’\nQuestion mark: ?\nColon: :\nDash: -\nLess than: <\nGreat then: >\nEquals: =\nAsterisk: *\nAnd symbol: &\nDollar symbol: $\nDivide symbol: %\nAt symbol: @\nParentheses: ( contents )\nBrackets: [ contents ]\nCurly braces: { contents }\nSemicolon: ;\nSlash: /\nPlus: +\nUp symbol: ^\nPound key: #\nExclamation: !") - # rubocop:enable Layout/LineLength - expect(response).to match_response_schema('message') - end + it 'responds to GET #show when camel-inflected' do + VCR.use_cassette('sm_client/messages/gets_a_message_with_id') do + get "/my_health/v1/messaging/messages/#{message_id}", headers: inflection_header + end - it 'responds to GET #show when camel-inflected' do - VCR.use_cassette('sm_client/messages/gets_a_message_with_id') do - get "/my_health/v1/messaging/messages/#{message_id}", headers: inflection_header + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_camelized_response_schema('message') end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_camelized_response_schema('message') - end + describe 'POST create' do + let(:attachment_type) { 'image/jpg' } + let(:uploads) do + [ + Rack::Test::UploadedFile.new('spec/fixtures/files/sm_file1.jpg', attachment_type), + Rack::Test::UploadedFile.new('spec/fixtures/files/sm_file2.jpg', attachment_type), + Rack::Test::UploadedFile.new('spec/fixtures/files/sm_file3.jpg', attachment_type), + Rack::Test::UploadedFile.new('spec/fixtures/files/sm_file4.jpg', attachment_type) + ] + end + let(:message_params) { attributes_for(:message, subject: 'CI Run', body: 'Continuous Integration') } + let(:params) { message_params.slice(:subject, :category, :recipient_id, :body) } + let(:params_with_attachments) { { message: params }.merge(uploads:) } + + context 'message' do + it 'without attachments' do + VCR.use_cassette('sm_client/messages/creates/a_new_message_without_attachments') do + post '/my_health/v1/messaging/messages', params: { message: params } + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') + expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') + expect(response).to match_response_schema('message') + end - describe 'POST create' do - let(:attachment_type) { 'image/jpg' } - let(:uploads) do - [ - Rack::Test::UploadedFile.new('spec/fixtures/files/sm_file1.jpg', attachment_type), - Rack::Test::UploadedFile.new('spec/fixtures/files/sm_file2.jpg', attachment_type), - Rack::Test::UploadedFile.new('spec/fixtures/files/sm_file3.jpg', attachment_type), - Rack::Test::UploadedFile.new('spec/fixtures/files/sm_file4.jpg', attachment_type) - ] - end - let(:message_params) { attributes_for(:message, subject: 'CI Run', body: 'Continuous Integration') } - let(:params) { message_params.slice(:subject, :category, :recipient_id, :body) } - let(:params_with_attachments) { { message: params }.merge(uploads:) } - - context 'message' do - it 'without attachments' do - VCR.use_cassette('sm_client/messages/creates/a_new_message_without_attachments') do - post '/my_health/v1/messaging/messages', params: { message: params } + it 'without attachments when camel-inflected' do + VCR.use_cassette('sm_client/messages/creates/a_new_message_without_attachments') do + post '/my_health/v1/messaging/messages', params: { message: params }, headers: inflection_header + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') + expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') + expect(response).to match_camelized_response_schema('message') end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') - expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') - expect(response).to match_response_schema('message') - end + it 'with attachments' do + VCR.use_cassette('sm_client/messages/creates/a_new_message_with_4_attachments') do + post '/my_health/v1/messaging/messages', params: params_with_attachments + end - it 'without attachments when camel-inflected' do - VCR.use_cassette('sm_client/messages/creates/a_new_message_without_attachments') do - post '/my_health/v1/messaging/messages', params: { message: params }, headers: inflection_header + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') + expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') + expect(response).to match_response_schema('message_with_attachment') end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') - expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') - expect(response).to match_camelized_response_schema('message') + it 'with attachments when camel-inflected' do + VCR.use_cassette('sm_client/messages/creates/a_new_message_with_4_attachments') do + post '/my_health/v1/messaging/messages', params: params_with_attachments, headers: inflection_header + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') + expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') + expect(response).to match_camelized_response_schema('message_with_attachment') + end end - it 'with attachments' do - VCR.use_cassette('sm_client/messages/creates/a_new_message_with_4_attachments') do - post '/my_health/v1/messaging/messages', params: params_with_attachments + context 'reply' do + let(:reply_message_id) { 674_838 } + + it 'without attachments' do + VCR.use_cassette('sm_client/messages/creates/a_reply_without_attachments') do + post "/my_health/v1/messaging/messages/#{reply_message_id}/reply", params: { message: params } + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') + expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') + expect(response).to match_response_schema('message') end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') - expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') - expect(response).to match_response_schema('message_with_attachment') - end + it 'without attachments when camel-inflected' do + VCR.use_cassette('sm_client/messages/creates/a_reply_without_attachments') do + post "/my_health/v1/messaging/messages/#{reply_message_id}/reply", + params: { message: params }, + headers: inflection_header + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') + expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') + expect(response).to match_camelized_response_schema('message') + end + + it 'with attachments' do + VCR.use_cassette('sm_client/messages/creates/a_reply_with_4_attachments') do + post "/my_health/v1/messaging/messages/#{reply_message_id}/reply", params: params_with_attachments + end - it 'with attachments when camel-inflected' do - VCR.use_cassette('sm_client/messages/creates/a_new_message_with_4_attachments') do - post '/my_health/v1/messaging/messages', params: params_with_attachments, headers: inflection_header + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') + expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') + expect(response).to match_response_schema('message_with_attachment') end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') - expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') - expect(response).to match_camelized_response_schema('message_with_attachment') + it 'with attachments when camel-inflected' do + VCR.use_cassette('sm_client/messages/creates/a_reply_with_4_attachments') do + post "/my_health/v1/messaging/messages/#{reply_message_id}/reply", + params: params_with_attachments, + headers: inflection_header + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') + expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') + expect(response).to match_camelized_response_schema('message_with_attachment') + end end end - context 'reply' do - let(:reply_message_id) { 674_838 } + describe '#thread' do + let(:thread_id) { 3_188_782 } - it 'without attachments' do - VCR.use_cassette('sm_client/messages/creates/a_reply_without_attachments') do - post "/my_health/v1/messaging/messages/#{reply_message_id}/reply", params: { message: params } + it 'responds to GET #thread' do + VCR.use_cassette('sm_client/messages/gets_a_message_thread_full') do + get "/my_health/v1/messaging/messages/#{thread_id}/thread" end - + json_response = JSON.parse(response.body) + data = json_response['data'] + expect(data).to be_an(Array) + first_message = data.first['attributes'] + expect(first_message['message_id']).to eq(3_207_476) + expect(first_message['thread_id']).to eq(3_188_781) + expect(first_message['sender_id']).to eq(251_391) + expect(first_message['sender_name']).to eq('MHVDAYMARK, MARK') + expect(first_message['recipient_id']).to eq(3_188_767) + expect(first_message['recipient_name']).to eq('TG API TESTING') + expect(first_message['sent_date']).to be_nil + expect(first_message['draft_date']).to eq('2023-12-19T17:21:47.000+00:00') + expect(first_message['triage_group_name']).to eq('TG API TESTING') + expect(first_message['has_attachments']).to eq(false) + expect(first_message['subject']).to eq('Test Inquiry') + expect(first_message['category']).to eq('TEST_RESULTS') + expect(first_message['folder_id']).to eq(-2) + expect(first_message['message_body']).to eq('TEST0101010101') + expect(first_message['proxy_sender_name']).to be_nil + expect(first_message['read_receipt']).to be_nil expect(response).to be_successful - expect(response.body).to be_a(String) - expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') - expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') - expect(response).to match_response_schema('message') end - it 'without attachments when camel-inflected' do - VCR.use_cassette('sm_client/messages/creates/a_reply_without_attachments') do - post "/my_health/v1/messaging/messages/#{reply_message_id}/reply", - params: { message: params }, - headers: inflection_header + it 'responds to GET #thread with full_body query param' do + VCR.use_cassette('sm_client/messages/gets_a_message_thread_full_body') do + get "/my_health/v1/messaging/messages/#{thread_id}/thread?full_body=true" end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') - expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') - expect(response).to match_camelized_response_schema('message') - end + json_response = JSON.parse(response.body) + data = json_response['data'] - it 'with attachments' do - VCR.use_cassette('sm_client/messages/creates/a_reply_with_4_attachments') do - post "/my_health/v1/messaging/messages/#{reply_message_id}/reply", params: params_with_attachments - end + expect(data).to be_an(Array) - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') - expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') - expect(response).to match_response_schema('message_with_attachment') + first_message = data.first['attributes'] + expect(first_message['message_id']).to eq(3_207_476) + expect(first_message['attachments']).to be_empty + + second_message = data[1]['attributes'] + expect(second_message['message_id']).to eq(3_204_755) + + attachments = second_message['attachments'] + expect(attachments.length).to eq(2) + + first_attachment = attachments.first + expect(first_attachment['id']).to eq(3_204_753) + expect(first_attachment['name']).to eq('almost4mbfile.pdf') + expect(first_attachment['attachment_size']).to eq(3_976_877) + expect(first_attachment['message_id']).to eq(3_204_755) + + third_message = data[2]['attributes'] + expect(third_message['message_id']).to eq(3_203_739) + expect(third_message['message_body'].length).to be > 200 end - it 'with attachments when camel-inflected' do - VCR.use_cassette('sm_client/messages/creates/a_reply_with_4_attachments') do - post "/my_health/v1/messaging/messages/#{reply_message_id}/reply", - params: params_with_attachments, - headers: inflection_header + it 'responds to GET #thread when camel-inflected' do + VCR.use_cassette('sm_client/messages/gets_a_message_thread_full') do + get "/my_health/v1/messaging/messages/#{thread_id}/thread", headers: { 'X-Key-Inflection': 'camel' } end + json_response = JSON.parse(response.body) + data = json_response['data'] + expect(response).to be_successful - expect(response.body).to be_a(String) - expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('CI Run') - expect(JSON.parse(response.body)['data']['attributes']['body']).to eq('Continuous Integration') - expect(response).to match_camelized_response_schema('message_with_attachment') + expect(data).to be_a(Array) + first_message = data.first['attributes'] + expect(first_message['messageId']).to eq(3_207_476) + expect(first_message['threadId']).to eq(3_188_781) + expect(first_message['senderId']).to eq(251_391) end end - end - describe '#thread' do - let(:thread_id) { 3_188_782 } + describe '#destroy' do + let(:message_id) { 573_052 } - it 'responds to GET #thread' do - VCR.use_cassette('sm_client/messages/gets_a_message_thread_full') do - get "/my_health/v1/messaging/messages/#{thread_id}/thread" - end - json_response = JSON.parse(response.body) - data = json_response['data'] - expect(data).to be_an(Array) - first_message = data.first['attributes'] - expect(first_message['message_id']).to eq(3_207_476) - expect(first_message['thread_id']).to eq(3_188_781) - expect(first_message['sender_id']).to eq(251_391) - expect(first_message['sender_name']).to eq('MHVDAYMARK, MARK') - expect(first_message['recipient_id']).to eq(3_188_767) - expect(first_message['recipient_name']).to eq('TG API TESTING') - expect(first_message['sent_date']).to be_nil - expect(first_message['draft_date']).to eq('2023-12-19T17:21:47.000+00:00') - expect(first_message['triage_group_name']).to eq('TG API TESTING') - expect(first_message['has_attachments']).to eq(false) - expect(first_message['subject']).to eq('Test Inquiry') - expect(first_message['category']).to eq('TEST_RESULTS') - expect(first_message['folder_id']).to eq(-2) - expect(first_message['message_body']).to eq('TEST0101010101') - expect(first_message['proxy_sender_name']).to be_nil - expect(first_message['read_receipt']).to be_nil - expect(response).to be_successful - end + it 'responds to DELETE' do + VCR.use_cassette('sm_client/messages/deletes_the_message_with_id') do + delete "/my_health/v1/messaging/messages/#{message_id}" + end - it 'responds to GET #thread with full_body query param' do - VCR.use_cassette('sm_client/messages/gets_a_message_thread_full_body') do - get "/my_health/v1/messaging/messages/#{thread_id}/thread?full_body=true" + expect(response).to be_successful + expect(response).to have_http_status(:no_content) end + end - json_response = JSON.parse(response.body) - data = json_response['data'] - - expect(data).to be_an(Array) - - first_message = data.first['attributes'] - expect(first_message['message_id']).to eq(3_207_476) - expect(first_message['attachments']).to be_empty - - second_message = data[1]['attributes'] - expect(second_message['message_id']).to eq(3_204_755) - - attachments = second_message['attachments'] - expect(attachments.length).to eq(2) + describe '#move' do + let(:message_id) { 573_052 } - first_attachment = attachments.first - expect(first_attachment['id']).to eq(3_204_753) - expect(first_attachment['name']).to eq('almost4mbfile.pdf') - expect(first_attachment['attachment_size']).to eq(3_976_877) - expect(first_attachment['message_id']).to eq(3_204_755) + it 'responds to PATCH messages/move' do + VCR.use_cassette('sm_client/messages/moves_a_message_with_id') do + patch "/my_health/v1/messaging/messages/#{message_id}/move?folder_id=0" + end - third_message = data[2]['attributes'] - expect(third_message['message_id']).to eq(3_203_739) - expect(third_message['message_body'].length).to be > 200 + expect(response).to be_successful + expect(response).to have_http_status(:no_content) + end end + end + end - it 'responds to GET #thread when camel-inflected' do - VCR.use_cassette('sm_client/messages/gets_a_message_thread_full') do - get "/my_health/v1/messaging/messages/#{thread_id}/thread", headers: { 'X-Key-Inflection': 'camel' } - end + context 'when legacy sm policy' do + before do + Flipper.disable(:mhv_sm_session_policy) + allow(SM::Client).to receive(:new).and_return(authenticated_client) + end - json_response = JSON.parse(response.body) - data = json_response['data'] + context 'Basic User' do + let(:mhv_account_type) { 'Basic' } - expect(response).to be_successful - expect(data).to be_a(Array) - first_message = data.first['attributes'] - expect(first_message['messageId']).to eq(3_207_476) - expect(first_message['threadId']).to eq(3_188_781) - expect(first_message['senderId']).to eq(251_391) - end + before { get '/my_health/v1/messaging/messages/categories' } + + include_examples 'for user account level', message: 'You do not have access to messaging' + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' end - describe '#destroy' do - let(:message_id) { 573_052 } + context 'Premium User' do + let(:mhv_account_type) { 'Premium' } - it 'responds to DELETE' do - VCR.use_cassette('sm_client/messages/deletes_the_message_with_id') do - delete "/my_health/v1/messaging/messages/#{message_id}" + context 'not a va patient' do + before { get '/my_health/v1/messaging/messages/categories' } + + let(:va_patient) { false } + let(:current_user) do + build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) end - expect(response).to be_successful - expect(response).to have_http_status(:no_content) + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' end - end - describe '#move' do - let(:message_id) { 573_052 } + describe '#show' do + it 'responds to GET #show' do + VCR.use_cassette('sm_client/messages/gets_a_message_with_id') do + get "/my_health/v1/messaging/messages/#{message_id}" + end - it 'responds to PATCH messages/move' do - VCR.use_cassette('sm_client/messages/moves_a_message_with_id') do - patch "/my_health/v1/messaging/messages/#{message_id}/move?folder_id=0" + expect(response).to be_successful + expect(response.body).to be_a(String) + # It should decode html entities + expect(JSON.parse(response.body)['data']['attributes']['subject']).to eq('Quote test: “test”') + # rubocop:disable Layout/LineLength + expect(JSON.parse(response.body)['data']['attributes']['body']).to eq("Einstein once said: “Profound quote contents here”. \n\nThat was supposed to show a regular quote but it didn’t display like it did in the compose form.\n\nLet’s try out more symbols here:\n\nSingle quote: ‘ contents’\nQuestion mark: ?\nColon: :\nDash: -\nLess than: <\nGreat then: >\nEquals: =\nAsterisk: *\nAnd symbol: &\nDollar symbol: $\nDivide symbol: %\nAt symbol: @\nParentheses: ( contents )\nBrackets: [ contents ]\nCurly braces: { contents }\nSemicolon: ;\nSlash: /\nPlus: +\nUp symbol: ^\nPound key: #\nExclamation: !") + # rubocop:enable Layout/LineLength + expect(response).to match_response_schema('message') end - - expect(response).to be_successful - expect(response).to have_http_status(:no_content) end end end diff --git a/modules/my_health/spec/request/v1/messaging_preferences_spec.rb b/modules/my_health/spec/request/v1/messaging_preferences_spec.rb index 89e29cab6a7..384a144b200 100644 --- a/modules/my_health/spec/request/v1/messaging_preferences_spec.rb +++ b/modules/my_health/spec/request/v1/messaging_preferences_spec.rb @@ -8,100 +8,148 @@ include SM::ClientHelpers include SchemaMatchers + let(:mhv_account_type) { 'Premium' } let(:va_patient) { true } let(:current_user) { build(:user, :mhv, va_patient:, mhv_account_type:) } before do - allow(SM::Client).to receive(:new).and_return(authenticated_client) sign_in_as(current_user) end - context 'Basic User' do - let(:mhv_account_type) { 'Basic' } + context 'when sm session policy is enabled' do + before do + Flipper.enable(:mhv_sm_session_policy) + Timecop.freeze(Time.zone.parse('2017-05-01T19:25:00Z')) + sign_in_as(current_user) + end - before { get '/my_health/v1/messaging/preferences' } + after do + Flipper.disable(:mhv_sm_session_policy) + Timecop.return + end - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + context 'when NOT authorized' do + before do + VCR.insert_cassette('sm_client/session_error') + get '/my_health/v1/messaging/preferences' + end - context 'Advanced User' do - let(:mhv_account_type) { 'Advanced' } + after do + VCR.eject_cassette + end - before { get '/my_health/v1/messaging/preferences' } + include_examples 'for user account level', message: 'You do not have access to messaging' + end - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + context 'when authorized' do + before do + VCR.insert_cassette('sm_client/session') + end - context 'Premium User' do - let(:mhv_account_type) { 'Premium' } + after do + VCR.eject_cassette + end - context 'not a va patient' do - before { get '/my_health/v1/messaging/preferences' } + it 'responds to GET #show of preferences' do + VCR.use_cassette('sm_client/preferences/fetches_email_settings_for_notifications') do + get '/my_health/v1/messaging/preferences' + end - let(:va_patient) { false } - let(:current_user) do - build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) + expect(response).to be_successful + expect(response.body).to be_a(String) + attrs = JSON.parse(response.body)['data']['attributes'] + expect(attrs['email_address']).to eq('muazzam.khan@va.gov') + expect(attrs['frequency']).to eq('daily') end - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + it 'responds to PUT #update of preferences' do + VCR.use_cassette('sm_client/preferences/sets_the_email_notification_settings', record: :none) do + params = { email_address: 'kamyar.karshenas@va.gov', + frequency: 'none' } + put '/my_health/v1/messaging/preferences', params: + end + + expect(response).to have_http_status(:ok) + expect(JSON.parse(response.body)['data']['id']) + .to eq('17126b0821ad0472ae11944e9861f82d6bdd17801433e200e6a760148a4866c3') + expect(JSON.parse(response.body)['data']['attributes']) + .to eq('email_address' => 'kamyar.karshenas@va.gov', 'frequency' => 'none') + end - it 'responds to GET #show of preferences' do - VCR.use_cassette('sm_client/preferences/fetches_email_settings_for_notifications') do - get '/my_health/v1/messaging/preferences' + it 'requires all parameters for update' do + VCR.use_cassette('sm_client/preferences/sets_the_email_notification_settings', record: :none) do + params = { email_address: 'kamyar.karshenas@va.gov' } + put '/my_health/v1/messaging/preferences', params: + end + + expect(response).to have_http_status(:unprocessable_entity) end - expect(response).to be_successful - expect(response.body).to be_a(String) - attrs = JSON.parse(response.body)['data']['attributes'] - expect(attrs['email_address']).to eq('muazzam.khan@va.gov') - expect(attrs['frequency']).to eq('daily') - end + it 'rejects unknown frequency parameters' do + VCR.use_cassette('sm_client/preferences/sets_the_email_notification_settings', record: :none) do + params = { email_address: 'kamyar.karshenas@va.gov', + frequency: 'hourly' } + put '/my_health/v1/messaging/preferences', params: + end - it 'responds to PUT #update of preferences' do - VCR.use_cassette('sm_client/preferences/sets_the_email_notification_settings', record: :none) do - params = { email_address: 'kamyar.karshenas@va.gov', - frequency: 'none' } - put '/my_health/v1/messaging/preferences', params: + expect(response).to have_http_status(:unprocessable_entity) end - expect(response).to have_http_status(:ok) - expect(JSON.parse(response.body)['data']['id']) - .to eq('17126b0821ad0472ae11944e9861f82d6bdd17801433e200e6a760148a4866c3') - expect(JSON.parse(response.body)['data']['attributes']) - .to eq('email_address' => 'kamyar.karshenas@va.gov', 'frequency' => 'none') - end + it 'returns a custom exception mapped from i18n when email contains spaces' do + VCR.use_cassette('sm_client/preferences/raises_a_backend_service_exception_when_email_includes_spaces') do + params = { email_address: 'kamyar karshenas@va.gov', + frequency: 'daily' } + put '/my_health/v1/messaging/preferences', params: + end - it 'requires all parameters for update' do - VCR.use_cassette('sm_client/preferences/sets_the_email_notification_settings', record: :none) do - params = { email_address: 'kamyar.karshenas@va.gov' } - put '/my_health/v1/messaging/preferences', params: + expect(response).to have_http_status(:unprocessable_entity) + expect(JSON.parse(response.body)['errors'].first['code']).to eq('SM152') end + end + end - expect(response).to have_http_status(:unprocessable_entity) + context 'when legacy sm policy' do + before do + Flipper.disable(:mhv_sm_session_policy) + allow(SM::Client).to receive(:new).and_return(authenticated_client) end - it 'rejects unknown frequency parameters' do - VCR.use_cassette('sm_client/preferences/sets_the_email_notification_settings', record: :none) do - params = { email_address: 'kamyar.karshenas@va.gov', - frequency: 'hourly' } - put '/my_health/v1/messaging/preferences', params: - end + context 'Basic User' do + let(:mhv_account_type) { 'Basic' } - expect(response).to have_http_status(:unprocessable_entity) + before { get '/my_health/v1/messaging/preferences' } + + include_examples 'for user account level', message: 'You do not have access to messaging' + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' end - it 'returns a custom exception mapped from i18n when email contains spaces' do - VCR.use_cassette('sm_client/preferences/raises_a_backend_service_exception_when_email_includes_spaces') do - params = { email_address: 'kamyar karshenas@va.gov', - frequency: 'daily' } - put '/my_health/v1/messaging/preferences', params: + context 'Premium User' do + let(:mhv_account_type) { 'Premium' } + + context 'not a va patient' do + before { get '/my_health/v1/messaging/preferences' } + + let(:va_patient) { false } + let(:current_user) do + build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) + end + + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' end - expect(response).to have_http_status(:unprocessable_entity) - expect(JSON.parse(response.body)['errors'].first['code']).to eq('SM152') + describe 'preferences' do + it 'responds to GET #show of preferences' do + VCR.use_cassette('sm_client/preferences/fetches_email_settings_for_notifications') do + get '/my_health/v1/messaging/preferences' + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + attrs = JSON.parse(response.body)['data']['attributes'] + expect(attrs['email_address']).to eq('muazzam.khan@va.gov') + expect(attrs['frequency']).to eq('daily') + end + end end end end diff --git a/modules/my_health/spec/request/v1/threads_request_spec.rb b/modules/my_health/spec/request/v1/threads_request_spec.rb index 898e7c6a7fd..d7660091c8a 100644 --- a/modules/my_health/spec/request/v1/threads_request_spec.rb +++ b/modules/my_health/spec/request/v1/threads_request_spec.rb @@ -12,100 +12,146 @@ let(:inbox_id) { 0 } let(:message_id) { 660_516 } let(:thread_id) { 660_515 } + let(:mhv_account_type) { 'Premium' } let(:va_patient) { true } let(:current_user) { build(:user, :mhv, va_patient:, mhv_account_type:) } let(:inflection_header) { { 'X-Key-Inflection' => 'camel' } } before do - allow(SM::Client).to receive(:new).and_return(authenticated_client) sign_in_as(current_user) end - context 'Basic User' do - let(:mhv_account_type) { 'Basic' } - - before { patch '/my_health/v1/messaging/threads/7259506/move?folder_id=0' } - - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + context 'when sm session policy is enabled' do + before do + Flipper.enable(:mhv_sm_session_policy) + Timecop.freeze(Time.zone.parse('2017-05-01T19:25:00Z')) + end - context 'Advanced User' do - let(:mhv_account_type) { 'Advanced' } + after do + Flipper.disable(:mhv_sm_session_policy) + Timecop.return + end - before { patch '/my_health/v1/messaging/threads/7259506/move?folder_id=0' } + context 'when NOT authorized' do + before do + VCR.insert_cassette('sm_client/session_error') + get "/my_health/v1/messaging/folders/#{inbox_id}/threads" + end - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + after do + VCR.eject_cassette + end - context 'Premium User' do - let(:mhv_account_type) { 'Premium' } + include_examples 'for user account level', message: 'You do not have access to messaging' + end - context 'not a va patient' do + context 'when authorized' do before do - get "/my_health/v1/messaging/folders/#{inbox_id}/threads", - params: { page_size: '5', page_number: '1', sort_field: 'SENDER_NAME', sort_order: 'ASC' } + VCR.insert_cassette('sm_client/session') end - let(:va_patient) { false } - let(:current_user) do - build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) + after do + VCR.eject_cassette end - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end - - describe '#index' do - context 'with valid params' do - it 'responds to GET #index' do - VCR.use_cassette('sm_client/threads/gets_threads_in_a_folder') do - get "/my_health/v1/messaging/folders/#{inbox_id}/threads", - params: { page_size: '5', page_number: '1', sort_field: 'SENDER_NAME', sort_order: 'ASC' } + describe '#index' do + context 'with valid params' do + it 'responds to GET #index' do + VCR.use_cassette('sm_client/threads/gets_threads_in_a_folder') do + get "/my_health/v1/messaging/folders/#{inbox_id}/threads", + params: { page_size: '5', page_number: '1', sort_field: 'SENDER_NAME', sort_order: 'ASC' } + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_response_schema('message_threads') end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_response_schema('message_threads') - end + it 'responds to GET #index when camel-inflected' do + VCR.use_cassette('sm_client/threads/gets_threads_in_a_folder_camel') do + get "/my_health/v1/messaging/folders/#{inbox_id}/threads", + params: { page_size: '5', page_number: '1', sort_field: 'SENDER_NAME', sort_order: 'ASC' }, + headers: { 'X-Key-Inflection' => 'camel' } + end - it 'responds to GET #index when camel-inflected' do - VCR.use_cassette('sm_client/threads/gets_threads_in_a_folder_camel') do - get "/my_health/v1/messaging/folders/#{inbox_id}/threads", - params: { page_size: '5', page_number: '1', sort_field: 'SENDER_NAME', sort_order: 'ASC' }, - headers: { 'X-Key-Inflection' => 'camel' } + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_camelized_response_schema('message_threads') end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_camelized_response_schema('message_threads') + it 'returns an empty array when there are no messages in the folder' do + VCR.use_cassette('sm_client/threads/gets_threads_in_a_folder_no_messages') do + get "/my_health/v1/messaging/folders/#{inbox_id}/threads", + params: { page_size: '5', page_number: '1', sort_field: 'SENDER_NAME', sort_order: 'ASC' } + end + + expect(response).to be_successful + + json_response = JSON.parse(response.body) + expect(json_response).to eq({ 'data' => [] }) + expect(response).to match_response_schema('message_threads_no_messages') + end end + end - it 'returns an empty array when there are no messages in the folder' do - VCR.use_cassette('sm_client/threads/gets_threads_in_a_folder_no_messages') do - get "/my_health/v1/messaging/folders/#{inbox_id}/threads", - params: { page_size: '5', page_number: '1', sort_field: 'SENDER_NAME', sort_order: 'ASC' } + describe '#move' do + let(:thread_id) { 7_065_799 } + + it 'responds to PATCH threads/move' do + VCR.use_cassette('sm_client/threads/moves_a_thread_with_id') do + patch "/my_health/v1/messaging/threads/#{thread_id}/move?folder_id=0" end expect(response).to be_successful - - json_response = JSON.parse(response.body) - expect(json_response).to eq({ 'data' => [] }) - expect(response).to match_response_schema('message_threads_no_messages') + expect(response).to have_http_status(:no_content) end end end + end + + context 'when legacy sm policy' do + before do + Flipper.disable(:mhv_sm_session_policy) + allow(SM::Client).to receive(:new).and_return(authenticated_client) + end + + context 'Basic User' do + let(:mhv_account_type) { 'Basic' } - describe '#move' do - let(:thread_id) { 7_065_799 } + before { patch '/my_health/v1/messaging/threads/7259506/move?folder_id=0' } - it 'responds to PATCH threads/move' do - VCR.use_cassette('sm_client/threads/moves_a_thread_with_id') do - patch "/my_health/v1/messaging/threads/#{thread_id}/move?folder_id=0" + include_examples 'for user account level', message: 'You do not have access to messaging' + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' + end + + context 'Premium User' do + let(:mhv_account_type) { 'Premium' } + + context 'not a va patient' do + before do + get "/my_health/v1/messaging/folders/#{inbox_id}/threads", + params: { page_size: '5', page_number: '1', sort_field: 'SENDER_NAME', sort_order: 'ASC' } end - expect(response).to be_successful - expect(response).to have_http_status(:no_content) + let(:va_patient) { false } + let(:current_user) do + build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) + end + + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' + end + + describe '#index' do + it 'responds to GET #index' do + VCR.use_cassette('sm_client/threads/gets_threads_in_a_folder') do + get "/my_health/v1/messaging/folders/#{inbox_id}/threads", + params: { page_size: '5', page_number: '1', sort_field: 'SENDER_NAME', sort_order: 'ASC' } + end + + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_response_schema('message_threads') + end end end end diff --git a/modules/my_health/spec/request/v1/triage_teams_request_spec.rb b/modules/my_health/spec/request/v1/triage_teams_request_spec.rb index 27e7625d51e..7866fe28dec 100644 --- a/modules/my_health/spec/request/v1/triage_teams_request_spec.rb +++ b/modules/my_health/spec/request/v1/triage_teams_request_spec.rb @@ -8,64 +8,109 @@ include SM::ClientHelpers include SchemaMatchers + let(:mhv_account_type) { 'Premium' } let(:va_patient) { true } let(:current_user) { build(:user, :mhv, va_patient:, mhv_account_type:) } before do - allow(SM::Client).to receive(:new).and_return(authenticated_client) sign_in_as(current_user) end - context 'Basic User' do - let(:mhv_account_type) { 'Basic' } + context 'when sm session policy is enabled' do + before do + Flipper.enable(:mhv_sm_session_policy) + Timecop.freeze(Time.zone.parse('2017-05-01T19:25:00Z')) + end - before { get '/my_health/v1/messaging/recipients' } + after do + Flipper.disable(:mhv_sm_session_policy) + Timecop.return + end - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + context 'when NOT authorized' do + before do + VCR.insert_cassette('sm_client/session_error') + get '/my_health/v1/messaging/recipients' + end - context 'Advanced User' do - let(:mhv_account_type) { 'Advanced' } + after do + VCR.eject_cassette + end - before { get '/my_health/v1/messaging/recipients' } + include_examples 'for user account level', message: 'You do not have access to messaging' + end - include_examples 'for user account level', message: 'You do not have access to messaging' - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + context 'when authorized' do + before do + VCR.insert_cassette('sm_client/session') + end - context 'Premium User' do - let(:mhv_account_type) { 'Premium' } + after do + VCR.eject_cassette + end - context 'not a va patient' do - before { get '/my_health/v1/messaging/recipients' } + it 'responds to GET #index' do + VCR.use_cassette('sm_client/triage_teams/gets_a_collection_of_triage_team_recipients') do + get '/my_health/v1/messaging/recipients' + end - let(:va_patient) { false } - let(:current_user) do - build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_response_schema('triage_teams') end - include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' - end + it 'responds to GET #index when camel-inflected' do + VCR.use_cassette('sm_client/triage_teams/gets_a_collection_of_triage_team_recipients') do + get '/my_health/v1/messaging/recipients', headers: { 'X-Key-Inflection' => 'camel' } + end - it 'responds to GET #index' do - VCR.use_cassette('sm_client/triage_teams/gets_a_collection_of_triage_team_recipients') do - get '/my_health/v1/messaging/recipients' + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_camelized_response_schema('triage_teams') end + end + end + + context 'when legacy sm policy' do + before do + Flipper.disable(:mhv_sm_session_policy) + allow(SM::Client).to receive(:new).and_return(authenticated_client) + end + + context 'Basic User' do + let(:mhv_account_type) { 'Basic' } + + before { get '/my_health/v1/messaging/recipients' } - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_response_schema('triage_teams') + include_examples 'for user account level', message: 'You do not have access to messaging' + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' end - it 'responds to GET #index when camel-inflected' do - VCR.use_cassette('sm_client/triage_teams/gets_a_collection_of_triage_team_recipients') do - get '/my_health/v1/messaging/recipients', headers: { 'X-Key-Inflection' => 'camel' } + context 'Premium User' do + let(:mhv_account_type) { 'Premium' } + + context 'not a va patient' do + before { get '/my_health/v1/messaging/recipients' } + + let(:va_patient) { false } + let(:current_user) do + build(:user, :mhv, :no_vha_facilities, va_patient:, mhv_account_type:) + end + + include_examples 'for non va patient user', authorized: false, message: 'You do not have access to messaging' end + end + + describe 'triage teams' do + it 'responds to GET #index' do + VCR.use_cassette('sm_client/triage_teams/gets_a_collection_of_triage_team_recipients') do + get '/my_health/v1/messaging/recipients' + end - expect(response).to be_successful - expect(response.body).to be_a(String) - expect(response).to match_camelized_response_schema('triage_teams') + expect(response).to be_successful + expect(response.body).to be_a(String) + expect(response).to match_response_schema('triage_teams') + end end end end diff --git a/modules/representation_management/app/controllers/representation_management/v0/power_of_attorney_controller.rb b/modules/representation_management/app/controllers/representation_management/v0/power_of_attorney_controller.rb new file mode 100644 index 00000000000..3ec5cfd7986 --- /dev/null +++ b/modules/representation_management/app/controllers/representation_management/v0/power_of_attorney_controller.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'lighthouse/benefits_claims/service' + +module RepresentationManagement + module V0 + class PowerOfAttorneyController < ApplicationController + service_tag 'representation-management' + + def index + @active_poa = lighthouse_service.get_power_of_attorney + + if @active_poa.blank? || record.blank? + render json: { data: {} }, status: :ok + else + render json: record, serializer:, status: :ok + end + end + + private + + def lighthouse_service + BenefitsClaims::Service.new(icn) + end + + def icn + @current_user&.icn + end + + def poa_code + @poa_code ||= @active_poa.dig('data', 'attributes', 'code') + end + + def poa_type + @poa_type ||= @active_poa.dig('data', 'type') + end + + def record + return @record if defined? @record + + @record ||= if poa_type == 'organization' + organization + else + representative + end + end + + def serializer + if poa_type == 'organization' + RepresentationManagement::PowerOfAttorney::OrganizationSerializer + else + RepresentationManagement::PowerOfAttorney::RepresentativeSerializer + end + end + + def organization + Veteran::Service::Organization.find_by(poa: poa_code) + end + + def representative + Veteran::Service::Representative.where('? = ANY(poa_codes)', poa_code).order(created_at: :desc).first + end + end + end +end diff --git a/modules/representation_management/app/serializers/representation_management/power_of_attorney/base_serializer.rb b/modules/representation_management/app/serializers/representation_management/power_of_attorney/base_serializer.rb new file mode 100644 index 00000000000..1b35a8a0605 --- /dev/null +++ b/modules/representation_management/app/serializers/representation_management/power_of_attorney/base_serializer.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module RepresentationManagement + module PowerOfAttorney + class BaseSerializer < ActiveModel::Serializer + attribute :address_line1 + attribute :address_line2 + attribute :address_line3 + attribute :address_type + attribute :city + attribute :country_name + attribute :country_code_iso3 + attribute :province + attribute :international_postal_code + attribute :state_code + attribute :zip_code + attribute :zip_suffix + attribute :phone + end + end +end diff --git a/modules/representation_management/app/serializers/representation_management/power_of_attorney/organization_serializer.rb b/modules/representation_management/app/serializers/representation_management/power_of_attorney/organization_serializer.rb new file mode 100644 index 00000000000..c7f97d5b1f4 --- /dev/null +++ b/modules/representation_management/app/serializers/representation_management/power_of_attorney/organization_serializer.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module RepresentationManagement + module PowerOfAttorney + class OrganizationSerializer < BaseSerializer + attribute :type + attribute :name + + def type + 'organization' + end + end + end +end diff --git a/modules/representation_management/app/serializers/representation_management/power_of_attorney/representative_serializer.rb b/modules/representation_management/app/serializers/representation_management/power_of_attorney/representative_serializer.rb new file mode 100644 index 00000000000..cade1119fed --- /dev/null +++ b/modules/representation_management/app/serializers/representation_management/power_of_attorney/representative_serializer.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module RepresentationManagement + module PowerOfAttorney + class RepresentativeSerializer < BaseSerializer + attribute :type + attribute :name + attribute :email + + def type + 'representative' + end + + def name + object.full_name + end + + def phone + object.phone_number + end + end + end +end diff --git a/modules/representation_management/config/routes.rb b/modules/representation_management/config/routes.rb index b5d3ba5ee0f..241b887ca2e 100644 --- a/modules/representation_management/config/routes.rb +++ b/modules/representation_management/config/routes.rb @@ -3,5 +3,6 @@ RepresentationManagement::Engine.routes.draw do namespace :v0, defaults: { format: 'json' } do resources :flag_accredited_representatives, only: %i[create] + resources :power_of_attorney, only: %i[index] end end diff --git a/modules/representation_management/spec/requests/v0/power_of_attorney_request_spec.rb b/modules/representation_management/spec/requests/v0/power_of_attorney_request_spec.rb new file mode 100644 index 00000000000..80dd5490738 --- /dev/null +++ b/modules/representation_management/spec/requests/v0/power_of_attorney_request_spec.rb @@ -0,0 +1,135 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'RepresentationManagement::V0::PowerOfAttorneyController', type: :request do + let(:index_path) { '/representation_management/v0/power_of_attorney' } + let(:user) { create(:user, :loa3) } + + describe 'index' do + context 'with a signed in user' do + before do + sign_in_as(user) + end + + context 'when an organization is the active poa' do + let(:org_poa) { 'og1' } + let!(:organization) { create(:organization, poa: org_poa) } + + it 'returns the expected organization response' do + lh_response = { + 'data' => { + 'type' => 'organization', + 'attributes' => { + 'code' => org_poa + } + } + } + allow_any_instance_of(BenefitsClaims::Service) + .to receive(:get_power_of_attorney) + .and_return(lh_response) + + get index_path + + response_body = JSON.parse(response.body) + + expect(response).to have_http_status(:ok) + expect(response_body['data']['id']).to eq(org_poa) + end + end + + context 'when a representative is the active poa' do + let(:rep_poa) { 'rp1' } + let(:registration_number) { '12345' } + let!(:representative) do + create(:representative, + representative_id: registration_number, poa_codes: [rep_poa]) + end + + it 'returns the expected representative response' do + lh_response = { + 'data' => { + 'type' => 'individual', + 'attributes' => { + 'code' => rep_poa + } + } + } + allow_any_instance_of(BenefitsClaims::Service) + .to receive(:get_power_of_attorney) + .and_return(lh_response) + + get index_path + + response_body = JSON.parse(response.body) + + expect(response).to have_http_status(:ok) + expect(response_body['data']['id']).to eq(registration_number) + end + end + + context 'when there is no active poa' do + it 'returns the expected empty response' do + lh_response = { + 'data' => {} + } + allow_any_instance_of(BenefitsClaims::Service) + .to receive(:get_power_of_attorney) + .and_return(lh_response) + + get index_path + + response_body = JSON.parse(response.body) + + expect(response).to have_http_status(:ok) + expect(response_body['data']).to eq({}) + end + end + + context 'when the poa record is not found in the database' do + it 'returns the expected empty response' do + lh_response = { + 'data' => { + 'type' => 'organization', + 'attributes' => { + 'code' => 'abc' + } + } + } + allow_any_instance_of(BenefitsClaims::Service) + .to receive(:get_power_of_attorney) + .and_return(lh_response) + + get index_path + + response_body = JSON.parse(response.body) + + expect(response).to have_http_status(:ok) + expect(response_body['data']).to eq({}) + end + end + + context 'when the service encounters an unprocessable entity error' do + it 'returns a 422/unprocessable_entity status' do + allow_any_instance_of(BenefitsClaims::Service) + .to receive(:get_power_of_attorney) + .and_raise(Common::Exceptions::UnprocessableEntity) + + get index_path + + expect(response).to have_http_status(:unprocessable_entity) + end + end + end + + context 'without a signed in user' do + describe 'GET #index' do + it 'returns a 401/unauthorized status' do + get index_path + + expect(response).to have_http_status(:unauthorized) + end + end + end + end +end diff --git a/modules/representation_management/spec/serializers/power_of_attorney/base_serializer_spec.rb b/modules/representation_management/spec/serializers/power_of_attorney/base_serializer_spec.rb new file mode 100644 index 00000000000..1daa886c08c --- /dev/null +++ b/modules/representation_management/spec/serializers/power_of_attorney/base_serializer_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'BaseSerializer' do + before do + create(:organization, poa: 'og1') + create(:representative, representative_id: '123', poa_codes: ['rp1']) + end + + def representative + Veteran::Service::Representative.find('123') + end + + def organization + Veteran::Service::Organization.find('og1') + end + + def assert_attributes(attributes) + expect(attributes.keys).to eq(%w[address_line1 + address_line2 + address_line3 + address_type + city + country_name + country_code_iso3 + province + international_postal_code + state_code + zip_code + zip_suffix + phone]) + end + + it 'can serialize a representative' do + result = serialize(representative, serializer_class: RepresentationManagement::PowerOfAttorney::BaseSerializer) + attributes = JSON.parse(result)['data']['attributes'] + assert_attributes(attributes) + end + + it 'can serialize an organization' do + result = serialize(organization, serializer_class: RepresentationManagement::PowerOfAttorney::BaseSerializer) + attributes = JSON.parse(result)['data']['attributes'] + assert_attributes(attributes) + end +end diff --git a/modules/representation_management/spec/serializers/power_of_attorney/organization_serializer_spec.rb b/modules/representation_management/spec/serializers/power_of_attorney/organization_serializer_spec.rb new file mode 100644 index 00000000000..9ec39fbe579 --- /dev/null +++ b/modules/representation_management/spec/serializers/power_of_attorney/organization_serializer_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'OrganizationSerializer' do + before do + create(:organization, poa: 'og1') + end + + def organization + Veteran::Service::Organization.find('og1') + end + + it 'can serialize an organization' do + result = serialize(organization, + serializer_class: RepresentationManagement::PowerOfAttorney::OrganizationSerializer) + attributes = JSON.parse(result)['data']['attributes'] + + expect(attributes.keys).to eq(%w[address_line1 + address_line2 + address_line3 + address_type + city + country_name + country_code_iso3 + province + international_postal_code + state_code + zip_code + zip_suffix + phone + type + name]) + end +end diff --git a/modules/representation_management/spec/serializers/power_of_attorney/representative_serializer_spec.rb b/modules/representation_management/spec/serializers/power_of_attorney/representative_serializer_spec.rb new file mode 100644 index 00000000000..c39ea43ec7e --- /dev/null +++ b/modules/representation_management/spec/serializers/power_of_attorney/representative_serializer_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'RepresentativeSerializer' do + before do + create(:representative, representative_id: '123', poa_codes: ['rp1']) + end + + def representative + Veteran::Service::Representative.find('123') + end + + it 'can serialize a representative' do + result = serialize(representative, + serializer_class: RepresentationManagement::PowerOfAttorney::RepresentativeSerializer) + attributes = JSON.parse(result)['data']['attributes'] + + expect(attributes.keys).to eq(%w[address_line1 + address_line2 + address_line3 + address_type + city + country_name + country_code_iso3 + province + international_postal_code + state_code + zip_code + zip_suffix + phone + type + name + email]) + end +end diff --git a/modules/vaos/app/controllers/vaos/v2/appointments_controller.rb b/modules/vaos/app/controllers/vaos/v2/appointments_controller.rb index fd2898f076c..44778701d7c 100644 --- a/modules/vaos/app/controllers/vaos/v2/appointments_controller.rb +++ b/modules/vaos/app/controllers/vaos/v2/appointments_controller.rb @@ -263,9 +263,7 @@ def merge_clinics(appointments) def merge_facilities(appointments) appointments.each do |appt| appt[:location] = get_facility_memoized(appt[:location_id]) unless appt[:location_id].nil? - if cerner?(appt) && appt[:location].is_a?(Hash) && appt[:location]&.values&.any? do |v| - v.include?('COL OR 1') - end + if cerner?(appt) && contains_substring(extract_all_values(appt[:location]), 'COL OR 1') log_appt_id_location_name(appt) end end @@ -310,6 +308,66 @@ def get_facility_memoized(location_id) end memoize :get_facility_memoized + # This method extracts all values from a given object, which can be either an `OpenStruct`, `Hash`, or `Array`. + # It recursively traverses the object and collects all values into an array. + # In case of an `Array`, it looks inside each element of the array for values. + # If the object is neither an OpenStruct, Hash, nor an Array, it returns the unmodified object in an array. + # + # @param object [OpenStruct, Hash, Array] The object from which to extract values. + # This could either be an OpenStruct, Hash or Array. + # + # @return [Array] An array of all values found in the object. + # If the object is not an OpenStruct, Hash, nor an Array, then the unmodified object is returned. + # + # @example + # extract_all_values({a: 1, b: 2, c: {d: 3, e: 4}}) # => [1, 2, 3, 4] + # extract_all_values(OpenStruct.new(a: 1, b: 2, c: OpenStruct.new(d: 3, e: 4))) # => [1, 2, 3, 4] + # extract_all_values([{a: 1}, {b: 2}]) # => [1, 2] + # extract_all_values({a: 1, b: [{c: 2}, {d: "hello"}]}) # => [1, 2, "hello"] + # extract_all_values("not a hash, openstruct, or array") # => ["not a hash, openstruct, or array"] + # + def extract_all_values(object) + return [object] unless object.is_a?(OpenStruct) || object.is_a?(Hash) || object.is_a?(Array) + + values = [] + object = object.to_h if object.is_a?(OpenStruct) + + if object.is_a?(Array) + object.each do |o| + values += extract_all_values(o) + end + else + object.each_pair do |_, value| + case value + when OpenStruct, Hash, Array then values += extract_all_values(value) + else values << value + end + end + end + + values + end + + # This method checks if any string element in the given array contains the specified substring. + # + # @param arr [Array] The array to be searched. + # @param substring [String] The substring to look for. + # + # @return [Boolean] Returns true if any string element in the array contains the substring, false otherwise. + # If the input parameters are not of the correct type the method will return false. + # + # @example + # contains_substring(['Hello', 'World'], 'ell') # => true + # contains_substring(['Hello', 'World'], 'xyz') # => false + # contains_substring('Hello', 'ell') # => false + # contains_substring(['Hello', 'World'], 123) # => false + # + def contains_substring(arr, substring) + return false unless arr.is_a?(Array) && substring.is_a?(String) + + arr.any? { |element| element.is_a?(String) && element.include?(substring) } + end + def scrape_appt_comments_and_log_details(appt, appt_method, comment_key) if appt&.[](:reason)&.include? comment_key log_appt_comment_data(appt, appt_method, appt&.[](:reason), comment_key, REASON) diff --git a/modules/vaos/spec/request/v2/appointments_request_spec.rb b/modules/vaos/spec/request/v2/appointments_request_spec.rb index b992b389d1a..82c3133f02e 100644 --- a/modules/vaos/spec/request/v2/appointments_request_spec.rb +++ b/modules/vaos/spec/request/v2/appointments_request_spec.rb @@ -22,6 +22,54 @@ } } + mock_appt_location_openstruct = OpenStruct.new( + { + 'id': '983', + 'vistaSite': '983', + 'vastParent': '983', + 'type': 'va_facilities', + 'name': 'COL OR 1', + 'classification': 'VA Medical Center (VAMC)', + 'lat': 39.744507, + 'long': -104.830956, + 'website': 'https://www.denver.va.gov/locations/directions.asp', + 'phone': { + 'main': '307-778-7550', + 'fax': '307-778-7381', + 'pharmacy': '866-420-6337', + 'afterHours': '307-778-7550', + 'patientAdvocate': '307-778-7550 x7517', + 'mentalHealthClinic': '307-778-7349', + 'enrollmentCoordinator': '307-778-7550 x7579' + }, + 'physicalAddress': { + 'type': 'physical', + 'line': ['2360 East Pershing Boulevard'], + 'city': 'Cheyenne', + 'state': 'WY', + 'postalCode': '82001-5356' + }, + 'mobile': false, + 'healthService': %w[Audiology Cardiology DentalServices EmergencyCare Gastroenterology + Gynecology MentalHealthCare Nutrition Ophthalmology Optometry Orthopedics + Podiatry PrimaryCare SpecialtyCare UrgentCare Urology WomensHealth], + 'operatingStatus': { + 'code': 'NORMAL' + } + } + ) + + mock_appt_location_extracted_values = ['983', '983', '983', 'va_facilities', 'COL OR 1', 'VA Medical Center (VAMC)', + 39.744507, -104.830956, 'https://www.denver.va.gov/locations/directions.asp', + '307-778-7550', '307-778-7381', '866-420-6337', '307-778-7550', + '307-778-7550 x7517', '307-778-7349', '307-778-7550 x7579', + 'physical', '2360 East Pershing Boulevard', 'Cheyenne', 'WY', + '82001-5356', false, 'Audiology', 'Cardiology', 'DentalServices', + 'EmergencyCare', 'Gastroenterology', 'Gynecology', 'MentalHealthCare', + 'Nutrition', 'Ophthalmology', 'Optometry', 'Orthopedics', + 'Podiatry', 'PrimaryCare', 'SpecialtyCare', + 'UrgentCare', 'Urology', 'WomensHealth', 'NORMAL'] + before do Flipper.enable('va_online_scheduling') sign_in_as(current_user) @@ -194,12 +242,17 @@ VCR.use_cassette('vaos/v2/appointments/get_appointments_200_booked_cerner_with_color1_location', match_requests_on: %i[method path query], allow_playback_repeats: true) do allow(Rails.logger).to receive(:info).at_least(:once) + allow_any_instance_of(VAOS::V2::AppointmentsController).to receive( + :get_facility_memoized + ).and_return(mock_appt_location_openstruct) get '/vaos/v2/appointments?_include=facilities,clinics', params:, headers: inflection_header data = JSON.parse(response.body)['data'] expect(response).to have_http_status(:ok) expect(response.body).to be_a(String) expect(data.size).to eq(2) - expect(data[0]['attributes']['location']).to eq(mock_facility) + expect(data[0]['attributes']['location']['attributes'].to_json).to eq( + mock_appt_location_openstruct.table.to_json + ) expect(Rails.logger).to have_received(:info).with("Details for Cerner 'COL OR 1' Appointment", any_args).at_least(:once) expect(response).to match_camelized_response_schema('vaos/v2/appointments', { strict: false }) @@ -598,5 +651,89 @@ end end end + + describe 'extract_all_values' do + context 'when processing an array, hash, or openstruct' do + let(:array1) { ['a', 'b', 'c', %w[100 200 300]] } + + let(:hash1) { { a: '100', b: '200', c: '300' } } + + let(:os1) do + OpenStruct.new({ 'a' => '100', 'b' => '200', 'c' => '300', 'd' => 400 }) + end + + it 'returns an array of values from an array' do + expect(subject.send(:extract_all_values, array1)).to eq(%w[a b c 100 200 300]) + end + + it 'returns an array of values from a hash' do + expect(subject.send(:extract_all_values, hash1)).to eq(%w[100 200 300]) + end + + it 'returns an array of values from a simple openstruct' do + expect(subject.send(:extract_all_values, os1)).to eq(['100', '200', '300', 400]) + end + + it 'returns an array of values from a nested openstruct' do + expect(subject.send(:extract_all_values, + mock_appt_location_openstruct)).to eq(mock_appt_location_extracted_values) + end + end + + context 'when processing input that is not an array, hash, or openstruct' do + it 'returns input object in an array' do + expect(subject.send(:extract_all_values, 'Simple String Input')).to eq(['Simple String Input']) + end + + it 'returns input object in an array (nil)' do + expect(subject.send(:extract_all_values, nil)).to eq([nil]) + end + end + end + + describe 'contains_substring' do + context 'when checking an input array that contains a given substring' do + it 'returns true' do + expect(subject.send(:contains_substring, ['given string', 'another string', 100], 'given string')).to be(true) + end + end + + context 'when checking an input array that does not contain a given substring' do + it 'returns false' do + expect(subject.send(:contains_substring, ['given string', 'another string', 100], + 'different string')).to be(false) + end + end + + context 'when checking a non-array and a string' do + it 'returns false' do + expect(subject.send(:contains_substring, 'given string', 'given string')).to be(false) + end + end + + context 'when checking nil and a string' do + it 'returns false' do + expect(subject.send(:contains_substring, nil, 'some string')).to be(false) + end + end + + context 'when checking an array and a non-string' do + it 'returns false' do + expect(subject.send(:contains_substring, ['given string', 'another string', 100], 100)).to be(false) + end + end + + context 'when the input array contains nil' do + it 'returns false' do + expect(subject.send(:contains_substring, [nil], 'some string')).to be(false) + end + end + + context 'when the input array is empty' do + it 'returns false' do + expect(subject.send(:contains_substring, [], 'some string')).to be(false) + end + end + end end end diff --git a/spec/controllers/v0/profile/contacts_controller_spec.rb b/spec/controllers/v0/profile/contacts_controller_spec.rb index 2ddf67c1864..62131d4d71d 100644 --- a/spec/controllers/v0/profile/contacts_controller_spec.rb +++ b/spec/controllers/v0/profile/contacts_controller_spec.rb @@ -44,7 +44,7 @@ end context 'feature disabled' do - it 'returns an unauthorized status code' do + it 'returns a not found status code' do Flipper.disable(:profile_contacts) sign_in_as user expect(subject).to have_http_status(:not_found) diff --git a/spec/fixtures/pdf_fill/21P-527EZ/merge_fields.json b/spec/fixtures/pdf_fill/21P-527EZ/merge_fields.json index 4a133a57e6d..2fed16bab53 100644 --- a/spec/fixtures/pdf_fill/21P-527EZ/merge_fields.json +++ b/spec/fixtures/pdf_fill/21P-527EZ/merge_fields.json @@ -77,8 +77,7 @@ "currentEmployers": [ { "jobType": "Customer service", - "jobHoursWeek": "20", - "jobTitle": "Manager" + "jobHoursWeek": "20" } ], "maritalStatus": 1, diff --git a/spec/lib/lighthouse/benefits_claims/service_spec.rb b/spec/lib/lighthouse/benefits_claims/service_spec.rb index 27035f97ea0..d5ecd4fe022 100644 --- a/spec/lib/lighthouse/benefits_claims/service_spec.rb +++ b/spec/lib/lighthouse/benefits_claims/service_spec.rb @@ -56,6 +56,27 @@ end end + describe "when requesting a user's power of attorney" do + context 'when the user has an active power of attorney' do + it 'retrieves the power of attorney from the Lighthouse API' do + VCR.use_cassette('lighthouse/benefits_claims/power_of_attorney/200_response') do + response = @service.get_power_of_attorney + expect(response['data']['type']).to eq('individual') + expect(response['data']['attributes']['code']).to eq('067') + end + end + end + + context 'when the user does not have an active power of attorney' do + it 'retrieves the power of attorney from the Lighthouse API' do + VCR.use_cassette('lighthouse/benefits_claims/power_of_attorney/200_empty_response') do + response = @service.get_power_of_attorney + expect(response['data']).to eq({}) + end + end + end + end + describe 'when posting a form526' do it 'when given a full request body, posts to the Lighthouse API' do VCR.use_cassette('lighthouse/benefits_claims/submit526/200_response') do diff --git a/spec/lib/va_profile/models/associated_person_spec.rb b/spec/lib/va_profile/models/associated_person_spec.rb index 8aedcb5ac90..42ee2701a06 100644 --- a/spec/lib/va_profile/models/associated_person_spec.rb +++ b/spec/lib/va_profile/models/associated_person_spec.rb @@ -35,15 +35,12 @@ it 'titlecases family_name' do expect(subject.family_name).to eq('Williams') end - - it 'titlecases relationship' do - expect(subject.relationship).to eq('Unrelated Friend') - end end context 'Virtus::Attribute, String type attributes' do %i[ contact_type + relationship address_line1 address_line2 address_line3 diff --git a/spec/lib/va_profile/profile/v3/health_benefit_bio_response_spec.rb b/spec/lib/va_profile/profile/v3/health_benefit_bio_response_spec.rb index 70f51f3ed61..8cc61adcadb 100644 --- a/spec/lib/va_profile/profile/v3/health_benefit_bio_response_spec.rb +++ b/spec/lib/va_profile/profile/v3/health_benefit_bio_response_spec.rb @@ -7,17 +7,22 @@ subject { described_class.new(response) } let(:response) do - double('Faraday::Response', - status: 200, - body: { - 'profile' => { - 'health_benefit' => { - 'associated_persons' => [{ - 'contact_type' => contact_type - }] - } - } - }) + double( + 'Faraday::Response', + status: 200, + body: { + 'profile' => { + 'health_benefit' => { + 'associated_persons' => [{ + 'contact_type' => contact_type + }] + } + } + }, + response_headers: { + 'vaprofiletxauditid' => 'abc123' + } + ) end describe 'Emergency contact' do diff --git a/spec/lib/va_profile/profile/v3/service_spec.rb b/spec/lib/va_profile/profile/v3/service_spec.rb index da5ec7b9b89..cd37ee8998d 100644 --- a/spec/lib/va_profile/profile/v3/service_spec.rb +++ b/spec/lib/va_profile/profile/v3/service_spec.rb @@ -55,6 +55,19 @@ describe '#get_health_benefit_bio' do let(:user) { build(:user, :loa3, idme_uuid:) } + let(:cassette_filename) { "spec/support/vcr_cassettes/#{cassette}.yml" } + let(:cassette_data) { YAML.load_file(cassette_filename) } + let(:va_profile_tx_audit_id) do + cassette_data['http_interactions'][0]['response']['headers']['Vaprofiletxauditid'][0] + end + let(:debug_data) do + { + status:, + message:, + va_profile_tx_audit_id: + } + end + around do |ex| VCR.use_cassette(cassette) { ex.run } end @@ -68,19 +81,21 @@ expect(response.status).to eq(200) expect(response.contacts.size).to eq(4) types = response.contacts.map(&:contact_type) - valid_contact_types = [ - VAProfile::Models::AssociatedPerson::EMERGENCY_CONTACT, - VAProfile::Models::AssociatedPerson::OTHER_EMERGENCY_CONTACT, - VAProfile::Models::AssociatedPerson::PRIMARY_NEXT_OF_KIN, - VAProfile::Models::AssociatedPerson::OTHER_NEXT_OF_KIN - ] + valid_contact_types = VAProfile::Models::AssociatedPerson::PERSONAL_HEALTH_CARE_CONTACT_TYPES expect(types).to match_array(valid_contact_types) end + + it 'does not call Sentry.set_extras' do + expect(Sentry).not_to receive(:set_extras) + subject.get_health_benefit_bio + end end context '404 response' do let(:idme_uuid) { '88f572d4-91af-46ef-a393-cba6c351e252' } let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_404' } + let(:status) { 404 } + let(:message) { 'MVI201 MviNotFound The person with the identifier requested was not found in MVI.' } it 'includes messages received from the api' do response = subject.get_health_benefit_bio @@ -88,11 +103,22 @@ expect(response.contacts.size).to eq(0) expect(response.messages.size).to eq(1) end + + it 'calls Sentry.set_extras' do + expect(Sentry).to receive(:set_extras).once.with(debug_data) + subject.get_health_benefit_bio + end end context '500 response' do let(:idme_uuid) { '88f572d4-91af-46ef-a393-cba6c351e252' } let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_500' } + let(:status) { 500 } + let(:message) do + result = 'MVI203 MviResponseError MVI returned acknowledgement error code ' + result += 'AE with error detail: More Than One Active Correlation Exists' + result + end it 'includes messages recieved from the api' do response = subject.get_health_benefit_bio @@ -100,6 +126,11 @@ expect(response.contacts.size).to eq(0) expect(response.messages.size).to eq(1) end + + it 'calls Sentry.set_extras' do + expect(Sentry).to receive(:set_extras).once.with(debug_data) + subject.get_health_benefit_bio + end end context 'api timeout' do diff --git a/spec/requests/user_request_spec.rb b/spec/requests/user_request_spec.rb index 8a4765d7b88..81d719ed82c 100644 --- a/spec/requests/user_request_spec.rb +++ b/spec/requests/user_request_spec.rb @@ -1,9 +1,11 @@ # frozen_string_literal: true require 'rails_helper' +require 'support/sm_client_helpers' RSpec.describe 'Fetching user data' do include SchemaMatchers + include SM::ClientHelpers context 'GET /v0/user - when an LOA 3 user is logged in' do let(:mhv_user) { build(:user, :mhv) } @@ -11,6 +13,7 @@ let(:edipi) { '1005127153' } before do + allow(SM::Client).to receive(:new).and_return(authenticated_client) allow_any_instance_of(MHVAccountTypeService).to receive(:mhv_account_type).and_return('Premium') create(:account, idme_uuid: mhv_user.uuid) sign_in_as(mhv_user) diff --git a/spec/requests/va_profile/contacts_request_spec.rb b/spec/requests/va_profile/contacts_request_spec.rb index b44363b3ddd..4f8fef43a7a 100644 --- a/spec/requests/va_profile/contacts_request_spec.rb +++ b/spec/requests/va_profile/contacts_request_spec.rb @@ -7,29 +7,65 @@ let(:user) { build(:user, :loa3, idme_uuid:) } let(:resource) { JSON.parse(response.body) } - describe 'GET /v0/profile/contacts -> 200' do - let(:idme_uuid) { 'dd681e7d6dea41ad8b80f8d39284ef29' } + around do |ex| + VCR.use_cassette(cassette) { ex.run } + end + + describe 'GET /v0/profile/contacts' do + context '200 response' do + let(:idme_uuid) { 'dd681e7d6dea41ad8b80f8d39284ef29' } + let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_200' } - it 'responds with contacts' do - sign_in_as(user) - VCR.use_cassette('va_profile/profile/v3/health_benefit_bio_200') do + it 'responds with contacts' do + sign_in_as(user) get '/v0/profile/contacts' + expect(response).to have_http_status(:ok) + expect(response).to match_response_schema('contacts') + expect(resource['data'].size).to eq(4) + end + end + + context '401 response' do + let(:idme_uuid) { 'dd681e7d6dea41ad8b80f8d39284ef29' } + let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_200' } + + it 'responds with 401 status' do + get '/v0/profile/contacts' + expect(response).to have_http_status(:unauthorized) + end + end + + context '403 response' do + let(:user) { build(:user, :loa1) } + let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_200' } + + it 'responds with 403 status' do + sign_in_as(user) + get '/v0/profile/contacts' + expect(response).to have_http_status(:forbidden) + end + end + + context '404 response' do + let(:idme_uuid) { '88f572d4-91af-46ef-a393-cba6c351e252' } + let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_404' } + + it 'responds with 404 status' do + sign_in_as(user) + get '/v0/profile/contacts' + expect(response).to have_http_status(:not_found) end - expect(response).to have_http_status(:ok) - expect(response).to match_response_schema('contacts') - expect(resource['data'].size).to eq(4) end - end - describe 'GET /v0/profile/contacts -> 404' do - let(:idme_uuid) { '88f572d4-91af-46ef-a393-cba6c351e252' } + context '500 response' do + let(:idme_uuid) { '88f572d4-91af-46ef-a393-cba6c351e252' } + let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_500' } - it 'responds with 404 status' do - sign_in_as(user) - VCR.use_cassette('va_profile/profile/v3/health_benefit_bio_404') do + it 'responds with 500 status' do + sign_in_as(user) get '/v0/profile/contacts' + expect(response).to have_http_status(:internal_server_error) end - expect(response).to have_http_status(:not_found) end end end diff --git a/spec/services/users/services_spec.rb b/spec/services/users/services_spec.rb index 1cd9938fd1c..0d82842665f 100644 --- a/spec/services/users/services_spec.rb +++ b/spec/services/users/services_spec.rb @@ -48,6 +48,16 @@ context 'with an MHV Premium user' do let(:user) { build(:user, :mhv) } + before do + Timecop.freeze(Time.zone.parse('2017-05-01T19:25:00Z')) + VCR.insert_cassette('sm_client/session') + end + + after do + VCR.eject_cassette + Timecop.return + end + it 'returns an array including the MHV services' do %w[health-records medical-records messaging rx].each do |service| expect(subject).to include(service) diff --git a/spec/support/vcr_cassettes/lighthouse/benefits_claims/power_of_attorney/200_empty_response.yml b/spec/support/vcr_cassettes/lighthouse/benefits_claims/power_of_attorney/200_empty_response.yml new file mode 100644 index 00000000000..d7878dd339e --- /dev/null +++ b/spec/support/vcr_cassettes/lighthouse/benefits_claims/power_of_attorney/200_empty_response.yml @@ -0,0 +1,77 @@ +--- +http_interactions: +- request: + method: get + uri: https://sandbox-api.va.gov/services/claims/v2/veterans/123498767V234859/power-of-attorney + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Vets.gov Agent + Authorization: Bearer + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 04 Apr 2024 17:45:59 GMT + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '11' + Connection: + - keep-alive + Ratelimit-Remaining: + - '118' + Ratelimit-Reset: + - '3' + X-Ratelimit-Limit-Minute: + - '120' + X-Ratelimit-Remaining-Minute: + - '118' + Ratelimit-Limit: + - '120' + Etag: + - W/"7fb9d166d1a15bce0b9f085f3818946f" + Referrer-Policy: + - strict-origin-when-cross-origin + Vary: + - Origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + - SAMEORIGIN + X-Git-Sha: + - 77911592048236d8eccb0f39f5e9f758564e282b + X-Github-Repository: + - https://github.com/department-of-veterans-affairs/vets-api + X-Permitted-Cross-Domain-Policies: + - none + X-Request-Id: + - 8dd9e3bb-6159-4f92-b92d-7dbe791547e0 + X-Runtime: + - '2.017096' + X-Xss-Protection: + - '0' + Access-Control-Allow-Origin: + - "*" + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Cache-Control: + - no-cache, no-store + Pragma: + - no-cache + body: + encoding: UTF-8 + string: '{"data":{}}' + recorded_at: Thu, 04 Apr 2024 17:46:00 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/support/vcr_cassettes/lighthouse/benefits_claims/power_of_attorney/200_response.yml b/spec/support/vcr_cassettes/lighthouse/benefits_claims/power_of_attorney/200_response.yml new file mode 100644 index 00000000000..bcf3bbe002d --- /dev/null +++ b/spec/support/vcr_cassettes/lighthouse/benefits_claims/power_of_attorney/200_response.yml @@ -0,0 +1,78 @@ +--- +http_interactions: +- request: + method: get + uri: https://sandbox-api.va.gov/services/claims/v2/veterans/123498767V234859/power-of-attorney + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Vets.gov Agent + Authorization: Bearer + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + Date: + - Tue, 02 Apr 2024 14:30:58 GMT + Content-Type: + - application/json; charset=utf-8 + Connection: + - keep-alive + X-Ratelimit-Remaining-Minute: + - '119' + X-Ratelimit-Limit-Minute: + - '120' + Ratelimit-Remaining: + - '119' + Ratelimit-Limit: + - '120' + Ratelimit-Reset: + - '10' + Etag: + - W/"f674f2056c77718a448e94dc8a1ed556" + Referrer-Policy: + - strict-origin-when-cross-origin + Vary: + - Origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + - SAMEORIGIN + X-Git-Sha: + - 11de6c4d9dc0e22795b79e94395598e9c7e0fc3c + X-Github-Repository: + - https://github.com/department-of-veterans-affairs/vets-api + X-Permitted-Cross-Domain-Policies: + - none + X-Request-Id: + - f7395f08-c7c7-4726-85e4-602c6ecf40fe + X-Runtime: + - '8.308072' + X-Xss-Protection: + - '0' + Access-Control-Allow-Origin: + - "*" + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Cache-Control: + - no-cache, no-store + Pragma: + - no-cache + Transfer-Encoding: + - chunked + body: + encoding: ASCII-8BIT + string: '{"data":{"type":"individual","attributes":{"code":"067","name":"Tamara + Ellis","phoneNumber":null}}}' + recorded_at: Tue, 02 Apr 2024 14:30:58 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/support/vcr_cassettes/sm_client/session_error.yml b/spec/support/vcr_cassettes/sm_client/session_error.yml new file mode 100644 index 00000000000..7a17bfb5768 --- /dev/null +++ b/spec/support/vcr_cassettes/sm_client/session_error.yml @@ -0,0 +1,40 @@ +--- +http_interactions: + - request: + method: get + uri: "/mhv-sm-api/patient/v1/session" + body: + encoding: US-ASCII + string: "" + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Vets.gov Agent + Apptoken: + - "" + Mhvcorrelationid: + - "10616687" + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 503 + message: Service unavailable + headers: + Server: + - Apache-Coyote/1.1 + X-Powered-By: + - Servlet/2.5 JSP/2.1 + Content-Length: + - "0" + Date: + - Fri, 12 May 2017 16:15:20 GMT + body: + encoding: UTF-8 + string: "" + http_version: + recorded_at: Fri, 12 May 2017 16:15:22 GMT +recorded_with: VCR 3.0.3