From c468255d505ea6ae6fd980f7928c0767a7e85e91 Mon Sep 17 00:00:00 2001 From: breedbah Date: Thu, 20 Jul 2023 13:50:25 -0400 Subject: [PATCH 01/62] Added feature toggles to index.html.rb --- app/views/queue/index.html.erb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/queue/index.html.erb b/app/views/queue/index.html.erb index e0ba7a1038a..6c6c22fda9a 100644 --- a/app/views/queue/index.html.erb +++ b/app/views/queue/index.html.erb @@ -53,7 +53,9 @@ cavc_remand_granted_substitute_appellant: FeatureToggle.enabled?(:cavc_remand_granted_substitute_appellant, user: current_user), cavc_dashboard_workflow: FeatureToggle.enabled?(:cavc_dashboard_workflow, user: current_user), cc_appeal_workflow: FeatureToggle.enabled?(:cc_appeal_workflow, user: current_user), - cc_vacatur_visibility: FeatureToggle.enabled?(:cc_vacatur_visibility, user: current_user) + cc_vacatur_visibility: FeatureToggle.enabled?(:cc_vacatur_visibility, user: current_user), + webex_conference_selection: FeatureToggle.enabled?(:webex_conference_selection, user: current_user), + pexip_conference_selection: FeatureToggle.enabled?(:pexip_conference_selection, user: current_user) } }) %> <% end %> From 7f0bae22d3c981cc818e5fa87ee2b37336639225 Mon Sep 17 00:00:00 2001 From: breedbah Date: Fri, 21 Jul 2023 12:07:15 -0400 Subject: [PATCH 02/62] Added toggle to index.html.erb --- app/views/queue/index.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/queue/index.html.erb b/app/views/queue/index.html.erb index 6c6c22fda9a..42546db9ac0 100644 --- a/app/views/queue/index.html.erb +++ b/app/views/queue/index.html.erb @@ -24,6 +24,7 @@ canEditCavcDashboards: current_user.can_edit_cavc_dashboards?, canViewCavcDashboards: current_user.can_view_cavc_dashboards?, userIsCobAdmin: ClerkOfTheBoard.singleton.admins.include?(current_user), + userCanScheduleWebexVirtual: current_user.can_schedule_webex_virtual? featureToggles: { collect_video_and_central_emails: FeatureToggle.enabled?(:collect_video_and_central_emails, user: current_user), enable_hearing_time_slots: FeatureToggle.enabled?(:enable_hearing_time_slots, user: current_user), @@ -54,8 +55,7 @@ cavc_dashboard_workflow: FeatureToggle.enabled?(:cavc_dashboard_workflow, user: current_user), cc_appeal_workflow: FeatureToggle.enabled?(:cc_appeal_workflow, user: current_user), cc_vacatur_visibility: FeatureToggle.enabled?(:cc_vacatur_visibility, user: current_user), - webex_conference_selection: FeatureToggle.enabled?(:webex_conference_selection, user: current_user), - pexip_conference_selection: FeatureToggle.enabled?(:pexip_conference_selection, user: current_user) + conference_selection: FeatureToggle.enabled?(:conference_selection, user:current_user) } }) %> <% end %> From 5fe469085eb4a8d54c2351cab6cad82fa12d763f Mon Sep 17 00:00:00 2001 From: 631862 Date: Fri, 21 Jul 2023 15:04:18 -0400 Subject: [PATCH 03/62] Progress on conference types radio field --- client/COPY.json | 5 ++++ client/app/queue/OrganizationUsers.jsx | 40 +++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/client/COPY.json b/client/COPY.json index 9bd85705be1..9e4fcd471e3 100644 --- a/client/COPY.json +++ b/client/COPY.json @@ -772,6 +772,11 @@ "USER_MANAGEMENT_GIVE_USER_ADMIN_RIGHTS_BUTTON_TEXT": "Add admin rights", "USER_MANAGEMENT_REMOVE_USER_ADMIN_RIGHTS_BUTTON_TEXT": "Remove admin rights", "USER_MANAGEMENT_REMOVE_USER_FROM_ORG_BUTTON_TEXT": "Remove from team", + "USER_MANAGEMENT_SELECT_HEARINGS_CONFERENCE_TYPE": "Schedule hearings using:", + "USER_MANAGMENT_HEARINGS_CONFERENCE_TYPES": { + "PEXIP": "Pexip", + "WEBEX": "Webex" + }, "MEMBERSHIP_REQUEST_ACTION_SUCCESS_TITLE": "You successfully %s %s's request", "MEMBERSHIP_REQUEST_ACTION_SUCCESS_MESSAGE": "The user was %s regular member access to %s.", "VHA_MEMBERSHIP_REQUEST_AUTOMATIC_VHA_ACCESS_NOTE": "Note: If you are requesting specialized access and are not a member of the general VHA group, you will automatically be given access to the general VHA group if your request is approved.", diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 3497cf30792..6b6b3ea4d90 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -1,6 +1,6 @@ /* eslint-disable no-nested-ternary */ /* eslint-disable max-len */ -import React from 'react'; +import React, { useState } from 'react'; import PropTypes from 'prop-types'; import { css } from 'glamor'; import { sprintf } from 'sprintf-js'; @@ -10,6 +10,7 @@ import AppSegment from '@department-of-veterans-affairs/caseflow-frontend-toolki import ApiUtil from '../util/ApiUtil'; import Alert from '../components/Alert'; import Button from '../components/Button'; +import RadioField from '../components/RadioField'; import SearchableDropdown from '../components/SearchableDropdown'; import { LOGO_COLORS } from '../constants/AppConstants'; @@ -44,6 +45,28 @@ const listStyle = css({ listStyle: 'none' }); +const radioOptions = [ + { displayText: 'Pexip', + value: '1'}, + { displayText: 'Webex', + value: '2' } +]; + +// const [value, setValue] = useState('1'); +// const onChange = (val) => setValue(val); +// const selectConferenceTypeRadioField = () => { +// // const [value, setValue] = useState('1'); +// // const onChange = (val) => setValue(val); + +//
+//
+// } + export default class OrganizationUsers extends React.PureComponent { constructor(props) { super(props); @@ -240,6 +263,19 @@ export default class OrganizationUsers extends React.PureComponent { loading={this.state.removingUser[user.id]} onClick={this.removeUser(user)} /> + // selectConferenceTypeRadioField = () => { + // // const [value, setValue] = useState('1'); + // // const onChange = (val) => setValue(val); + + //
+ //
+ // } + mainContent = () => { const judgeTeam = this.state.judgeTeam; const dvcTeam = this.state.dvcTeam; @@ -249,11 +285,13 @@ export default class OrganizationUsers extends React.PureComponent { return
  • {this.formatName(user)} + {/* { this.selectConferenceTypeRadioField() } */} { judgeTeam && admin && ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} ) } { dvcTeam && dvc && ( {COPY.USER_MANAGEMENT_DVC_LABEL} ) } { judgeTeam && !admin && ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} ) } { (judgeTeam || dvcTeam) && admin && ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} ) }
  • + {/* { this.selectConferenceTypeRadioField()} */} { (judgeTeam || dvcTeam) && admin ?
    :
    From 6780e007ba027a79ab4802473edd58cfd79f5774 Mon Sep 17 00:00:00 2001 From: 631862 Date: Mon, 24 Jul 2023 12:18:47 -0400 Subject: [PATCH 04/62] adding conference type selection logic --- client/app/queue/OrganizationUsers.jsx | 51 +++++++++++--------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 6b6b3ea4d90..2409bcdf633 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -49,24 +49,9 @@ const radioOptions = [ { displayText: 'Pexip', value: '1'}, { displayText: 'Webex', - value: '2' } + value: '2'} ]; -// const [value, setValue] = useState('1'); -// const onChange = (val) => setValue(val); -// const selectConferenceTypeRadioField = () => { -// // const [value, setValue] = useState('1'); -// // const onChange = (val) => setValue(val); - -//
    -//
    -// } - export default class OrganizationUsers extends React.PureComponent { constructor(props) { super(props); @@ -230,6 +215,12 @@ export default class OrganizationUsers extends React.PureComponent { }); } + modifyConferenceType = () => { + const [value, setValue] = useState('1'); + + const onChange = (val) => setValue(val); + } + asyncLoadUser = (inputValue) => { // don't search till we have min length input if (inputValue.length < 2) { @@ -263,18 +254,19 @@ export default class OrganizationUsers extends React.PureComponent { loading={this.state.removingUser[user.id]} onClick={this.removeUser(user)} />
    - // selectConferenceTypeRadioField = () => { - // // const [value, setValue] = useState('1'); - // // const onChange = (val) => setValue(val); - - //
    - //
    - // } + selectConferenceTypeRadioField = () => { + // const [value, setValue] = useState('1'); + // const onChange = (val) = setValue(val); + +
    +
    + } mainContent = () => { const judgeTeam = this.state.judgeTeam; @@ -285,7 +277,7 @@ export default class OrganizationUsers extends React.PureComponent { return
  • {this.formatName(user)} - {/* { this.selectConferenceTypeRadioField() } */} + { this.selectConferenceTypeRadioField() } { judgeTeam && admin && ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} ) } { dvcTeam && dvc && ( {COPY.USER_MANAGEMENT_DVC_LABEL} ) } { judgeTeam && !admin && ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} ) } @@ -297,6 +289,7 @@ export default class OrganizationUsers extends React.PureComponent {
    { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } { this.removeUserButton(user) } + {/* { this.selectConferenceTypeRadioField() } */}
    } ; }); From 72cc0925a7518059fd9fea2541df20742d139f97 Mon Sep 17 00:00:00 2001 From: Ariana Konhilas Date: Mon, 24 Jul 2023 17:02:33 -0400 Subject: [PATCH 05/62] APPEALS-25141: created migrations to add pexip bool column to users virtual hearings and conference links --- db/migrate/20230724205500_add_pexip_to_virtual_hearings.rb | 5 +++++ db/migrate/20230724205643_add_pexip_to_conference_links.rb | 5 +++++ db/migrate/20230724205759_add_pexip_to_users.rb | 5 +++++ 3 files changed, 15 insertions(+) create mode 100644 db/migrate/20230724205500_add_pexip_to_virtual_hearings.rb create mode 100644 db/migrate/20230724205643_add_pexip_to_conference_links.rb create mode 100644 db/migrate/20230724205759_add_pexip_to_users.rb diff --git a/db/migrate/20230724205500_add_pexip_to_virtual_hearings.rb b/db/migrate/20230724205500_add_pexip_to_virtual_hearings.rb new file mode 100644 index 00000000000..a577e0ca816 --- /dev/null +++ b/db/migrate/20230724205500_add_pexip_to_virtual_hearings.rb @@ -0,0 +1,5 @@ +class AddPexipToVirtualHearings < ActiveRecord::Migration[5.2] + def change + add_column :virtual_hearings, :pexip, :boolean + end +end diff --git a/db/migrate/20230724205643_add_pexip_to_conference_links.rb b/db/migrate/20230724205643_add_pexip_to_conference_links.rb new file mode 100644 index 00000000000..88b5454ef7b --- /dev/null +++ b/db/migrate/20230724205643_add_pexip_to_conference_links.rb @@ -0,0 +1,5 @@ +class AddPexipToConferenceLinks < ActiveRecord::Migration[5.2] + def change + add_column :conference_links, :pexip, :boolean + end +end diff --git a/db/migrate/20230724205759_add_pexip_to_users.rb b/db/migrate/20230724205759_add_pexip_to_users.rb new file mode 100644 index 00000000000..ee6e505ff5b --- /dev/null +++ b/db/migrate/20230724205759_add_pexip_to_users.rb @@ -0,0 +1,5 @@ +class AddPexipToUsers < ActiveRecord::Migration[5.2] + def change + add_column :users, :pexip, :boolean + end +end From e18314c5e619dcc83a4891b0eecc1c05f6d585a4 Mon Sep 17 00:00:00 2001 From: Ariana Konhilas Date: Mon, 24 Jul 2023 17:19:41 -0400 Subject: [PATCH 06/62] APPEALS-25141: set default value to true on users --- db/migrate/20230724205759_add_pexip_to_users.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20230724205759_add_pexip_to_users.rb b/db/migrate/20230724205759_add_pexip_to_users.rb index ee6e505ff5b..f9839906fd1 100644 --- a/db/migrate/20230724205759_add_pexip_to_users.rb +++ b/db/migrate/20230724205759_add_pexip_to_users.rb @@ -1,5 +1,5 @@ class AddPexipToUsers < ActiveRecord::Migration[5.2] def change - add_column :users, :pexip, :boolean + add_column :users, :pexip, :boolean, default: true end end From 07be38748148ec34c294f75d4e83252c9ab125f0 Mon Sep 17 00:00:00 2001 From: 631862 Date: Mon, 24 Jul 2023 17:48:19 -0400 Subject: [PATCH 07/62] Work on radio field selection --- client/app/queue/OrganizationUsers.jsx | 35 ++++++------ .../queue/SelectConferenceTypeRadioField.jsx | 54 +++++++++++++++++++ 2 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 client/app/queue/SelectConferenceTypeRadioField.jsx diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 2409bcdf633..5d6ce0570e2 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -17,6 +17,7 @@ import { LOGO_COLORS } from '../constants/AppConstants'; import COPY from '../../COPY'; import LoadingDataDisplay from '../components/LoadingDataDisplay'; import MembershipRequestTable from './MembershipRequestTable'; +import SelectConferenceTypeRadioField from './SelectConferenceTypeRadioField'; const userStyle = css({ margin: '.5rem 0 .5rem', @@ -68,10 +69,18 @@ export default class OrganizationUsers extends React.PureComponent { addingUser: null, changingAdminRights: {}, removingUser: {}, - isVhaOrg: false + isVhaOrg: false, + value: '1' }; } + onChange = (value) => { + this.setState({ + value + }); + } + // handleChange = (event) => (event.target.value); + loadingPromise = () => { return ApiUtil.get(`/organizations/${this.props.organization}/users`).then((response) => { this.setState({ @@ -215,12 +224,6 @@ export default class OrganizationUsers extends React.PureComponent { }); } - modifyConferenceType = () => { - const [value, setValue] = useState('1'); - - const onChange = (val) => setValue(val); - } - asyncLoadUser = (inputValue) => { // don't search till we have min length input if (inputValue.length < 2) { @@ -254,19 +257,16 @@ export default class OrganizationUsers extends React.PureComponent { loading={this.state.removingUser[user.id]} onClick={this.removeUser(user)} /> - selectConferenceTypeRadioField = () => { - // const [value, setValue] = useState('1'); - // const onChange = (val) = setValue(val); - + selectConferenceTypeRadioField = () =>
    - } mainContent = () => { const judgeTeam = this.state.judgeTeam; @@ -277,19 +277,18 @@ export default class OrganizationUsers extends React.PureComponent { return
  • {this.formatName(user)} - { this.selectConferenceTypeRadioField() } { judgeTeam && admin && ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} ) } { dvcTeam && dvc && ( {COPY.USER_MANAGEMENT_DVC_LABEL} ) } { judgeTeam && !admin && ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} ) } { (judgeTeam || dvcTeam) && admin && ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} ) }
  • - {/* { this.selectConferenceTypeRadioField()} */} + { (judgeTeam || dvcTeam) && admin ?
    :
    { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } { this.removeUserButton(user) } - {/* { this.selectConferenceTypeRadioField() } */} + {/* */}
    }
    ; }); diff --git a/client/app/queue/SelectConferenceTypeRadioField.jsx b/client/app/queue/SelectConferenceTypeRadioField.jsx new file mode 100644 index 00000000000..75732367e22 --- /dev/null +++ b/client/app/queue/SelectConferenceTypeRadioField.jsx @@ -0,0 +1,54 @@ +import React, { useState } from 'react'; +import RadioField from '../components/RadioField'; + +// const radioOptions = [ +// { displayText: 'Pexip', +// value: '1'}, +// { displayText: 'Webex', +// value: '2'} +// ]; + +// export default class SelectConferenceTypeRadioField extends React.PureComponent { +// constructor(props) { +// super(props); + +// this.state = { +// value: '1' +// } +// } + +// render = () => +//
    +//
    +// } +const radioOptions = [ + { displayText: 'Pexip', + value: '1'}, + { displayText: 'Webex', + value: '2'} +]; + +const SelectConferenceTypeRadioField = () => { + const [value, setValue] = useState("1") + + return ( +
    + setValue(value)} + vertical + />
    + ); +} + +export default SelectConferenceTypeRadioField; From 4d9694c73554cca980873805e9a8bc07a658cb42 Mon Sep 17 00:00:00 2001 From: 631862 Date: Mon, 24 Jul 2023 18:17:08 -0400 Subject: [PATCH 08/62] Fixed errors with conference selection radio field --- client/app/queue/OrganizationUsers.jsx | 22 ++++++------- .../queue/SelectConferenceTypeRadioField.jsx | 33 ++----------------- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 5d6ce0570e2..216a2050a1a 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -257,16 +257,16 @@ export default class OrganizationUsers extends React.PureComponent { loading={this.state.removingUser[user.id]} onClick={this.removeUser(user)} /> - selectConferenceTypeRadioField = () => -
    -
    + // selectConferenceTypeRadioField = () => + //
    + //
    mainContent = () => { const judgeTeam = this.state.judgeTeam; @@ -282,7 +282,7 @@ export default class OrganizationUsers extends React.PureComponent { { judgeTeam && !admin && ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} ) } { (judgeTeam || dvcTeam) && admin && ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} ) } - + { (judgeTeam || dvcTeam) && admin ?
    :
    diff --git a/client/app/queue/SelectConferenceTypeRadioField.jsx b/client/app/queue/SelectConferenceTypeRadioField.jsx index 75732367e22..a6aafca75f8 100644 --- a/client/app/queue/SelectConferenceTypeRadioField.jsx +++ b/client/app/queue/SelectConferenceTypeRadioField.jsx @@ -1,33 +1,6 @@ import React, { useState } from 'react'; import RadioField from '../components/RadioField'; -// const radioOptions = [ -// { displayText: 'Pexip', -// value: '1'}, -// { displayText: 'Webex', -// value: '2'} -// ]; - -// export default class SelectConferenceTypeRadioField extends React.PureComponent { -// constructor(props) { -// super(props); - -// this.state = { -// value: '1' -// } -// } - -// render = () => -//
    -//
    -// } const radioOptions = [ { displayText: 'Pexip', value: '1'}, @@ -35,17 +8,17 @@ const radioOptions = [ value: '2'} ]; -const SelectConferenceTypeRadioField = () => { +const SelectConferenceTypeRadioField = ({name}) => { const [value, setValue] = useState("1") return (
    setValue(value)} + onChange={(newValue) => setValue(newValue)} vertical />
    ); From 3264c4b783ca760d09dfd06c40988dcda53a41e9 Mon Sep 17 00:00:00 2001 From: 631862 Date: Tue, 25 Jul 2023 12:04:49 -0400 Subject: [PATCH 09/62] Clean up code after new import file --- client/app/queue/OrganizationUsers.jsx | 29 +------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 216a2050a1a..fbf421d1d60 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -1,6 +1,6 @@ /* eslint-disable no-nested-ternary */ /* eslint-disable max-len */ -import React, { useState } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import { css } from 'glamor'; import { sprintf } from 'sprintf-js'; @@ -10,7 +10,6 @@ import AppSegment from '@department-of-veterans-affairs/caseflow-frontend-toolki import ApiUtil from '../util/ApiUtil'; import Alert from '../components/Alert'; import Button from '../components/Button'; -import RadioField from '../components/RadioField'; import SearchableDropdown from '../components/SearchableDropdown'; import { LOGO_COLORS } from '../constants/AppConstants'; @@ -46,13 +45,6 @@ const listStyle = css({ listStyle: 'none' }); -const radioOptions = [ - { displayText: 'Pexip', - value: '1'}, - { displayText: 'Webex', - value: '2'} -]; - export default class OrganizationUsers extends React.PureComponent { constructor(props) { super(props); @@ -74,13 +66,6 @@ export default class OrganizationUsers extends React.PureComponent { }; } - onChange = (value) => { - this.setState({ - value - }); - } - // handleChange = (event) => (event.target.value); - loadingPromise = () => { return ApiUtil.get(`/organizations/${this.props.organization}/users`).then((response) => { this.setState({ @@ -257,17 +242,6 @@ export default class OrganizationUsers extends React.PureComponent { loading={this.state.removingUser[user.id]} onClick={this.removeUser(user)} />
    - // selectConferenceTypeRadioField = () => - //
    - //
    - mainContent = () => { const judgeTeam = this.state.judgeTeam; const dvcTeam = this.state.dvcTeam; @@ -288,7 +262,6 @@ export default class OrganizationUsers extends React.PureComponent {
    { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } { this.removeUserButton(user) } - {/* */}
    }
    ; }); From fc72e956a914ed0ed1f5ebc46eac94da68b05017 Mon Sep 17 00:00:00 2001 From: 631862 Date: Tue, 25 Jul 2023 12:11:08 -0400 Subject: [PATCH 10/62] Update copy file and state --- client/COPY.json | 4 ---- client/app/queue/OrganizationUsers.jsx | 1 - client/app/queue/SelectConferenceTypeRadioField.jsx | 3 ++- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/client/COPY.json b/client/COPY.json index 9e4fcd471e3..f02e14b0e86 100644 --- a/client/COPY.json +++ b/client/COPY.json @@ -773,10 +773,6 @@ "USER_MANAGEMENT_REMOVE_USER_ADMIN_RIGHTS_BUTTON_TEXT": "Remove admin rights", "USER_MANAGEMENT_REMOVE_USER_FROM_ORG_BUTTON_TEXT": "Remove from team", "USER_MANAGEMENT_SELECT_HEARINGS_CONFERENCE_TYPE": "Schedule hearings using:", - "USER_MANAGMENT_HEARINGS_CONFERENCE_TYPES": { - "PEXIP": "Pexip", - "WEBEX": "Webex" - }, "MEMBERSHIP_REQUEST_ACTION_SUCCESS_TITLE": "You successfully %s %s's request", "MEMBERSHIP_REQUEST_ACTION_SUCCESS_MESSAGE": "The user was %s regular member access to %s.", "VHA_MEMBERSHIP_REQUEST_AUTOMATIC_VHA_ACCESS_NOTE": "Note: If you are requesting specialized access and are not a member of the general VHA group, you will automatically be given access to the general VHA group if your request is approved.", diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index fbf421d1d60..d8be72d94db 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -62,7 +62,6 @@ export default class OrganizationUsers extends React.PureComponent { changingAdminRights: {}, removingUser: {}, isVhaOrg: false, - value: '1' }; } diff --git a/client/app/queue/SelectConferenceTypeRadioField.jsx b/client/app/queue/SelectConferenceTypeRadioField.jsx index a6aafca75f8..da3a5b34e46 100644 --- a/client/app/queue/SelectConferenceTypeRadioField.jsx +++ b/client/app/queue/SelectConferenceTypeRadioField.jsx @@ -1,5 +1,6 @@ import React, { useState } from 'react'; import RadioField from '../components/RadioField'; +import COPY from '../../COPY'; const radioOptions = [ { displayText: 'Pexip', @@ -14,7 +15,7 @@ const SelectConferenceTypeRadioField = ({name}) => { return (
    Date: Wed, 26 Jul 2023 15:26:35 -0400 Subject: [PATCH 11/62] APPEALS-25112 Added styling for radio field component --- client/app/queue/OrganizationUsers.jsx | 41 ++++++++++++------- .../queue/SelectConferenceTypeRadioField.jsx | 4 +- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index d8be72d94db..0a38880623e 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -39,11 +39,18 @@ const buttonStyle = css({ const buttonContainerStyle = css({ borderBottom: '1rem solid gray', borderWidth: '1px', - padding: '.5rem 0 2rem', + padding: '.5rem 7rem 2rem 0', + display: 'flex', + justifyContent: 'space-between', + flexWrap: 'wrap' }); const listStyle = css({ listStyle: 'none' }); +const radioContainerStyle = css({ + padding: '-5rem 5rem 2rem 2rem', + marginTop: '-3.8rem' +}) export default class OrganizationUsers extends React.PureComponent { constructor(props) { @@ -249,19 +256,25 @@ export default class OrganizationUsers extends React.PureComponent { const style = i === 0 ? topUserStyle : userStyle; return -
  • {this.formatName(user)} - { judgeTeam && admin && ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} ) } - { dvcTeam && dvc && ( {COPY.USER_MANAGEMENT_DVC_LABEL} ) } - { judgeTeam && !admin && ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} ) } - { (judgeTeam || dvcTeam) && admin && ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} ) } -
  • - - { (judgeTeam || dvcTeam) && admin ? -
    : -
    - { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } - { this.removeUserButton(user) } -
    } +
    +
  • {this.formatName(user)} + { judgeTeam && admin && ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} ) } + { dvcTeam && dvc && ( {COPY.USER_MANAGEMENT_DVC_LABEL} ) } + { judgeTeam && !admin && ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} ) } + { (judgeTeam || dvcTeam) && admin && ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} ) } +
  • + { (judgeTeam || dvcTeam) && admin ? +
    : +
    +
    + { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } + { this.removeUserButton(user) } +
    +
    + +
    +
    } +
    ; }); diff --git a/client/app/queue/SelectConferenceTypeRadioField.jsx b/client/app/queue/SelectConferenceTypeRadioField.jsx index da3a5b34e46..328e9123bae 100644 --- a/client/app/queue/SelectConferenceTypeRadioField.jsx +++ b/client/app/queue/SelectConferenceTypeRadioField.jsx @@ -1,4 +1,6 @@ import React, { useState } from 'react'; +import { css } from 'glamor'; + import RadioField from '../components/RadioField'; import COPY from '../../COPY'; @@ -13,7 +15,7 @@ const SelectConferenceTypeRadioField = ({name}) => { const [value, setValue] = useState("1") return ( -
    +
    Date: Wed, 26 Jul 2023 15:56:55 -0400 Subject: [PATCH 12/62] APPEALS-25130 updated user.rb --- app/models/user.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index 65076b555b2..5307e80377e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -147,6 +147,11 @@ def can_intake_appeals? BvaIntake.singleton.users.include?(self) end + def can_schedule_webex_virtual? + @vc_user = User.where(css_id: normalize_css_id) + # conference_selection = @vc_user.meeting_type + end + def administer_org_users? admin? || granted?("Admin Intake") || roles.include?("Admin Intake") || member_of_organization?(Bva.singleton) end From ba63cf89ee3ac014908bd71fdec5f4b740582ffb Mon Sep 17 00:00:00 2001 From: Ariana Konhilas Date: Wed, 26 Jul 2023 16:50:26 -0400 Subject: [PATCH 13/62] APPEALS-25141: rolling back changes, creating new migrations, deleting the old, to meeting type varchar default on users only --- db/migrate/20230724205500_add_pexip_to_virtual_hearings.rb | 5 ----- db/migrate/20230724205643_add_pexip_to_conference_links.rb | 5 ----- db/migrate/20230724205759_add_pexip_to_users.rb | 5 ----- db/migrate/20230726201514_add_meeting_type_to_users.rb | 5 +++++ .../20230726203030_add_meeting_type_to_virtual_hearings.rb | 5 +++++ .../20230726203750_add_meeting_type_to_conference_links.rb | 5 +++++ db/schema.rb | 5 ++++- 7 files changed, 19 insertions(+), 16 deletions(-) delete mode 100644 db/migrate/20230724205500_add_pexip_to_virtual_hearings.rb delete mode 100644 db/migrate/20230724205643_add_pexip_to_conference_links.rb delete mode 100644 db/migrate/20230724205759_add_pexip_to_users.rb create mode 100644 db/migrate/20230726201514_add_meeting_type_to_users.rb create mode 100644 db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb create mode 100644 db/migrate/20230726203750_add_meeting_type_to_conference_links.rb diff --git a/db/migrate/20230724205500_add_pexip_to_virtual_hearings.rb b/db/migrate/20230724205500_add_pexip_to_virtual_hearings.rb deleted file mode 100644 index a577e0ca816..00000000000 --- a/db/migrate/20230724205500_add_pexip_to_virtual_hearings.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddPexipToVirtualHearings < ActiveRecord::Migration[5.2] - def change - add_column :virtual_hearings, :pexip, :boolean - end -end diff --git a/db/migrate/20230724205643_add_pexip_to_conference_links.rb b/db/migrate/20230724205643_add_pexip_to_conference_links.rb deleted file mode 100644 index 88b5454ef7b..00000000000 --- a/db/migrate/20230724205643_add_pexip_to_conference_links.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddPexipToConferenceLinks < ActiveRecord::Migration[5.2] - def change - add_column :conference_links, :pexip, :boolean - end -end diff --git a/db/migrate/20230724205759_add_pexip_to_users.rb b/db/migrate/20230724205759_add_pexip_to_users.rb deleted file mode 100644 index f9839906fd1..00000000000 --- a/db/migrate/20230724205759_add_pexip_to_users.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddPexipToUsers < ActiveRecord::Migration[5.2] - def change - add_column :users, :pexip, :boolean, default: true - end -end diff --git a/db/migrate/20230726201514_add_meeting_type_to_users.rb b/db/migrate/20230726201514_add_meeting_type_to_users.rb new file mode 100644 index 00000000000..f5f6e2b5a35 --- /dev/null +++ b/db/migrate/20230726201514_add_meeting_type_to_users.rb @@ -0,0 +1,5 @@ +class AddMeetingTypeToUsers < Caseflow::Migration[5.2] + def change + add_column :users, :meeting_type, :varChar, default: "pexip", comment: "Video Conferencing Application Type" + end +end diff --git a/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb b/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb new file mode 100644 index 00000000000..baa487c921e --- /dev/null +++ b/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb @@ -0,0 +1,5 @@ +class AddMeetingTypeToVirtualHearings < Caseflow::Migration[5.2] + def change + add_column :virtual_hearings, :meeting_type, :varChar, comment: "Video Conferencing Application Type" + end +end diff --git a/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb b/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb new file mode 100644 index 00000000000..4734f7e1b51 --- /dev/null +++ b/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb @@ -0,0 +1,5 @@ +class AddMeetingTypeToConferenceLinks < Caseflow::Migration[5.2] + def change + add_column :conference_links, :meeting_type, :varChar, comment: "Video Conferencing Application Type" + end +end diff --git a/db/schema.rb b/db/schema.rb index c43d1649e9d..bd3a4116857 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2023_05_08_202742) do +ActiveRecord::Schema.define(version: 2023_07_26_203750) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -555,6 +555,7 @@ t.string "host_link", comment: "Conference link generated from external conference service" t.integer "host_pin", comment: "Pin for the host of the conference to get into the conference" t.string "host_pin_long", limit: 8, comment: "Generated host pin stored as a string" + t.string "meeting_type", comment: "Video Conferencing Application Type" t.datetime "updated_at", comment: "Date and Time record was last updated" t.bigint "updated_by_id", comment: "user id of the user to last update the record. FK on the User table" t.index ["created_by_id"], name: "index_created_by_id" @@ -1776,6 +1777,7 @@ t.string "email" t.string "full_name" t.datetime "last_login_at", comment: "The last time the user-agent (browser) provided session credentials; see User.from_session for precision" + t.string "meeting_type", default: "pexip", comment: "Video Conferencing Application Type" t.string "roles", array: true t.string "selected_regional_office" t.string "station_id", null: false @@ -1879,6 +1881,7 @@ t.string "host_pin_long", limit: 8, comment: "Change the host pin to store a longer pin with the # sign trailing" t.string "judge_email", comment: "Judge's email address" t.boolean "judge_email_sent", default: false, null: false, comment: "Whether or not a notification email was sent to the judge" + t.string "meeting_type", comment: "Video Conferencing Application Type" t.string "representative_email", comment: "Veteran's representative's email address" t.boolean "representative_email_sent", default: false, null: false, comment: "Whether or not a notification email was sent to the veteran's representative" t.datetime "representative_reminder_sent_at", comment: "The datetime the last reminder email was sent to the representative." From 0e48803c367e35c01ca8d400201f43126fcd9dca Mon Sep 17 00:00:00 2001 From: Ariana Konhilas Date: Wed, 26 Jul 2023 16:58:55 -0400 Subject: [PATCH 14/62] APPEALS-25141: removed version 5.2 from migrations --- db/migrate/20230726201514_add_meeting_type_to_users.rb | 2 +- .../20230726203030_add_meeting_type_to_virtual_hearings.rb | 2 +- .../20230726203750_add_meeting_type_to_conference_links.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/db/migrate/20230726201514_add_meeting_type_to_users.rb b/db/migrate/20230726201514_add_meeting_type_to_users.rb index f5f6e2b5a35..1f69fe54f3c 100644 --- a/db/migrate/20230726201514_add_meeting_type_to_users.rb +++ b/db/migrate/20230726201514_add_meeting_type_to_users.rb @@ -1,4 +1,4 @@ -class AddMeetingTypeToUsers < Caseflow::Migration[5.2] +class AddMeetingTypeToUsers < Caseflow::Migration def change add_column :users, :meeting_type, :varChar, default: "pexip", comment: "Video Conferencing Application Type" end diff --git a/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb b/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb index baa487c921e..3c5a2e79b83 100644 --- a/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb +++ b/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb @@ -1,4 +1,4 @@ -class AddMeetingTypeToVirtualHearings < Caseflow::Migration[5.2] +class AddMeetingTypeToVirtualHearings < Caseflow::Migration def change add_column :virtual_hearings, :meeting_type, :varChar, comment: "Video Conferencing Application Type" end diff --git a/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb b/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb index 4734f7e1b51..c754c4dfd1e 100644 --- a/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb +++ b/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb @@ -1,4 +1,4 @@ -class AddMeetingTypeToConferenceLinks < Caseflow::Migration[5.2] +class AddMeetingTypeToConferenceLinks < Caseflow::Migration def change add_column :conference_links, :meeting_type, :varChar, comment: "Video Conferencing Application Type" end From bdc3a5276f1bec0bbde8ad8ee28cac9b5016139b Mon Sep 17 00:00:00 2001 From: 631862 Date: Fri, 28 Jul 2023 10:55:50 -0400 Subject: [PATCH 15/62] Create jest test --- .../SelectConferenceTypeRadioField.test.js | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 client/test/app/queue/SelectConferenceTypeRadioField.test.js diff --git a/client/test/app/queue/SelectConferenceTypeRadioField.test.js b/client/test/app/queue/SelectConferenceTypeRadioField.test.js new file mode 100644 index 00000000000..22b404721bf --- /dev/null +++ b/client/test/app/queue/SelectConferenceTypeRadioField.test.js @@ -0,0 +1,44 @@ +import React from 'react'; +import { render } from '@testing-library/react'; + +import SelectConferenceTypeRadioField from 'app/queue/SelectConferenceTypeRadioField'; + +const defaults = { + name: 'field1', + value: 'option2', + options: [ + { displayText: 'Option 1', value: 'option1' }, + { displayText: 'Option 2', value: 'option2' }, + ], +}; + +describe('SelectConferenceTypeRadioField', () => { + const handleChange = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + const setup = (props = {}) => { + const utils = render( + + ); + const inputs = utils.getAllByRole('radio'); + + return { + inputs, + ...utils, + }; + }; + + it('renders correctly', async () => { + const { container } = setup(); + + expect(container).toMatchSnapshot(); + }); +}); From 3dae8f58d645980db2cfa83be404ccfbb48b59c1 Mon Sep 17 00:00:00 2001 From: 631862 Date: Fri, 28 Jul 2023 12:01:07 -0400 Subject: [PATCH 16/62] Test passing --- .../SelectConferenceTypeRadioField.test.js | 6 +- ...electConferenceTypeRadioField.test.js.snap | 57 +++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap diff --git a/client/test/app/queue/SelectConferenceTypeRadioField.test.js b/client/test/app/queue/SelectConferenceTypeRadioField.test.js index 22b404721bf..f021b3ebbd9 100644 --- a/client/test/app/queue/SelectConferenceTypeRadioField.test.js +++ b/client/test/app/queue/SelectConferenceTypeRadioField.test.js @@ -7,8 +7,10 @@ const defaults = { name: 'field1', value: 'option2', options: [ - { displayText: 'Option 1', value: 'option1' }, - { displayText: 'Option 2', value: 'option2' }, + { displayText: 'Option 1', + value: 'option1' }, + { displayText: 'Option 2', + value: 'option2' }, ], }; diff --git a/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap b/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap new file mode 100644 index 00000000000..3fde5f14a4b --- /dev/null +++ b/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap @@ -0,0 +1,57 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SelectConferenceTypeRadioField renders correctly 1`] = ` +
    +
    +
    + + + Schedule hearings using: + + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    +`; From 5bfdc9b3c01263613293a47977bb1864c8f5ce2c Mon Sep 17 00:00:00 2001 From: 631862 Date: Fri, 28 Jul 2023 14:01:52 -0400 Subject: [PATCH 17/62] Fixed syntax errors from merged code --- app/views/queue/index.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/queue/index.html.erb b/app/views/queue/index.html.erb index 42546db9ac0..c3515e17d60 100644 --- a/app/views/queue/index.html.erb +++ b/app/views/queue/index.html.erb @@ -24,7 +24,7 @@ canEditCavcDashboards: current_user.can_edit_cavc_dashboards?, canViewCavcDashboards: current_user.can_view_cavc_dashboards?, userIsCobAdmin: ClerkOfTheBoard.singleton.admins.include?(current_user), - userCanScheduleWebexVirtual: current_user.can_schedule_webex_virtual? + userCanScheduleWebexVirtual: current_user.can_schedule_webex_virtual?, featureToggles: { collect_video_and_central_emails: FeatureToggle.enabled?(:collect_video_and_central_emails, user: current_user), enable_hearing_time_slots: FeatureToggle.enabled?(:enable_hearing_time_slots, user: current_user), @@ -55,7 +55,7 @@ cavc_dashboard_workflow: FeatureToggle.enabled?(:cavc_dashboard_workflow, user: current_user), cc_appeal_workflow: FeatureToggle.enabled?(:cc_appeal_workflow, user: current_user), cc_vacatur_visibility: FeatureToggle.enabled?(:cc_vacatur_visibility, user: current_user), - conference_selection: FeatureToggle.enabled?(:conference_selection, user:current_user) + conference_selection: FeatureToggle.enabled?(:conference_selection, user: current_user) } }) %> <% end %> From c023af41e814193a0980266a673db5c1e96549f2 Mon Sep 17 00:00:00 2001 From: 631862 Date: Fri, 28 Jul 2023 15:23:00 -0400 Subject: [PATCH 18/62] Radio buttons fixed to only display on Hearings Admin page --- client/app/queue/OrganizationUsers.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 0a38880623e..61866b105ff 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -49,7 +49,7 @@ const listStyle = css({ }); const radioContainerStyle = css({ padding: '-5rem 5rem 2rem 2rem', - marginTop: '-3.8rem' + // marginTop: '-3.5rem' }) export default class OrganizationUsers extends React.PureComponent { @@ -68,7 +68,7 @@ export default class OrganizationUsers extends React.PureComponent { addingUser: null, changingAdminRights: {}, removingUser: {}, - isVhaOrg: false, + isVhaOrg: false }; } @@ -270,9 +270,11 @@ export default class OrganizationUsers extends React.PureComponent { { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } { this.removeUserButton(user) }
    + { this.state.organizationName === "Hearing Admin" &&
    + }
    }
    ; From 08c7910a4e0f72c683cf2b2ed89d4c66dd25e54d Mon Sep 17 00:00:00 2001 From: 631862 Date: Fri, 28 Jul 2023 16:07:08 -0400 Subject: [PATCH 19/62] Wrap li elements in ul elements --- client/app/queue/OrganizationUsers.jsx | 46 ++++++++++++++------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 61866b105ff..4e7b5dda142 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -257,25 +257,27 @@ export default class OrganizationUsers extends React.PureComponent { return
    -
  • {this.formatName(user)} - { judgeTeam && admin && ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} ) } - { dvcTeam && dvc && ( {COPY.USER_MANAGEMENT_DVC_LABEL} ) } - { judgeTeam && !admin && ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} ) } - { (judgeTeam || dvcTeam) && admin && ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} ) } -
  • - { (judgeTeam || dvcTeam) && admin ? -
    : -
    -
    - { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } - { this.removeUserButton(user) } -
    - { this.state.organizationName === "Hearing Admin" && -
    - -
    - } -
    } +
      +
    • {this.formatName(user)} + { judgeTeam && admin && ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} ) } + { dvcTeam && dvc && ( {COPY.USER_MANAGEMENT_DVC_LABEL} ) } + { judgeTeam && !admin && ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} ) } + { (judgeTeam || dvcTeam) && admin && ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} ) } +
    • + { (judgeTeam || dvcTeam) && admin ? +
      : +
      +
      + { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } + { this.removeUserButton(user) } +
      + { this.state.organizationName === "Hearing Admin" && +
      + +
      + } +
      } +
    ; }); @@ -302,10 +304,10 @@ export default class OrganizationUsers extends React.PureComponent {

    {COPY.USER_MANAGEMENT_EDIT_USER_IN_ORG_LABEL}

      - { (judgeTeam || dvcTeam) ? '' :
    • {COPY.USER_MANAGEMENT_ADMIN_RIGHTS_HEADING}{COPY.USER_MANAGEMENT_ADMIN_RIGHTS_DESCRIPTION}
    • } -
    • {COPY.USER_MANAGEMENT_REMOVE_USER_HEADING}{ judgeTeam ? + { (judgeTeam || dvcTeam) ? '' :
      • {COPY.USER_MANAGEMENT_ADMIN_RIGHTS_HEADING}{COPY.USER_MANAGEMENT_ADMIN_RIGHTS_DESCRIPTION}
      } +
      • {COPY.USER_MANAGEMENT_REMOVE_USER_HEADING}{ judgeTeam ? COPY.USER_MANAGEMENT_JUDGE_TEAM_REMOVE_USER_DESCRIPTION : - COPY.USER_MANAGEMENT_REMOVE_USER_DESCRIPTION }
      • + COPY.USER_MANAGEMENT_REMOVE_USER_DESCRIPTION }
      {listOfUsers}
    From 7421103127e445a71d9bf29d40a6c0e49ace805f Mon Sep 17 00:00:00 2001 From: 631862 Date: Fri, 28 Jul 2023 16:26:03 -0400 Subject: [PATCH 20/62] Test that radio button values change when selected --- .../SelectConferenceTypeRadioField.test.js | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/client/test/app/queue/SelectConferenceTypeRadioField.test.js b/client/test/app/queue/SelectConferenceTypeRadioField.test.js index f021b3ebbd9..d7d5b26939b 100644 --- a/client/test/app/queue/SelectConferenceTypeRadioField.test.js +++ b/client/test/app/queue/SelectConferenceTypeRadioField.test.js @@ -1,16 +1,17 @@ import React from 'react'; -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import SelectConferenceTypeRadioField from 'app/queue/SelectConferenceTypeRadioField'; const defaults = { name: 'field1', - value: 'option2', + value: '1', options: [ - { displayText: 'Option 1', - value: 'option1' }, - { displayText: 'Option 2', - value: 'option2' }, + { displayText: 'Pexip', + value: '1' }, + { displayText: 'Webex', + value: '2' }, ], }; @@ -21,7 +22,7 @@ describe('SelectConferenceTypeRadioField', () => { jest.clearAllMocks(); }); - const setup = (props = {}) => { + const setupComponent = (props = {}) => { const utils = render( { }; it('renders correctly', async () => { - const { container } = setup(); + const { container } = setupComponent(); expect(container).toMatchSnapshot(); }); + + it('has the correct default value', async () => { + expect(defaults.value) === "1"; + }) + + it('changes values by radio button selected', async () => { + setupComponent(); + const webexRadioButton = screen.getByText('Webex'); + + await userEvent.click(webexRadioButton); + + expect(defaults.value) === "2"; + }) }); From daae3bf52985ba3118bf8772368ac01674961f23 Mon Sep 17 00:00:00 2001 From: 631862 Date: Fri, 28 Jul 2023 16:58:56 -0400 Subject: [PATCH 21/62] Update to testing logic with radio buttons --- .../test/app/queue/SelectConferenceTypeRadioField.test.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/client/test/app/queue/SelectConferenceTypeRadioField.test.js b/client/test/app/queue/SelectConferenceTypeRadioField.test.js index d7d5b26939b..8dc2a89204f 100644 --- a/client/test/app/queue/SelectConferenceTypeRadioField.test.js +++ b/client/test/app/queue/SelectConferenceTypeRadioField.test.js @@ -45,12 +45,10 @@ describe('SelectConferenceTypeRadioField', () => { expect(container).toMatchSnapshot(); }); - it('has the correct default value', async () => { - expect(defaults.value) === "1"; - }) - it('changes values by radio button selected', async () => { setupComponent(); + expect (defaults.value) === "1"; + const webexRadioButton = screen.getByText('Webex'); await userEvent.click(webexRadioButton); From 5115f7ca01445d133198d08dce3f9fd23f8f07c8 Mon Sep 17 00:00:00 2001 From: Ariana Konhilas Date: Mon, 31 Jul 2023 11:48:02 -0400 Subject: [PATCH 22/62] APPEALS-25141: refactoring migrations to include up/down methods, adding default for virt hearings and conf links --- db/migrate/20230726201514_add_meeting_type_to_users.rb | 6 +++++- ...20230726203030_add_meeting_type_to_virtual_hearings.rb | 8 ++++++-- ...20230726203750_add_meeting_type_to_conference_links.rb | 8 ++++++-- db/schema.rb | 4 ++-- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/db/migrate/20230726201514_add_meeting_type_to_users.rb b/db/migrate/20230726201514_add_meeting_type_to_users.rb index 1f69fe54f3c..b07b732c95f 100644 --- a/db/migrate/20230726201514_add_meeting_type_to_users.rb +++ b/db/migrate/20230726201514_add_meeting_type_to_users.rb @@ -1,5 +1,9 @@ class AddMeetingTypeToUsers < Caseflow::Migration - def change + def up add_column :users, :meeting_type, :varChar, default: "pexip", comment: "Video Conferencing Application Type" end + + def down + remove_column :users, :meeting_type + end end diff --git a/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb b/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb index 3c5a2e79b83..6b8f6b1e1c6 100644 --- a/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb +++ b/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb @@ -1,5 +1,9 @@ class AddMeetingTypeToVirtualHearings < Caseflow::Migration - def change - add_column :virtual_hearings, :meeting_type, :varChar, comment: "Video Conferencing Application Type" + def up + add_column :virtual_hearings, :meeting_type, :varChar, default: "pexip", comment: "Video Conferencing Application Type" + end + + def down + remove_column :virtual_hearings, :meeting_type end end diff --git a/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb b/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb index c754c4dfd1e..dc0713e3f35 100644 --- a/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb +++ b/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb @@ -1,5 +1,9 @@ class AddMeetingTypeToConferenceLinks < Caseflow::Migration - def change - add_column :conference_links, :meeting_type, :varChar, comment: "Video Conferencing Application Type" + def up + add_column :conference_links, :meeting_type, :varChar, default: "pexip", comment: "Video Conferencing Application Type" + end + + def down + remove_column :conference_links, :meeting_type end end diff --git a/db/schema.rb b/db/schema.rb index bd3a4116857..ff30505ca9e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -555,7 +555,7 @@ t.string "host_link", comment: "Conference link generated from external conference service" t.integer "host_pin", comment: "Pin for the host of the conference to get into the conference" t.string "host_pin_long", limit: 8, comment: "Generated host pin stored as a string" - t.string "meeting_type", comment: "Video Conferencing Application Type" + t.string "meeting_type", default: "pexip", comment: "Video Conferencing Application Type" t.datetime "updated_at", comment: "Date and Time record was last updated" t.bigint "updated_by_id", comment: "user id of the user to last update the record. FK on the User table" t.index ["created_by_id"], name: "index_created_by_id" @@ -1881,7 +1881,7 @@ t.string "host_pin_long", limit: 8, comment: "Change the host pin to store a longer pin with the # sign trailing" t.string "judge_email", comment: "Judge's email address" t.boolean "judge_email_sent", default: false, null: false, comment: "Whether or not a notification email was sent to the judge" - t.string "meeting_type", comment: "Video Conferencing Application Type" + t.string "meeting_type", default: "pexip", comment: "Video Conferencing Application Type" t.string "representative_email", comment: "Veteran's representative's email address" t.boolean "representative_email_sent", default: false, null: false, comment: "Whether or not a notification email was sent to the veteran's representative" t.datetime "representative_reminder_sent_at", comment: "The datetime the last reminder email was sent to the representative." From 78af497db3be4bd9848f5c007222b0922d79f119 Mon Sep 17 00:00:00 2001 From: 631862 Date: Tue, 1 Aug 2023 09:35:20 -0400 Subject: [PATCH 23/62] Styling comments updated after review --- client/app/queue/OrganizationUsers.jsx | 1 - client/app/queue/SelectConferenceTypeRadioField.jsx | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 4e7b5dda142..d982c9f2e3a 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -49,7 +49,6 @@ const listStyle = css({ }); const radioContainerStyle = css({ padding: '-5rem 5rem 2rem 2rem', - // marginTop: '-3.5rem' }) export default class OrganizationUsers extends React.PureComponent { diff --git a/client/app/queue/SelectConferenceTypeRadioField.jsx b/client/app/queue/SelectConferenceTypeRadioField.jsx index 328e9123bae..0b9f16466ea 100644 --- a/client/app/queue/SelectConferenceTypeRadioField.jsx +++ b/client/app/queue/SelectConferenceTypeRadioField.jsx @@ -1,5 +1,4 @@ import React, { useState } from 'react'; -import { css } from 'glamor'; import RadioField from '../components/RadioField'; import COPY from '../../COPY'; @@ -15,7 +14,7 @@ const SelectConferenceTypeRadioField = ({name}) => { const [value, setValue] = useState("1") return ( -
    + <> { value={value} onChange={(newValue) => setValue(newValue)} vertical - />
    + /> ); } From 0ab42a3c775cbbb58e0e65f00a8863248595ed01 Mon Sep 17 00:00:00 2001 From: Matthew Thornton Date: Tue, 1 Aug 2023 11:55:15 -0400 Subject: [PATCH 24/62] Revert 'Merge pull request #19038 from department-of-veterans-affairs/b_reed/APPEALS-25130-v3' This reverts commit ab8ce3c4819ede8aa95322e3a4cf4e9c86c1d7a2, reversing changes made to 6fc2c0f77a52febdb5325c4fedfc7519f857aac9. --- app/models/user.rb | 5 ----- app/views/queue/index.html.erb | 4 +--- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 5307e80377e..65076b555b2 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -147,11 +147,6 @@ def can_intake_appeals? BvaIntake.singleton.users.include?(self) end - def can_schedule_webex_virtual? - @vc_user = User.where(css_id: normalize_css_id) - # conference_selection = @vc_user.meeting_type - end - def administer_org_users? admin? || granted?("Admin Intake") || roles.include?("Admin Intake") || member_of_organization?(Bva.singleton) end diff --git a/app/views/queue/index.html.erb b/app/views/queue/index.html.erb index c3515e17d60..e0ba7a1038a 100644 --- a/app/views/queue/index.html.erb +++ b/app/views/queue/index.html.erb @@ -24,7 +24,6 @@ canEditCavcDashboards: current_user.can_edit_cavc_dashboards?, canViewCavcDashboards: current_user.can_view_cavc_dashboards?, userIsCobAdmin: ClerkOfTheBoard.singleton.admins.include?(current_user), - userCanScheduleWebexVirtual: current_user.can_schedule_webex_virtual?, featureToggles: { collect_video_and_central_emails: FeatureToggle.enabled?(:collect_video_and_central_emails, user: current_user), enable_hearing_time_slots: FeatureToggle.enabled?(:enable_hearing_time_slots, user: current_user), @@ -54,8 +53,7 @@ cavc_remand_granted_substitute_appellant: FeatureToggle.enabled?(:cavc_remand_granted_substitute_appellant, user: current_user), cavc_dashboard_workflow: FeatureToggle.enabled?(:cavc_dashboard_workflow, user: current_user), cc_appeal_workflow: FeatureToggle.enabled?(:cc_appeal_workflow, user: current_user), - cc_vacatur_visibility: FeatureToggle.enabled?(:cc_vacatur_visibility, user: current_user), - conference_selection: FeatureToggle.enabled?(:conference_selection, user: current_user) + cc_vacatur_visibility: FeatureToggle.enabled?(:cc_vacatur_visibility, user: current_user) } }) %> <% end %> From 97bba81b54f505aa50aa20bb8d2f6d4c9c3f3d4b Mon Sep 17 00:00:00 2001 From: 631862 Date: Tue, 1 Aug 2023 13:44:12 -0400 Subject: [PATCH 25/62] Fixed linting issues and updated jest snapshot --- client/app/queue/OrganizationUsers.jsx | 40 ++++----- .../queue/SelectConferenceTypeRadioField.jsx | 17 ++-- ...electConferenceTypeRadioField.test.js.snap | 88 +++++++++---------- 3 files changed, 74 insertions(+), 71 deletions(-) diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index d982c9f2e3a..00c128bf118 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -49,7 +49,7 @@ const listStyle = css({ }); const radioContainerStyle = css({ padding: '-5rem 5rem 2rem 2rem', -}) +}); export default class OrganizationUsers extends React.PureComponent { constructor(props) { @@ -255,29 +255,29 @@ export default class OrganizationUsers extends React.PureComponent { const style = i === 0 ? topUserStyle : userStyle; return -
    -
      -
    • {this.formatName(user)} - { judgeTeam && admin && ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} ) } - { dvcTeam && dvc && ( {COPY.USER_MANAGEMENT_DVC_LABEL} ) } - { judgeTeam && !admin && ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} ) } - { (judgeTeam || dvcTeam) && admin && ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} ) } -
    • - { (judgeTeam || dvcTeam) && admin ? -
      : -
      -
      - { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } - { this.removeUserButton(user) } -
      - { this.state.organizationName === "Hearing Admin" && +
      +
        +
      • {this.formatName(user)} + { judgeTeam && admin && ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} ) } + { dvcTeam && dvc && ( {COPY.USER_MANAGEMENT_DVC_LABEL} ) } + { judgeTeam && !admin && ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} ) } + { (judgeTeam || dvcTeam) && admin && ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} ) } +
      • + { (judgeTeam || dvcTeam) && admin ? +
        : +
        +
        + { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } + { this.removeUserButton(user) } +
        + { this.state.organizationName === 'Hearing Admin' &&
        - +
        }
        } -
      -
      +
    +
    ; }); diff --git a/client/app/queue/SelectConferenceTypeRadioField.jsx b/client/app/queue/SelectConferenceTypeRadioField.jsx index 0b9f16466ea..96c070a138a 100644 --- a/client/app/queue/SelectConferenceTypeRadioField.jsx +++ b/client/app/queue/SelectConferenceTypeRadioField.jsx @@ -1,17 +1,18 @@ import React, { useState } from 'react'; +import PropTypes from 'prop-types'; import RadioField from '../components/RadioField'; import COPY from '../../COPY'; const radioOptions = [ { displayText: 'Pexip', - value: '1'}, + value: '1' }, { displayText: 'Webex', - value: '2'} + value: '2' } ]; -const SelectConferenceTypeRadioField = ({name}) => { - const [value, setValue] = useState("1") +const SelectConferenceTypeRadioField = ({ name }) => { + const [value, setValue] = useState('1'); return ( <> @@ -22,8 +23,12 @@ const SelectConferenceTypeRadioField = ({name}) => { value={value} onChange={(newValue) => setValue(newValue)} vertical - /> + /> ); -} +}; + +SelectConferenceTypeRadioField.propTypes = { + name: PropTypes.string +}; export default SelectConferenceTypeRadioField; diff --git a/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap b/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap index 3fde5f14a4b..4c89e26a554 100644 --- a/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap +++ b/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap @@ -2,56 +2,54 @@ exports[`SelectConferenceTypeRadioField renders correctly 1`] = `
    -
    -
    + + + Schedule hearings using: + + + +
    - - - Schedule hearings using: - - -
    -
    +
    -
    +
    +
    + +
    + Webex +
    -
    -
    +
    + `; From b78168acb0374155405bc90efacee7c639dcb00c Mon Sep 17 00:00:00 2001 From: Ariana Konhilas Date: Thu, 3 Aug 2023 11:04:07 -0400 Subject: [PATCH 26/62] APPEALS-25141: updated user_spec.rb --- spec/models/user_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index f6e7f770bb7..385941f08a0 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -158,7 +158,8 @@ :display_name => css_id.upcase, "name" => "Tom Brady", "status" => Constants.USER_STATUSES.active, - "status_updated_at" => nil + "status_updated_at" => nil, + "meeting_type" => "pexip" } end From df20d923a76c610cd97f5fbcef64788f9f64774a Mon Sep 17 00:00:00 2001 From: 631862 Date: Thu, 3 Aug 2023 14:16:54 -0400 Subject: [PATCH 27/62] APPEALS-26633 Added method to update meeting_type in Users Controller, and updated Organizations User model with new method to change meeting_type --- app/controllers/organizations/users_controller.rb | 6 ++++++ app/models/organizations_user.rb | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/app/controllers/organizations/users_controller.rb b/app/controllers/organizations/users_controller.rb index 6a125576a84..88909a00c87 100644 --- a/app/controllers/organizations/users_controller.rb +++ b/app/controllers/organizations/users_controller.rb @@ -67,6 +67,12 @@ def adjust_admin_rights end end + def update_user_meeting_type + if params[:admin] == true + OrganizationsUser.update_user_to_webex_conference_type(user_to_modify, organization) + end + end + def organization_url params[:organization_url] end diff --git a/app/models/organizations_user.rb b/app/models/organizations_user.rb index 189d98de647..e6280abfc92 100644 --- a/app/models/organizations_user.rb +++ b/app/models/organizations_user.rb @@ -28,6 +28,12 @@ def remove_admin_rights_from_user(user, organization) existing_record(user, organization)&.update!(admin: false) end + def update_user_to_webex_conference_type(user, organization) + if user.roles.include?("HearingCoordinator") + user.update!(pexip: false) + end + end + def remove_user_from_organization(user, organization) if user_is_judge_of_team?(user, organization) fail Caseflow::Error::ActionForbiddenError, message: COPY::JUDGE_TEAM_REMOVE_JUDGE_ERROR From 6a8edf6b4ab4b149fc43a512a8320572a4859249 Mon Sep 17 00:00:00 2001 From: 631862 Date: Mon, 7 Aug 2023 10:20:58 -0400 Subject: [PATCH 28/62] APPEALS-26633 Progress on linking backend and frontend radio option changes and added modifyConferenceTypes --- app/models/organizations_user.rb | 6 ++++++ client/app/queue/OrganizationUsers.jsx | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/app/models/organizations_user.rb b/app/models/organizations_user.rb index e6280abfc92..5474f7d01c4 100644 --- a/app/models/organizations_user.rb +++ b/app/models/organizations_user.rb @@ -34,6 +34,12 @@ def update_user_to_webex_conference_type(user, organization) end end + def update_user_to_pexip_conference_type(user, organization) + if user.roles.include?("HearingCoordinator") + user.update!(pexip: true) + end + end + def remove_user_from_organization(user, organization) if user_is_judge_of_team?(user, organization) fail Caseflow::Error::ActionForbiddenError, message: COPY::JUDGE_TEAM_REMOVE_JUDGE_ERROR diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 00c128bf118..8fcd229eb6c 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -214,6 +214,20 @@ export default class OrganizationUsers extends React.PureComponent { }); } + modifyConferenceType = (user, conferenceFlag) => () => { + const flagName = 'changingConferenceType'; + + this.modifyUser(user, flagName); + + const payload = { data: { admin: conferenceFlag } }; + + ApiUtil.patch(`/organizations/${this.props.organization}/users/${user.id}`, payload).then((response) => { + this.modifyUserSuccess(response, user, flagName); + }, (error) => { + this.modifyUserError(COPY.USER_MANAGEMENT_ADMIN_RIGHTS_CHANGE_ERROR_TITLE, error.message, user, flagName); + }); + } + asyncLoadUser = (inputValue) => { // don't search till we have min length input if (inputValue.length < 2) { From 55ac16f76f41f23c565fa19f7a232b66038f47ec Mon Sep 17 00:00:00 2001 From: 631862 Date: Mon, 7 Aug 2023 17:09:25 -0400 Subject: [PATCH 29/62] APPEALS-26633 Framing for logic to link onChange function --- client/app/queue/OrganizationUsers.jsx | 33 ++++++++++++++++---------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 8fcd229eb6c..c11a603a593 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -214,19 +214,26 @@ export default class OrganizationUsers extends React.PureComponent { }); } - modifyConferenceType = (user, conferenceFlag) => () => { - const flagName = 'changingConferenceType'; - - this.modifyUser(user, flagName); - - const payload = { data: { admin: conferenceFlag } }; - - ApiUtil.patch(`/organizations/${this.props.organization}/users/${user.id}`, payload).then((response) => { - this.modifyUserSuccess(response, user, flagName); - }, (error) => { - this.modifyUserError(COPY.USER_MANAGEMENT_ADMIN_RIGHTS_CHANGE_ERROR_TITLE, error.message, user, flagName); - }); - } + // modifyConference = (user, flagName) => { + // this.setState({ + // [flagName]: { ...this.state[flagName], + // [user.id]: true } + // }); + // } + + // modifyConferenceType = (user, conferenceFlag) => () => { + // const flagName = 'changingConferenceType'; + + // this.modifyConference(user, flagName); + + // const payload = { data: { admin: conferenceFlag } }; + + // ApiUtil.patch(`/organizations/${this.props.organization}/users/${user.id}`, payload).then((response) => { + // this.modifyUserSuccess(response, user, flagName); + // }, (error) => { + // this.modifyUserError(COPY.USER_MANAGEMENT_ADMIN_RIGHTS_CHANGE_ERROR_TITLE, error.message, user, flagName); + // }); + // } asyncLoadUser = (inputValue) => { // don't search till we have min length input From e670373a6da4bbc04a475c7fe2d8d0017f438163 Mon Sep 17 00:00:00 2001 From: 631862 Date: Wed, 9 Aug 2023 13:11:55 -0400 Subject: [PATCH 30/62] Adding modifyConferenceType to patch to backend --- .../organizations/users_controller.rb | 2 ++ client/app/queue/OrganizationUsers.jsx | 25 ++++------------ .../queue/SelectConferenceTypeRadioField.jsx | 16 ++++++++-- db/schema.rb | 30 +++++++++++++++++++ 4 files changed, 51 insertions(+), 22 deletions(-) diff --git a/app/controllers/organizations/users_controller.rb b/app/controllers/organizations/users_controller.rb index 88909a00c87..13114138df1 100644 --- a/app/controllers/organizations/users_controller.rb +++ b/app/controllers/organizations/users_controller.rb @@ -30,6 +30,8 @@ def update if params.key?(:admin) adjust_admin_rights + elsif params.key?(:user) + update_user_meeting_type end render json: { users: json_administered_users([user_to_modify]) }, status: :ok diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index c11a603a593..9838a03223b 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -214,26 +214,13 @@ export default class OrganizationUsers extends React.PureComponent { }); } - // modifyConference = (user, flagName) => { - // this.setState({ - // [flagName]: { ...this.state[flagName], - // [user.id]: true } - // }); - // } + modifyConferenceType = (user) => () => { + console.log('hi'); - // modifyConferenceType = (user, conferenceFlag) => () => { - // const flagName = 'changingConferenceType'; + const payload = { data: { user } }; - // this.modifyConference(user, flagName); - - // const payload = { data: { admin: conferenceFlag } }; - - // ApiUtil.patch(`/organizations/${this.props.organization}/users/${user.id}`, payload).then((response) => { - // this.modifyUserSuccess(response, user, flagName); - // }, (error) => { - // this.modifyUserError(COPY.USER_MANAGEMENT_ADMIN_RIGHTS_CHANGE_ERROR_TITLE, error.message, user, flagName); - // }); - // } + ApiUtil.patch(`/organizations/${this.props.organization}/users/${user.id}`, payload); + } asyncLoadUser = (inputValue) => { // don't search till we have min length input @@ -293,7 +280,7 @@ export default class OrganizationUsers extends React.PureComponent { { this.state.organizationName === 'Hearing Admin' &&
    - +
    } } diff --git a/client/app/queue/SelectConferenceTypeRadioField.jsx b/client/app/queue/SelectConferenceTypeRadioField.jsx index 96c070a138a..b601d06a96e 100644 --- a/client/app/queue/SelectConferenceTypeRadioField.jsx +++ b/client/app/queue/SelectConferenceTypeRadioField.jsx @@ -1,5 +1,6 @@ import React, { useState } from 'react'; import PropTypes from 'prop-types'; +// import ApiUtil from '../util/ApiUtil'; import RadioField from '../components/RadioField'; import COPY from '../../COPY'; @@ -11,9 +12,17 @@ const radioOptions = [ value: '2' } ]; -const SelectConferenceTypeRadioField = ({ name }) => { +const SelectConferenceTypeRadioField = ({ name, onClick }) => { const [value, setValue] = useState('1'); + // const modifyConferenceType = (user) => { + // const payload = { data: { user } }; + + // console.log('hi'); + + // ApiUtil.patch(`/organizations/${this.props.organization}/users/${user.id}`, payload); + // }; + return ( <> { name={name} options={radioOptions} value={value} - onChange={(newValue) => setValue(newValue)} + onChange={((newValue) => setValue(newValue) && onClick)} vertical /> ); }; SelectConferenceTypeRadioField.propTypes = { - name: PropTypes.string + name: PropTypes.string, + onClick: PropTypes.func }; export default SelectConferenceTypeRadioField; diff --git a/db/schema.rb b/db/schema.rb index 95034ba47d9..0b6f4994243 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -598,6 +598,8 @@ t.string "diagnostic_code", comment: "If a decision resulted in a rating, this is the rating issue's diagnostic code." t.string "disposition", comment: "The disposition for a decision issue. Dispositions made in Caseflow and dispositions made in VBMS can have different values." t.date "end_product_last_action_date", comment: "After an end product gets synced with a status of CLR (cleared), the end product's last_action_date is saved on any decision issues that are created as a result. This is used as a proxy for decision date for non-rating issues that are processed in VBMS because they don't have a rating profile date, and the exact decision date is not available." + t.boolean "mst_status", default: false, comment: "Indicates if decision issue is related to Military Sexual Trauma (MST)" + t.boolean "pact_status", default: false, comment: "Indicates if decision issue is related to Promise to Address Comprehensive Toxics (PACT) Act" t.string "participant_id", null: false, comment: "The Veteran's participant id." t.string "percent_number", comment: "percent_number from RatingIssue (prcntNo from Rating Profile)" t.string "rating_issue_reference_id", comment: "Identifies the specific issue on the rating that resulted from the decision issue (a rating issue can be connected to multiple contentions)." @@ -1473,9 +1475,13 @@ t.string "ineligible_reason", comment: "The reason for a Request Issue being ineligible. If a Request Issue has an ineligible_reason, it is still captured, but it will not get a contention in VBMS or a decision." t.boolean "is_predocket_needed", comment: "Indicates whether or not an issue has been selected to go to the pre-docket queue opposed to normal docketing." t.boolean "is_unidentified", comment: "Indicates whether a Request Issue is unidentified, meaning it wasn't found in the list of contestable issues, and is not a new nonrating issue. Contentions for unidentified issues are created on a rating End Product if processed in VBMS but without the issue description, and someone is required to edit it in Caseflow before proceeding with the decision." + t.boolean "mst_status", default: false, comment: "Indicates if issue is related to Military Sexual Trauma (MST)" + t.text "mst_status_update_reason_notes", comment: "The reason for why Request Issue is Military Sexual Trauma (MST)" t.string "nonrating_issue_category", comment: "The category selected for nonrating request issues. These vary by business line." t.string "nonrating_issue_description", comment: "The user entered description if the issue is a nonrating issue" t.text "notes", comment: "Notes added by the Claims Assistant when adding request issues. This may be used to capture handwritten notes on the form, or other comments the CA wants to capture." + t.boolean "pact_status", default: false, comment: "Indicates if issue is related to Promise to Address Comprehensive Toxics (PACT) Act" + t.text "pact_status_update_reason_notes", comment: "The reason for why Request Issue is Promise to Address Comprehensive Toxics (PACT) Act" t.string "ramp_claim_id", comment: "If a rating issue was created as a result of an issue intaken for a RAMP Review, it will be connected to the former RAMP issue by its End Product's claim ID." t.datetime "rating_issue_associated_at", comment: "Timestamp when a contention and its contested rating issue are associated in VBMS." t.string "split_issue_status", comment: "If a request issue is part of a split, on_hold status applies to the original request issues while active are request issues on splitted appeals" @@ -1486,6 +1492,8 @@ t.datetime "updated_at", comment: "Automatic timestamp whenever the record changes." t.string "vacols_id", comment: "The vacols_id of the legacy appeal that had an issue found to match the request issue." t.integer "vacols_sequence_id", comment: "The vacols_sequence_id, for the specific issue on the legacy appeal which the Claims Assistant determined to match the request issue on the Decision Review. A combination of the vacols_id (for the legacy appeal), and vacols_sequence_id (for which issue on the legacy appeal), is required to identify the issue being opted-in." + t.boolean "vbms_mst_status", default: false, comment: "Indicates if issue is related to Military Sexual Trauma (MST) and was imported from VBMS" + t.boolean "vbms_pact_status", default: false, comment: "Indicates if issue is related to Promise to Address Comprehensive Toxics (PACT) Act and was imported from VBMS" t.boolean "verified_unidentified_issue", comment: "A verified unidentified issue allows an issue whose rating data is missing to be intaken as a regular rating issue. In order to be marked as verified, a VSR needs to confirm that they were able to find the record of the decision for the issue." t.string "veteran_participant_id", comment: "The veteran participant ID. This should be unique in upstream systems and used in the future to reconcile duplicates." t.index ["closed_at"], name: "index_request_issues_on_closed_at" @@ -1511,6 +1519,8 @@ t.integer "edited_request_issue_ids", comment: "An array of the request issue IDs that were edited during this request issues update", array: true t.string "error", comment: "The error message if the last attempt at processing the request issues update was not successful." t.datetime "last_submitted_at", comment: "Timestamp for when the processing for the request issues update was last submitted. Used to determine how long to continue retrying the processing job. Can be reset to allow for additional retries." + t.integer "mst_edited_request_issue_ids", comment: "An array of the request issue IDs that were updated to be associated with MST in request issues update", array: true + t.integer "pact_edited_request_issue_ids", comment: "An array of the request issue IDs that were updated to be associated with PACT in request issues update", array: true t.datetime "processed_at", comment: "Timestamp for when the request issue update successfully completed processing." t.bigint "review_id", null: false, comment: "The ID of the decision review edited." t.string "review_type", null: false, comment: "The type of the decision review edited." @@ -1559,6 +1569,26 @@ t.index ["sent_by_id"], name: "index_sent_hearing_email_events_on_sent_by_id" end + create_table "special_issue_changes", force: :cascade do |t| + t.bigint "appeal_id", null: false, comment: "AMA or Legacy Appeal ID that the issue is tied to" + t.string "appeal_type", null: false, comment: "Appeal Type (Appeal or LegacyAppeal)" + t.string "change_category", null: false, comment: "Type of change that occured to the issue (Established Issue, Added Issue, Edited Issue, Removed Issue)" + t.datetime "created_at", null: false, comment: "Date the special issue change was made" + t.string "created_by_css_id", null: false, comment: "CSS ID of the user that made the special issue change" + t.bigint "created_by_id", null: false, comment: "User ID of the user that made the special issue change" + t.bigint "decision_issue_id", comment: "ID of the decision issue that had a special issue change from its corresponding request issue" + t.bigint "issue_id", null: false, comment: "ID of the issue that was changed" + t.boolean "mst_from_vbms", comment: "Indication that the MST status originally came from VBMS on intake" + t.string "mst_reason_for_change", comment: "Reason for changing the MST status on an issue" + t.boolean "original_mst_status", null: false, comment: "Original MST special issue status of the issue" + t.boolean "original_pact_status", null: false, comment: "Original PACT special issue status of the issue" + t.boolean "pact_from_vbms" + t.string "pact_reason_for_change", comment: "Reason for changing the PACT status on an issue" + t.bigint "task_id", null: false, comment: "Task ID of the IssueUpdateTask or EstablishmentTask used to log this issue in the case timeline" + t.boolean "updated_mst_status", comment: "Updated MST special issue status of the issue" + t.boolean "updated_pact_status", comment: "Updated PACT special issue status of the issue" + end + create_table "special_issue_lists", comment: "Associates special issues to an AMA or legacy appeal for Caseflow Queue. Caseflow Dispatch uses special issues stored in legacy_appeals. They are intentionally disconnected.", force: :cascade do |t| t.bigint "appeal_id", comment: "The ID of the appeal associated with this record" t.string "appeal_type", comment: "The type of appeal associated with this record" From 8d74aad42be771276583d7c5973bdcbe48841406 Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Mon, 14 Aug 2023 10:44:00 -0400 Subject: [PATCH 31/62] Adding shell script for DTA/DOO description remediaiton SOP --- .../dta_dto_description_remediation_by_report_load.sh | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh diff --git a/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh b/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh new file mode 100644 index 00000000000..3e92d9d181a --- /dev/null +++ b/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh @@ -0,0 +1,5 @@ +#! /bin/bash +cd /opt/caseflow-certification/src; bin/rails c << DONETOKEN +x = WarRoom::DtaDooDescriptionRemediationByReportLoad.new +x.run_by_report_load("$1", "$2") +DONETOKEN From 26fd47906ba6e3eccf03a66628bf4382fa04129c Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Mon, 14 Aug 2023 16:24:59 -0400 Subject: [PATCH 32/62] First iteration of DTA/DOO description remediation script --- ...taDooDescriptionRemediationByReportLoad.rb | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb diff --git a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb new file mode 100644 index 00000000000..60a39868442 --- /dev/null +++ b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true + +module WarRoom + + # Purpose: + class DtaDooDescriptionRemediation + + def run_by_report_load(report_load, di_ids = [], env='prod') + logs = ["DtaDooDescriptionRemediation::Log\n"]; + no_remand_generated = []; + remand_generated = []; + + # Set the user + RequestStore[:current_user] = User.system_user + + decision_issues = DecisionIssue.where(id: di_ids) + + higher_levels_reviews = decision_issues.map { |di| di.decision_review if di.decision_review.is_a?(HigherLevelReview) }.compact.uniq + + higher_levels_reviews.each do |hlr| + decision_issues = decision_issues.select { |di| di.decision_review_id == hlr.id && di.decision_review_type == 'HigherLevelReview' } + decision_issues.each do |di| + prev_disp = di.disposition ? di.disposition : "null" + new_disp = "" + if di.description.downcase.include?("duty to assist") && + !di.disposition.include?("DTA Error") && + !di.disposition.include?("Difference of Opinion") + + new_disp = "DTA Error" + di.update!(disposition: new_disp) + + log_message = <<-TEXT + #{Time.zone.now} DtaDooDescriptionRemediation::Log + HLR ID: #{di.decision_review.id}. DI ID: #{di.id} + Previous Disposition: '#{prev_disp}'. + DI Description: #{di.description} + Updating Disposition to '#{new_disp}'. + TEXT + logs.push(log_message) + + elsif di.description.downcase.include?("difference of opinion") && + !di.disposition.include?("Difference of Opinion") && + !di.disposition.include?("DTA Error") + + new_disp = "Difference of Opinion" + di.update!(disposition: new_disp) + + log_message <<-TEXT + #{Time.zone.now} DtaDooDescriptionRemediation::Log + HLR ID: #{di.decision_review.id}. DI ID: #{di.id} + Previous Disposition: '#{prev_disp}'. + DI Description: #{di.description} + Updating Disposition to '#{new_disp}'. + TEXT + logs.push(log_message) + end + end + + hlr.create_remand_supplemental_claims! + log_message = <<-TEXT + #{Time.zone.now} DtaDooDescriptionRemediation::Log + Creating Remand Supplemental Claim for + HLR ID: #{hlr.id}. + TEXT + logs.push(log_message) + end + + logs.push("Remediation Summary Report\n"); + remand_count = 0; + no_remand_count = 0; + + higher_levels_reviews.each do |hlr| + supp = SupplementalClaim.find_by(decision_review_remanded_id: hlr.id, decision_review_remanded_type: "HigherLevelReview") + if supp + remand_count += 1 + remand_generated.push("Remand Supplemental Claim ID: #{supp.id} was generated for HLR ID: #{hlr.id}. Claim ID: #{supp&.end_product_establishments&.first&.reference_id}") + else + no_remand_count += 1 + no_remand_generated.push("Error: No Remand Supplemental Claim was generated for HLR ID: #{hlr.id}.") + end + end + + log_message = <<-TEXT + Expected Number of Remand Supplemental Claims to be generated: #{hlrs.count}. + Number of Remand Supplemental Claims created: #{remand_count}. + Number of Remand Supplemental Claims NOT created: #{no_remand_count}. + TEXT + logs.push(log_message) + + logs = logs + remand_generated + no_remand_generated; + upload_logs_to_aws_s3 logs + + rescue => StandardError => error + logs.push("DtaDooDescriptionRemediation::Error -- Reference id #{ep_ref}"\ + "Time: #{Time.zone.now}"\ + "#{error.backtrace}") + end + + private + + def upload_logs_to_aws_s3(logs) + s3client = Aws::S3::Client.new; + s3resource = Aws::S3::Resource.new(client: s3client); + s3bucket = s3resource.bucket("data-remediation-output"); + file_name = "dta-doo-description-remediation-logs/dta-doo-description-remediation-log-#{Time.zone.now}"; + content = logs.join("\n"); + temporary_file = Tempfile.new("dta-log.txt"); + filepath = temporary_file.path; + temporary_file.write(content); + temporary_file.flush; + s3bucket.object(file_name).upload_file(filepath, acl: "private", server_side_encryption: "AES256"); + temporary_file.close!; + end + + end +end From c376385e4bc72298494b049e9aa4099c3af46e38 Mon Sep 17 00:00:00 2001 From: 631862 Date: Tue, 15 Aug 2023 11:54:04 -0400 Subject: [PATCH 33/62] Add meeting_type to user to capture new meeting type from frontend, debugging in byebug --- .../organizations/users_controller.rb | 9 ++--- app/models/organizations_user.rb | 20 ++++++----- .../administered_user_serializer.rb | 1 + client/app/queue/OrganizationUsers.jsx | 18 ++++++---- .../queue/SelectConferenceTypeRadioField.jsx | 35 ++++++++++++------- 5 files changed, 52 insertions(+), 31 deletions(-) diff --git a/app/controllers/organizations/users_controller.rb b/app/controllers/organizations/users_controller.rb index 13114138df1..d0a383ed6ca 100644 --- a/app/controllers/organizations/users_controller.rb +++ b/app/controllers/organizations/users_controller.rb @@ -30,10 +30,9 @@ def update if params.key?(:admin) adjust_admin_rights - elsif params.key?(:user) - update_user_meeting_type end + update_user_meeting_type render json: { users: json_administered_users([user_to_modify]) }, status: :ok end @@ -70,9 +69,11 @@ def adjust_admin_rights end def update_user_meeting_type - if params[:admin] == true - OrganizationsUser.update_user_to_webex_conference_type(user_to_modify, organization) + byebug + if params[:user] + OrganizationsUser.update_user_conference_type(user_to_modify, organization) end + byebug end def organization_url diff --git a/app/models/organizations_user.rb b/app/models/organizations_user.rb index 5474f7d01c4..6a477177f5c 100644 --- a/app/models/organizations_user.rb +++ b/app/models/organizations_user.rb @@ -28,18 +28,22 @@ def remove_admin_rights_from_user(user, organization) existing_record(user, organization)&.update!(admin: false) end - def update_user_to_webex_conference_type(user, organization) - if user.roles.include?("HearingCoordinator") - user.update!(pexip: false) - end - end + def update_user_conference_type(user, organization) + byebug - def update_user_to_pexip_conference_type(user, organization) - if user.roles.include?("HearingCoordinator") - user.update!(pexip: true) + if user.meeting_type + user.update!(meeting_type) end + + byebug end + # def update_user_to_pexip_conference_type(user, organization) + # if user.roles.include?("HearingCoordinator") + # user.update!(pexip: true) + # end + # end + def remove_user_from_organization(user, organization) if user_is_judge_of_team?(user, organization) fail Caseflow::Error::ActionForbiddenError, message: COPY::JUDGE_TEAM_REMOVE_JUDGE_ERROR diff --git a/app/models/serializers/work_queue/administered_user_serializer.rb b/app/models/serializers/work_queue/administered_user_serializer.rb index 61b86097292..f4ffcf0e3a9 100644 --- a/app/models/serializers/work_queue/administered_user_serializer.rb +++ b/app/models/serializers/work_queue/administered_user_serializer.rb @@ -11,4 +11,5 @@ class WorkQueue::AdministeredUserSerializer < WorkQueue::UserSerializer params[:organization].dvc&.eql?(object) end end + attribute :meeting_type end diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 9838a03223b..ad9d06d597e 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -214,12 +214,13 @@ export default class OrganizationUsers extends React.PureComponent { }); } - modifyConferenceType = (user) => () => { - console.log('hi'); + modifyConferenceType = (user, newMeetingType) => () => { + const payload = { data: { ...user, meeting_type: newMeetingType } }; + console.log(newMeetingType); - const payload = { data: { user } }; - - ApiUtil.patch(`/organizations/${this.props.organization}/users/${user.id}`, payload); + ApiUtil.patch(`/organizations/${this.props.organization}/users/${user.id}`, payload).then((response) => { + console.log(response); + }); } asyncLoadUser = (inputValue) => { @@ -280,7 +281,12 @@ export default class OrganizationUsers extends React.PureComponent { { this.state.organizationName === 'Hearing Admin' &&
    - +
    } } diff --git a/client/app/queue/SelectConferenceTypeRadioField.jsx b/client/app/queue/SelectConferenceTypeRadioField.jsx index b601d06a96e..103451a6d89 100644 --- a/client/app/queue/SelectConferenceTypeRadioField.jsx +++ b/client/app/queue/SelectConferenceTypeRadioField.jsx @@ -1,27 +1,30 @@ import React, { useState } from 'react'; import PropTypes from 'prop-types'; -// import ApiUtil from '../util/ApiUtil'; +import ApiUtil from '../util/ApiUtil'; import RadioField from '../components/RadioField'; import COPY from '../../COPY'; const radioOptions = [ { displayText: 'Pexip', - value: '1' }, + value: 'pexip' }, { displayText: 'Webex', - value: '2' } + value: 'webex' } ]; -const SelectConferenceTypeRadioField = ({ name, onClick }) => { - const [value, setValue] = useState('1'); +const SelectConferenceTypeRadioField = ({ name, meetingType, organization, user }) => { + const [value, setValue] = useState(meetingType); - // const modifyConferenceType = (user) => { - // const payload = { data: { user } }; + const modifyConferenceType = (newMeetingType) => { + const payload = { data: { ...user, attributes: { ...user.attributes, meeting_type: newMeetingType } } }; + console.log(newMeetingType); - // console.log('hi'); + ApiUtil.patch(`/organizations/${organization}/users/${user.id}`, payload).then((response) => { + console.log(response); + }); - // ApiUtil.patch(`/organizations/${this.props.organization}/users/${user.id}`, payload); - // }; + console.log(newMeetingType); + }; return ( <> @@ -30,15 +33,21 @@ const SelectConferenceTypeRadioField = ({ name, onClick }) => { name={name} options={radioOptions} value={value} - onChange={((newValue) => setValue(newValue) && onClick)} + onChange={((newValue) => setValue(newValue) || modifyConferenceType(newValue))} vertical /> ); }; SelectConferenceTypeRadioField.propTypes = { - name: PropTypes.string, - onClick: PropTypes.func + name: PropTypes.number, + onClick: PropTypes.func, + meetingType: PropTypes.string, + organization: PropTypes.string, + user: PropTypes.shape({ + id: PropTypes.number, + attributes: PropTypes.object + }) }; export default SelectConferenceTypeRadioField; From 2252eb2a6e299c126d9af2cfcebbeba248e09edc Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Tue, 15 Aug 2023 12:38:40 -0400 Subject: [PATCH 34/62] Updating DTA DOO remediation script --- ...taDooDescriptionRemediationByReportLoad.rb | 140 +++++++++++++++--- ..._description_remediation_by_report_load.sh | 0 2 files changed, 117 insertions(+), 23 deletions(-) mode change 100644 => 100755 lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh diff --git a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb index 60a39868442..4729d5f07ae 100644 --- a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb +++ b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb @@ -2,20 +2,30 @@ module WarRoom - # Purpose: - class DtaDooDescriptionRemediation + # Purpose: This remediation is intended to resolve an ongoing issue where a user in VBMS + # will inadvertantly set the disposition on a contention incorecctly when dealing with + # DTA Errors and Difference of Opinion. + class DtaDooDescriptionRemediationByReportLoad - def run_by_report_load(report_load, di_ids = [], env='prod') - logs = ["DtaDooDescriptionRemediation::Log\n"]; - no_remand_generated = []; - remand_generated = []; + S3_FILE_NAME = "dta-doo-description-remediation-logs/dta-doo-description-remediation-log" + S3_ACL = "private" + S3_ENCRYPTION = "AES256" + S3_BUCKET = "data-remediation-output" + + def run_by_report_load(report_load, env='prod') + logs = ["DtaDooDescriptionRemediation::Log\n"] + no_remand_generated = [] + remand_generated = [] # Set the user RequestStore[:current_user] = User.system_user - decision_issues = DecisionIssue.where(id: di_ids) + decision_issue_ids = get_decision_issue_ids(rep_load) + + decision_issues = DecisionIssue.where(id: decision_issue_ids) - higher_levels_reviews = decision_issues.map { |di| di.decision_review if di.decision_review.is_a?(HigherLevelReview) }.compact.uniq + # higher_levels_reviews = decision_issues.map { |di| di.decision_review if di.decision_review.is_a?(HigherLevelReview) }.compact.uniq + higher_levels_reviews = decision_issues.where(type: HigherLevelReview).map(&:decision_review).compact.uniq higher_levels_reviews.each do |hlr| decision_issues = decision_issues.select { |di| di.decision_review_id == hlr.id && di.decision_review_type == 'HigherLevelReview' } @@ -45,7 +55,7 @@ def run_by_report_load(report_load, di_ids = [], env='prod') new_disp = "Difference of Opinion" di.update!(disposition: new_disp) - log_message <<-TEXT + log_message = <<-TEXT #{Time.zone.now} DtaDooDescriptionRemediation::Log HLR ID: #{di.decision_review.id}. DI ID: #{di.id} Previous Disposition: '#{prev_disp}'. @@ -90,26 +100,110 @@ def run_by_report_load(report_load, di_ids = [], env='prod') logs = logs + remand_generated + no_remand_generated; upload_logs_to_aws_s3 logs - rescue => StandardError => error - logs.push("DtaDooDescriptionRemediation::Error -- Reference id #{ep_ref}"\ + # return report to user running remediation + logs + rescue StandardError => e + logs.push("DtaDooDescriptionRemediation::Error -- #{e.message}"\ "Time: #{Time.zone.now}"\ - "#{error.backtrace}") + "#{e.backtrace}") + + upload_logs_to_aws_s3 logs + logs end private def upload_logs_to_aws_s3(logs) - s3client = Aws::S3::Client.new; - s3resource = Aws::S3::Resource.new(client: s3client); - s3bucket = s3resource.bucket("data-remediation-output"); - file_name = "dta-doo-description-remediation-logs/dta-doo-description-remediation-log-#{Time.zone.now}"; - content = logs.join("\n"); - temporary_file = Tempfile.new("dta-log.txt"); - filepath = temporary_file.path; - temporary_file.write(content); - temporary_file.flush; - s3bucket.object(file_name).upload_file(filepath, acl: "private", server_side_encryption: "AES256"); - temporary_file.close!; + s3client = Aws::S3::Client.new + s3resource = Aws::S3::Resource.new(client: s3client) + s3bucket = s3resource.bucket(S3_BUCKET) + content = logs.join("\n") + temporary_file = Tempfile.new("dta-log.txt") + filepath = temporary_file.path + temporary_file.write(content) + temporary_file.flush + s3bucket.object("#{S3_FILE_NAME}-#{Time.zone.now}").upload_file(filepath, acl: S3_ACL, server_side_encryption: S3_ENCRYPTION) + temporary_file.close! + end + + # Grab qualifying descision issue IDs so we know what to remediate + def get_decision_issue_ids(rep_load, conn) + # Establish connection + conn = ActiveRecord::Base.connection + + raw_sql = <<~SQL + WITH oar_epe_ids as ( + SELECT DISTINCT epe.id as epe_id + FROM end_product_establishments epe + WHERE epe.reference_id in (SELECT DISTINCT reference_id + FROM ep_establishment_workaround + WHERE report_load = #{rep_load} + ) + ), + di_id_list as ( + SELECT DISTINCT di.id as decision_issue_ids + FROM end_product_establishments epe + JOIN request_issues ri + ON epe.id = ri.end_product_establishment_id + JOIN request_decision_issues rdi + ON ri.id = rdi.request_issue_id + JOIN decision_issues di + ON rdi.decision_issue_id = di.id + JOIN higher_level_reviews hlr + ON epe.source_type = 'HigherLevelReview' AND epe.source_id = hlr.id + WHERE epe.id IN (SELECT epe_id FROM oar_epe_ids) + AND (di.description ilike'%duty to assist%' OR di.description ilike '%Difference of Opinion%') + AND di.disposition not like '%DTA Error%' + AND di.disposition not like '%Difference of Opinion%' + AND epe.source_type = 'HigherLevelReview' + AND epe.synced_status = 'CLR' + ), + hlr_id_list as ( + SELECT DISTINCT hlr.id as hlr_ids + FROM end_product_establishments epe + JOIN request_issues ri + ON epe.id = ri.end_product_establishment_id + JOIN request_decision_issues rdi + ON ri.id = rdi.request_issue_id + JOIN decision_issues di + ON rdi.decision_issue_id = di.id + JOIN higher_level_reviews hlr + ON epe.source_type = 'HigherLevelReview' AND epe.source_id = hlr.id + WHERE epe.id IN (SELECT epe_id FROM oar_epe_ids) + AND (di.description ilike'%duty to assist%' OR di.description ilike '%Difference of Opinion%') + AND di.disposition not like '%DTA Error%' + AND di.disposition not like '%Difference of Opinion%' + AND epe.source_type = 'HigherLevelReview' + ), + remanded_hlr_ids as( + SELECT supplemental_claims.decision_review_remanded_id as hlr_ids_with_remand + FROM supplemental_claims + WHERE supplemental_claims.decision_review_remanded_id in (SELECT hlr_ids FROM hlr_id_list) + ) + SELECT DISTINCT di.id as decision_issue_ids, di.description, di.disposition, epe.id as epe_id, hlr.id as higher_level_review_id + FROM end_product_establishments epe + JOIN request_issues ri + ON epe.id = ri.end_product_establishment_id + JOIN request_decision_issues rdi + ON ri.id = rdi.request_issue_id + JOIN decision_issues di + ON rdi.decision_issue_id = di.id + JOIN higher_level_reviews hlr + ON epe.source_type = 'HigherLevelReview' AND epe.source_id = hlr.id + WHERE epe.id IN (SELECT epe_id FROM oar_epe_ids) + AND (di.description ilike'%duty to assist%' OR di.description ilike '%Difference of Opinion%') + AND di.disposition not like '%DTA Error%' + AND di.disposition not like '%Difference of Opinion%' + AND epe.source_type = 'HigherLevelReview' + AND hlr.id not in (SELECT hlr_ids_with_remand FROM remanded_hlr_ids) + SQL + + response = conn.execute(raw_sql) + + # Close the connection + conn.close + + response end end diff --git a/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh b/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh old mode 100644 new mode 100755 From d5df546e052de69674046117ef66659170b588c6 Mon Sep 17 00:00:00 2001 From: 631862 Date: Tue, 15 Aug 2023 15:59:57 -0400 Subject: [PATCH 35/62] Fixed bug so frontend hearings change is persisted to backend and updates user meeting type --- app/controllers/organizations/users_controller.rb | 8 ++++---- app/models/organizations_user.rb | 14 ++------------ client/app/queue/OrganizationUsers.jsx | 2 +- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/app/controllers/organizations/users_controller.rb b/app/controllers/organizations/users_controller.rb index d0a383ed6ca..fb319d65466 100644 --- a/app/controllers/organizations/users_controller.rb +++ b/app/controllers/organizations/users_controller.rb @@ -69,11 +69,11 @@ def adjust_admin_rights end def update_user_meeting_type - byebug - if params[:user] - OrganizationsUser.update_user_conference_type(user_to_modify, organization) + new_meeting_type = params.dig(:attributes, :meeting_type) + + if organization["url"] == HearingAdmin.singleton.url && new_meeting_type + OrganizationsUser.update_user_conference_type(user_to_modify, new_meeting_type) end - byebug end def organization_url diff --git a/app/models/organizations_user.rb b/app/models/organizations_user.rb index 6a477177f5c..23ce4f1c4b4 100644 --- a/app/models/organizations_user.rb +++ b/app/models/organizations_user.rb @@ -28,22 +28,12 @@ def remove_admin_rights_from_user(user, organization) existing_record(user, organization)&.update!(admin: false) end - def update_user_conference_type(user, organization) - byebug - + def update_user_conference_type(user, new_meeting_type) if user.meeting_type - user.update!(meeting_type) + user.update!(meeting_type: new_meeting_type) end - - byebug end - # def update_user_to_pexip_conference_type(user, organization) - # if user.roles.include?("HearingCoordinator") - # user.update!(pexip: true) - # end - # end - def remove_user_from_organization(user, organization) if user_is_judge_of_team?(user, organization) fail Caseflow::Error::ActionForbiddenError, message: COPY::JUDGE_TEAM_REMOVE_JUDGE_ERROR diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index ad9d06d597e..ecd4b47ef6b 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -286,7 +286,7 @@ export default class OrganizationUsers extends React.PureComponent { name={user.id} meetingType={user.attributes.meeting_type} organization={this.props.organization} - user={user}/> + user={user} /> } } From 6b2dad9a81dd58dcf7960e3a31f190d689fb4324 Mon Sep 17 00:00:00 2001 From: 631862 Date: Thu, 17 Aug 2023 11:59:35 -0400 Subject: [PATCH 36/62] Fixed linting issues and added rspec test to check the new meeting type --- client/app/queue/OrganizationUsers.jsx | 9 --------- .../app/queue/SelectConferenceTypeRadioField.jsx | 7 +------ spec/models/organizations_user_spec.rb | 14 ++++++++++++++ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index ecd4b47ef6b..15a96cdbe5d 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -214,15 +214,6 @@ export default class OrganizationUsers extends React.PureComponent { }); } - modifyConferenceType = (user, newMeetingType) => () => { - const payload = { data: { ...user, meeting_type: newMeetingType } }; - console.log(newMeetingType); - - ApiUtil.patch(`/organizations/${this.props.organization}/users/${user.id}`, payload).then((response) => { - console.log(response); - }); - } - asyncLoadUser = (inputValue) => { // don't search till we have min length input if (inputValue.length < 2) { diff --git a/client/app/queue/SelectConferenceTypeRadioField.jsx b/client/app/queue/SelectConferenceTypeRadioField.jsx index 103451a6d89..df60b69dfdb 100644 --- a/client/app/queue/SelectConferenceTypeRadioField.jsx +++ b/client/app/queue/SelectConferenceTypeRadioField.jsx @@ -17,13 +17,8 @@ const SelectConferenceTypeRadioField = ({ name, meetingType, organization, user const modifyConferenceType = (newMeetingType) => { const payload = { data: { ...user, attributes: { ...user.attributes, meeting_type: newMeetingType } } }; - console.log(newMeetingType); - ApiUtil.patch(`/organizations/${organization}/users/${user.id}`, payload).then((response) => { - console.log(response); - }); - - console.log(newMeetingType); + ApiUtil.patch(`/organizations/${organization}/users/${user.id}`, payload); }; return ( diff --git a/spec/models/organizations_user_spec.rb b/spec/models/organizations_user_spec.rb index bc148bd7a4f..5da85604906 100644 --- a/spec/models/organizations_user_spec.rb +++ b/spec/models/organizations_user_spec.rb @@ -114,4 +114,18 @@ end end end + + describe ".update_user_conference_type" do + let(:meeting_type) {user.meeting_type} + let(:new_meeting_type) {"webex"} + + subject { OrganizationsUser.update_user_conference_type(user, new_meeting_type) } + + context "when meeting type exists" do + it "should set meeting type to equal new meeting type" do + subject + expect(meeting_type).to eq(new_meeting_type) + end + end + end end From 14d76756416d0ae17db750db3af79692fddebac1 Mon Sep 17 00:00:00 2001 From: 631862 Date: Thu, 17 Aug 2023 14:43:51 -0400 Subject: [PATCH 37/62] Add information about patch response test --- .../app/queue/SelectConferenceTypeRadioField.test.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client/test/app/queue/SelectConferenceTypeRadioField.test.js b/client/test/app/queue/SelectConferenceTypeRadioField.test.js index 8dc2a89204f..df5b056ad74 100644 --- a/client/test/app/queue/SelectConferenceTypeRadioField.test.js +++ b/client/test/app/queue/SelectConferenceTypeRadioField.test.js @@ -4,6 +4,8 @@ import userEvent from '@testing-library/user-event'; import SelectConferenceTypeRadioField from 'app/queue/SelectConferenceTypeRadioField'; +jest.mock('app/util/ApiUtil'); + const defaults = { name: 'field1', value: '1', @@ -16,6 +18,7 @@ const defaults = { }; describe('SelectConferenceTypeRadioField', () => { + // the patch response change is being tested in the organizations_user_spec.rb test file const handleChange = jest.fn(); beforeEach(() => { @@ -47,12 +50,12 @@ describe('SelectConferenceTypeRadioField', () => { it('changes values by radio button selected', async () => { setupComponent(); - expect (defaults.value) === "1"; + expect(defaults.value) === '1'; const webexRadioButton = screen.getByText('Webex'); await userEvent.click(webexRadioButton); - expect(defaults.value) === "2"; - }) + expect(defaults.value) === '2'; + }); }); From 7c0f3c630cb7c5c60f7d12fc9834e1312bed4da3 Mon Sep 17 00:00:00 2001 From: 631862 Date: Thu, 17 Aug 2023 15:22:46 -0400 Subject: [PATCH 38/62] Fix code climates issues --- spec/models/organizations_user_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/models/organizations_user_spec.rb b/spec/models/organizations_user_spec.rb index 5da85604906..f68b294517d 100644 --- a/spec/models/organizations_user_spec.rb +++ b/spec/models/organizations_user_spec.rb @@ -116,8 +116,8 @@ end describe ".update_user_conference_type" do - let(:meeting_type) {user.meeting_type} - let(:new_meeting_type) {"webex"} + let(:meeting_type) { user.meeting_type } + let(:new_meeting_type) { "webex" } subject { OrganizationsUser.update_user_conference_type(user, new_meeting_type) } From 73aa405e46da112691c1e3058ff9dc861cddba44 Mon Sep 17 00:00:00 2001 From: 631862 Date: Fri, 18 Aug 2023 14:27:44 -0400 Subject: [PATCH 39/62] Jest testing fixed to check for changing values by radio button selection --- .../queue/SelectConferenceTypeRadioField.jsx | 4 +- .../SelectConferenceTypeRadioField.test.js | 45 +++++++++++++------ ...electConferenceTypeRadioField.test.js.snap | 12 ++--- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/client/app/queue/SelectConferenceTypeRadioField.jsx b/client/app/queue/SelectConferenceTypeRadioField.jsx index df60b69dfdb..805c88f26c1 100644 --- a/client/app/queue/SelectConferenceTypeRadioField.jsx +++ b/client/app/queue/SelectConferenceTypeRadioField.jsx @@ -35,12 +35,12 @@ const SelectConferenceTypeRadioField = ({ name, meetingType, organization, user }; SelectConferenceTypeRadioField.propTypes = { - name: PropTypes.number, + name: PropTypes.string, onClick: PropTypes.func, meetingType: PropTypes.string, organization: PropTypes.string, user: PropTypes.shape({ - id: PropTypes.number, + id: PropTypes.string, attributes: PropTypes.object }) }; diff --git a/client/test/app/queue/SelectConferenceTypeRadioField.test.js b/client/test/app/queue/SelectConferenceTypeRadioField.test.js index df5b056ad74..dd36e4f4343 100644 --- a/client/test/app/queue/SelectConferenceTypeRadioField.test.js +++ b/client/test/app/queue/SelectConferenceTypeRadioField.test.js @@ -1,35 +1,45 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import ApiUtil from 'app/util/ApiUtil'; import SelectConferenceTypeRadioField from 'app/queue/SelectConferenceTypeRadioField'; -jest.mock('app/util/ApiUtil'); +const createSpy = () => jest.spyOn(ApiUtil, 'patch'). + mockImplementation(() => jest.fn(() => Promise.resolve( + { + body: { } + } + ))); const defaults = { name: 'field1', value: '1', options: [ { displayText: 'Pexip', - value: '1' }, + value: 'pexip' }, { displayText: 'Webex', - value: '2' }, + value: 'webex' }, ], }; describe('SelectConferenceTypeRadioField', () => { - // the patch response change is being tested in the organizations_user_spec.rb test file - const handleChange = jest.fn(); - beforeEach(() => { jest.clearAllMocks(); }); - const setupComponent = (props = {}) => { + const setupComponent = (props = { + user: { + attributes: { + id: 1 + } + }, + meetingType: 'pexip', + organization: 'my org' + }) => { const utils = render( @@ -48,14 +58,23 @@ describe('SelectConferenceTypeRadioField', () => { expect(container).toMatchSnapshot(); }); - it('changes values by radio button selected', async () => { + it('changes values by radio button selected', () => { + let requestPatchSpy = createSpy(); + setupComponent(); - expect(defaults.value) === '1'; - const webexRadioButton = screen.getByText('Webex'); + const webexRadioButton = screen.getByRole('radio', { name: 'Webex' }); + const pexipRadioButton = screen.getByRole('radio', { name: 'Pexip' }); + + expect(webexRadioButton).not.toHaveAttribute('checked', ''); + expect(pexipRadioButton).toHaveAttribute('checked', ''); + + userEvent.click(webexRadioButton); + + expect(requestPatchSpy.mock.calls[0][1].data.attributes.meeting_type).toBe('webex'); - await userEvent.click(webexRadioButton); + userEvent.click(pexipRadioButton); - expect(defaults.value) === '2'; + expect(requestPatchSpy.mock.calls[1][1].data.attributes.meeting_type).toBe('pexip'); }); }); diff --git a/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap b/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap index 4c89e26a554..40d135d3387 100644 --- a/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap +++ b/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap @@ -21,14 +21,14 @@ exports[`SelectConferenceTypeRadioField renders correctly 1`] = ` > @@ -37,14 +37,14 @@ exports[`SelectConferenceTypeRadioField renders correctly 1`] = ` class="cf-form-radio-option" > From fac53e0daf229775652415e1f8a3cc8d5cd9ae00 Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Mon, 21 Aug 2023 08:21:17 -0400 Subject: [PATCH 40/62] Updating script to fix duplication --- ...taDooDescriptionRemediationByReportLoad.rb | 104 +++++++----------- 1 file changed, 41 insertions(+), 63 deletions(-) diff --git a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb index 4729d5f07ae..e794b238fa7 100644 --- a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb +++ b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb @@ -1,18 +1,16 @@ # frozen_string_literal: true module WarRoom - # Purpose: This remediation is intended to resolve an ongoing issue where a user in VBMS # will inadvertantly set the disposition on a contention incorecctly when dealing with # DTA Errors and Difference of Opinion. class DtaDooDescriptionRemediationByReportLoad - - S3_FILE_NAME = "dta-doo-description-remediation-logs/dta-doo-description-remediation-log" + S3_FILE_NAME = "dta-doo-description-remediation-logs" S3_ACL = "private" S3_ENCRYPTION = "AES256" S3_BUCKET = "data-remediation-output" - def run_by_report_load(report_load, env='prod') + def run_by_report_load(report_load) logs = ["DtaDooDescriptionRemediation::Log\n"] no_remand_generated = [] remand_generated = [] @@ -20,93 +18,73 @@ def run_by_report_load(report_load, env='prod') # Set the user RequestStore[:current_user] = User.system_user - decision_issue_ids = get_decision_issue_ids(rep_load) - - decision_issues = DecisionIssue.where(id: decision_issue_ids) + decision_issues = DecisionIssue.where(id: get_decision_issue_ids(report_load)) - # higher_levels_reviews = decision_issues.map { |di| di.decision_review if di.decision_review.is_a?(HigherLevelReview) }.compact.uniq higher_levels_reviews = decision_issues.where(type: HigherLevelReview).map(&:decision_review).compact.uniq higher_levels_reviews.each do |hlr| - decision_issues = decision_issues.select { |di| di.decision_review_id == hlr.id && di.decision_review_type == 'HigherLevelReview' } + decision_issues = decision_issues.select do |di| + di.decision_review_id == hlr.id && di.decision_review_type == 'HigherLevelReview' + end + decision_issues.each do |di| - prev_disp = di.disposition ? di.disposition : "null" - new_disp = "" - if di.description.downcase.include?("duty to assist") && - !di.disposition.include?("DTA Error") && - !di.disposition.include?("Difference of Opinion") - - new_disp = "DTA Error" - di.update!(disposition: new_disp) - - log_message = <<-TEXT - #{Time.zone.now} DtaDooDescriptionRemediation::Log - HLR ID: #{di.decision_review.id}. DI ID: #{di.id} - Previous Disposition: '#{prev_disp}'. - DI Description: #{di.description} - Updating Disposition to '#{new_disp}'. - TEXT - logs.push(log_message) - - elsif di.description.downcase.include?("difference of opinion") && - !di.disposition.include?("Difference of Opinion") && - !di.disposition.include?("DTA Error") - - new_disp = "Difference of Opinion" - di.update!(disposition: new_disp) - - log_message = <<-TEXT - #{Time.zone.now} DtaDooDescriptionRemediation::Log - HLR ID: #{di.decision_review.id}. DI ID: #{di.id} - Previous Disposition: '#{prev_disp}'. - DI Description: #{di.description} - Updating Disposition to '#{new_disp}'. - TEXT - logs.push(log_message) - end + next if di.disposition.include?("Difference of Opinion") + next if di.disposition.include?("DTA Error") + + new_disp = if di.description.downcase.include?("duty to assist") + "DTA Error" + elsif di.description.downcase.include?("difference of opinion") + "Difference of Opinion" + end + + logs.push <<-TEXT + #{Time.zone.now} DtaDooDescriptionRemediation::Log + HLR ID: #{di.decision_review.id}. DI ID: #{di.id} + Previous Disposition: '#{di.disposition}'. + DI Description: #{di.description} + Updating Disposition to '#{new_disp}'. + TEXT + + di.update!(disposition: new_disp) end hlr.create_remand_supplemental_claims! - log_message = <<-TEXT + logs.push <<-TEXT #{Time.zone.now} DtaDooDescriptionRemediation::Log Creating Remand Supplemental Claim for HLR ID: #{hlr.id}. TEXT - logs.push(log_message) end logs.push("Remediation Summary Report\n"); - remand_count = 0; - no_remand_count = 0; + remand_count = 0 + no_remand_count = 0 higher_levels_reviews.each do |hlr| - supp = SupplementalClaim.find_by(decision_review_remanded_id: hlr.id, decision_review_remanded_type: "HigherLevelReview") + supp = SupplementalClaim.find_by(decision_review_remanded_id: hlr.id, + decision_review_remanded_type: "HigherLevelReview") if supp remand_count += 1 - remand_generated.push("Remand Supplemental Claim ID: #{supp.id} was generated for HLR ID: #{hlr.id}. Claim ID: #{supp&.end_product_establishments&.first&.reference_id}") + remand_generated.push("Remand Supplemental Claim ID: #{supp.id} was generated for HLR ID: #{hlr.id}. + Claim ID: #{supp&.end_product_establishments&.first&.reference_id}") else no_remand_count += 1 no_remand_generated.push("Error: No Remand Supplemental Claim was generated for HLR ID: #{hlr.id}.") end end - log_message = <<-TEXT + logs.push <<-TEXT Expected Number of Remand Supplemental Claims to be generated: #{hlrs.count}. Number of Remand Supplemental Claims created: #{remand_count}. Number of Remand Supplemental Claims NOT created: #{no_remand_count}. TEXT - logs.push(log_message) - logs = logs + remand_generated + no_remand_generated; - upload_logs_to_aws_s3 logs - - # return report to user running remediation - logs - rescue StandardError => e - logs.push("DtaDooDescriptionRemediation::Error -- #{e.message}"\ + logs = logs + remand_generated + no_remand_generated + rescue StandardError => error + logs.push("DtaDooDescriptionRemediation::Error -- #{error.message}"\ "Time: #{Time.zone.now}"\ - "#{e.backtrace}") - + "#{error.backtrace}") + ensure upload_logs_to_aws_s3 logs logs end @@ -122,12 +100,13 @@ def upload_logs_to_aws_s3(logs) filepath = temporary_file.path temporary_file.write(content) temporary_file.flush - s3bucket.object("#{S3_FILE_NAME}-#{Time.zone.now}").upload_file(filepath, acl: S3_ACL, server_side_encryption: S3_ENCRYPTION) + s3bucket.object("#{S3_FILE_NAME}-#{Time.zone.now}") + .upload_file(filepath, acl: S3_ACL, server_side_encryption: S3_ENCRYPTION) temporary_file.close! end # Grab qualifying descision issue IDs so we know what to remediate - def get_decision_issue_ids(rep_load, conn) + def get_decision_issue_ids(rep_load) # Establish connection conn = ActiveRecord::Base.connection @@ -205,6 +184,5 @@ def get_decision_issue_ids(rep_load, conn) response end - end end From c741cc43e70c29a88f8905c2a16fab69f86a7d2b Mon Sep 17 00:00:00 2001 From: Prajwal Amatya <122557351+pamatyatake2@users.noreply.github.com> Date: Mon, 21 Aug 2023 09:00:33 -0600 Subject: [PATCH 41/62] Pamatya/APPEALS-24131: Fix flaky/skipped tests in models/idt/token_spec.rb (#19208) * removing the xit and adding new test * Added a test for an expired key for the Idt::Token active method * APPEALS-24131: removed unused let statement * Removed the sleep statement from the test. * Included a docket_spec test fix as well. --------- Co-authored-by: = --- spec/models/docket_spec.rb | 3 +-- spec/models/idt/token_spec.rb | 8 +++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/spec/models/docket_spec.rb b/spec/models/docket_spec.rb index 78e6734650b..fe65466a522 100644 --- a/spec/models/docket_spec.rb +++ b/spec/models/docket_spec.rb @@ -553,12 +553,11 @@ end it "sets the case ids when a redistribution occurs" do - distributed_case.id ymd = Time.zone.today.strftime("%F") result = subject expect(DistributedCase.find(distributed_case.id).case_id).to eq("#{distributed_appeal.uuid}-redistributed-#{ymd}") - expect(result[0].case_id).to eq(distributed_appeal.uuid) + expect(result.any? { |item| item.case_id == distributed_appeal.uuid }).to be_truthy end end diff --git a/spec/models/idt/token_spec.rb b/spec/models/idt/token_spec.rb index 90a17bf2c1b..6401aecfa79 100644 --- a/spec/models/idt/token_spec.rb +++ b/spec/models/idt/token_spec.rb @@ -7,6 +7,7 @@ let(:css_id) { "TEST_ID" } let(:key_token_pair) { Idt::Token.generate_one_time_key_and_proposed_token } + # rubocop:disable Metrics/LineLength let(:invalid_token) { "9373a256a2ac3c3bd320adeeb8a1e4d996ef064d1332357954410f25740bf0c17b6565e152760c461a85587e6a6845457f955ccfa20a8e462a77b776eb10b72c" } # rubocop:enable Metrics/LineLength @@ -50,7 +51,12 @@ expect(Idt::Token.active?(invalid_token)).to eq(false) end - xit "returns false after a token expires" do + it "returns false after a token expires" do + key, token = key_token_pair + Idt::Token.activate_proposed_token(key, css_id) + expect(Idt::Token.active?(token)).to eq(true) + Idt::Token.client.expire("valid_tokens_key" + token, -1) + expect(Idt::Token.active?(token)).to eq(false) end end end From 96cc94ecfa86f9aa8172ef0d8cb847beeb4d8170 Mon Sep 17 00:00:00 2001 From: Brandon Lee Dorner Date: Mon, 21 Aug 2023 10:34:09 -0500 Subject: [PATCH 42/62] Remove skipped and unneeded feature test (#19214) This will be explained more in the accompanying PR but this test has been skipped for a couple years and does not need to be in the code base anymore as it does not add any value. --- .../substitute_appellant_task_copy_spec.rb | 149 ------------------ 1 file changed, 149 deletions(-) delete mode 100644 spec/feature/queue/substitute_appellant/substitute_appellant_task_copy_spec.rb diff --git a/spec/feature/queue/substitute_appellant/substitute_appellant_task_copy_spec.rb b/spec/feature/queue/substitute_appellant/substitute_appellant_task_copy_spec.rb deleted file mode 100644 index 30b7536c417..00000000000 --- a/spec/feature/queue/substitute_appellant/substitute_appellant_task_copy_spec.rb +++ /dev/null @@ -1,149 +0,0 @@ -# frozen_string_literal: true - -def wait_for_page_render - # This find forces a wait for the page to render. Without it, a test asserting presence or absence of content - # may pass whether the content is present or not! - find("div", id: "caseTitleDetailsSubheader") -end - -def select_task_ids_in_ui(task_ids) - visit "/queue" - visit "/queue/appeals/#{appeal.uuid}" - wait_for_page_render - - click_on "+ Add Substitute" - - fill_in("substitutionDate", with: Time.zone.parse("2021-01-01")) - find("label", text: "Bob Vance, Spouse").click - click_on "Continue" - - # Uncomment this if you wish to use demo specific selections in the browser - # binding.pry - # appeal.treee - - task_ids.each do |task_id| - find("div", class: "checkbox-wrapper-taskIds[#{task_id}]").find("label").click - end - click_on "Continue" - click_on "Confirm" - wait_for_page_render -end - -# Since the appeal is imported from JSON, the IDs here are always the below values. -# Give them friendly names for easier access -TASKS = { - distribution: 2_000_758_353, - schedule_hearing: 2_000_758_355, - assign_hearing_disposition: 2_001_178_199, - address_verify: 2_001_143_838, - transcription: 2_001_233_993, - evidence_submission_window: 2_001_233_994, - evidence_or_argument_mail: 2_001_578_851 -}.freeze - -note = "This test is only used to aid manual testing/demonstration." -RSpec.feature "CASEFLOW-1501 Substitute appellant behavior", :postgres, skip: note do - describe "Substitute Appellant appeal creation" do - before do - cob_user = create(:user, css_id: "COB_USER", station_id: "101") - ClerkOfTheBoard.singleton.add_user(cob_user) - OrganizationsUser.make_user_admin(cob_user, ClerkOfTheBoard.singleton) - User.authenticate!(user: cob_user) - end - - let!(:appeal) do - sji = SanitizedJsonImporter.from_file( - "db/seeds/sanitized_json/b5eba21a-9baf-41a3-ac1c-08470c2b79c4.json", - verbosity: 0 - ) - sji.import - sji.imported_records[Appeal.table_name].first - end - - let(:new_appeal) do - appellant_substitution = AppellantSubstitution.find_by(source_appeal_id: appeal.id) - appellant_substitution.target_appeal - end - - context "with an EvidenceSubmissionWindowTask selected" do - before do - select_task_ids_in_ui([TASKS[:evidence_submission_window]]) - end - - it "show a success message" do - expect(page).to have_content("You have successfully added a substitute appellant") - end - - it "prints the generated task tree" do - new_appeal.treee - end - end - - context "with a ScheduleHearingTask selected" do - before do - select_task_ids_in_ui([TASKS[:schedule_hearing]]) - end - - it "prints a task tree" do - new_appeal.treee - end - end - - context "with a HearingAdminActionVerifyAddressTask selected" do - before do - select_task_ids_in_ui([TASKS[:address_verify]]) - end - - it "creates a proper task tree" do - new_appeal.treee - - sht = ScheduleHearingTask.find_by(appeal_id: new_appeal.id) - expect(sht.status).to eq "on_hold" - - haavat = HearingAdminActionVerifyAddressTask.find_by(appeal_id: new_appeal.id) - expect(haavat.status).to eq "assigned" - expect(haavat.assigned_to.type).to eq "HearingsManagement" - end - end - - context "with an AssignHearingDispositionTask selected" do - before do - select_task_ids_in_ui([TASKS[:assign_hearing_disposition]]) - end - - it "prints a task tree" do - new_appeal.treee - end - end - - context "with a TranscriptionTask selected" do - before do - select_task_ids_in_ui([TASKS[:transcription]]) - end - - it "prints a task tree" do - new_appeal.treee - end - end - - context "with EvidenceSubmissionWindow and Transcription selected" do - before do - select_task_ids_in_ui([TASKS[:evidence_submission_window], TASKS[:transcription]]) - end - - it "prints a task tree" do - new_appeal.treee - end - end - - context "with Verify Address and Schedule Hearing selected" do - before do - select_task_ids_in_ui([TASKS[:address_verify], TASKS[:schedule_hearing]]) - end - - it "prints a task tree" do - new_appeal.treee - end - end - end -end From 71aefea59f8e968f1e14c3f0bb6a46f1edd7aa69 Mon Sep 17 00:00:00 2001 From: Sean Craig <110493538+seancva@users.noreply.github.com> Date: Mon, 21 Aug 2023 10:45:03 -0500 Subject: [PATCH 43/62] APPEALS-24145 Fix test scenario "Assigning it to complete the claims establishment" (#19209) * deleted a flakey hang and added an expect for the url * Added a few more expects * small formating changes * removed no longer needed comment * removed unneccesarcy expect --- spec/feature/dispatch/establish_claim_spec.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/spec/feature/dispatch/establish_claim_spec.rb b/spec/feature/dispatch/establish_claim_spec.rb index 15442585c9a..02cab5c7992 100644 --- a/spec/feature/dispatch/establish_claim_spec.rb +++ b/spec/feature/dispatch/establish_claim_spec.rb @@ -141,6 +141,7 @@ end visit "/dispatch/work-assignments" + expect(page).to have_content("1.\nJanet Smith\n0 0 1 1 3") expect(page).to have_content("2.\nJune Smith\n1 0 0 1 2") expect(page).to have_content("3.\nJeffers Smith\n0 1 0 1 2") @@ -544,6 +545,7 @@ click_label("confirmNote") click_on "Finish routing claim" + expect(page).to have_current_path("/dispatch/establish-claim/#{task.id}") expect(page).to have_content("Success!") expect(page).to have_content("Reviewed Full Grant decision") expect(page).to have_content("Established EP: 070BVAGR - BVA Grant (070) for Station 351 - Muskogee") @@ -579,6 +581,7 @@ click_on "Finish routing claim" # Confirmation Page + expect(page).to have_current_path("/dispatch/establish-claim/#{task.id}") expect(page).to have_content("Success!") expect(page).to have_content("Added VBMS Note on Rice Compliance") @@ -623,7 +626,7 @@ ) end - scenario "Assigning it to complete the claims establishment", skip: "flakey hang" do + scenario "Assigning it to complete the claims establishment" do visit "/dispatch/establish-claim" click_on "Establish next claim" @@ -631,8 +634,9 @@ expect(page).to have_current_path("/dispatch/establish-claim/#{task.id}") expect(page).to have_content("Route Claim") expect(page).to have_selector(:link_or_button, "Assign to Claim") - click_on "Assign to Claim" # unknown reason sometimes hangs here + click_on "Assign to Claim" + expect(page).to have_current_path("/dispatch/establish-claim/#{task.id}") expect(page).to have_content("Success!") expect(task.reload.outgoing_reference_id).to eq(end_product.claim_id) @@ -671,6 +675,7 @@ click_on "Create End Product" # Confirmation Page + expect(page).to have_current_path("/dispatch/establish-claim/#{task.id}") expect(page).to have_content("Success!") expect(page).to have_content("Established EP: 070RMBVAGARC - ARC Remand with BVA Grant for Station 397 - ARC") expect(page).to have_content("VACOLS Updated: Changed Location to 98") @@ -768,6 +773,7 @@ safe_click "#button-Finish-routing-claim" + expect(page).to have_current_path("/dispatch/establish-claim/#{task.id}") expect(page).to have_content("Success!") expect(page).to have_content("VACOLS Updated: Changed Location to 50") expect(page).to have_content("Added VBMS Note on Rice Compliance") @@ -824,6 +830,7 @@ click_on "Finish routing claim" + expect(page).to have_current_path("/dispatch/establish-claim/#{task.id}") expect(page).to have_content("Success!") expect(task.reload.completion_status).to eq("special_issue_vacols_routed") end @@ -855,6 +862,7 @@ click_on "Create new EP" click_on "Create End Product" + expect(page).to have_current_path("/dispatch/establish-claim/#{task.id}") expect(page).to have_content("Success!") expect(Fakes::VBMSService).to have_received(:establish_claim!).with( From 71e5a1e41af0447663f01444352c3782381b0063 Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Mon, 21 Aug 2023 14:13:32 -0400 Subject: [PATCH 44/62] Cleaning up loop for disposition selection and remediation --- lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb index e794b238fa7..ba84729e170 100644 --- a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb +++ b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb @@ -35,6 +35,8 @@ def run_by_report_load(report_load) "DTA Error" elsif di.description.downcase.include?("difference of opinion") "Difference of Opinion" + else + next end logs.push <<-TEXT From b5d3f28ff7a854e5b722673ee298a562ccc82231 Mon Sep 17 00:00:00 2001 From: mikefinneran <110622959+mikefinneran@users.noreply.github.com> Date: Mon, 21 Aug 2023 14:35:13 -0400 Subject: [PATCH 45/62] Revert "laurenoelle/APPEALS-19871 initial files" --- app/controllers/application_controller.rb | 5 --- app/views/reader/appeal/index.html.erb | 1 - client/app/reader/DecisionReviewer.jsx | 2 - .../DocumentList/DocumentListActions.js | 7 ++-- .../DocumentList/DocumentListReducer.js | 6 ++- client/app/reader/LastRetrievalAlert.jsx | 38 ++++++++----------- client/app/reader/LastRetrievalInfo.jsx | 13 +++++-- client/app/reader/PdfListView.jsx | 8 ++-- config/environments/demo.rb | 3 -- 9 files changed, 37 insertions(+), 46 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index bb3e4cc7797..f1e67283d53 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -380,11 +380,6 @@ def feedback_url end helper_method :feedback_url - def efolder_express_url - Rails.application.config.efolder_url.to_s - end - helper_method :efolder_express_url - def help_url { "certification" => certification_help_path, diff --git a/app/views/reader/appeal/index.html.erb b/app/views/reader/appeal/index.html.erb index f57c2c57ca4..7c65fbd45f0 100644 --- a/app/views/reader/appeal/index.html.erb +++ b/app/views/reader/appeal/index.html.erb @@ -7,7 +7,6 @@ applicationUrls: application_urls, page: "DecisionReviewer", feedbackUrl: feedback_url, - efolderExpressUrl: efolder_express_url, featureToggles: { interfaceVersion2: FeatureToggle.enabled?(:interface_version_2, user: current_user), windowSlider: FeatureToggle.enabled?(:window_slider, user: current_user), diff --git a/client/app/reader/DecisionReviewer.jsx b/client/app/reader/DecisionReviewer.jsx index dcbda91528a..2d676eb5e62 100644 --- a/client/app/reader/DecisionReviewer.jsx +++ b/client/app/reader/DecisionReviewer.jsx @@ -92,7 +92,6 @@ export class DecisionReviewer extends React.PureComponent { annotations={this.props.annotations} vacolsId={vacolsId}> ({ } }); -export const onReceiveManifests = (manifestVbmsFetchedAt) => ({ +export const onReceiveManifests = (manifestVbmsFetchedAt, manifestVvaFetchedAt) => ({ type: Constants.RECEIVE_MANIFESTS, - payload: { - manifestVbmsFetchedAt - } + payload: { manifestVbmsFetchedAt, + manifestVvaFetchedAt } }); diff --git a/client/app/reader/DocumentList/DocumentListReducer.js b/client/app/reader/DocumentList/DocumentListReducer.js index 1107e7cea8b..dd96cc2539e 100644 --- a/client/app/reader/DocumentList/DocumentListReducer.js +++ b/client/app/reader/DocumentList/DocumentListReducer.js @@ -54,7 +54,8 @@ const initialState = { category: false } }, - manifestVbmsFetchedAt: null + manifestVbmsFetchedAt: null, + manifestVvaFetchedAt: null }; const documentListReducer = (state = initialState, action = {}) => { @@ -180,6 +181,9 @@ const documentListReducer = (state = initialState, action = {}) => { return update(state, { manifestVbmsFetchedAt: { $set: action.payload.manifestVbmsFetchedAt + }, + manifestVvaFetchedAt: { + $set: action.payload.manifestVvaFetchedAt } }); case Constants.UPDATE_FILTERED_RESULTS: diff --git a/client/app/reader/LastRetrievalAlert.jsx b/client/app/reader/LastRetrievalAlert.jsx index e5a3d341f27..880296536b5 100644 --- a/client/app/reader/LastRetrievalAlert.jsx +++ b/client/app/reader/LastRetrievalAlert.jsx @@ -1,7 +1,6 @@ import _ from 'lodash'; import moment from 'moment'; import React from 'react'; -import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import Alert from '../components/Alert'; import { css } from 'glamor'; @@ -16,33 +15,34 @@ class LastRetrievalAlert extends React.PureComponent { render() { - // Check that document manifests have been recieved from VBMS -- red banner - if (!this.props.manifestVbmsFetchedAt) { + // Check that document manifests have been recieved from VVA and VBMS + if (!this.props.manifestVbmsFetchedAt || !this.props.manifestVvaFetchedAt) { return
    - Some of {this.props.appeal.veteran_full_name}'s documents are unavailable at the moment due to - a loading error from their eFolder. As a result, you may be viewing a partial list of eFolder documents. + Some of {this.props.appeal.veteran_full_name}'s documents are not available at the moment due to + a loading error from VBMS or VVA. As a result, you may be viewing a partial list of claims folder documents.
    - Please visit eFolder Express to fetch the - latest list of documents or submit a support ticket to sync their eFolder with Reader. +
    + Please refresh your browser at a later point to view a complete list of documents in the claims + folder.
    ; } const staleCacheTime = moment().subtract(CACHE_TIMEOUT_HOURS, 'h'), - vbmsManifestTimestamp = moment(this.props.manifestVbmsFetchedAt, 'MM/DD/YY HH:mma Z'); + vbmsManifestTimestamp = moment(this.props.manifestVbmsFetchedAt, 'MM/DD/YY HH:mma Z'), + vvaManifestTimestamp = moment(this.props.manifestVvaFetchedAt, 'MM/DD/YY HH:mma Z'); - // Check that manifest results are fresh -- yellow banner - if (vbmsManifestTimestamp.isBefore(staleCacheTime)) { + // Check that manifest results are fresh + if (vbmsManifestTimestamp.isBefore(staleCacheTime) || vvaManifestTimestamp.isBefore(staleCacheTime)) { const now = moment(), - vbmsDiff = now.diff(vbmsManifestTimestamp, 'hours'); + vbmsDiff = now.diff(vbmsManifestTimestamp, 'hours'), + vvaDiff = now.diff(vvaManifestTimestamp, 'hours'); return
    - Reader last synced the list of documents with {this.props.appeal.veteran_full_name}'s eFolder - {vbmsDiff} hours ago. If you'd like to view documents in Reader uploaded to their eFolder since - the last sync, please visit eFolder Express - to fetch the latest list of documents or submit a support ticket to sync their eFolder with Reader. + We last synced with VBMS and VVA {Math.max(vbmsDiff, vvaDiff)} hours ago. If you'd like to check for new + documents, refresh the page.
    ; } @@ -51,12 +51,6 @@ class LastRetrievalAlert extends React.PureComponent { } } -LastRetrievalAlert.propTypes = { - manifestVbmsFetchedAt: PropTypes.string, - efolderExpressUrl: PropTypes.string, - appeal: PropTypes.object, -}; - export default connect( - (state) => _.pick(state.documentList, 'manifestVbmsFetchedAt') + (state) => _.pick(state.documentList, ['manifestVvaFetchedAt', 'manifestVbmsFetchedAt']) )(LastRetrievalAlert); diff --git a/client/app/reader/LastRetrievalInfo.jsx b/client/app/reader/LastRetrievalInfo.jsx index 845929f2076..01e43efda38 100644 --- a/client/app/reader/LastRetrievalInfo.jsx +++ b/client/app/reader/LastRetrievalInfo.jsx @@ -7,15 +7,22 @@ class UnconnectedLastRetrievalInfo extends React.PureComponent { return [ this.props.manifestVbmsFetchedAt ?
    - Last synced with {this.props.appeal.veteran_full_name}'s eFolder: {this.props.manifestVbmsFetchedAt.slice(0, -5)} + Last VBMS retrieval: {this.props.manifestVbmsFetchedAt.slice(0, -5)}
    :
    - Unable to display eFolder documents at this time + Unable to display VBMS documents at this time +
    , + this.props.manifestVvaFetchedAt ? +
    + Last VVA retrieval: {this.props.manifestVvaFetchedAt.slice(0, -5)} +
    : +
    + Unable to display VVA documents at this time
    ]; } } export default connect( - (state) => _.pick(state.documentList, 'manifestVbmsFetchedAt') + (state) => _.pick(state.documentList, ['manifestVvaFetchedAt', 'manifestVbmsFetchedAt']) )(UnconnectedLastRetrievalInfo); diff --git a/client/app/reader/PdfListView.jsx b/client/app/reader/PdfListView.jsx index 4a2c907bd45..8ac596eba42 100644 --- a/client/app/reader/PdfListView.jsx +++ b/client/app/reader/PdfListView.jsx @@ -68,7 +68,7 @@ export class PdfListView extends React.Component {
    - + - +
    ; } } @@ -108,8 +108,6 @@ export default connect( PdfListView.propTypes = { documents: PropTypes.arrayOf(PropTypes.object).isRequired, - efolderExpressUrl: PropTypes.string, onJumpToComment: PropTypes.func, - sortBy: PropTypes.string, - appeal: PropTypes.object, + sortBy: PropTypes.string }; diff --git a/config/environments/demo.rb b/config/environments/demo.rb index e937ce9b7ff..f6d7574b65f 100644 --- a/config/environments/demo.rb +++ b/config/environments/demo.rb @@ -82,9 +82,6 @@ ENV["DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL"] ||= "true" - # eFolder Express URL for demo environment used as a mock link - ENV["EFOLDER_EXPRESS_URL"] ||= "http://localhost:4000" - # Setup S3 config.s3_enabled = ENV["AWS_BUCKET_NAME"].present? config.s3_bucket_name = ENV["AWS_BUCKET_NAME"] From 0ae957633f25cf0ce3f26600a7d8a7a69bfcef7d Mon Sep 17 00:00:00 2001 From: 631862 Date: Tue, 22 Aug 2023 10:24:36 -0400 Subject: [PATCH 46/62] Hearing Admin selection changed to Hearings Management --- app/controllers/organizations/users_controller.rb | 2 +- client/app/queue/OrganizationUsers.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/organizations/users_controller.rb b/app/controllers/organizations/users_controller.rb index fb319d65466..4d6cd9eb2a5 100644 --- a/app/controllers/organizations/users_controller.rb +++ b/app/controllers/organizations/users_controller.rb @@ -71,7 +71,7 @@ def adjust_admin_rights def update_user_meeting_type new_meeting_type = params.dig(:attributes, :meeting_type) - if organization["url"] == HearingAdmin.singleton.url && new_meeting_type + if organization["url"] == HearingsManagement.singleton.url && new_meeting_type OrganizationsUser.update_user_conference_type(user_to_modify, new_meeting_type) end end diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 15a96cdbe5d..12b38c018c0 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -270,7 +270,7 @@ export default class OrganizationUsers extends React.PureComponent { { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } { this.removeUserButton(user) } - { this.state.organizationName === 'Hearing Admin' && + { this.state.organizationName === 'Hearings Management' &&
    Date: Wed, 23 Aug 2023 09:18:53 -0600 Subject: [PATCH 47/62] fixing flaky test (#19231) * fixing flaky test * removing commented code --- spec/feature/queue/motion_to_vacate_spec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/feature/queue/motion_to_vacate_spec.rb b/spec/feature/queue/motion_to_vacate_spec.rb index 1841031eaf7..6729215647a 100644 --- a/spec/feature/queue/motion_to_vacate_spec.rb +++ b/spec/feature/queue/motion_to_vacate_spec.rb @@ -678,7 +678,7 @@ def return_to_lit_support(disposition:) it "correctly handles return to judge" do User.authenticate!(user: drafting_attorney) - visit "/queue/appeals/#{vacate_stream.uuid}" + reload_case_detail_page(vacate_stream.uuid) check_cavc_alert verify_cavc_conflict_action @@ -691,7 +691,9 @@ def return_to_lit_support(disposition:) expect(page.current_path).to eq(review_decisions_path) - find(".usa-alert-text").find("a").click + within find(".usa-alert-text") do + click_link("please return to the judge") + end expect(page).to have_content(COPY::MTV_CHECKOUT_RETURN_TO_JUDGE_MODAL_TITLE) expect(page).to have_content(COPY::MTV_CHECKOUT_RETURN_TO_JUDGE_MODAL_DESCRIPTION) From 68b51af9748686c57da1d4a174b212d62d530aaf Mon Sep 17 00:00:00 2001 From: Clay Sheppard Date: Wed, 23 Aug 2023 10:29:25 -0500 Subject: [PATCH 48/62] fix flakey tests in login spec (#19233) --- spec/feature/login_spec.rb | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/spec/feature/login_spec.rb b/spec/feature/login_spec.rb index 9555e6785bf..44007d61175 100644 --- a/spec/feature/login_spec.rb +++ b/spec/feature/login_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.feature "Login", :all_dbs do - let(:appeal) { create(:legacy_appeal, vacols_case: create(:case)) } + let(:appeal) { create(:legacy_appeal, vacols_case: create(:case_with_ssoc)) } let(:station_id) { "405" } let(:user_email) { "test@example.com" } let(:roles) { ["Certify Appeal"] } @@ -105,18 +105,16 @@ def select_ro_from_dropdown # :nocov: # https://stackoverflow.com/questions/36472930/session-sometimes-not-persisting-in-capybara-selenium-test - scenario "with valid credentials", - skip: "This test sometimes fails because sessions do not persist across requests" do + scenario "with valid credentials" do visit "certifications/new/#{appeal.vacols_id}" expect(page).to have_content("Please select the regional office you are logging in from.") select_ro_from_dropdown click_on "Log in" - expect(page).to have_current_path(new_certification_path(vacols_id: appeal.vacols_id)) + expect(page).to have_current_path("/certifications/#{appeal.vacols_id}/check_documents") expect(find("#menu-trigger")).to have_content("ANNE MERICA (RO05)") end - scenario "logging out redirects to home page", - skip: "This test sometimes fails because sessions do not persist across requests" do + scenario "logging out redirects to home page" do visit "certifications/new/#{appeal.vacols_id}" # vacols login @@ -125,7 +123,7 @@ def select_ro_from_dropdown click_on "Log in" click_on "ANNE MERICA (RO05)" - click_on "Sign out" + click_on "Sign Out" visit "certifications/new/#{appeal.vacols_id}" expect(page).to have_current_path("/login") end @@ -164,12 +162,20 @@ def select_ro_from_dropdown end # :nocov: - scenario "Single Sign On is down", - skip: "This test sometimes fails because it cannot find the expected text" do - Rails.application.config.sso_service_disabled = true - visit "certifications/new/#{appeal.vacols_id}" + context "Single Sign on is down" do + before do + Rails.application.config.sso_service_disabled = true + end - expect(page).to have_content("Login Service Unavailable") + after do + Rails.application.config.sso_service_disabled = false + end + + scenario "it displays the error page" do + visit "certifications/new/#{appeal.vacols_id}" + + expect(page).to have_content("Something went wrong") + end end # :nocov: end From de3c51cbec758ff35d145250cb3a29fc2b31678b Mon Sep 17 00:00:00 2001 From: mchbidwell <122634362+mchbidwell@users.noreply.github.com> Date: Wed, 23 Aug 2023 10:33:51 -0500 Subject: [PATCH 49/62] Revert "lthompson/APPEALS-26633" --- .../organizations/users_controller.rb | 9 --- app/models/organizations_user.rb | 6 -- .../administered_user_serializer.rb | 1 - client/COPY.json | 1 - client/app/queue/OrganizationUsers.jsx | 55 ++++--------- .../queue/SelectConferenceTypeRadioField.jsx | 48 ----------- .../SelectConferenceTypeRadioField.test.js | 80 ------------------- ...electConferenceTypeRadioField.test.js.snap | 55 ------------- ...0230726201514_add_meeting_type_to_users.rb | 9 --- ...30_add_meeting_type_to_virtual_hearings.rb | 9 --- ...50_add_meeting_type_to_conference_links.rb | 9 --- db/schema.rb | 33 -------- spec/models/organizations_user_spec.rb | 14 ---- spec/models/user_spec.rb | 3 +- 14 files changed, 17 insertions(+), 315 deletions(-) delete mode 100644 client/app/queue/SelectConferenceTypeRadioField.jsx delete mode 100644 client/test/app/queue/SelectConferenceTypeRadioField.test.js delete mode 100644 client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap delete mode 100644 db/migrate/20230726201514_add_meeting_type_to_users.rb delete mode 100644 db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb delete mode 100644 db/migrate/20230726203750_add_meeting_type_to_conference_links.rb diff --git a/app/controllers/organizations/users_controller.rb b/app/controllers/organizations/users_controller.rb index 4d6cd9eb2a5..6a125576a84 100644 --- a/app/controllers/organizations/users_controller.rb +++ b/app/controllers/organizations/users_controller.rb @@ -32,7 +32,6 @@ def update adjust_admin_rights end - update_user_meeting_type render json: { users: json_administered_users([user_to_modify]) }, status: :ok end @@ -68,14 +67,6 @@ def adjust_admin_rights end end - def update_user_meeting_type - new_meeting_type = params.dig(:attributes, :meeting_type) - - if organization["url"] == HearingsManagement.singleton.url && new_meeting_type - OrganizationsUser.update_user_conference_type(user_to_modify, new_meeting_type) - end - end - def organization_url params[:organization_url] end diff --git a/app/models/organizations_user.rb b/app/models/organizations_user.rb index 23ce4f1c4b4..189d98de647 100644 --- a/app/models/organizations_user.rb +++ b/app/models/organizations_user.rb @@ -28,12 +28,6 @@ def remove_admin_rights_from_user(user, organization) existing_record(user, organization)&.update!(admin: false) end - def update_user_conference_type(user, new_meeting_type) - if user.meeting_type - user.update!(meeting_type: new_meeting_type) - end - end - def remove_user_from_organization(user, organization) if user_is_judge_of_team?(user, organization) fail Caseflow::Error::ActionForbiddenError, message: COPY::JUDGE_TEAM_REMOVE_JUDGE_ERROR diff --git a/app/models/serializers/work_queue/administered_user_serializer.rb b/app/models/serializers/work_queue/administered_user_serializer.rb index f4ffcf0e3a9..61b86097292 100644 --- a/app/models/serializers/work_queue/administered_user_serializer.rb +++ b/app/models/serializers/work_queue/administered_user_serializer.rb @@ -11,5 +11,4 @@ class WorkQueue::AdministeredUserSerializer < WorkQueue::UserSerializer params[:organization].dvc&.eql?(object) end end - attribute :meeting_type end diff --git a/client/COPY.json b/client/COPY.json index f02e14b0e86..9bd85705be1 100644 --- a/client/COPY.json +++ b/client/COPY.json @@ -772,7 +772,6 @@ "USER_MANAGEMENT_GIVE_USER_ADMIN_RIGHTS_BUTTON_TEXT": "Add admin rights", "USER_MANAGEMENT_REMOVE_USER_ADMIN_RIGHTS_BUTTON_TEXT": "Remove admin rights", "USER_MANAGEMENT_REMOVE_USER_FROM_ORG_BUTTON_TEXT": "Remove from team", - "USER_MANAGEMENT_SELECT_HEARINGS_CONFERENCE_TYPE": "Schedule hearings using:", "MEMBERSHIP_REQUEST_ACTION_SUCCESS_TITLE": "You successfully %s %s's request", "MEMBERSHIP_REQUEST_ACTION_SUCCESS_MESSAGE": "The user was %s regular member access to %s.", "VHA_MEMBERSHIP_REQUEST_AUTOMATIC_VHA_ACCESS_NOTE": "Note: If you are requesting specialized access and are not a member of the general VHA group, you will automatically be given access to the general VHA group if your request is approved.", diff --git a/client/app/queue/OrganizationUsers.jsx b/client/app/queue/OrganizationUsers.jsx index 12b38c018c0..3497cf30792 100644 --- a/client/app/queue/OrganizationUsers.jsx +++ b/client/app/queue/OrganizationUsers.jsx @@ -16,7 +16,6 @@ import { LOGO_COLORS } from '../constants/AppConstants'; import COPY from '../../COPY'; import LoadingDataDisplay from '../components/LoadingDataDisplay'; import MembershipRequestTable from './MembershipRequestTable'; -import SelectConferenceTypeRadioField from './SelectConferenceTypeRadioField'; const userStyle = css({ margin: '.5rem 0 .5rem', @@ -39,17 +38,11 @@ const buttonStyle = css({ const buttonContainerStyle = css({ borderBottom: '1rem solid gray', borderWidth: '1px', - padding: '.5rem 7rem 2rem 0', - display: 'flex', - justifyContent: 'space-between', - flexWrap: 'wrap' + padding: '.5rem 0 2rem', }); const listStyle = css({ listStyle: 'none' }); -const radioContainerStyle = css({ - padding: '-5rem 5rem 2rem 2rem', -}); export default class OrganizationUsers extends React.PureComponent { constructor(props) { @@ -255,34 +248,18 @@ export default class OrganizationUsers extends React.PureComponent { const style = i === 0 ? topUserStyle : userStyle; return -
    -
      -
    • {this.formatName(user)} - { judgeTeam && admin && ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} ) } - { dvcTeam && dvc && ( {COPY.USER_MANAGEMENT_DVC_LABEL} ) } - { judgeTeam && !admin && ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} ) } - { (judgeTeam || dvcTeam) && admin && ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} ) } -
    • - { (judgeTeam || dvcTeam) && admin ? -
      : -
      -
      - { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } - { this.removeUserButton(user) } -
      - { this.state.organizationName === 'Hearings Management' && -
      - -
      - } -
      } -
    -
    +
  • {this.formatName(user)} + { judgeTeam && admin && ( {COPY.USER_MANAGEMENT_JUDGE_LABEL} ) } + { dvcTeam && dvc && ( {COPY.USER_MANAGEMENT_DVC_LABEL} ) } + { judgeTeam && !admin && ( {COPY.USER_MANAGEMENT_ATTORNEY_LABEL} ) } + { (judgeTeam || dvcTeam) && admin && ( {COPY.USER_MANAGEMENT_ADMIN_LABEL} ) } +
  • + { (judgeTeam || dvcTeam) && admin ? +
    : +
    + { (judgeTeam || dvcTeam) ? '' : this.adminButton(user, admin) } + { this.removeUserButton(user) } +
    }
    ; }); @@ -308,10 +285,10 @@ export default class OrganizationUsers extends React.PureComponent {

    {COPY.USER_MANAGEMENT_EDIT_USER_IN_ORG_LABEL}

      - { (judgeTeam || dvcTeam) ? '' :
      • {COPY.USER_MANAGEMENT_ADMIN_RIGHTS_HEADING}{COPY.USER_MANAGEMENT_ADMIN_RIGHTS_DESCRIPTION}
      } -
      • {COPY.USER_MANAGEMENT_REMOVE_USER_HEADING}{ judgeTeam ? + { (judgeTeam || dvcTeam) ? '' :
      • {COPY.USER_MANAGEMENT_ADMIN_RIGHTS_HEADING}{COPY.USER_MANAGEMENT_ADMIN_RIGHTS_DESCRIPTION}
      • } +
      • {COPY.USER_MANAGEMENT_REMOVE_USER_HEADING}{ judgeTeam ? COPY.USER_MANAGEMENT_JUDGE_TEAM_REMOVE_USER_DESCRIPTION : - COPY.USER_MANAGEMENT_REMOVE_USER_DESCRIPTION }
      + COPY.USER_MANAGEMENT_REMOVE_USER_DESCRIPTION }
      {listOfUsers}
    diff --git a/client/app/queue/SelectConferenceTypeRadioField.jsx b/client/app/queue/SelectConferenceTypeRadioField.jsx deleted file mode 100644 index 805c88f26c1..00000000000 --- a/client/app/queue/SelectConferenceTypeRadioField.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import React, { useState } from 'react'; -import PropTypes from 'prop-types'; -import ApiUtil from '../util/ApiUtil'; - -import RadioField from '../components/RadioField'; -import COPY from '../../COPY'; - -const radioOptions = [ - { displayText: 'Pexip', - value: 'pexip' }, - { displayText: 'Webex', - value: 'webex' } -]; - -const SelectConferenceTypeRadioField = ({ name, meetingType, organization, user }) => { - const [value, setValue] = useState(meetingType); - - const modifyConferenceType = (newMeetingType) => { - const payload = { data: { ...user, attributes: { ...user.attributes, meeting_type: newMeetingType } } }; - - ApiUtil.patch(`/organizations/${organization}/users/${user.id}`, payload); - }; - - return ( - <> - setValue(newValue) || modifyConferenceType(newValue))} - vertical - /> - ); -}; - -SelectConferenceTypeRadioField.propTypes = { - name: PropTypes.string, - onClick: PropTypes.func, - meetingType: PropTypes.string, - organization: PropTypes.string, - user: PropTypes.shape({ - id: PropTypes.string, - attributes: PropTypes.object - }) -}; - -export default SelectConferenceTypeRadioField; diff --git a/client/test/app/queue/SelectConferenceTypeRadioField.test.js b/client/test/app/queue/SelectConferenceTypeRadioField.test.js deleted file mode 100644 index dd36e4f4343..00000000000 --- a/client/test/app/queue/SelectConferenceTypeRadioField.test.js +++ /dev/null @@ -1,80 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import ApiUtil from 'app/util/ApiUtil'; - -import SelectConferenceTypeRadioField from 'app/queue/SelectConferenceTypeRadioField'; - -const createSpy = () => jest.spyOn(ApiUtil, 'patch'). - mockImplementation(() => jest.fn(() => Promise.resolve( - { - body: { } - } - ))); - -const defaults = { - name: 'field1', - value: '1', - options: [ - { displayText: 'Pexip', - value: 'pexip' }, - { displayText: 'Webex', - value: 'webex' }, - ], -}; - -describe('SelectConferenceTypeRadioField', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - const setupComponent = (props = { - user: { - attributes: { - id: 1 - } - }, - meetingType: 'pexip', - organization: 'my org' - }) => { - const utils = render( - - ); - const inputs = utils.getAllByRole('radio'); - - return { - inputs, - ...utils, - }; - }; - - it('renders correctly', async () => { - const { container } = setupComponent(); - - expect(container).toMatchSnapshot(); - }); - - it('changes values by radio button selected', () => { - let requestPatchSpy = createSpy(); - - setupComponent(); - - const webexRadioButton = screen.getByRole('radio', { name: 'Webex' }); - const pexipRadioButton = screen.getByRole('radio', { name: 'Pexip' }); - - expect(webexRadioButton).not.toHaveAttribute('checked', ''); - expect(pexipRadioButton).toHaveAttribute('checked', ''); - - userEvent.click(webexRadioButton); - - expect(requestPatchSpy.mock.calls[0][1].data.attributes.meeting_type).toBe('webex'); - - userEvent.click(pexipRadioButton); - - expect(requestPatchSpy.mock.calls[1][1].data.attributes.meeting_type).toBe('pexip'); - }); -}); diff --git a/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap b/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap deleted file mode 100644 index 40d135d3387..00000000000 --- a/client/test/app/queue/__snapshots__/SelectConferenceTypeRadioField.test.js.snap +++ /dev/null @@ -1,55 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SelectConferenceTypeRadioField renders correctly 1`] = ` -
    -
    - - - Schedule hearings using: - - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -`; diff --git a/db/migrate/20230726201514_add_meeting_type_to_users.rb b/db/migrate/20230726201514_add_meeting_type_to_users.rb deleted file mode 100644 index b07b732c95f..00000000000 --- a/db/migrate/20230726201514_add_meeting_type_to_users.rb +++ /dev/null @@ -1,9 +0,0 @@ -class AddMeetingTypeToUsers < Caseflow::Migration - def up - add_column :users, :meeting_type, :varChar, default: "pexip", comment: "Video Conferencing Application Type" - end - - def down - remove_column :users, :meeting_type - end -end diff --git a/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb b/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb deleted file mode 100644 index 6b8f6b1e1c6..00000000000 --- a/db/migrate/20230726203030_add_meeting_type_to_virtual_hearings.rb +++ /dev/null @@ -1,9 +0,0 @@ -class AddMeetingTypeToVirtualHearings < Caseflow::Migration - def up - add_column :virtual_hearings, :meeting_type, :varChar, default: "pexip", comment: "Video Conferencing Application Type" - end - - def down - remove_column :virtual_hearings, :meeting_type - end -end diff --git a/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb b/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb deleted file mode 100644 index dc0713e3f35..00000000000 --- a/db/migrate/20230726203750_add_meeting_type_to_conference_links.rb +++ /dev/null @@ -1,9 +0,0 @@ -class AddMeetingTypeToConferenceLinks < Caseflow::Migration - def up - add_column :conference_links, :meeting_type, :varChar, default: "pexip", comment: "Video Conferencing Application Type" - end - - def down - remove_column :conference_links, :meeting_type - end -end diff --git a/db/schema.rb b/db/schema.rb index 06240150d9a..2f02f9c82e3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -556,7 +556,6 @@ t.string "host_link", comment: "Conference link generated from external conference service" t.integer "host_pin", comment: "Pin for the host of the conference to get into the conference" t.string "host_pin_long", limit: 8, comment: "Generated host pin stored as a string" - t.string "meeting_type", default: "pexip", comment: "Video Conferencing Application Type" t.datetime "updated_at", comment: "Date and Time record was last updated" t.bigint "updated_by_id", comment: "user id of the user to last update the record. FK on the User table" t.index ["created_by_id"], name: "index_created_by_id" @@ -598,8 +597,6 @@ t.string "diagnostic_code", comment: "If a decision resulted in a rating, this is the rating issue's diagnostic code." t.string "disposition", comment: "The disposition for a decision issue. Dispositions made in Caseflow and dispositions made in VBMS can have different values." t.date "end_product_last_action_date", comment: "After an end product gets synced with a status of CLR (cleared), the end product's last_action_date is saved on any decision issues that are created as a result. This is used as a proxy for decision date for non-rating issues that are processed in VBMS because they don't have a rating profile date, and the exact decision date is not available." - t.boolean "mst_status", default: false, comment: "Indicates if decision issue is related to Military Sexual Trauma (MST)" - t.boolean "pact_status", default: false, comment: "Indicates if decision issue is related to Promise to Address Comprehensive Toxics (PACT) Act" t.string "participant_id", null: false, comment: "The Veteran's participant id." t.string "percent_number", comment: "percent_number from RatingIssue (prcntNo from Rating Profile)" t.string "rating_issue_reference_id", comment: "Identifies the specific issue on the rating that resulted from the decision issue (a rating issue can be connected to multiple contentions)." @@ -1475,13 +1472,9 @@ t.string "ineligible_reason", comment: "The reason for a Request Issue being ineligible. If a Request Issue has an ineligible_reason, it is still captured, but it will not get a contention in VBMS or a decision." t.boolean "is_predocket_needed", comment: "Indicates whether or not an issue has been selected to go to the pre-docket queue opposed to normal docketing." t.boolean "is_unidentified", comment: "Indicates whether a Request Issue is unidentified, meaning it wasn't found in the list of contestable issues, and is not a new nonrating issue. Contentions for unidentified issues are created on a rating End Product if processed in VBMS but without the issue description, and someone is required to edit it in Caseflow before proceeding with the decision." - t.boolean "mst_status", default: false, comment: "Indicates if issue is related to Military Sexual Trauma (MST)" - t.text "mst_status_update_reason_notes", comment: "The reason for why Request Issue is Military Sexual Trauma (MST)" t.string "nonrating_issue_category", comment: "The category selected for nonrating request issues. These vary by business line." t.string "nonrating_issue_description", comment: "The user entered description if the issue is a nonrating issue" t.text "notes", comment: "Notes added by the Claims Assistant when adding request issues. This may be used to capture handwritten notes on the form, or other comments the CA wants to capture." - t.boolean "pact_status", default: false, comment: "Indicates if issue is related to Promise to Address Comprehensive Toxics (PACT) Act" - t.text "pact_status_update_reason_notes", comment: "The reason for why Request Issue is Promise to Address Comprehensive Toxics (PACT) Act" t.string "ramp_claim_id", comment: "If a rating issue was created as a result of an issue intaken for a RAMP Review, it will be connected to the former RAMP issue by its End Product's claim ID." t.datetime "rating_issue_associated_at", comment: "Timestamp when a contention and its contested rating issue are associated in VBMS." t.string "split_issue_status", comment: "If a request issue is part of a split, on_hold status applies to the original request issues while active are request issues on splitted appeals" @@ -1492,8 +1485,6 @@ t.datetime "updated_at", comment: "Automatic timestamp whenever the record changes." t.string "vacols_id", comment: "The vacols_id of the legacy appeal that had an issue found to match the request issue." t.integer "vacols_sequence_id", comment: "The vacols_sequence_id, for the specific issue on the legacy appeal which the Claims Assistant determined to match the request issue on the Decision Review. A combination of the vacols_id (for the legacy appeal), and vacols_sequence_id (for which issue on the legacy appeal), is required to identify the issue being opted-in." - t.boolean "vbms_mst_status", default: false, comment: "Indicates if issue is related to Military Sexual Trauma (MST) and was imported from VBMS" - t.boolean "vbms_pact_status", default: false, comment: "Indicates if issue is related to Promise to Address Comprehensive Toxics (PACT) Act and was imported from VBMS" t.boolean "verified_unidentified_issue", comment: "A verified unidentified issue allows an issue whose rating data is missing to be intaken as a regular rating issue. In order to be marked as verified, a VSR needs to confirm that they were able to find the record of the decision for the issue." t.string "veteran_participant_id", comment: "The veteran participant ID. This should be unique in upstream systems and used in the future to reconcile duplicates." t.index ["closed_at"], name: "index_request_issues_on_closed_at" @@ -1519,8 +1510,6 @@ t.integer "edited_request_issue_ids", comment: "An array of the request issue IDs that were edited during this request issues update", array: true t.string "error", comment: "The error message if the last attempt at processing the request issues update was not successful." t.datetime "last_submitted_at", comment: "Timestamp for when the processing for the request issues update was last submitted. Used to determine how long to continue retrying the processing job. Can be reset to allow for additional retries." - t.integer "mst_edited_request_issue_ids", comment: "An array of the request issue IDs that were updated to be associated with MST in request issues update", array: true - t.integer "pact_edited_request_issue_ids", comment: "An array of the request issue IDs that were updated to be associated with PACT in request issues update", array: true t.datetime "processed_at", comment: "Timestamp for when the request issue update successfully completed processing." t.bigint "review_id", null: false, comment: "The ID of the decision review edited." t.string "review_type", null: false, comment: "The type of the decision review edited." @@ -1569,26 +1558,6 @@ t.index ["sent_by_id"], name: "index_sent_hearing_email_events_on_sent_by_id" end - create_table "special_issue_changes", force: :cascade do |t| - t.bigint "appeal_id", null: false, comment: "AMA or Legacy Appeal ID that the issue is tied to" - t.string "appeal_type", null: false, comment: "Appeal Type (Appeal or LegacyAppeal)" - t.string "change_category", null: false, comment: "Type of change that occured to the issue (Established Issue, Added Issue, Edited Issue, Removed Issue)" - t.datetime "created_at", null: false, comment: "Date the special issue change was made" - t.string "created_by_css_id", null: false, comment: "CSS ID of the user that made the special issue change" - t.bigint "created_by_id", null: false, comment: "User ID of the user that made the special issue change" - t.bigint "decision_issue_id", comment: "ID of the decision issue that had a special issue change from its corresponding request issue" - t.bigint "issue_id", null: false, comment: "ID of the issue that was changed" - t.boolean "mst_from_vbms", comment: "Indication that the MST status originally came from VBMS on intake" - t.string "mst_reason_for_change", comment: "Reason for changing the MST status on an issue" - t.boolean "original_mst_status", null: false, comment: "Original MST special issue status of the issue" - t.boolean "original_pact_status", null: false, comment: "Original PACT special issue status of the issue" - t.boolean "pact_from_vbms" - t.string "pact_reason_for_change", comment: "Reason for changing the PACT status on an issue" - t.bigint "task_id", null: false, comment: "Task ID of the IssueUpdateTask or EstablishmentTask used to log this issue in the case timeline" - t.boolean "updated_mst_status", comment: "Updated MST special issue status of the issue" - t.boolean "updated_pact_status", comment: "Updated PACT special issue status of the issue" - end - create_table "special_issue_lists", comment: "Associates special issues to an AMA or legacy appeal for Caseflow Queue. Caseflow Dispatch uses special issues stored in legacy_appeals. They are intentionally disconnected.", force: :cascade do |t| t.bigint "appeal_id", comment: "The ID of the appeal associated with this record" t.string "appeal_type", comment: "The type of appeal associated with this record" @@ -1810,7 +1779,6 @@ t.string "email" t.string "full_name" t.datetime "last_login_at", comment: "The last time the user-agent (browser) provided session credentials; see User.from_session for precision" - t.string "meeting_type", default: "pexip", comment: "Video Conferencing Application Type" t.string "roles", array: true t.string "selected_regional_office" t.string "station_id", null: false @@ -1976,7 +1944,6 @@ t.string "host_pin_long", limit: 8, comment: "Change the host pin to store a longer pin with the # sign trailing" t.string "judge_email", comment: "Judge's email address" t.boolean "judge_email_sent", default: false, null: false, comment: "Whether or not a notification email was sent to the judge" - t.string "meeting_type", default: "pexip", comment: "Video Conferencing Application Type" t.string "representative_email", comment: "Veteran's representative's email address" t.boolean "representative_email_sent", default: false, null: false, comment: "Whether or not a notification email was sent to the veteran's representative" t.datetime "representative_reminder_sent_at", comment: "The datetime the last reminder email was sent to the representative." diff --git a/spec/models/organizations_user_spec.rb b/spec/models/organizations_user_spec.rb index f68b294517d..bc148bd7a4f 100644 --- a/spec/models/organizations_user_spec.rb +++ b/spec/models/organizations_user_spec.rb @@ -114,18 +114,4 @@ end end end - - describe ".update_user_conference_type" do - let(:meeting_type) { user.meeting_type } - let(:new_meeting_type) { "webex" } - - subject { OrganizationsUser.update_user_conference_type(user, new_meeting_type) } - - context "when meeting type exists" do - it "should set meeting type to equal new meeting type" do - subject - expect(meeting_type).to eq(new_meeting_type) - end - end - end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 6c5b35355d5..7b25a645c36 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -158,8 +158,7 @@ :display_name => css_id.upcase, "name" => "Tom Brady", "status" => Constants.USER_STATUSES.active, - "status_updated_at" => nil, - "meeting_type" => "pexip" + "status_updated_at" => nil } end From 1a4a11a8cb7c47a384ab60a1a6504635a84baf11 Mon Sep 17 00:00:00 2001 From: Jeffrey Aaron Willis Date: Wed, 23 Aug 2023 11:35:21 -0400 Subject: [PATCH 50/62] APPEALS-28989 Added Ensure block that will always update last_synced_at date/time regardless of error to ensure that SyncReviewsJob does not immediately re-queue failing end product establishment and allows for other end product estaablishments to attempt sync with BGS first. Updated RSPEC to reflect this change. --- app/models/end_product_establishment.rb | 10 ++++++---- spec/models/end_product_establishment_spec.rb | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/app/models/end_product_establishment.rb b/app/models/end_product_establishment.rb index bab3e8c5cdf..f8e0c1730f6 100644 --- a/app/models/end_product_establishment.rb +++ b/app/models/end_product_establishment.rb @@ -210,10 +210,7 @@ def sync! contentions unless result.status_type_code == EndProduct::STATUSES.key("Canceled") transaction do - update!( - synced_status: result.status_type_code, - last_synced_at: Time.zone.now - ) + update!(synced_status: result.status_type_code) status_cancelled? ? handle_cancelled_ep! : sync_source! close_request_issues_with_no_decision! end @@ -224,6 +221,11 @@ def sync! rescue StandardError => error Raven.extra_context(end_product_establishment_id: id) raise error + ensure + # Always update last_synced_at to ensure that SyncReviewsJob does not immediately re-enqueue + # End Product Establishments that fail to sync with BGS into the EndProductSyncJob. + # This will allow for other End Product Establishments to sync first before re-attempting. + update!(last_synced_at: Time.zone.now) end def fetch_dispositions_from_vbms diff --git a/spec/models/end_product_establishment_spec.rb b/spec/models/end_product_establishment_spec.rb index 1685fb68b51..e1005d656bb 100644 --- a/spec/models/end_product_establishment_spec.rb +++ b/spec/models/end_product_establishment_spec.rb @@ -855,6 +855,13 @@ it "raises EstablishedEndProductNotFound error" do expect { subject }.to raise_error(EndProductEstablishment::EstablishedEndProductNotFound) end + + it "last_synced_at updates upon error to ensure SyncReviewsJob allows other EPEs to sync before re-attempt" do + expect(end_product_establishment.last_synced_at).to eq(nil) + expect { subject }.to raise_error(EndProductEstablishment::EstablishedEndProductNotFound) + end_product_establishment.reload + expect(end_product_establishment.last_synced_at).to eq(Time.zone.now) + end end context "when a matching end product has been established" do @@ -882,6 +889,13 @@ it "re-raises error" do expect { subject }.to raise_error(BGS::ShareError) end + + it "last_synced_at updates upon error to ensure SyncReviewsJob allows other EPEs to sync before re-attempt" do + expect(end_product_establishment.last_synced_at).to eq(nil) + expect { subject }.to raise_error(BGS::ShareError) + end_product_establishment.reload + expect(end_product_establishment.last_synced_at).to eq(Time.zone.now) + end end context "when the claim_type_code has changed outside of Caseflow" do From 1a3def33f1d14798cc0af66be1b113d0695a8c05 Mon Sep 17 00:00:00 2001 From: Brandon Lee Dorner Date: Wed, 23 Aug 2023 10:47:10 -0500 Subject: [PATCH 51/62] Add jest tests for `CancelIntakeModal` (#19238) --- .../components/CancelIntakeModal.test.js | 100 ++++ .../CancelIntakeModal.test.js.snap | 440 ++++++++++++++++++ 2 files changed, 540 insertions(+) create mode 100644 client/test/app/intake/components/CancelIntakeModal.test.js create mode 100644 client/test/app/intake/components/__snapshots__/CancelIntakeModal.test.js.snap diff --git a/client/test/app/intake/components/CancelIntakeModal.test.js b/client/test/app/intake/components/CancelIntakeModal.test.js new file mode 100644 index 00000000000..4888a381d7e --- /dev/null +++ b/client/test/app/intake/components/CancelIntakeModal.test.js @@ -0,0 +1,100 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import userEvent from '@testing-library/user-event'; +import { createStore, applyMiddleware } from 'redux'; +import thunk from 'redux-thunk'; +import rootReducer from 'app/queue/reducers'; +import CancelIntakeModal from 'app/intake/components/CancelIntakeModal'; +import { CANCELLATION_REASONS } from 'app/intake/constants'; + +jest.mock('redux', () => ({ + ...jest.requireActual('redux'), + bindActionCreators: () => jest.fn().mockImplementation(() => Promise.resolve(true)), +})); + +describe('CancelIntakeModal', () => { + const defaultProps = { + closeHandler: () => {}, + intakeId: '123 change?', + clearClaimant: jest.fn().mockImplementation(() => Promise.resolve(true)), + clearPoa: jest.fn().mockImplementation(() => Promise.resolve(true)), + submitCancel: jest.fn().mockImplementation(() => Promise.resolve(true)) + }; + const buttonText = 'Cancel intake'; + + afterEach(() => { + jest.clearAllMocks(); + }); + + const store = createStore(rootReducer, applyMiddleware(thunk)); + + const setup = (props) => + render( + + + + ); + + it('renders correctly', () => { + const modal = setup(defaultProps); + + expect(modal).toMatchSnapshot(); + }); + + it('displays cancellation options', () => { + const modal = setup(defaultProps); + + Object.values(CANCELLATION_REASONS).map((reason) => ( + expect(modal.getByText(reason.name)).toBeInTheDocument() + )); + }); + + it('should show other reason input when other is selected', async () => { + const modal = setup(defaultProps); + + await userEvent.click(screen.getByText('Other')); + + expect(modal.getByText('Tell us more about your situation.')).toBeInTheDocument(); + }); + + describe('cancel button', () => { + it('is disabled until "Other" is selected and the text input is filled out', async () => { + const modal = setup(defaultProps); + + expect(modal.getByText(buttonText)).toBeDisabled(); + + await userEvent.click(modal.getByText('Other')); + + expect(modal.getByText('Tell us more about your situation.')).toBeInTheDocument(); + expect(modal.getByText(buttonText)).toBeDisabled(); + + await userEvent.type(modal.getByRole('textbox'), 'Test'); + + expect(modal.getByText(buttonText)).not.toBeDisabled(); + }); + + it('is disabled until value (that is not "Other") is selected', async () => { + const modal = setup(defaultProps); + + expect(modal.getByText(buttonText)).toBeDisabled(); + + await userEvent.click(modal.getByText('System error')); + expect(modal.getByText(buttonText)).not.toBeDisabled(); + }); + }); + + it('should call the appropiate functions when Cancel intake is clicked', async () => { + const modal = setup(defaultProps); + + await userEvent.click(modal.getByText('System error')); + expect(modal.getByText(buttonText)).not.toBeDisabled(); + + await userEvent.click(modal.getByText('Cancel intake')); + expect(defaultProps.clearClaimant).toHaveBeenCalled(); + expect(defaultProps.clearPoa).toHaveBeenCalled(); + expect(defaultProps.submitCancel).toHaveBeenCalled(); + }); +}); diff --git a/client/test/app/intake/components/__snapshots__/CancelIntakeModal.test.js.snap b/client/test/app/intake/components/__snapshots__/CancelIntakeModal.test.js.snap new file mode 100644 index 00000000000..899aed3921f --- /dev/null +++ b/client/test/app/intake/components/__snapshots__/CancelIntakeModal.test.js.snap @@ -0,0 +1,440 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CancelIntakeModal renders correctly 1`] = ` +Object { + "asFragment": [Function], + "baseElement": +
    +
    + + ; +
    +
    + , + "container":
    +
    + + ; +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; From e2aa20500516a8c670a54bc5439d3dffdf5fccf6 Mon Sep 17 00:00:00 2001 From: Sean Craig <110493538+seancva@users.noreply.github.com> Date: Wed, 23 Aug 2023 12:28:56 -0500 Subject: [PATCH 52/62] added the code needed for the test to pass (#19243) --- spec/workflows/post_decision_motion_updater_spec.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/workflows/post_decision_motion_updater_spec.rb b/spec/workflows/post_decision_motion_updater_spec.rb index 3032c289b93..0aa599cf297 100644 --- a/spec/workflows/post_decision_motion_updater_spec.rb +++ b/spec/workflows/post_decision_motion_updater_spec.rb @@ -66,7 +66,11 @@ verify_vacate_stream end - it "should create decision issues on new vacate" + it "should create decision issues on new vacate" do + subject.process + expect(task.reload.status).to eq Constants.TASK_STATUSES.completed + verify_decision_issues_created + end end context "when vacate type is straight vacate" do From 59241651fd6451347745694c26e23fbf2c18976e Mon Sep 17 00:00:00 2001 From: Tyler Broyles <109369527+TylerBroyles@users.noreply.github.com> Date: Wed, 23 Aug 2023 14:48:31 -0400 Subject: [PATCH 53/62] TYLERB/APPEALS-29085: Fix flakyness in the pre_docket_spec.rb file (#19247) * Added a few more expect statements to the predocket spec to attempt to reduce flakyness. * Changed the visit case details to the reload_case_details method. * Changed all of the visit appeal uuid/external id links to the case details page to use the reload_case_detail_page to reduce flakyness. --- spec/feature/queue/pre_docket_spec.rb | 42 ++++++++++++++------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/spec/feature/queue/pre_docket_spec.rb b/spec/feature/queue/pre_docket_spec.rb index 278122aa539..178e4ad86f3 100644 --- a/spec/feature/queue/pre_docket_spec.rb +++ b/spec/feature/queue/pre_docket_spec.rb @@ -86,7 +86,7 @@ appeal = vha_document_search_task.appeal expect(vha_document_search_task.assigned_to).to eq vha_caregiver - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) expect(page).to have_content("Pre-Docket") expect(page).to have_content(category) @@ -102,7 +102,7 @@ appeal = vha_document_search_task.appeal - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) find(".cf-select__control", text: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL).click find( @@ -136,7 +136,7 @@ appeal = vha_document_search_task.appeal - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) task_name = Constants.TASK_ACTIONS.VHA_CAREGIVER_SUPPORT_RETURN_TO_BOARD_INTAKE.label @@ -224,9 +224,11 @@ expect(appeal.tasks.last.parent.status).to eq Constants.TASK_STATUSES.assigned # Navigate to the appeal that was just returned to board intake and verify the timeline - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) + expect(page).to have_content("Case Timeline") # Click the timeline display link - find(".cf-submit", text: "View task instructions").click + find("#case-timeline-table .cf-submit", text: "View task instructions").click + expect(page).to have_content("Hide task instructions") # Verify the text in the timeline to match the other text field and optional text field. expect(page).to have_content("Other - #{other_text_field_text}") expect(page).to have_content(optional_text_field_text) @@ -240,7 +242,7 @@ appeal = vha_document_search_task.appeal - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) find(".cf-select__control", text: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL).click find( @@ -283,7 +285,7 @@ User.authenticate!(user: bva_intake_user) - visit "/queue/appeals/#{appeal.uuid}" + reload_case_detail_page(appeal.external_id) click_dropdown(text: Constants.TASK_ACTIONS.BVA_INTAKE_RETURN_TO_CAREGIVER.label) @@ -355,7 +357,7 @@ appeal = vha_document_search_task.appeal expect(vha_document_search_task.assigned_to).to eq camo - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) expect(page).to have_content("Pre-Docket") expect(page).to have_content(camo.name) @@ -448,7 +450,7 @@ step "Program Office can assign AssessDocumentationTask to Regional Office" do appeal = Appeal.last - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) dropdown_visn_text = "VISN #{Constants::VISNS_NUMBERED[regional_office.name]} - #{regional_office.name}" @@ -508,7 +510,7 @@ step "Regional Office can send appeal to Program Office as Ready for Review" do appeal = Appeal.last - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) find(".cf-select__control", text: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL).click find( @@ -526,7 +528,7 @@ "?tab=po_completed&#{default_query_params}") appeal = Appeal.last - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) find_all("button", text: COPY::TASK_SNAPSHOT_VIEW_TASK_INSTRUCTIONS_LABEL)[1].click expect(page).to have_content("Documents for this appeal are stored in VBMS") @@ -547,7 +549,7 @@ step "Program Office can send appeal to VHA CAMO as Ready for Review" do appeal = Appeal.last - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) find(".cf-select__control", text: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL).click find( @@ -564,7 +566,7 @@ expect(page).to have_current_path("/organizations/#{program_office.url}"\ "?tab=po_completed&#{default_query_params}") - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) find_all("button", text: COPY::TASK_SNAPSHOT_VIEW_TASK_INSTRUCTIONS_LABEL).first.click expect(page).to have_content("Documents for this appeal are stored in VBMS") expect(page).to have_content(po_instructions) @@ -577,7 +579,7 @@ appeal = vha_document_search_task.appeal - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) task_name = Constants.TASK_ACTIONS.VHA_RETURN_TO_BOARD_INTAKE.label @@ -668,7 +670,7 @@ camo_task.children.each { |task| task.update!(status: "completed") } User.authenticate!(user: camo_user) - visit "/queue/appeals/#{appeal.uuid}" + reload_case_detail_page(appeal.external_id) find(".cf-select__control", text: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL).click find( "div", @@ -701,7 +703,7 @@ User.authenticate!(user: bva_intake_user) - visit "/queue/appeals/#{appeal.uuid}" + reload_case_detail_page(appeal.external_id) find(".cf-select__control", text: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL).click find( @@ -735,7 +737,7 @@ camo_task.completed! User.authenticate!(user: bva_intake_user) - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) bva_intake_dockets_appeal expect(page).to have_content(COPY::DOCKET_APPEAL_CONFIRMATION_TITLE) @@ -777,7 +779,7 @@ camo_task = VhaDocumentSearchTask.last bva_intake_task = PreDocketTask.last - visit "/queue/appeals/#{appeal.external_id}" + reload_case_detail_page(appeal.external_id) bva_intake_dockets_appeal expect(page).to have_content(COPY::DOCKET_APPEAL_CONFIRMATION_TITLE) @@ -1231,7 +1233,7 @@ def bva_intake_dockets_appeal User.authenticate!(user: bva_intake_user) - visit "/queue/appeals/#{emo_task.appeal.uuid}" + reload_case_detail_page(emo_task.appeal.external_id) find(".cf-select__control", text: COPY::TASK_ACTION_DROPDOWN_BOX_LABEL).click find( @@ -1264,7 +1266,7 @@ def bva_intake_dockets_appeal emo_task = create(:education_document_search_task, :assigned, assigned_to: emo) emo_task.completed! - visit "/queue/appeals/#{emo_task.appeal.uuid}" + reload_case_detail_page(emo_task.appeal.external_id) click_dropdown(text: Constants.TASK_ACTIONS.DOCKET_APPEAL.label) From 8125b6cbeb5112e47562aaa4e502803658109e99 Mon Sep 17 00:00:00 2001 From: Craig Reese <109101548+craigrva@users.noreply.github.com> Date: Fri, 25 Aug 2023 11:53:17 -0500 Subject: [PATCH 54/62] Update MAC_M1.md --- MAC_M1.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/MAC_M1.md b/MAC_M1.md index 603c98e0b71..6600e77dc99 100644 --- a/MAC_M1.md +++ b/MAC_M1.md @@ -118,7 +118,7 @@ OpenSSL --- 1. Download openssl@1.1 and openssl@3 from this [link](https://boozallen.sharepoint.com/teams/VABID/appeals/Documents/Forms/AllItems.aspx?id=%2Fteams%2FVABID%2Fappeals%2FDocuments%2FDevelopment%2FDeveloper%20Setup%20Resources%2FM1%20Mac%20Developer%20Setup&viewid=8a8eaf3e%2D2c12%2D4c87%2Db95f%2D4eab3428febd) 2. Open “Finder” and find the two folders under “Downloads” -3. Extract the `.tar.gz` files +3. Extract the `.tar.gz` or `.zip` archives 4. In each of the extracted folders: 1. Navigate to the `/usr/local/homebrew/Cellar` subfolder 2. Copy the openssl folder to your local machine's `/usr/local/homebrew/Cellar` folder @@ -168,22 +168,26 @@ Run dev setup scripts in Caseflow repo 1. Open a **Rosetta** terminal and navigate to /usr/local, run the command ```sudo spctl --global-disable``` 2. In the **Rosetta** terminal, install pyenv and the required python2 version: 1. `brew install pyenv` - 2. `pyenv install 2.7.18` - 3. In the caseflow directory, run `pyenv local 2.7.18` to set the version + 2. `pyenv rehash` + 3. `pyenv install 2.7.18` + 4. In the caseflow directory, run `pyenv local 2.7.18` to set the version 3. In the **Rosetta** terminal navigate to caseflow folder: - 1. set ```RUBY_CONFIGURE_OPTS="--with-openssl-dir=/usr/local/homebrew/Cellar/openssl@1.1"``` - 2. run `rbenv install 2.7.3` - 3. run `gem install pg:1.1.4 -- --with-pg-config=/Applications/Postgres.app/Contents/Versions/latest/bin/pg_config` - 4. Install v8@3.15 by doing the following (these steps assume that vi/vim is the default editor): + 1. set ```export RUBY_CONFIGURE_OPTS="--with-openssl-dir=/usr/local/homebrew/Cellar/openssl@1.1"``` + 2. run `rbenv install $(cat .ruby-version)` + 3. run `rbenv rehash` + 4. run `gem install bundler -v $(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1)` + 5. run `gem install pg:1.1.4 -- --with-pg-config=/Applications/Postgres.app/Contents/Versions/latest/bin/pg_config` + 6. Install v8@3.15 by doing the following (these steps assume that vi/vim is the default editor): 1. run `brew edit v8@3.15` 2. go to line 21 in the editor by typing `:21` Note: the line being removed is `disable! date: "2023-06-19", because: "depends on Python 2 to build"` 3. delete the line by pressing `d` twice 4. save and quit by typing `:x` - 5. Configure build opts for gem `therubyracer`: + 5. run `HOMEBREW_NO_INSTALL_FROM_API=1 brew install v8@3.15` + 7. Configure build opts for gem `therubyracer`: 1. `bundle config build.libv8 --with-system-v8` 2. `bundle config build.therubyracer --with-v8-dir=$(brew --prefix v8@3.15)` - 6. run ```./scripts/dev_env_setup_step2.sh``` + 8. run ```./scripts/dev_env_setup_step2.sh``` If you get a permission error while running gem install or bundle install, **do not run using sudo.** Set the permissions back to you for every directory under /.rbenv * Enter command: `sudo chown -R /Users//.rbenv` From 4bd6e436f9eeae3230e465ae6092ee2563cdbba0 Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Fri, 25 Aug 2023 13:11:04 -0400 Subject: [PATCH 55/62] Updating script --- lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb index ba84729e170..cdb48bb0261 100644 --- a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb +++ b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb @@ -18,7 +18,8 @@ def run_by_report_load(report_load) # Set the user RequestStore[:current_user] = User.system_user - decision_issues = DecisionIssue.where(id: get_decision_issue_ids(report_load)) + di_ids = get_decision_issue_ids(report_load).map(&:decision_issue_ids) + decision_issues = DecisionIssue.where(id: di_ids) higher_levels_reviews = decision_issues.where(type: HigherLevelReview).map(&:decision_review).compact.uniq From 9c34873698524a98d1dba1564f184decf33f7241 Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Mon, 14 Aug 2023 10:44:00 -0400 Subject: [PATCH 56/62] Adding shell script for DTA/DOO description remediaiton SOP --- .../dta_dto_description_remediation_by_report_load.sh | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh diff --git a/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh b/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh new file mode 100644 index 00000000000..3e92d9d181a --- /dev/null +++ b/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh @@ -0,0 +1,5 @@ +#! /bin/bash +cd /opt/caseflow-certification/src; bin/rails c << DONETOKEN +x = WarRoom::DtaDooDescriptionRemediationByReportLoad.new +x.run_by_report_load("$1", "$2") +DONETOKEN From c461f5918e45bf9f34b7b52dbaae40d6b0b1d344 Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Mon, 14 Aug 2023 16:24:59 -0400 Subject: [PATCH 57/62] First iteration of DTA/DOO description remediation script --- ...taDooDescriptionRemediationByReportLoad.rb | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb diff --git a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb new file mode 100644 index 00000000000..60a39868442 --- /dev/null +++ b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true + +module WarRoom + + # Purpose: + class DtaDooDescriptionRemediation + + def run_by_report_load(report_load, di_ids = [], env='prod') + logs = ["DtaDooDescriptionRemediation::Log\n"]; + no_remand_generated = []; + remand_generated = []; + + # Set the user + RequestStore[:current_user] = User.system_user + + decision_issues = DecisionIssue.where(id: di_ids) + + higher_levels_reviews = decision_issues.map { |di| di.decision_review if di.decision_review.is_a?(HigherLevelReview) }.compact.uniq + + higher_levels_reviews.each do |hlr| + decision_issues = decision_issues.select { |di| di.decision_review_id == hlr.id && di.decision_review_type == 'HigherLevelReview' } + decision_issues.each do |di| + prev_disp = di.disposition ? di.disposition : "null" + new_disp = "" + if di.description.downcase.include?("duty to assist") && + !di.disposition.include?("DTA Error") && + !di.disposition.include?("Difference of Opinion") + + new_disp = "DTA Error" + di.update!(disposition: new_disp) + + log_message = <<-TEXT + #{Time.zone.now} DtaDooDescriptionRemediation::Log + HLR ID: #{di.decision_review.id}. DI ID: #{di.id} + Previous Disposition: '#{prev_disp}'. + DI Description: #{di.description} + Updating Disposition to '#{new_disp}'. + TEXT + logs.push(log_message) + + elsif di.description.downcase.include?("difference of opinion") && + !di.disposition.include?("Difference of Opinion") && + !di.disposition.include?("DTA Error") + + new_disp = "Difference of Opinion" + di.update!(disposition: new_disp) + + log_message <<-TEXT + #{Time.zone.now} DtaDooDescriptionRemediation::Log + HLR ID: #{di.decision_review.id}. DI ID: #{di.id} + Previous Disposition: '#{prev_disp}'. + DI Description: #{di.description} + Updating Disposition to '#{new_disp}'. + TEXT + logs.push(log_message) + end + end + + hlr.create_remand_supplemental_claims! + log_message = <<-TEXT + #{Time.zone.now} DtaDooDescriptionRemediation::Log + Creating Remand Supplemental Claim for + HLR ID: #{hlr.id}. + TEXT + logs.push(log_message) + end + + logs.push("Remediation Summary Report\n"); + remand_count = 0; + no_remand_count = 0; + + higher_levels_reviews.each do |hlr| + supp = SupplementalClaim.find_by(decision_review_remanded_id: hlr.id, decision_review_remanded_type: "HigherLevelReview") + if supp + remand_count += 1 + remand_generated.push("Remand Supplemental Claim ID: #{supp.id} was generated for HLR ID: #{hlr.id}. Claim ID: #{supp&.end_product_establishments&.first&.reference_id}") + else + no_remand_count += 1 + no_remand_generated.push("Error: No Remand Supplemental Claim was generated for HLR ID: #{hlr.id}.") + end + end + + log_message = <<-TEXT + Expected Number of Remand Supplemental Claims to be generated: #{hlrs.count}. + Number of Remand Supplemental Claims created: #{remand_count}. + Number of Remand Supplemental Claims NOT created: #{no_remand_count}. + TEXT + logs.push(log_message) + + logs = logs + remand_generated + no_remand_generated; + upload_logs_to_aws_s3 logs + + rescue => StandardError => error + logs.push("DtaDooDescriptionRemediation::Error -- Reference id #{ep_ref}"\ + "Time: #{Time.zone.now}"\ + "#{error.backtrace}") + end + + private + + def upload_logs_to_aws_s3(logs) + s3client = Aws::S3::Client.new; + s3resource = Aws::S3::Resource.new(client: s3client); + s3bucket = s3resource.bucket("data-remediation-output"); + file_name = "dta-doo-description-remediation-logs/dta-doo-description-remediation-log-#{Time.zone.now}"; + content = logs.join("\n"); + temporary_file = Tempfile.new("dta-log.txt"); + filepath = temporary_file.path; + temporary_file.write(content); + temporary_file.flush; + s3bucket.object(file_name).upload_file(filepath, acl: "private", server_side_encryption: "AES256"); + temporary_file.close!; + end + + end +end From c1f87bf7877761ed8b3a293664ab913e96d2ad6f Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Tue, 15 Aug 2023 12:38:40 -0400 Subject: [PATCH 58/62] Updating DTA DOO remediation script --- ...taDooDescriptionRemediationByReportLoad.rb | 140 +++++++++++++++--- ..._description_remediation_by_report_load.sh | 0 2 files changed, 117 insertions(+), 23 deletions(-) mode change 100644 => 100755 lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh diff --git a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb index 60a39868442..4729d5f07ae 100644 --- a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb +++ b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb @@ -2,20 +2,30 @@ module WarRoom - # Purpose: - class DtaDooDescriptionRemediation + # Purpose: This remediation is intended to resolve an ongoing issue where a user in VBMS + # will inadvertantly set the disposition on a contention incorecctly when dealing with + # DTA Errors and Difference of Opinion. + class DtaDooDescriptionRemediationByReportLoad - def run_by_report_load(report_load, di_ids = [], env='prod') - logs = ["DtaDooDescriptionRemediation::Log\n"]; - no_remand_generated = []; - remand_generated = []; + S3_FILE_NAME = "dta-doo-description-remediation-logs/dta-doo-description-remediation-log" + S3_ACL = "private" + S3_ENCRYPTION = "AES256" + S3_BUCKET = "data-remediation-output" + + def run_by_report_load(report_load, env='prod') + logs = ["DtaDooDescriptionRemediation::Log\n"] + no_remand_generated = [] + remand_generated = [] # Set the user RequestStore[:current_user] = User.system_user - decision_issues = DecisionIssue.where(id: di_ids) + decision_issue_ids = get_decision_issue_ids(rep_load) + + decision_issues = DecisionIssue.where(id: decision_issue_ids) - higher_levels_reviews = decision_issues.map { |di| di.decision_review if di.decision_review.is_a?(HigherLevelReview) }.compact.uniq + # higher_levels_reviews = decision_issues.map { |di| di.decision_review if di.decision_review.is_a?(HigherLevelReview) }.compact.uniq + higher_levels_reviews = decision_issues.where(type: HigherLevelReview).map(&:decision_review).compact.uniq higher_levels_reviews.each do |hlr| decision_issues = decision_issues.select { |di| di.decision_review_id == hlr.id && di.decision_review_type == 'HigherLevelReview' } @@ -45,7 +55,7 @@ def run_by_report_load(report_load, di_ids = [], env='prod') new_disp = "Difference of Opinion" di.update!(disposition: new_disp) - log_message <<-TEXT + log_message = <<-TEXT #{Time.zone.now} DtaDooDescriptionRemediation::Log HLR ID: #{di.decision_review.id}. DI ID: #{di.id} Previous Disposition: '#{prev_disp}'. @@ -90,26 +100,110 @@ def run_by_report_load(report_load, di_ids = [], env='prod') logs = logs + remand_generated + no_remand_generated; upload_logs_to_aws_s3 logs - rescue => StandardError => error - logs.push("DtaDooDescriptionRemediation::Error -- Reference id #{ep_ref}"\ + # return report to user running remediation + logs + rescue StandardError => e + logs.push("DtaDooDescriptionRemediation::Error -- #{e.message}"\ "Time: #{Time.zone.now}"\ - "#{error.backtrace}") + "#{e.backtrace}") + + upload_logs_to_aws_s3 logs + logs end private def upload_logs_to_aws_s3(logs) - s3client = Aws::S3::Client.new; - s3resource = Aws::S3::Resource.new(client: s3client); - s3bucket = s3resource.bucket("data-remediation-output"); - file_name = "dta-doo-description-remediation-logs/dta-doo-description-remediation-log-#{Time.zone.now}"; - content = logs.join("\n"); - temporary_file = Tempfile.new("dta-log.txt"); - filepath = temporary_file.path; - temporary_file.write(content); - temporary_file.flush; - s3bucket.object(file_name).upload_file(filepath, acl: "private", server_side_encryption: "AES256"); - temporary_file.close!; + s3client = Aws::S3::Client.new + s3resource = Aws::S3::Resource.new(client: s3client) + s3bucket = s3resource.bucket(S3_BUCKET) + content = logs.join("\n") + temporary_file = Tempfile.new("dta-log.txt") + filepath = temporary_file.path + temporary_file.write(content) + temporary_file.flush + s3bucket.object("#{S3_FILE_NAME}-#{Time.zone.now}").upload_file(filepath, acl: S3_ACL, server_side_encryption: S3_ENCRYPTION) + temporary_file.close! + end + + # Grab qualifying descision issue IDs so we know what to remediate + def get_decision_issue_ids(rep_load, conn) + # Establish connection + conn = ActiveRecord::Base.connection + + raw_sql = <<~SQL + WITH oar_epe_ids as ( + SELECT DISTINCT epe.id as epe_id + FROM end_product_establishments epe + WHERE epe.reference_id in (SELECT DISTINCT reference_id + FROM ep_establishment_workaround + WHERE report_load = #{rep_load} + ) + ), + di_id_list as ( + SELECT DISTINCT di.id as decision_issue_ids + FROM end_product_establishments epe + JOIN request_issues ri + ON epe.id = ri.end_product_establishment_id + JOIN request_decision_issues rdi + ON ri.id = rdi.request_issue_id + JOIN decision_issues di + ON rdi.decision_issue_id = di.id + JOIN higher_level_reviews hlr + ON epe.source_type = 'HigherLevelReview' AND epe.source_id = hlr.id + WHERE epe.id IN (SELECT epe_id FROM oar_epe_ids) + AND (di.description ilike'%duty to assist%' OR di.description ilike '%Difference of Opinion%') + AND di.disposition not like '%DTA Error%' + AND di.disposition not like '%Difference of Opinion%' + AND epe.source_type = 'HigherLevelReview' + AND epe.synced_status = 'CLR' + ), + hlr_id_list as ( + SELECT DISTINCT hlr.id as hlr_ids + FROM end_product_establishments epe + JOIN request_issues ri + ON epe.id = ri.end_product_establishment_id + JOIN request_decision_issues rdi + ON ri.id = rdi.request_issue_id + JOIN decision_issues di + ON rdi.decision_issue_id = di.id + JOIN higher_level_reviews hlr + ON epe.source_type = 'HigherLevelReview' AND epe.source_id = hlr.id + WHERE epe.id IN (SELECT epe_id FROM oar_epe_ids) + AND (di.description ilike'%duty to assist%' OR di.description ilike '%Difference of Opinion%') + AND di.disposition not like '%DTA Error%' + AND di.disposition not like '%Difference of Opinion%' + AND epe.source_type = 'HigherLevelReview' + ), + remanded_hlr_ids as( + SELECT supplemental_claims.decision_review_remanded_id as hlr_ids_with_remand + FROM supplemental_claims + WHERE supplemental_claims.decision_review_remanded_id in (SELECT hlr_ids FROM hlr_id_list) + ) + SELECT DISTINCT di.id as decision_issue_ids, di.description, di.disposition, epe.id as epe_id, hlr.id as higher_level_review_id + FROM end_product_establishments epe + JOIN request_issues ri + ON epe.id = ri.end_product_establishment_id + JOIN request_decision_issues rdi + ON ri.id = rdi.request_issue_id + JOIN decision_issues di + ON rdi.decision_issue_id = di.id + JOIN higher_level_reviews hlr + ON epe.source_type = 'HigherLevelReview' AND epe.source_id = hlr.id + WHERE epe.id IN (SELECT epe_id FROM oar_epe_ids) + AND (di.description ilike'%duty to assist%' OR di.description ilike '%Difference of Opinion%') + AND di.disposition not like '%DTA Error%' + AND di.disposition not like '%Difference of Opinion%' + AND epe.source_type = 'HigherLevelReview' + AND hlr.id not in (SELECT hlr_ids_with_remand FROM remanded_hlr_ids) + SQL + + response = conn.execute(raw_sql) + + # Close the connection + conn.close + + response end end diff --git a/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh b/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh old mode 100644 new mode 100755 From f56c2251f3792f11ac80f2b927e18cc6bc0110c2 Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Mon, 21 Aug 2023 08:21:17 -0400 Subject: [PATCH 59/62] Updating script to fix duplication --- ...taDooDescriptionRemediationByReportLoad.rb | 104 +++++++----------- 1 file changed, 41 insertions(+), 63 deletions(-) diff --git a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb index 4729d5f07ae..e794b238fa7 100644 --- a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb +++ b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb @@ -1,18 +1,16 @@ # frozen_string_literal: true module WarRoom - # Purpose: This remediation is intended to resolve an ongoing issue where a user in VBMS # will inadvertantly set the disposition on a contention incorecctly when dealing with # DTA Errors and Difference of Opinion. class DtaDooDescriptionRemediationByReportLoad - - S3_FILE_NAME = "dta-doo-description-remediation-logs/dta-doo-description-remediation-log" + S3_FILE_NAME = "dta-doo-description-remediation-logs" S3_ACL = "private" S3_ENCRYPTION = "AES256" S3_BUCKET = "data-remediation-output" - def run_by_report_load(report_load, env='prod') + def run_by_report_load(report_load) logs = ["DtaDooDescriptionRemediation::Log\n"] no_remand_generated = [] remand_generated = [] @@ -20,93 +18,73 @@ def run_by_report_load(report_load, env='prod') # Set the user RequestStore[:current_user] = User.system_user - decision_issue_ids = get_decision_issue_ids(rep_load) - - decision_issues = DecisionIssue.where(id: decision_issue_ids) + decision_issues = DecisionIssue.where(id: get_decision_issue_ids(report_load)) - # higher_levels_reviews = decision_issues.map { |di| di.decision_review if di.decision_review.is_a?(HigherLevelReview) }.compact.uniq higher_levels_reviews = decision_issues.where(type: HigherLevelReview).map(&:decision_review).compact.uniq higher_levels_reviews.each do |hlr| - decision_issues = decision_issues.select { |di| di.decision_review_id == hlr.id && di.decision_review_type == 'HigherLevelReview' } + decision_issues = decision_issues.select do |di| + di.decision_review_id == hlr.id && di.decision_review_type == 'HigherLevelReview' + end + decision_issues.each do |di| - prev_disp = di.disposition ? di.disposition : "null" - new_disp = "" - if di.description.downcase.include?("duty to assist") && - !di.disposition.include?("DTA Error") && - !di.disposition.include?("Difference of Opinion") - - new_disp = "DTA Error" - di.update!(disposition: new_disp) - - log_message = <<-TEXT - #{Time.zone.now} DtaDooDescriptionRemediation::Log - HLR ID: #{di.decision_review.id}. DI ID: #{di.id} - Previous Disposition: '#{prev_disp}'. - DI Description: #{di.description} - Updating Disposition to '#{new_disp}'. - TEXT - logs.push(log_message) - - elsif di.description.downcase.include?("difference of opinion") && - !di.disposition.include?("Difference of Opinion") && - !di.disposition.include?("DTA Error") - - new_disp = "Difference of Opinion" - di.update!(disposition: new_disp) - - log_message = <<-TEXT - #{Time.zone.now} DtaDooDescriptionRemediation::Log - HLR ID: #{di.decision_review.id}. DI ID: #{di.id} - Previous Disposition: '#{prev_disp}'. - DI Description: #{di.description} - Updating Disposition to '#{new_disp}'. - TEXT - logs.push(log_message) - end + next if di.disposition.include?("Difference of Opinion") + next if di.disposition.include?("DTA Error") + + new_disp = if di.description.downcase.include?("duty to assist") + "DTA Error" + elsif di.description.downcase.include?("difference of opinion") + "Difference of Opinion" + end + + logs.push <<-TEXT + #{Time.zone.now} DtaDooDescriptionRemediation::Log + HLR ID: #{di.decision_review.id}. DI ID: #{di.id} + Previous Disposition: '#{di.disposition}'. + DI Description: #{di.description} + Updating Disposition to '#{new_disp}'. + TEXT + + di.update!(disposition: new_disp) end hlr.create_remand_supplemental_claims! - log_message = <<-TEXT + logs.push <<-TEXT #{Time.zone.now} DtaDooDescriptionRemediation::Log Creating Remand Supplemental Claim for HLR ID: #{hlr.id}. TEXT - logs.push(log_message) end logs.push("Remediation Summary Report\n"); - remand_count = 0; - no_remand_count = 0; + remand_count = 0 + no_remand_count = 0 higher_levels_reviews.each do |hlr| - supp = SupplementalClaim.find_by(decision_review_remanded_id: hlr.id, decision_review_remanded_type: "HigherLevelReview") + supp = SupplementalClaim.find_by(decision_review_remanded_id: hlr.id, + decision_review_remanded_type: "HigherLevelReview") if supp remand_count += 1 - remand_generated.push("Remand Supplemental Claim ID: #{supp.id} was generated for HLR ID: #{hlr.id}. Claim ID: #{supp&.end_product_establishments&.first&.reference_id}") + remand_generated.push("Remand Supplemental Claim ID: #{supp.id} was generated for HLR ID: #{hlr.id}. + Claim ID: #{supp&.end_product_establishments&.first&.reference_id}") else no_remand_count += 1 no_remand_generated.push("Error: No Remand Supplemental Claim was generated for HLR ID: #{hlr.id}.") end end - log_message = <<-TEXT + logs.push <<-TEXT Expected Number of Remand Supplemental Claims to be generated: #{hlrs.count}. Number of Remand Supplemental Claims created: #{remand_count}. Number of Remand Supplemental Claims NOT created: #{no_remand_count}. TEXT - logs.push(log_message) - logs = logs + remand_generated + no_remand_generated; - upload_logs_to_aws_s3 logs - - # return report to user running remediation - logs - rescue StandardError => e - logs.push("DtaDooDescriptionRemediation::Error -- #{e.message}"\ + logs = logs + remand_generated + no_remand_generated + rescue StandardError => error + logs.push("DtaDooDescriptionRemediation::Error -- #{error.message}"\ "Time: #{Time.zone.now}"\ - "#{e.backtrace}") - + "#{error.backtrace}") + ensure upload_logs_to_aws_s3 logs logs end @@ -122,12 +100,13 @@ def upload_logs_to_aws_s3(logs) filepath = temporary_file.path temporary_file.write(content) temporary_file.flush - s3bucket.object("#{S3_FILE_NAME}-#{Time.zone.now}").upload_file(filepath, acl: S3_ACL, server_side_encryption: S3_ENCRYPTION) + s3bucket.object("#{S3_FILE_NAME}-#{Time.zone.now}") + .upload_file(filepath, acl: S3_ACL, server_side_encryption: S3_ENCRYPTION) temporary_file.close! end # Grab qualifying descision issue IDs so we know what to remediate - def get_decision_issue_ids(rep_load, conn) + def get_decision_issue_ids(rep_load) # Establish connection conn = ActiveRecord::Base.connection @@ -205,6 +184,5 @@ def get_decision_issue_ids(rep_load, conn) response end - end end From c51691bcb6c10d99df2d707e7d031824594f7184 Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Mon, 21 Aug 2023 14:13:32 -0400 Subject: [PATCH 60/62] Cleaning up loop for disposition selection and remediation --- lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb index e794b238fa7..ba84729e170 100644 --- a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb +++ b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb @@ -35,6 +35,8 @@ def run_by_report_load(report_load) "DTA Error" elsif di.description.downcase.include?("difference of opinion") "Difference of Opinion" + else + next end logs.push <<-TEXT From 7d804bf8f4f06adbe048960fff0de318d8c3d5b3 Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Fri, 25 Aug 2023 13:11:04 -0400 Subject: [PATCH 61/62] Updating script --- lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb index ba84729e170..cdb48bb0261 100644 --- a/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb +++ b/lib/helpers/DtaDooDescriptionRemediationByReportLoad.rb @@ -18,7 +18,8 @@ def run_by_report_load(report_load) # Set the user RequestStore[:current_user] = User.system_user - decision_issues = DecisionIssue.where(id: get_decision_issue_ids(report_load)) + di_ids = get_decision_issue_ids(report_load).map(&:decision_issue_ids) + decision_issues = DecisionIssue.where(id: di_ids) higher_levels_reviews = decision_issues.where(type: HigherLevelReview).map(&:decision_review).compact.uniq From 1d072485d435accd7c0d0e19f90f760861bd7ec2 Mon Sep 17 00:00:00 2001 From: raymond-hughes Date: Wed, 30 Aug 2023 19:36:19 -0400 Subject: [PATCH 62/62] Fixing error from testing in UAT --- .../scripts/dta_dto_description_remediation_by_report_load.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh b/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh index 3e92d9d181a..c3f015a17a7 100755 --- a/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh +++ b/lib/helpers/scripts/dta_dto_description_remediation_by_report_load.sh @@ -1,5 +1,5 @@ #! /bin/bash cd /opt/caseflow-certification/src; bin/rails c << DONETOKEN x = WarRoom::DtaDooDescriptionRemediationByReportLoad.new -x.run_by_report_load("$1", "$2") +x.run_by_report_load("$1") DONETOKEN