Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
9e63aad
Add prototype routing for opt-in IPP experiment
Nov 7, 2023
c594043
Add phone_with_camera placeholder value
Nov 7, 2023
ed10d41
Remove console.log
Nov 7, 2023
5fd7eb8
Modifying opt-in IPP to use doc capture page
Nov 8, 2023
607233d
Delete unused opt_in_ipp page
Nov 8, 2023
9673b99
Couple little cleanups
Nov 8, 2023
ccabc6b
add variable to hybrid mobile view
gina-yamada Nov 13, 2023
e9cc671
pulled in main, resolved conflicts
gina-yamada Nov 15, 2023
5c7fa64
set skip_doc_auth to false
gina-yamada Nov 15, 2023
d7bb67c
Updated for params are handled
gina-yamada Nov 16, 2023
f4ab8ff
Add const, require idv_how_to_verify_form for params
gina-yamada Nov 16, 2023
fd5a861
delete opt-in-ipp component and use existing flow to skip doc auth wh…
gina-yamada Nov 17, 2023
4c864e8
fix linter errors
gina-yamada Nov 17, 2023
2c2da02
fix failing test
gina-yamada Nov 17, 2023
7de7b41
add var to specs
gina-yamada Nov 20, 2023
fef5a5b
changelog: Upcoming Features, In-person proofing, Redirect users who …
gina-yamada Nov 20, 2023
16a5306
Add inPersonURL to prop list
gina-yamada Nov 20, 2023
21881c7
fix linter error
gina-yamada Nov 20, 2023
87c8eb4
pulled in main, resolved conflicts
gina-yamada Nov 20, 2023
258b179
add props to in-person context
gina-yamada Nov 20, 2023
82de75c
fix linter errors
gina-yamada Nov 20, 2023
7150d78
reset idv_session.skip_doc_auth, add before action
gina-yamada Nov 20, 2023
b6d5a87
make first step dynamic
gina-yamada Nov 20, 2023
636673b
remove comment
gina-yamada Nov 20, 2023
20acbf2
set const only if inside if block
gina-yamada Nov 20, 2023
f917339
Del logic in form-steps change skipDocAuth to bool
gina-yamada Nov 21, 2023
13506a3
utilize initialStep in form-steps to del doc logic
gina-yamada Nov 21, 2023
406e1fe
add specs
gina-yamada Nov 21, 2023
1672de5
move code to one line
gina-yamada Nov 21, 2023
fc6308d
Use constant to eval/assign
gina-yamada Nov 22, 2023
158cb19
moved attr in alpha order
gina-yamada Nov 22, 2023
dc71edf
removing additional check
gina-yamada Nov 22, 2023
94ffba2
pulled in main, resolved conflict
gina-yamada Nov 22, 2023
54cc97a
update comment
gina-yamada Nov 22, 2023
0dbcf3d
Merge branch 'main' of github.com:18F/identity-idp into yamada/LG-114…
gina-yamada Nov 28, 2023
20d1410
Pass in selection if going back, del before actio
gina-yamada Nov 28, 2023
4854b8e
added before action to allow back button
gina-yamada Nov 28, 2023
655af88
Made dry
gina-yamada Nov 28, 2023
ba889ef
Refactor to make code dry
gina-yamada Nov 28, 2023
a4a4932
fix linter error
gina-yamada Nov 28, 2023
949d99f
Merge branch 'main' of github.com:18F/identity-idp into yamada/LG-114…
gina-yamada Nov 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/controllers/idv/document_capture_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def extra_view_variables
sp_name: decorated_sp_session.sp_name,
failure_to_proof_url: return_to_sp_failure_to_proof_url(step: 'document_capture'),
phone_with_camera: idv_session.phone_with_camera,
skip_doc_auth: idv_session.skip_doc_auth,
}.merge(
acuant_sdk_upgrade_a_b_testing_variables,
phone_question_ab_test_analytics_bucket,
Expand Down
15 changes: 13 additions & 2 deletions app/controllers/idv/how_to_verify_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@ class HowToVerifyController < ApplicationController
include RenderConditionConcern

before_action :confirm_step_allowed
before_action :confirm_verify_info_step_needed

check_or_render_not_found -> { self.class.enabled? }

def show
@selection = if idv_session.skip_doc_auth == false
Idv::HowToVerifyForm::REMOTE
elsif idv_session.skip_doc_auth == true
Idv::HowToVerifyForm::IPP
end

analytics.idv_doc_auth_how_to_verify_visited(**analytics_arguments)
@idv_how_to_verify_form = Idv::HowToVerifyForm.new
@idv_how_to_verify_form = Idv::HowToVerifyForm.new(selection: @selection)
end

def update
Expand All @@ -23,10 +30,14 @@ def update

if result.success?
if how_to_verify_form_params['selection'] == Idv::HowToVerifyForm::REMOTE
idv_session.skip_doc_auth = false
redirect_to idv_hybrid_handoff_url
else
idv_session.flow_path = 'standard'
idv_session.skip_doc_auth = true
redirect_to idv_document_capture_url
end

else
flash[:error] = result.first_error_message
redirect_to idv_how_to_verify_url
Expand All @@ -41,7 +52,7 @@ def self.step_info
preconditions: ->(idv_session:, user:) do
self.enabled? && idv_session.idv_consent_given
end,
undo_step: ->(idv_session:, user:) {}, # clear any saved data
undo_step: ->(idv_session:, user:) { idv_session.skip_doc_auth = nil },
)
end

Expand Down
33 changes: 7 additions & 26 deletions app/forms/idv/how_to_verify_form.rb
Original file line number Diff line number Diff line change
@@ -1,42 +1,23 @@
# frozen_string_literal: true

module Idv
class HowToVerifyForm
include ActiveModel::Model
ATTRIBUTES = [:selection].freeze
REMOTE = 'remote'
IPP = 'ipp'

attr_accessor :selection
REMOTE = 'remote'.freeze
IPP = 'ipp'.freeze

attr_reader :selection

validates :selection, inclusion: {
in: [REMOTE, IPP],
}
validates :selection, presence: {
message: proc { I18n.t('errors.doc_auth.how_to_verify_form') },
}
validates :selection,
presence: { message: proc { I18n.t('errors.doc_auth.how_to_verify_form') } }

def initialize(selection: nil)
@selection = selection
end

def submit(params)
consume_params(params)
@selection = params[:selection]

FormResponse.new(success: valid?, errors: errors)
end

private

def consume_params(params)
params.each do |key, value|
raise_invalid_how_to_verify_parameter_error(key) unless ATTRIBUTES.include?(key.to_sym)
send("#{key}=", value)
end
end

def raise_invalid_how_to_verify_parameter_error(key)
raise ArgumentError, "#{key} is an invalid how_to_verify attribute"
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function DocumentCapture({ onStepChange = () => {} }: DocumentCaptureProps) {
const { t } = useI18n();
const { flowPath, phoneWithCamera } = useContext(UploadContext);
const { trackSubmitEvent, trackVisitEvent } = useContext(AnalyticsContext);
const { inPersonFullAddressEntryEnabled, inPersonURL } = useContext(InPersonContext);
const { inPersonFullAddressEntryEnabled, inPersonURL, skipDocAuth } = useContext(InPersonContext);
const appName = getConfigValue('appName');

useDidUpdateEffect(onStepChange, [stepName]);
Expand Down Expand Up @@ -105,7 +105,7 @@ function DocumentCapture({ onStepChange = () => {} }: DocumentCaptureProps) {
},
].filter(Boolean) as FormStep[]);

const steps: FormStep[] = submissionError
const defaultSteps: FormStep[] = submissionError
? (
[
{
Expand Down Expand Up @@ -133,8 +133,14 @@ function DocumentCapture({ onStepChange = () => {} }: DocumentCaptureProps) {
},
].filter(Boolean) as FormStep[]);

// If the user got here by opting-in to in-person proofing, when skipDocAuth === true,
// then set steps to inPersonSteps
const steps: FormStep[] = skipDocAuth ? inPersonSteps : defaultSteps;

// If the user got here by opting-in to in-person proofing, when skipDocAuth === true,
// then set stepIndicatorPath to VerifyFlowPath.IN_PERSON
const stepIndicatorPath =
stepName && ['location', 'prepare', 'switch_back'].includes(stepName)
(stepName && ['location', 'prepare', 'switch_back'].includes(stepName)) || skipDocAuth
? VerifyFlowPath.IN_PERSON
: VerifyFlowPath.DEFAULT;

Expand Down Expand Up @@ -173,6 +179,7 @@ function DocumentCapture({ onStepChange = () => {} }: DocumentCaptureProps) {
onStepSubmit={trackSubmitEvent}
autoFocus={!!submissionError}
titleFormat={`%{step} - ${appName}`}
initialStep={skipDocAuth ? steps[0].name : undefined}
/>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Link, PageHeading, ProcessList, ProcessListItem } from '@18f/identity-c
import { getConfigValue } from '@18f/identity-config';
import { useI18n } from '@18f/identity-react-i18n';
import { FormStepsButton } from '@18f/identity-form-steps';
import { forceRedirect } from '@18f/identity-url';
import UploadContext from '../context/upload';
import MarketingSiteContext from '../context/marketing-site';
import BackButton from './back-button';
Expand All @@ -14,8 +15,21 @@ function InPersonPrepareStep({ toPreviousStep }) {
const { t } = useI18n();
const { flowPath } = useContext(UploadContext);
const { securityAndPrivacyHowItWorksURL } = useContext(MarketingSiteContext);
const { inPersonURL, inPersonOutageMessageEnabled, inPersonOutageExpectedUpdateDate } =
useContext(InPersonContext);
const {
inPersonURL,
inPersonOutageMessageEnabled,
inPersonOutageExpectedUpdateDate,
skipDocAuth,
howToVerifyURL,
} = useContext(InPersonContext);

function goBack() {
if (skipDocAuth && howToVerifyURL) {
forceRedirect(howToVerifyURL);
} else {
toPreviousStep();
}
}

return (
<>
Expand Down Expand Up @@ -58,7 +72,7 @@ function InPersonPrepareStep({ toPreviousStep }) {
)}
</p>
<InPersonTroubleshootingOptions />
<BackButton role="link" includeBorder onClick={toPreviousStep} />
<BackButton role="link" includeBorder onClick={goBack} />
</>
);
}
Expand Down
12 changes: 12 additions & 0 deletions app/javascript/packages/document-capture/context/in-person.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ export interface InPersonContextProps {
* Each item is [Long name, abbreviation], e.g. ['Ohio', 'OH']
*/
usStatesTerritories: Array<[string, string]>;

/**
* When skipDocAuth is true and in_person_proofing_opt_in_enabled is true,
* users are directed to the beginning of the IPP flow. This is set to true when
* they choose Opt-in IPP on the new How To Verify page
*/
skipDocAuth?: boolean;

/**
* URL for Opt-in IPP, used when in_person_proofing_opt_in_enabled is enabled
*/
howToVerifyURL?: string;
}

const InPersonContext = createContext<InPersonContextProps>({
Expand Down
6 changes: 6 additions & 0 deletions app/javascript/packs/document-capture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ interface AppRootData {
exitUrl: string;
idvInPersonUrl?: string;
securityAndPrivacyHowItWorksUrl: string;
skipDocAuth: string;
howToVerifyURL: string;
uiNotReadySectionEnabled: string;
uiExitQuestionSectionEnabled: string;
}
Expand Down Expand Up @@ -103,6 +105,8 @@ const {
inPersonOutageExpectedUpdateDate,
usStatesTerritories = '',
phoneWithCamera = '',
skipDocAuth,
howToVerifyUrl,
uiNotReadySectionEnabled = '',
uiExitQuestionSectionEnabled = '',
} = appRoot.dataset as DOMStringMap & AppRootData;
Expand All @@ -126,6 +130,8 @@ const App = composeComponents(
inPersonOutageExpectedUpdateDate,
inPersonFullAddressEntryEnabled: inPersonFullAddressEntryEnabled === 'true',
usStatesTerritories: parsedUsStatesTerritories,
skipDocAuth: skipDocAuth === 'true',
howToVerifyURL: howToVerifyUrl,
},
},
],
Expand Down
1 change: 1 addition & 0 deletions app/services/idv/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class Session
profile_id
redo_document_capture
resolution_successful
skip_doc_auth
skip_hybrid_handoff
ssn
threatmetrix_review_status
Expand Down
1 change: 1 addition & 0 deletions app/views/idv/document_capture/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
acuant_version: acuant_version,
phone_question_ab_test_bucket: phone_question_ab_test_bucket,
phone_with_camera: phone_with_camera,
skip_doc_auth: skip_doc_auth,
) %>
1 change: 1 addition & 0 deletions app/views/idv/hybrid_mobile/document_capture/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
acuant_version: acuant_version,
phone_question_ab_test_bucket: phone_question_ab_test_bucket,
phone_with_camera: phone_with_camera,
skip_doc_auth: false,
) %>
2 changes: 2 additions & 0 deletions app/views/idv/shared/_document_capture.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
in_person_outage_expected_update_date: IdentityConfig.store.in_person_outage_expected_update_date,
us_states_territories: us_states_territories,
doc_auth_selfie_capture: IdentityConfig.store.doc_auth_selfie_capture,
skip_doc_auth: skip_doc_auth,
how_to_verify_url: idv_how_to_verify_url,
ui_not_ready_section_enabled: IdentityConfig.store.doc_auth_not_ready_section_enabled,
ui_exit_question_section_enabled: IdentityConfig.store.doc_auth_exit_question_section_enabled,
} %>
Expand Down
37 changes: 37 additions & 0 deletions spec/controllers/idv/how_to_verify_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
it 'renders the show template' do
get :show

expect(subject.idv_session.skip_doc_auth).to be_nil
expect(response).to render_template :show
end

Expand All @@ -48,10 +49,46 @@
end

describe '#update' do
let(:params) do
{
idv_how_to_verify_form: { selection: selection },
}
end
let(:selection) { 'remote' }

it 'invalidates future steps' do
expect(subject).to receive(:clear_future_steps!)

put :update
end

context 'remote' do
it 'sets skip doc auth on idv session to false and redirects to hybrid handoff' do
put :update, params: params

expect(subject.idv_session.skip_doc_auth).to be false
expect(response).to redirect_to(idv_hybrid_handoff_url)
end
end

context 'ipp' do
let(:selection) { 'ipp' }

it 'sets skip doc auth on idv session to true and redirects to document capture' do
put :update, params: params

expect(subject.idv_session.skip_doc_auth).to be true
expect(response).to redirect_to(idv_document_capture_url)
end
end

context 'undo/back' do
it 'sets skip_doc_auth to nil and does not redirect' do
put :update, params: { undo_step: true }

expect(subject.idv_session.skip_doc_auth).to be_nil
expect(response).to redirect_to(idv_how_to_verify_url)
end
end
end
end
27 changes: 14 additions & 13 deletions spec/features/idv/doc_auth/how_to_verify_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,31 @@
include IdvHelper
include DocAuthHelper

context 'opt-in ipp is turned on' do
let(:enabled) { true }
let(:enabled) { true }

before do
allow(IdentityConfig.store).to receive(:in_person_proofing_opt_in_enabled) { enabled }
before do
allow(IdentityConfig.store).to receive(:in_person_proofing_opt_in_enabled) { enabled }

sign_in_and_2fa_user
complete_doc_auth_steps_before_agreement_step
complete_agreement_step
end
sign_in_and_2fa_user
complete_doc_auth_steps_before_agreement_step
complete_agreement_step
end

context 'opt-in ipp is turned off' do
let(:enabled) { false }
context 'opt-in ipp is turned off' do
let(:enabled) { false }

it 'skips when disabled' do
expect(page).to have_current_path(idv_hybrid_handoff_url)
end
it 'skips when disabled' do
expect(page).to have_current_path(idv_hybrid_handoff_url)
end
end

context 'opt-in ipp is turned on' do
it 'displays expected content and requires a choice' do
expect(page).to have_current_path(idv_how_to_verify_path)

# Try to continue without an option
click_continue

expect(page).to have_current_path(idv_how_to_verify_path)
expect(page).to have_content(t('errors.doc_auth.how_to_verify_form'))

Expand Down
16 changes: 0 additions & 16 deletions spec/forms/idv/how_to_verify_form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,6 @@
expect(result.errors).to be_empty
end
end

context 'when the form is invalid' do
it 'returns an unsuccessful form response' do
result = subject.submit(selection: 'peanut butter')

expect(result).to be_kind_of(FormResponse)
expect(result.success?).to eq(false)
end
end

context 'when the form has invalid attributes' do
it 'raises an error' do
expect { subject.submit(selection: Idv::HowToVerifyForm::REMOTE, foo: 1) }.
to raise_error(ArgumentError, 'foo is an invalid how_to_verify attribute')
end
end
end

describe 'presence validations' do
Expand Down
Loading