Skip to content
Merged
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
12 changes: 12 additions & 0 deletions app/services/analytics_events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,10 @@ def idv_doc_auth_cancel_link_sent_submitted(**extra)
track_event('IdV: doc auth cancel_link_sent submitted', **extra)
end

def idv_doc_auth_cancel_send_link_submitted(**extra)
track_event('IdV: doc auth cancel_send_link submitted', **extra)
end

# @identity.idp.previous_event_name IdV: in person proofing cancel_update_ssn submitted
def idv_doc_auth_cancel_update_ssn_submitted(**extra)
track_event('IdV: doc auth cancel_update_ssn submitted', **extra)
Expand Down Expand Up @@ -779,6 +783,14 @@ def idv_doc_auth_redo_document_capture_submitted(**extra)
track_event('IdV: doc auth redo_document_capture submitted', **extra)
end

def idv_doc_auth_send_link_visited(**extra)
track_event('IdV: doc auth send_link visited', **extra)
end

def idv_doc_auth_send_link_submitted(**extra)
track_event('IdV: doc auth send_link submitted', **extra)
end

# @identity.idp.previous_event_name IdV: in person proofing ssn submitted
def idv_doc_auth_ssn_submitted(**extra)
track_event('IdV: doc auth ssn submitted', **extra)
Expand Down
5 changes: 4 additions & 1 deletion app/services/idv/actions/cancel_link_sent_action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ def self.analytics_submitted_event
end

def call
mark_step_incomplete(:upload)
mark_step_incomplete(:send_link)
if IdentityConfig.store.doc_auth_combined_hybrid_handoff_enabled
mark_step_incomplete(:upload)
end
end
end
end
Expand Down
13 changes: 13 additions & 0 deletions app/services/idv/actions/cancel_send_link_action.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Idv
module Actions
class CancelSendLinkAction < Idv::Steps::DocAuthBaseStep
def self.analytics_submitted_event
:idv_doc_auth_cancel_send_link_submitted
end

def call
mark_step_incomplete(:upload)
end
end
end
end
2 changes: 2 additions & 0 deletions app/services/idv/flows/doc_auth_flow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class DocAuthFlow < Flow::BaseFlow
welcome: Idv::Steps::WelcomeStep,
agreement: Idv::Steps::AgreementStep,
upload: Idv::Steps::UploadStep,
send_link: Idv::Steps::SendLinkStep,
link_sent: Idv::Steps::LinkSentStep,
email_sent: Idv::Steps::EmailSentStep,
document_capture: Idv::Steps::DocumentCaptureStep,
Expand All @@ -29,6 +30,7 @@ class DocAuthFlow < Flow::BaseFlow
OPTIONAL_SHOW_STEPS = {}.freeze

ACTIONS = {
cancel_send_link: Idv::Actions::CancelSendLinkAction,
cancel_link_sent: Idv::Actions::CancelLinkSentAction,
redo_address: Idv::Actions::RedoAddressAction,
redo_document_capture: Idv::Actions::RedoDocumentCaptureAction,
Expand Down
128 changes: 128 additions & 0 deletions app/services/idv/steps/send_link_step.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
module Idv
module Steps
class SendLinkStep < DocAuthBaseStep
include ActionView::Helpers::DateHelper

STEP_INDICATOR_STEP = :verify_id

def self.analytics_visited_event
:idv_doc_auth_send_link_visited
end

def self.analytics_submitted_event
:idv_doc_auth_send_link_submitted
end

def call
throttle.increment!
return throttled_failure if throttle.throttled?
telephony_result = send_link
failure_reason = nil
if !telephony_result.success?
failure_reason = { telephony: [telephony_result.error.class.name.demodulize] }
end
idv_session[:phone_for_mobile_flow] = permit(:phone)[:phone]
@flow.irs_attempts_api_tracker.idv_phone_upload_link_sent(
success: telephony_result.success?,
phone_number: formatted_destination_phone,
failure_reason: failure_reason,
)
build_telephony_form_response(telephony_result)
end

def extra_view_variables
{
idv_phone_form: build_form,
}
end

private

def build_form
Idv::PhoneForm.new(
previous_params: {},
user: current_user,
delivery_methods: [:sms],
)
end

def build_telephony_form_response(telephony_result)
FormResponse.new(
success: telephony_result.success?,
errors: { message: telephony_result.error&.friendly_message },
extra: { telephony_response: telephony_result.to_h },
)
end

def throttled_failure
@flow.analytics.throttler_rate_limit_triggered(
throttle_type: :idv_send_link,
)
message = I18n.t(
'errors.doc_auth.send_link_throttle',
timeout: distance_of_time_in_words(
Time.zone.now,
[throttle.expires_at, Time.zone.now].compact.max,
except: :seconds,
),
)

@flow.irs_attempts_api_tracker.idv_phone_send_link_rate_limited(
phone_number: formatted_destination_phone,
)

failure(message)
end

def send_link
session_uuid = flow_session[:document_capture_session_uuid]
update_document_capture_session_requested_at(session_uuid)
Telephony.send_doc_auth_link(
to: formatted_destination_phone,
link: link(session_uuid),
country_code: Phonelib.parse(formatted_destination_phone).country,
sp_or_app_name: sp_or_app_name,
)
end

def sp_or_app_name
current_sp&.friendly_name.presence || APP_NAME
end

def form_submit
params = permit(:phone)
params[:otp_delivery_preference] = 'sms'
build_form.submit(params)
end

def formatted_destination_phone
raw_phone = permit(:phone)[:phone]
PhoneFormatter.format(raw_phone, country_code: 'US')
end

def update_document_capture_session_requested_at(session_uuid)
document_capture_session = DocumentCaptureSession.find_by(uuid: session_uuid)
return unless document_capture_session
document_capture_session.update!(
requested_at: Time.zone.now,
cancelled_at: nil,
issuer: sp_session[:issuer],
)
end

def link(session_uuid)
idv_capture_doc_dashes_url(
'document-capture-session': session_uuid,
request_id: sp_session[:request_id],
)
end

def throttle
@throttle ||= Throttle.new(
user: current_user,
throttle_type: :idv_send_link,
)
end
end
end
end
40 changes: 36 additions & 4 deletions app/services/idv/steps/upload_step.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,27 @@ def call
# app/views/idv/doc_auth/upload.html.erb
if params[:type] == 'desktop'
handle_desktop_selection
else
return bypass_send_link_steps if mobile_device?
elsif params[:combined]
# The user was shown the new combined view and
# submitted a phone number to this step with feature flag on
# OR
# The user was originally shown the new combined view,
# but has submitted to a step with the feature flag off
# (50/50 from new to old)
handle_phone_submission
else
handle_mobile_selection
end
end

def extra_view_variables
{ idv_phone_form: build_form }
if IdentityConfig.store.doc_auth_combined_hybrid_handoff_enabled
{
idv_phone_form: build_form,
}
else
{}
end
end

private
Expand All @@ -50,13 +63,26 @@ def build_form
end

def form_submit
return super unless params[:type] == 'mobile'
return super if !IdentityConfig.store.doc_auth_combined_hybrid_handoff_enabled
return super if params[:type] == 'desktop'

# Remove after 50/50 deploy w/ flag
return super if params[:type] != 'combined'

params = permit(:phone)
params[:otp_delivery_preference] = 'sms'
build_form.submit(params)
end

# To be removed after 50/50
def handle_mobile_selection
if mobile_device?
bypass_send_link_steps
else
send_user_to_send_link_step
end
end

def handle_phone_submission
throttle.increment!
return throttled_failure if throttle.throttled?
Expand Down Expand Up @@ -99,7 +125,13 @@ def send_user_to_email_sent_step
form_response(destination: :email_sent)
end

def send_user_to_send_link_step
mark_step_complete(:email_sent)
form_response(destination: :send_link)
end

def bypass_send_link_steps
mark_step_complete(:send_link)
mark_step_complete(:link_sent)
mark_step_complete(:email_sent)
form_response(destination: :document_capture)
Expand Down
74 changes: 74 additions & 0 deletions app/views/idv/doc_auth/_combined_upload.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<% title t('titles.doc_auth.upload') %>

<%= render 'idv/doc_auth/error_messages', flow_session: flow_session %>

<%= render PageHeadingComponent.new do %>
<%= t('doc_auth.headings.combined_upload') %>
<% end %>

<p>
<%= t('doc_auth.info.combined_upload') %>
</p>

<div class="grid-row grid-gap grid-gap-2">
<div class="grid-col-12 tablet:grid-col-auto">
<%= image_tag(
asset_url('idv/phone-icon.svg'),
alt: t('image_description.camera_mobile_phone'),
width: 88,
height: 88,
) %>
</div>
<div class="grid-col-12 tablet:grid-col-fill">
<div class="usa-tag usa-tag--informative">
<%= t('doc_auth.info.tag') %>
</div>
<h2 class="margin-y-105">
<%= t('doc_auth.headings.combined_upload_from_phone') %>
</h2>
<%= t('doc_auth.info.combined_upload_from_phone') %>
<%= simple_form_for(
idv_phone_form,
as: :doc_auth,
url: url_for(type: :mobile, combined: true),
method: 'PUT',
html: { autocomplete: 'off' },
) do |f| %>
<%= render PhoneInputComponent.new(
form: f,
required: true,
delivery_methods: [:sms],
class: 'margin-bottom-4',
) %>
<%= f.submit t('forms.buttons.send_link') %>
<% end %>
</div>
</div>

<hr class="margin-y-4" />
<div class="grid-row grid-gap grid-gap-2">
<div class="grid-col-12 tablet:grid-col-auto">
<%= image_tag(
asset_url('idv/laptop-icon.svg'),
alt: t('image_description.laptop'),
width: 88,
height: 88,
) %>
</div>
<div class="grid-col-12 tablet:grid-col-fill">
<h2 class="margin-y-105">
<%= t('doc_auth.headings.combined_upload_from_computer') %>
</h2>
<%= t('doc_auth.info.combined_upload_from_computer') %>&nbsp;
<%= simple_form_for(
:doc_auth,
url: url_for(type: :desktop),
method: 'PUT',
class: 'margin-bottom-4',
) do |f| %>
<%= f.submit t('forms.buttons.upload_photos'), outline: true %>
<% end %>
</div>
</div>

<%= render 'idv/doc_auth/cancel', step: 'upload' %>
Loading