Skip to content

Commit

Permalink
Merge branch 'feature/APPEALS-46324' into uat/FY24Q4.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
youfoundmanesh committed Aug 28, 2024
2 parents f22dc4e + 0c2d233 commit 14e38da
Show file tree
Hide file tree
Showing 22 changed files with 463 additions and 42 deletions.
14 changes: 7 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ GEM
coffee-script-source
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.3.3)
concurrent-ruby (1.3.4)
crack (1.0.0)
bigdecimal
rexml
Expand Down Expand Up @@ -260,7 +260,7 @@ GEM
activesupport (>= 5.0)
gyoku (1.3.1)
builder (>= 2.1.2)
hashdiff (1.1.0)
hashdiff (1.1.1)
hashie (4.1.0)
httparty (0.18.1)
mime-types (~> 3.0)
Expand Down Expand Up @@ -310,7 +310,7 @@ GEM
mini_magick (4.11.0)
mini_mime (1.1.5)
mini_portile2 (2.8.7)
minitest (5.24.1)
minitest (5.25.0)
moment_timezone-rails (0.5.14)
momentjs-rails (~> 2.15.1)
momentjs-rails (2.15.1)
Expand Down Expand Up @@ -358,7 +358,7 @@ GEM
public_suffix (5.1.1)
puma (5.6.4)
nio4r (~> 2.0)
racc (1.8.0)
racc (1.8.1)
rack (2.2.9)
rack-cors (1.1.1)
rack (>= 2.0.0)
Expand Down Expand Up @@ -426,7 +426,7 @@ GEM
regexp_parser (2.8.3)
request_store (1.5.0)
rack (>= 1.4)
rexml (3.3.1)
rexml (3.3.5)
strscan
rspec (3.10.0)
rspec-core (~> 3.10.0)
Expand Down Expand Up @@ -570,7 +570,7 @@ GEM
xpath (3.2.0)
nokogiri (~> 1.8)
zaru (0.3.0)
zeitwerk (2.6.16)
zeitwerk (2.6.17)
zero_downtime_migrations (0.0.7)
activerecord

Expand Down Expand Up @@ -653,4 +653,4 @@ DEPENDENCIES
zero_downtime_migrations

BUNDLED WITH
2.4.19
2.4.22
10 changes: 10 additions & 0 deletions app/assets/stylesheets/_commons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,16 @@ dd {
}
}

.cf-icon-external-link {
vertical-align: -.45ex;
width: 1em;
height: 1em;

path {
fill: $cf-link;
}
}

.cf-icon-close {
display: block;
margin: auto;
Expand Down
7 changes: 6 additions & 1 deletion app/controllers/api/v1/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ def sensitive_record
end

def forbidden(reason = "Forbidden: unspecified")
render json: { status: reason }, status: 403
render json: {
status: reason,
featureToggles: {
checkUserSensitivity: FeatureToggle.enabled?(:check_user_sensitivity)
}
}, status: :forbidden
end

def missing_header(header)
Expand Down
5 changes: 5 additions & 0 deletions app/controllers/api/v2/manifests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ def start
manifest = Manifest.includes(:sources, :records).find_or_create_by_user(user: current_user, file_number: file_number)
manifest.start!
render json: json_manifests(manifest)
rescue BGS::SensitivityLevelCheckFailure
forbidden("This user does not have permission to access this information")
end

def refresh
Expand All @@ -15,6 +17,8 @@ def refresh

manifest.start!
render json: json_manifests(manifest)
rescue BGS::SensitivityLevelCheckFailure
forbidden("This user does not have permission to access this information")
end

def progress
Expand All @@ -23,6 +27,7 @@ def progress
files_download ||= FilesDownload.find_with_manifest(manifest_id: params[:id], user_id: current_user.id)
end
return record_not_found unless files_download

render json: json_manifests(files_download.manifest)
end

Expand Down
1 change: 1 addition & 0 deletions app/exceptions/bgs_errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ class InvalidApplication < StandardError; end
class NoActiveStations < StandardError; end
class NoCaseflowAccess < StandardError; end
class StationAssertionRequired < StandardError; end
class SensitivityLevelCheckFailure < StandardError; end
end
18 changes: 17 additions & 1 deletion app/models/manifest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,18 @@ def start!
# Reset stale manifests.
update!(fetched_files_status: :initialized) if ready_for_refresh?

vbms_source.start!
if FeatureToggle.enabled?(:check_user_sensitivity)
if sensitivity_checker.sensitivity_levels_compatible?(
user: user,
veteran_file_number: file_number
)
vbms_source.start!
else
raise BGS::SensitivityLevelCheckFailure.new, "Unauthorized"
end
else
vbms_source.start!
end
vva_source.start! unless FeatureToggle.enabled?(:skip_vva)
end

Expand All @@ -41,6 +52,7 @@ def download_and_package_files!
expiration: SECONDS_TO_AUTO_UNLOCK)
s.lock(SECONDS_TO_AUTO_UNLOCK) do
return if pending?

update(fetched_files_status: :pending)
end

Expand Down Expand Up @@ -168,4 +180,8 @@ def update_veteran_info
veteran_last_name: veteran.last_name || "",
veteran_last_four_ssn: veteran.last_four_ssn || "")
end

def sensitivity_checker
@sensitivity_checker ||= SensitivityChecker.new
end
end
1 change: 1 addition & 0 deletions app/models/manifest_source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class ManifestSource < ApplicationRecord

def start!
return if current? || processing?

V2::DownloadManifestJob.perform_later(self, RequestStore[:current_user])
rescue StandardError
update(status: :initialized)
Expand Down
45 changes: 45 additions & 0 deletions app/services/external_api/bgs_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,51 @@ def initialize(client: nil)
@client = client || self.class.init_client
end

def sensitivity_level_for_user(user)
fail "Invalid user" if !user.instance_of?(User)

participant_id = user.participant_id

Rails.cache.fetch("sensitivity_level_for_user_id_#{user.id}", expires_in: 1.hour) do
MetricsService.record(
"Efolder BGS: sensitivity level for user #{user.id}",
service: :bgs,
name: "security.find_person_scrty_log_by_ptcpnt_id"
) do
response = client.security.find_person_scrty_log_by_ptcpnt_id(participant_id)

response.key?(:scrty_level_type_cd) ? Integer(response[:scrty_level_type_cd]) : 0
rescue BGS::ShareError
0
end
end
end

def sensitivity_level_for_veteran(veteran_file_number)
vet_info = fetch_veteran_info(veteran_file_number)

participant_id = vet_info.present? ? vet_info[:participant_id] : nil

fail "Invalid veteran" if participant_id.blank?

Rails.cache.fetch("sensitivity_level_for_veteran_participant_id_#{participant_id}", expires_in: 1.hour) do
MetricsService.record(
"Efolder BGS: sensitivity level for veteran participant ID #{participant_id}",
service: :bgs,
name: "security.find_sensitivity_level_by_participant_id"
) do
response = client.security.find_sensitivity_level_by_participant_id(participant_id)

# guard clause for no response
return 0 if response.blank?

response&.key?(:scrty_level_type_cd) ? Integer(response[:scrty_level_type_cd]) : 0
rescue BGS::ShareError
0
end
end
end

def parse_veteran_info(veteran_data)
ssn = veteran_data[:ssn] ? veteran_data[:ssn] : veteran_data[:soc_sec_number]
last_four_ssn = ssn ? ssn[ssn.length - 4..ssn.length] : nil
Expand Down
16 changes: 16 additions & 0 deletions app/services/external_api/vbms_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ def self.fetch_documents_for(download)
end

def self.v2_fetch_documents_for(veteran_file_number)
verify_user_veteran_access(veteran_file_number)

documents = []

if FeatureToggle.enabled?(:use_ce_api)
Expand All @@ -44,6 +46,8 @@ def self.v2_fetch_documents_for(veteran_file_number)
end

def self.fetch_delta_documents_for(veteran_file_number, begin_date_range, end_date_range = Time.zone.now)
verify_user_veteran_access(veteran_file_number)

documents = []

if FeatureToggle.enabled?(:use_ce_api)
Expand All @@ -69,6 +73,8 @@ def self.fetch_document_file(document)
end

def self.v2_fetch_document_file(document)
verify_user_veteran_access(document.file_number)

if FeatureToggle.enabled?(:use_ce_api)
# Not using #send_and_log_request because logging to MetricService implemeneted in CE API gem
# Method call returns the response body, so no need to return response.content/body
Expand Down Expand Up @@ -110,4 +116,14 @@ def self.vbms_client

@vbms_client = init_client
end

def self.verify_user_veteran_access(veteran_file_number)
return if !FeatureToggle.enabled?(:check_user_sensitivity)

raise "User does not have permission to access this information" unless
SensitivityChecker.new.sensitivity_levels_compatible?(
user: RequestStore[:current_user],
veteran_file_number: veteran_file_number
)
end
end
18 changes: 18 additions & 0 deletions app/services/sensitivity_checker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

class SensitivityChecker
def sensitivity_levels_compatible?(user:, veteran_file_number:)
bgs_service.sensitivity_level_for_user(user) >=
bgs_service.sensitivity_level_for_veteran(veteran_file_number)
rescue StandardError => error
ExceptionLogger.capture(error)

false
end

private

def bgs_service
@bgs_service ||= BGSService.new
end
end
1 change: 1 addition & 0 deletions client/src/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE';
export const SET_MANIFEST_ID = 'SET_MANIFEST_ID';
export const SET_RECENT_DOWNLOADS = 'SET_RECENT_DOWNLOADS';
export const SET_SEARCH_TEXT = 'SET_SEARCH_TEXT';
export const SET_SHOW_UNAUTHORIZED_VETERAN_MESSAGE = 'SET_SHOW_UNAUTHORIZED_VETERAN_MESSAGE';
export const SET_VETERAN_ID = 'SET_VETERAN_ID';
export const SET_VETERAN_NAME = 'SET_VETERAN_NAME';
export const SHOW_CONFIRM_DOWNLOAD_MODAL = 'SHOW_CONFIRM_DOWNLOAD_MODAL';
6 changes: 6 additions & 0 deletions client/src/actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
SET_MANIFEST_ID,
SET_RECENT_DOWNLOADS,
SET_SEARCH_TEXT,
SET_SHOW_UNAUTHORIZED_VETERAN_MESSAGE,
SET_VETERAN_ID,
SET_VETERAN_NAME,
SHOW_CONFIRM_DOWNLOAD_MODAL
Expand Down Expand Up @@ -56,6 +57,11 @@ export const setDocumentSources = (sources) => ({
payload: sources
});

export const setShowUnauthorizedVeteranMessage = (showMessage) => ({
type: SET_SHOW_UNAUTHORIZED_VETERAN_MESSAGE,
payload: showMessage
});

export const setErrorMessage = (msg) => ({
type: SET_ERROR_MESSAGE,
payload: msg
Expand Down
13 changes: 12 additions & 1 deletion client/src/apiActions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
setDocumentsFetchStatus,
setDocumentSources,
setErrorMessage,
setShowUnauthorizedVeteranMessage,
setManifestId,
setRecentDownloads,
setVeteranId,
Expand Down Expand Up @@ -165,6 +166,10 @@ export const restartManifestFetch = (manifestId, csrfToken) => (dispatch) => {
};

export const startManifestFetch = (veteranId, csrfToken, redirectFunction) => (dispatch) => {
// Reset any error messages currently being displayed
dispatch(setShowUnauthorizedVeteranMessage(false));
dispatch(setErrorMessage(''));

postRequest('/api/v2/manifests/', csrfToken, { 'FILE-NUMBER': veteranId }).
then(
(resp) => {
Expand All @@ -175,7 +180,13 @@ export const startManifestFetch = (veteranId, csrfToken, redirectFunction) => (d
dispatch(setManifestId(manifestId));
redirectFunction(`/downloads/${manifestId}`);
},
(err) => dispatch(setErrorMessage(buildErrorMessageFromResponse(err.response)))
(err) => {
if (err.response.statusCode === 403 && err.response.body.featureToggles.checkUserSensitivity === true) {
dispatch(setShowUnauthorizedVeteranMessage(true));
} else {
dispatch(setErrorMessage(buildErrorMessageFromResponse(err.response)));
}
}
);
};

Expand Down
2 changes: 1 addition & 1 deletion client/src/components/AlertBanner.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default class AlertBanner extends React.PureComponent {
break;
}

return <div className={`usa-alert ${alertTypeClass}`} role="alert">
return <div className={`usa-alert ${alertTypeClass}`} role="alert" style={this.props.inlineStyles}>
<div className="usa-alert-body">
<h2 className="usa-alert-heading">{this.props.title}</h2>
<div className="usa-alert-text" {...reduceDoubleTopMargin}>{this.props.children}</div>
Expand Down
Loading

0 comments on commit 14e38da

Please sign in to comment.