diff --git a/app/components/vendor_outage_alert_component.rb b/app/components/vendor_outage_alert_component.rb
index dbf7a21d104..822ff103efa 100644
--- a/app/components/vendor_outage_alert_component.rb
+++ b/app/components/vendor_outage_alert_component.rb
@@ -37,6 +37,6 @@ def outages
end
def vendor_status
- @vendor_status ||= VendorStatus.new
+ @vendor_status ||= OutageStatus.new
end
end
diff --git a/app/controllers/concerns/idv/verify_info_concern.rb b/app/controllers/concerns/idv/verify_info_concern.rb
index 9e1acd7dce2..4f3dd6402a7 100644
--- a/app/controllers/concerns/idv/verify_info_concern.rb
+++ b/app/controllers/concerns/idv/verify_info_concern.rb
@@ -114,7 +114,7 @@ def async_state_done(current_async_state)
move_applicant_to_idv_session
idv_session.mark_verify_info_step_complete!
idv_session.invalidate_steps_after_verify_info!
- redirect_to idv_phone_url
+ redirect_to next_step_url
else
idv_session.invalidate_verify_info_step!
end
@@ -122,6 +122,11 @@ def async_state_done(current_async_state)
analytics.idv_doc_auth_verify_proofing_results(**form_response.to_h)
end
+ def next_step_url
+ return idv_gpo_url if OutageStatus.new.gpo_only?
+ idv_phone_url
+ end
+
def summarize_result_and_throttle_failures(summary_result)
if summary_result.success?
add_proofing_components
diff --git a/app/controllers/idv/doc_auth_controller.rb b/app/controllers/idv/doc_auth_controller.rb
index 2861a53eb7f..b2e55231a30 100644
--- a/app/controllers/idv/doc_auth_controller.rb
+++ b/app/controllers/idv/doc_auth_controller.rb
@@ -70,11 +70,30 @@ def flow_session
end
def check_for_outage
- if VendorStatus.new.any_ial2_vendor_outage?
- session[:vendor_outage_redirect] = current_step
- session[:vendor_outage_redirect_from_idv] = true
- redirect_to vendor_outage_url
- end
+ return if flow_session[:skip_vendor_outage]
+
+ return redirect_for_proofing_vendor_outage if OutageStatus.new.any_idv_vendor_outage?
+ return redirect_for_gpo_only if FeatureManagement.idv_gpo_only?
+ end
+
+ def redirect_for_proofing_vendor_outage
+ session[:vendor_outage_redirect] = current_step
+ session[:vendor_outage_redirect_from_idv] = true
+
+ redirect_to vendor_outage_url
+ end
+
+ def redirect_for_gpo_only
+ return redirect_to vendor_outage_url unless FeatureManagement.gpo_verification_enabled?
+
+ # During a phone outage, skip the hybrid handoff
+ # step and go straight to document upload
+ flow_session[:skip_upload_step] = true unless FeatureManagement.idv_allow_hybrid_flow?
+
+ session[:vendor_outage_redirect] = current_step
+ session[:vendor_outage_redirect_from_idv] = true
+
+ redirect_to idv_mail_only_warning_url
end
end
end
diff --git a/app/controllers/idv/gpo_only_warning_controller.rb b/app/controllers/idv/gpo_only_warning_controller.rb
new file mode 100644
index 00000000000..8735f8fa13f
--- /dev/null
+++ b/app/controllers/idv/gpo_only_warning_controller.rb
@@ -0,0 +1,17 @@
+module Idv
+ class GpoOnlyWarningController < ApplicationController
+ include IdvSession
+ include StepIndicatorConcern
+
+ before_action :confirm_two_factor_authenticated
+
+ def show
+ user_session['idv/doc_auth'][:skip_vendor_outage] = true
+ render :show, locals: { current_sp:, exit_url: }
+ end
+
+ def exit_url
+ current_sp&.return_to_sp_url || account_path
+ end
+ end
+end
diff --git a/app/controllers/idv/phone_controller.rb b/app/controllers/idv/phone_controller.rb
index ab424f8da29..6afe9035396 100644
--- a/app/controllers/idv/phone_controller.rb
+++ b/app/controllers/idv/phone_controller.rb
@@ -62,7 +62,7 @@ def throttle
def redirect_to_next_step
if phone_confirmation_required?
- if VendorStatus.new.all_phone_vendor_outage?
+ if OutageStatus.new.all_phone_vendor_outage?
redirect_to vendor_outage_path(from: :idv_phone)
else
send_phone_confirmation_otp_and_handle_result
@@ -182,7 +182,7 @@ def new_phone_added?
def gpo_letter_available
return @gpo_letter_available if defined?(@gpo_letter_available)
- @gpo_letter_available ||= FeatureManagement.enable_gpo_verification? &&
+ @gpo_letter_available ||= FeatureManagement.gpo_verification_enabled? &&
!Idv::GpoMail.new(current_user).mail_spammed?
end
diff --git a/app/controllers/idv/phone_errors_controller.rb b/app/controllers/idv/phone_errors_controller.rb
index 31cfab5e2ec..fed541d4730 100644
--- a/app/controllers/idv/phone_errors_controller.rb
+++ b/app/controllers/idv/phone_errors_controller.rb
@@ -56,7 +56,7 @@ def track_event(type:)
# rubocop:disable Naming/MemoizedInstanceVariableName
def set_gpo_letter_available
return @gpo_letter_available if defined?(@gpo_letter_available)
- @gpo_letter_available ||= FeatureManagement.enable_gpo_verification? &&
+ @gpo_letter_available ||= FeatureManagement.gpo_verification_enabled? &&
!Idv::GpoMail.new(current_user).mail_spammed?
end
# rubocop:enable Naming/MemoizedInstanceVariableName
diff --git a/app/controllers/sign_up/registrations_controller.rb b/app/controllers/sign_up/registrations_controller.rb
index 19204b5c997..51a9ddb7e71 100644
--- a/app/controllers/sign_up/registrations_controller.rb
+++ b/app/controllers/sign_up/registrations_controller.rb
@@ -72,7 +72,7 @@ def sp_request_id
end
def redirect_if_ial2_and_vendor_outage
- return unless ial2_requested? && VendorStatus.new.any_ial2_vendor_outage?
+ return unless ial2_requested? && OutageStatus.new.any_idv_vendor_outage?
session[:vendor_outage_redirect] = CREATE_ACCOUNT
return redirect_to vendor_outage_url
diff --git a/app/controllers/users/phones_controller.rb b/app/controllers/users/phones_controller.rb
index 22c3210acd9..ca4f3988773 100644
--- a/app/controllers/users/phones_controller.rb
+++ b/app/controllers/users/phones_controller.rb
@@ -31,7 +31,7 @@ def create
private
def redirect_if_phone_vendor_outage
- return unless VendorStatus.new.all_phone_vendor_outage?
+ return unless OutageStatus.new.all_phone_vendor_outage?
redirect_to vendor_outage_path(from: :users_phones)
end
diff --git a/app/controllers/users/two_factor_authentication_controller.rb b/app/controllers/users/two_factor_authentication_controller.rb
index 7b152845a77..b413a5bc881 100644
--- a/app/controllers/users/two_factor_authentication_controller.rb
+++ b/app/controllers/users/two_factor_authentication_controller.rb
@@ -43,7 +43,7 @@ def non_phone_redirect
end
def phone_redirect
- return unless phone_enabled? && !VendorStatus.new.any_phone_vendor_outage?
+ return unless phone_enabled? && !OutageStatus.new.any_phone_vendor_outage?
validate_otp_delivery_preference_and_send_code
true
end
@@ -145,7 +145,7 @@ def redirect_if_blank_phone
end
def redirect_to_vendor_outage_if_phone_only
- return unless VendorStatus.new.all_phone_vendor_outage? &&
+ return unless OutageStatus.new.all_phone_vendor_outage? &&
phone_enabled? &&
!MfaPolicy.new(current_user).multiple_factors_enabled?
redirect_to vendor_outage_path(from: :two_factor_authentication)
diff --git a/app/controllers/vendor_outage_controller.rb b/app/controllers/vendor_outage_controller.rb
index ab47989c85e..fdc023b203f 100644
--- a/app/controllers/vendor_outage_controller.rb
+++ b/app/controllers/vendor_outage_controller.rb
@@ -1,6 +1,6 @@
class VendorOutageController < ApplicationController
def show
- vendor_status = VendorStatus.new(
+ vendor_status = OutageStatus.new(
sp: current_sp,
from: session.delete(:vendor_outage_redirect),
from_idv: session.delete(:vendor_outage_redirect_from_idv),
@@ -17,7 +17,7 @@ def from_idv_phone?
end
def gpo_letter_available?
- FeatureManagement.enable_gpo_verification? &&
+ FeatureManagement.gpo_verification_enabled? &&
current_user &&
!Idv::GpoMail.new(current_user).mail_spammed?
end
diff --git a/app/forms/new_phone_form.rb b/app/forms/new_phone_form.rb
index af4f76885e0..068310eafea 100644
--- a/app/forms/new_phone_form.rb
+++ b/app/forms/new_phone_form.rb
@@ -46,11 +46,11 @@ def submit(params)
end
def delivery_preference_sms?
- !VendorStatus.new.vendor_outage?(:sms)
+ !OutageStatus.new.vendor_outage?(:sms)
end
def delivery_preference_voice?
- VendorStatus.new.vendor_outage?(:sms) || setup_voice_preference?
+ OutageStatus.new.vendor_outage?(:sms) || setup_voice_preference?
end
# @return [Telephony::PhoneNumberInfo, nil]
diff --git a/app/presenters/idv/gpo_presenter.rb b/app/presenters/idv/gpo_presenter.rb
index 1ee0cb8ed12..9c7b210bb3e 100644
--- a/app/presenters/idv/gpo_presenter.rb
+++ b/app/presenters/idv/gpo_presenter.rb
@@ -18,6 +18,7 @@ def button
end
def fallback_back_path
+ return idv_verify_info_path if OutageStatus.new.any_phone_vendor_outage?
user_needs_address_otp_verification? ? idv_gpo_verify_path : idv_phone_path
end
@@ -25,6 +26,22 @@ def resend_requested?
current_user.decorate.pending_profile_requires_verification?
end
+ def back_or_cancel_partial
+ if OutageStatus.new.gpo_only?
+ 'idv/doc_auth/cancel'
+ else
+ 'idv/shared/back'
+ end
+ end
+
+ def back_or_cancel_parameters
+ if OutageStatus.new.gpo_only?
+ { step: 'gpo' }
+ else
+ { fallback_path: fallback_back_path }
+ end
+ end
+
private
def user_needs_address_otp_verification?
diff --git a/app/presenters/two_factor_authentication/phone_selection_presenter.rb b/app/presenters/two_factor_authentication/phone_selection_presenter.rb
index f452e2142e1..1954589607c 100644
--- a/app/presenters/two_factor_authentication/phone_selection_presenter.rb
+++ b/app/presenters/two_factor_authentication/phone_selection_presenter.rb
@@ -21,7 +21,7 @@ def mfa_configuration_count
end
def disabled?
- VendorStatus.new.all_phone_vendor_outage? || user&.phone_configurations&.any?
+ OutageStatus.new.all_phone_vendor_outage? || user&.phone_configurations&.any?
end
end
end
diff --git a/app/presenters/two_factor_authentication/sms_selection_presenter.rb b/app/presenters/two_factor_authentication/sms_selection_presenter.rb
index 081efd9d847..3226ae6adc3 100644
--- a/app/presenters/two_factor_authentication/sms_selection_presenter.rb
+++ b/app/presenters/two_factor_authentication/sms_selection_presenter.rb
@@ -16,7 +16,7 @@ def info
end
def disabled?
- VendorStatus.new.vendor_outage?(:sms)
+ OutageStatus.new.vendor_outage?(:sms)
end
end
end
diff --git a/app/presenters/two_factor_authentication/voice_selection_presenter.rb b/app/presenters/two_factor_authentication/voice_selection_presenter.rb
index b2e4a061785..369878c5e5d 100644
--- a/app/presenters/two_factor_authentication/voice_selection_presenter.rb
+++ b/app/presenters/two_factor_authentication/voice_selection_presenter.rb
@@ -16,7 +16,7 @@ def info
end
def disabled?
- VendorStatus.new.vendor_outage?(:voice)
+ OutageStatus.new.vendor_outage?(:voice)
end
end
end
diff --git a/app/services/idv/steps/welcome_step.rb b/app/services/idv/steps/welcome_step.rb
index 1a5744a5e94..67116884635 100644
--- a/app/services/idv/steps/welcome_step.rb
+++ b/app/services/idv/steps/welcome_step.rb
@@ -12,7 +12,10 @@ def self.analytics_submitted_event
end
def call
+ flow_session[:skip_upload_step] = true unless FeatureManagement.idv_allow_hybrid_flow?
+
return no_camera_redirect if params[:no_camera]
+
create_document_capture_session(document_capture_session_uuid_key)
cancel_previous_in_person_enrollments
end
diff --git a/app/services/vendor_status.rb b/app/services/outage_status.rb
similarity index 82%
rename from app/services/vendor_status.rb
rename to app/services/outage_status.rb
index 32af74b2370..33a7950ba54 100644
--- a/app/services/vendor_status.rb
+++ b/app/services/outage_status.rb
@@ -1,4 +1,4 @@
-class VendorStatus
+class OutageStatus
include ActionView::Helpers::TranslationHelper
def initialize(from: nil, from_idv: nil, sp: nil)
@@ -7,9 +7,9 @@ def initialize(from: nil, from_idv: nil, sp: nil)
@sp = sp
end
- IAL2_VENDORS = %i[acuant lexisnexis_instant_verify lexisnexis_trueid].freeze
+ IDV_VENDORS = %i[acuant lexisnexis_instant_verify lexisnexis_trueid].freeze
PHONE_VENDORS = %i[sms voice].freeze
- ALL_VENDORS = (IAL2_VENDORS + PHONE_VENDORS).freeze
+ ALL_VENDORS = (IDV_VENDORS + PHONE_VENDORS).freeze
def vendor_outage?(vendor)
status = case vendor
@@ -37,8 +37,8 @@ def all_vendor_outage?(vendors = ALL_VENDORS)
vendors.all? { |vendor| vendor_outage?(vendor) }
end
- def any_ial2_vendor_outage?
- any_vendor_outage?(IAL2_VENDORS)
+ def any_idv_vendor_outage?
+ any_vendor_outage?(IDV_VENDORS)
end
def any_phone_vendor_outage?
@@ -49,6 +49,16 @@ def all_phone_vendor_outage?
all_vendor_outage?(PHONE_VENDORS)
end
+ def gpo_only?
+ IdentityConfig.store.feature_idv_force_gpo_verification_enabled ||
+ any_phone_vendor_outage?
+ end
+
+ def allow_hybrid_flow?
+ IdentityConfig.store.feature_idv_hybrid_flow_enabled &&
+ !any_phone_vendor_outage?
+ end
+
def from_idv?
from_idv
end
@@ -58,7 +68,7 @@ def from_idv?
#
# @return [String, nil] the localized message.
def outage_message
- if any_ial2_vendor_outage?
+ if any_idv_vendor_outage?
if from_idv?
if sp
t('vendor_outage.blocked.idv.with_sp', service_provider: sp.friendly_name)
diff --git a/app/views/idv/gpo/index.html.erb b/app/views/idv/gpo/index.html.erb
index ac0e48dd06b..69ec0f3f07b 100644
--- a/app/views/idv/gpo/index.html.erb
+++ b/app/views/idv/gpo/index.html.erb
@@ -42,4 +42,4 @@
],
) %>
-<%= render 'idv/shared/back', fallback_path: @presenter.fallback_back_path %>
+<%= render @presenter.back_or_cancel_partial, @presenter.back_or_cancel_parameters %>
diff --git a/app/views/idv/gpo_only_warning/show.html.erb b/app/views/idv/gpo_only_warning/show.html.erb
new file mode 100644
index 00000000000..78e7a4c77e0
--- /dev/null
+++ b/app/views/idv/gpo_only_warning/show.html.erb
@@ -0,0 +1,53 @@
+<%= render StepIndicatorComponent.new(
+ steps: step_indicator_steps,
+ current_step: :getting_started,
+ locale_scope: 'idv',
+ class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4',
+ ) %>
+
+<%= render StatusPageComponent.new(status: :warning) do |c| %>
+ <% c.header { t('vendor_outage.alerts.pinpoint.idv.header') } %>
+
+ <%= t('vendor_outage.alerts.pinpoint.idv.message_html', app_name: APP_NAME, sp_name: current_sp&.friendly_name || APP_NAME) %>
+
+ <%= t('vendor_outage.alerts.pinpoint.idv.options_prompt') %>
+
+ <% t('vendor_outage.alerts.pinpoint.idv.options_html', status_page_url: StatusPage.base_url).each do | option | %>
+ -
+ <%= option %>
+
+ <% end %>
+
+ <% c.action_button(
+ action: ->(**tag_options, &block) do
+ link_to(idv_doc_auth_step_path(step: :welcome), **tag_options, &block)
+ end,
+ big: true,
+ wide: true,
+ class: 'usa-button',
+ ).with_content(t('doc_auth.buttons.continue')) %>
+ <% c.action_button(
+ action: ->(**tag_options, &block) do
+ link_to(exit_url, **tag_options, &block)
+ end,
+ big: true,
+ wide: true,
+ outline: true,
+ class: 'usa-button',
+ ).with_content(t('links.exit_login', app_name: APP_NAME)) %>
+ <% c.troubleshooting_options do |tc| %>
+ <% tc.header { t('components.troubleshooting_options.default_heading') } %>
+ <% tc.option(
+ url: StatusPage.base_url,
+ new_tab: true,
+ ).with_content(t('vendor_outage.get_updates_on_status_page')) %>
+ <% if decorated_session.sp_name %>
+ <% tc.option(
+ url: current_sp.return_to_sp_url,
+ new_tab: true,
+ ).with_content(
+ t('idv.troubleshooting.options.get_help_at_sp', sp_name: decorated_session.sp_name),
+ ) %>
+ <% end %>
+ <% end %>
+<% end %>
diff --git a/app/views/idv/gpo_verify/index.html.erb b/app/views/idv/gpo_verify/index.html.erb
index 3b57f850770..e9921d693a0 100644
--- a/app/views/idv/gpo_verify/index.html.erb
+++ b/app/views/idv/gpo_verify/index.html.erb
@@ -41,7 +41,7 @@
<% end %>
-<% if FeatureManagement.enable_gpo_verification? && !@mail_spammed %>
+<% if FeatureManagement.gpo_verification_enabled? && !@mail_spammed %>
<%= link_to t('idv.messages.gpo.resend'), idv_gpo_path, class: 'display-block margin-bottom-2' %>
<% end %>
diff --git a/app/views/idv/phone/new.html.erb b/app/views/idv/phone/new.html.erb
index e0a34dec849..2c6e5f38dfc 100644
--- a/app/views/idv/phone/new.html.erb
+++ b/app/views/idv/phone/new.html.erb
@@ -71,8 +71,8 @@
<%= f.radio_button(
:otp_delivery_preference,
:sms,
- checked: !VendorStatus.new.vendor_outage?(:sms), # We want SMS to be default checked
- disabled: VendorStatus.new.vendor_outage?(:sms),
+ checked: !OutageStatus.new.vendor_outage?(:sms), # We want SMS to be default checked
+ disabled: OutageStatus.new.vendor_outage?(:sms),
class: 'usa-radio__input usa-radio__input--bordered',
) %>
<%= f.label :otp_delivery_preference_sms, t('two_factor_authentication.otp_delivery_preference.sms'), class: 'usa-radio__label width-full' %>
@@ -81,7 +81,7 @@
<%= f.radio_button(
:otp_delivery_preference,
:voice,
- disabled: VendorStatus.new.vendor_outage?(:voice),
+ disabled: OutageStatus.new.vendor_outage?(:voice),
class: 'usa-radio__input usa-radio__input--bordered',
) %>
<%= f.label :otp_delivery_preference_voice, t('two_factor_authentication.otp_delivery_preference.voice'), class: 'usa-radio__label width-full' %>
diff --git a/app/views/users/shared/_otp_delivery_preference_selection.html.erb b/app/views/users/shared/_otp_delivery_preference_selection.html.erb
index cc3bb484104..3727d029215 100644
--- a/app/views/users/shared/_otp_delivery_preference_selection.html.erb
+++ b/app/views/users/shared/_otp_delivery_preference_selection.html.erb
@@ -14,7 +14,7 @@
form_name_label,
:sms,
form_obj.delivery_preference_sms?,
- disabled: VendorStatus.new.vendor_outage?(:sms),
+ disabled: OutageStatus.new.vendor_outage?(:sms),
class: 'js-otp-delivery-preference usa-radio__input usa-radio__input--bordered',
) %>