Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LG-15337: Socure Try again page for hybrid mobile flow #11734

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion app/controllers/concerns/idv/document_capture_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def selfie_requirement_met?
stored_result.selfie_check_performed?
end

def redirect_to_correct_vendor(vendor, in_hybrid_mobile)
def redirect_to_correct_vendor(vendor, in_hybrid_mobile: false)
expected_doc_auth_vendor = doc_auth_vendor
return if vendor == expected_doc_auth_vendor
return if vendor == Idp::Constants::Vendors::LEXIS_NEXIS &&
Expand Down
6 changes: 4 additions & 2 deletions app/controllers/idv/document_capture_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ class DocumentCaptureController < ApplicationController
before_action :confirm_step_allowed, unless: -> { allow_direct_ipp? }
before_action :override_csp_to_allow_acuant
before_action :set_usps_form_presenter
before_action -> { redirect_to_correct_vendor(Idp::Constants::Vendors::LEXIS_NEXIS, false) },
only: [:show], unless: -> { allow_direct_ipp? }
before_action -> do
redirect_to_correct_vendor(Idp::Constants::Vendors::LEXIS_NEXIS, in_hybrid_mobile: false)
end, only: [:show], unless: -> { allow_direct_ipp? }

def show
analytics.idv_doc_auth_document_capture_visited(**analytics_arguments)
Expand Down Expand Up @@ -48,6 +49,7 @@ def update
def direct_in_person
attributes = {
remaining_submit_attempts: rate_limiter.remaining_count,
flow_path: :standard,
}.merge(ab_test_analytics_buckets)
analytics.idv_in_person_direct_start(**attributes)

Expand Down
35 changes: 33 additions & 2 deletions app/controllers/idv/hybrid_mobile/document_capture_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ class DocumentCaptureController < ApplicationController
before_action :override_csp_to_allow_acuant
before_action :confirm_document_capture_needed, only: :show
before_action :set_usps_form_presenter
before_action -> { redirect_to_correct_vendor(Idp::Constants::Vendors::LEXIS_NEXIS, true) },
only: :show
before_action -> do
redirect_to_correct_vendor(Idp::Constants::Vendors::LEXIS_NEXIS, in_hybrid_mobile: true)
end, only: [:show], unless: -> { allow_direct_ipp? }

def show
analytics.idv_doc_auth_document_capture_visited(**analytics_arguments)
Expand Down Expand Up @@ -43,13 +44,26 @@ def update
end
end

# Given that the start of the IPP flow is in the TrueID doc_auth React app,
# we need a generic, direct way to start the IPP flow
def direct_in_person
attributes = {
remaining_submit_attempts: rate_limiter.remaining_count,
flow_path: :hybrid,
}.merge(ab_test_analytics_buckets)
analytics.idv_in_person_direct_start(**attributes)

redirect_to idv_hybrid_mobile_document_capture_url(step: :idv_doc_auth)
end

def extra_view_variables
{
flow_path: 'hybrid',
mock_client: doc_auth_vendor == 'mock',
document_capture_session_uuid: document_capture_session_uuid,
failure_to_proof_url: return_to_sp_failure_to_proof_url(step: 'document_capture'),
doc_auth_selfie_capture: resolved_authn_context_result.facial_match?,
skip_doc_auth_from_socure_hybrid: @skip_doc_auth_from_socure_hybrid,
Copy link
Contributor

@amirbey amirbey Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
skip_doc_auth_from_socure_hybrid: @skip_doc_auth_from_socure_hybrid,
skip_doc_auth_from_socure: @skip_doc_auth_from_socure,

this is great! can we add this same attribute when opting into IPP from Socure standard flow which currently misrepesents the source of opting into IPP as hybrid handoff.

}.merge(
acuant_sdk_upgrade_a_b_testing_variables,
)
Expand All @@ -69,6 +83,19 @@ def analytics_arguments
)
end

def allow_direct_ipp?
return false if params[:step].blank?
return false if params[:action].to_s != 'show' && params[:action] != 'direct_in_person'
# Only allow direct access to document capture if IPP available
return false unless IdentityConfig.store.in_person_doc_auth_button_enabled &&
Idv::InPersonConfig.enabled_for_issuer?(sp_session[:issuer])

# allow
@previous_step_url = params[:step] == 'hybrid_handoff' ? idv_hybrid_handoff_path : nil
@skip_doc_auth_from_socure_hybrid = true
true
end

def confirm_document_capture_needed
return unless stored_result&.success?
return if redo_document_capture_pending?
Expand All @@ -86,6 +113,10 @@ def redo_document_capture_pending?
def set_usps_form_presenter
@presenter = Idv::InPerson::UspsFormPresenter.new
end

def rate_limiter
RateLimiter.new(user: document_capture_user, rate_limit_type: :idv_doc_auth)
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ class DocumentCaptureController < ApplicationController

check_or_render_not_found -> { IdentityConfig.store.socure_docv_enabled }
before_action :check_valid_document_capture_session, except: [:update]
before_action -> { redirect_to_correct_vendor(Idp::Constants::Vendors::SOCURE, true) },
only: :show
before_action -> do
redirect_to_correct_vendor(Idp::Constants::Vendors::SOCURE, in_hybrid_mobile: true)
end, only: :show
before_action :fetch_test_verification_data, only: [:update]

def show
Expand Down Expand Up @@ -97,9 +98,7 @@ def wait_for_result?
# If the stored_result is nil, the job fetching the results has not completed.
analytics.idv_doc_auth_document_capture_polling_wait_visited(**analytics_arguments)
if wait_timed_out?
# flash[:error] = I18n.t('errors.doc_auth.polling_timeout')
# TODO: redirect to try again page LG-14873/14952/15059
render plain: 'Technical difficulties!!!', status: :ok
redirect_to idv_hybrid_mobile_socure_errors_timeout_path
else
@refresh_interval =
IdentityConfig.store.doc_auth_socure_wait_polling_refresh_max_seconds
Expand Down
73 changes: 73 additions & 0 deletions app/controllers/idv/hybrid_mobile/socure/errors_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# frozen_string_literal: true

module Idv
module HybridMobile
module Socure
class ErrorsController < ApplicationController
include DocumentCaptureConcern
include HybridMobileConcern
include AvailabilityConcern
include StepIndicatorConcern
include SocureErrorsConcern

def show
error_code = error_code_for(handle_stored_result)
track_event(error_code: error_code)
@presenter = socure_errors_presenter(error_code)
end

def timeout
track_event(error_code: :timeout)
@presenter = socure_errors_presenter(:timeout)
render :show
end

def self.step_info
Idv::StepInfo.new(
key: :hybrid_socure_errors,
controller: self,
action: :timeout,
next_steps: [FlowPolicy::FINAL],
preconditions: ->(idv_session:, user:) do
true
end,
undo_step: ->(idv_session:, user:) {},
)
end

private

def rate_limiter
RateLimiter.new(user: document_capture_session&.user, rate_limit_type: :idv_doc_auth)
end

def remaining_submit_attempts
@remaining_submit_attempts ||= rate_limiter.remaining_count
end

def track_event(error_code:)
attributes = {
error_code:,
remaining_submit_attempts:,
}

analytics.idv_doc_auth_socure_error_visited(**attributes)
end

def socure_errors_presenter(error_code)
SocureErrorPresenter.new(
error_code:,
remaining_attempts: remaining_submit_attempts,
sp_name: service_provider&.friendly_name || APP_NAME,
issuer: service_provider&.issuer,
flow_path: :hybrid,
)
end

def service_provider
@service_provider ||= ServiceProvider.find_by(issuer: document_capture_session&.issuer)
end
end
end
end
end
5 changes: 3 additions & 2 deletions app/controllers/idv/socure/document_capture_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ class DocumentCaptureController < ApplicationController
check_or_render_not_found -> { IdentityConfig.store.socure_docv_enabled }
before_action :confirm_not_rate_limited
before_action :confirm_step_allowed
before_action -> { redirect_to_correct_vendor(Idp::Constants::Vendors::SOCURE, false) },
only: :show
before_action -> do
redirect_to_correct_vendor(Idp::Constants::Vendors::SOCURE, in_hybrid_mobile: false)
end, only: :show
before_action :fetch_test_verification_data, only: [:update]

# reconsider and maybe remove these when implementing the real
Expand Down
1 change: 0 additions & 1 deletion app/controllers/idv/socure/errors_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ def self.step_info
action: :timeout,
next_steps: [FlowPolicy::FINAL],
preconditions: ->(idv_session:, user:) do
# idv_session.socure_docv_wait_polling_started_at.present?
true
end,
undo_step: ->(idv_session:, user:) {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ function DocumentCapture({ onStepChange = () => {} }: DocumentCaptureProps) {
inPersonURL,
skipDocAuthFromHandoff,
skipDocAuthFromHowToVerify,
skipDocAuthFromSocureHybrid,
} = useContext(InPersonContext);
useDidUpdateEffect(onStepChange, [stepName]);
useEffect(() => {
Expand Down Expand Up @@ -142,7 +143,8 @@ function DocumentCapture({ onStepChange = () => {} }: DocumentCaptureProps) {
}
// If the user got here by opting-in to in-person proofing, when skipDocAuthFromHowToVerify === true
// then set steps to inPersonSteps
const isInPersonStepEnabled = skipDocAuthFromHowToVerify || skipDocAuthFromHandoff;
const isInPersonStepEnabled =
skipDocAuthFromHowToVerify || skipDocAuthFromHandoff || skipDocAuthFromSocureHybrid;
const inPersonSteps: FormStep[] =
inPersonURL === undefined
? []
Expand All @@ -157,13 +159,13 @@ function DocumentCapture({ onStepChange = () => {} }: DocumentCaptureProps) {
steps = [reviewFormStep, ...inPersonSteps];
}
// If the user got here by opting-in to in-person proofing, when skipDocAuthFromHowToVerify === true
// or opting-in ipp from handoff page, and selfie is required, when skipDocAuthFromHandoff === true
// or opting-in ipp from handoff page, and selfie is required, when skipDocAuthFromHandoff === true,
// or opting-in ipp from socure hybrid, when skipDocAuthFromSocureHybrid === true,
// then set stepIndicatorPath to VerifyFlowPath.IN_PERSON
const stepIndicatorPath =
(stepName && ['location', 'prepare', 'switch_back'].includes(stepName)) || isInPersonStepEnabled
? VerifyFlowPath.IN_PERSON
: VerifyFlowPath.DEFAULT;

return (
<>
<VerifyFlowStepIndicator currentStep="document_capture" path={stepIndicatorPath} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function InPersonPrepareStep({ toPreviousStep }) {
inPersonOutageExpectedUpdateDate,
skipDocAuthFromHowToVerify,
skipDocAuthFromHandoff,
skipDocAuthFromSocureHybrid,
howToVerifyURL,
previousStepURL,
} = useContext(InPersonContext);
Expand All @@ -31,6 +32,9 @@ function InPersonPrepareStep({ toPreviousStep }) {
forceRedirect(previousStepURL);
} else if (skipDocAuthFromHowToVerify && howToVerifyURL) {
forceRedirect(howToVerifyURL);
} else if (skipDocAuthFromSocureHybrid) {
// directly from Socure Hybrid page
forceRedirect('https://google.com');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left over form testing? 😅

} else {
toPreviousStep();
}
Expand Down
5 changes: 5 additions & 0 deletions app/javascript/packages/document-capture/context/in-person.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ export interface InPersonContextProps {
*/
skipDocAuthFromHandoff?: boolean;

/**
* Flag set when user select IPP from the Socure Hybrid page when IPP is available
*/
skipDocAuthFromSocureHybrid?: boolean;

/**
* URL for Opt-in IPP, used when in_person_proofing_opt_in_enabled is enabled
*/
Expand Down
3 changes: 3 additions & 0 deletions app/javascript/packs/document-capture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ interface AppRootData {
securityAndPrivacyHowItWorksUrl: string;
skipDocAuthFromHowToVerify: string;
skipDocAuthFromHandoff: string;
skipDocAuthFromSocureHybrid: string;
howToVerifyURL: string;
previousStepUrl: string;
docAuthSelfieDesktopTestMode: string;
Expand Down Expand Up @@ -107,6 +108,7 @@ const {
usStatesTerritories = '',
skipDocAuthFromHowToVerify,
skipDocAuthFromHandoff,
skipDocAuthFromSocureHybrid,
howToVerifyUrl,
previousStepUrl,
docAuthSelfieDesktopTestMode,
Expand Down Expand Up @@ -138,6 +140,7 @@ render(
usStatesTerritories: parsedUsStatesTerritories,
skipDocAuthFromHowToVerify: skipDocAuthFromHowToVerify === 'true',
skipDocAuthFromHandoff: skipDocAuthFromHandoff === 'true',
skipDocAuthFromSocureHybrid: skipDocAuthFromSocureHybrid === 'true',
howToVerifyURL: howToVerifyUrl,
previousStepURL: previousStepUrl,
}}
Expand Down
8 changes: 5 additions & 3 deletions app/presenters/socure_error_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,13 @@ def secondary_action_text
end

def secondary_action
url = flow_path == :hybrid ? idv_hybrid_mobile_in_person_direct_url :
idv_in_person_direct_url

if in_person_enabled?
{
text: I18n.t('in_person_proofing.body.cta.button'),
url: idv_in_person_direct_url,
url:,
}
end
end
Expand Down Expand Up @@ -176,7 +179,6 @@ def error_string_for(error_code)

def in_person_enabled?
IdentityConfig.store.in_person_doc_auth_button_enabled &&
Idv::InPersonConfig.enabled_for_issuer?(issuer) &&
flow_path.to_s == 'standard'
Idv::InPersonConfig.enabled_for_issuer?(issuer)
end
end
3 changes: 3 additions & 0 deletions app/services/analytics_events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2816,17 +2816,20 @@ def idv_image_capture_failed(

# User chooses to try In Person, e.g. from a doc_auth timeout error page
# @param [Integer] remaining_submit_attempts The number of remaining attempts to submit
# @param ["hybrid","standard"] flow_path Document capture user flow
# @param [Boolean] skip_hybrid_handoff Whether the user skipped the hybrid handoff A/B test
# @param [Boolean] opted_in_to_in_person_proofing Whether the user opted into in-person proofing
def idv_in_person_direct_start(
remaining_submit_attempts:,
flow_path:,
skip_hybrid_handoff: nil,
opted_in_to_in_person_proofing: nil,
**extra
)
track_event(
:idv_in_person_direct_start,
remaining_submit_attempts:,
flow_path:,
skip_hybrid_handoff:,
opted_in_to_in_person_proofing:,
**extra,
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 @@ -10,6 +10,7 @@
opted_in_to_in_person_proofing: opted_in_to_in_person_proofing,
skip_doc_auth_from_how_to_verify: skip_doc_auth_from_how_to_verify,
skip_doc_auth_from_handoff: skip_doc_auth_from_handoff,
skip_doc_auth_from_socure_hybrid: false,
doc_auth_selfie_capture: doc_auth_selfie_capture,
mock_client: mock_client,
) %>
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 @@ -10,6 +10,7 @@
opted_in_to_in_person_proofing: false,
skip_doc_auth_from_how_to_verify: false,
skip_doc_auth_from_handoff: nil,
skip_doc_auth_from_socure_hybrid: @skip_doc_auth_from_socure_hybrid,
doc_auth_selfie_capture: doc_auth_selfie_capture,
mock_client: mock_client,
) %>
17 changes: 17 additions & 0 deletions app/views/idv/hybrid_mobile/socure/errors/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<%= render(
'idv/shared/error',
type: :warning,
heading: @presenter.heading,
action: @presenter.action,
secondary_action: @presenter.secondary_action,
current_step: :verify_id,
troubleshooting_heading: @presenter.troubleshooting_heading,
secondary_action_heading: @presenter.secondary_action_heading,
secondary_action_text: @presenter.secondary_action_text,
options: @presenter.options,
step_indicator_steps: @presenter.step_indicator_steps,
) do
%>
<p><%= @presenter.body_text %></p>
<p><%= @presenter.rate_limit_text %></p>
<% end %>
1 change: 1 addition & 0 deletions app/views/idv/shared/_document_capture.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
doc_auth_selfie_desktop_test_mode: IdentityConfig.store.doc_auth_selfie_desktop_test_mode,
skip_doc_auth_from_how_to_verify: skip_doc_auth_from_how_to_verify,
skip_doc_auth_from_handoff: skip_doc_auth_from_handoff,
skip_doc_auth_from_socure_hybrid: skip_doc_auth_from_socure_hybrid,
how_to_verify_url: idv_how_to_verify_url,
previous_step_url: @previous_step_url,
locations_url: idv_in_person_usps_locations_url,
Expand Down
Loading