From e44b47fb274530dae2d155473a24eeaad3b7bc25 Mon Sep 17 00:00:00 2001 From: A Shukla Date: Mon, 9 Dec 2024 10:07:59 -0600 Subject: [PATCH] Lg-14279 document request analytics event (#11581) * started work on ticket defined methods * changelog: Upcoming Features, socure, socure analytics * changelog: Upcoming Features, socure, socure analytics logging * Resolving PR comments * Resolving PR comments * Resolving PR comments * resolving some comments still needs works * Fixing lint, resolving PR comments, might fail hybrid test * Fixing hybrid test * Resolving PR comments for hybrid flow * Fixing Rebase --- .../concerns/idv/document_capture_concern.rb | 18 +++++ .../socure/document_capture_controller.rb | 13 ++-- .../idv/socure/document_capture_controller.rb | 14 ++-- app/services/analytics_events.rb | 70 +++++++++++++++++++ .../socure/requests/document_request.rb | 14 ++-- app/services/idv/analytics_events_enhancer.rb | 3 +- .../document_capture_controller_spec.rb | 6 ++ .../document_capture_controller_spec.rb | 6 ++ .../doc_auth/socure_document_capture_spec.rb | 32 ++++++++- .../hybrid_socure_mobile_spec.rb | 29 +++++++- 10 files changed, 178 insertions(+), 27 deletions(-) diff --git a/app/controllers/concerns/idv/document_capture_concern.rb b/app/controllers/concerns/idv/document_capture_concern.rb index 32835a320a8..746657959a4 100644 --- a/app/controllers/concerns/idv/document_capture_concern.rb +++ b/app/controllers/concerns/idv/document_capture_concern.rb @@ -95,6 +95,24 @@ def fetch_test_verification_data ) end + def track_document_request_event(document_request:, document_response:, timer:) + document_request_body = JSON.parse(document_request.body, symbolize_names: true)[:config] + response_hash = document_response.to_h + log_extras = { + reference_id: response_hash[:referenceId], + vendor: 'Socure', + vendor_request_time_in_ms: timer.results['vendor_request'], + success: @url.present?, + document_type: document_request_body[:documentType], + docv_transaction_token: response_hash.dig(:data, :docvTransactionToken), + } + analytics_hash = log_extras.merge(analytics_arguments). + merge(document_request_body).except( + :documentType, # requested document type + ).merge(response_body: document_response.to_h) + analytics.idv_socure_document_request_submitted(**analytics_hash) + end + private def track_document_issuing_state(user, state) diff --git a/app/controllers/idv/hybrid_mobile/socure/document_capture_controller.rb b/app/controllers/idv/hybrid_mobile/socure/document_capture_controller.rb index b3d36f455ad..5fa8e17c763 100644 --- a/app/controllers/idv/hybrid_mobile/socure/document_capture_controller.rb +++ b/app/controllers/idv/hybrid_mobile/socure/document_capture_controller.rb @@ -25,12 +25,16 @@ def show redirect_url: idv_hybrid_mobile_socure_document_capture_update_url, language: I18n.locale, ) - document_response = document_request.fetch + timer = JobHelpers::Timer.new + document_response = timer.time('vendor_request') do + document_request.fetch + end - @document_request = document_request - @document_response = document_response @url = document_response.dig(:data, :url) + track_document_request_event(document_request:, document_response:, timer:) + + # placeholder until we get an error page for url not being present if @url.nil? redirect_to idv_hybrid_mobile_socure_document_capture_errors_url return @@ -48,9 +52,6 @@ def show :url, ) document_capture_session.save - # useful for analytics - @msg = document_response[:msg] - @reference_id = document_response[:referenceId] end def update diff --git a/app/controllers/idv/socure/document_capture_controller.rb b/app/controllers/idv/socure/document_capture_controller.rb index 7636e9a8275..8beee4f8a92 100644 --- a/app/controllers/idv/socure/document_capture_controller.rb +++ b/app/controllers/idv/socure/document_capture_controller.rb @@ -35,13 +35,15 @@ def show redirect_url: idv_socure_document_capture_update_url, language: I18n.locale, ) + timer = JobHelpers::Timer.new + document_response = timer.time('vendor_request') do + document_request.fetch + end - document_response = document_request.fetch - - @document_request = document_request - @document_response = document_response @url = document_response.dig(:data, :url) + track_document_request_event(document_request:, document_response:, timer:) + # placeholder until we get an error page for url not being present if @url.nil? redirect_to idv_socure_document_capture_errors_url @@ -61,10 +63,6 @@ def show :url, ) document_capture_session.save - - # useful for analytics - @msg = document_response[:msg] - @reference_id = document_response[:referenceId] end def update diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb index 82bb250b27d..8e867239b69 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -4729,6 +4729,76 @@ def idv_session_error_visited( ) end + # @param [Boolean] success Whether form validation was successful + # @param [Hash] errors Errors resulting from form validation + # @param [String] exception any exceptions thrown during request + # @param [String] docv_transaction_token socure transaction token + # @param [String] reference_id socure interal id for transaction + # @param [String] language lagnuage presented to user + # @param [String] step current step of idv to user + # @param [String] analytics_id id of analytics + # @param [Boolean] redo_document_capture if user is redoing doc capture + # @param [Boolean] skip_hybrid_handoff if user is skipping handoff + # @param [Boolean] selfie_check_required is selfie check required + # @param [Boolean] opted_in_to_in_person_proofing user opts in to IPP + # @param [Hash] redirect hash for redirect (url and method) + # @param [Hash] response_body hash received from socure + # @param ["hybrid","standard"] flow_path Document capture user flow + # @param [Float] vendor_request_time_in_ms Time it took to upload images & get a response. + # @param [Boolean] liveness_checking_required Whether or not the selfie is required + # @param [Boolean] liveness_enabled Whether or not the selfie result is included in response + # @param [String] vendor which 2rd party we are using for doc auth + # @param [Hash] document_type type of socument submitted (Drivers Licenese, etc.) + # The request for socure verification was sent + def idv_socure_document_request_submitted( + success:, + redirect:, + liveness_checking_required:, + vendor_request_time_in_ms:, + vendor:, + language:, + step:, + analytics_id:, + response_body:, + redo_document_capture: nil, + skip_hybrid_handoff: nil, + selfie_check_required: nil, + opted_in_to_in_person_proofing: nil, + errors: nil, + exception: nil, + reference_id: nil, + liveness_enabled: nil, + document_type: nil, + docv_transaction_token: nil, + flow_path: nil, + **extra + ) + track_event( + :idv_socure_document_request_submitted, + success:, + redirect:, + liveness_checking_required:, + vendor_request_time_in_ms:, + vendor:, + language:, + step:, + analytics_id:, + redo_document_capture:, + skip_hybrid_handoff:, + selfie_check_required:, + opted_in_to_in_person_proofing:, + errors:, + exception:, + reference_id:, + response_body:, + liveness_enabled:, + document_type:, + docv_transaction_token:, + flow_path:, + **extra, + ) + end + # Socure Reason Codes were downloaded and synced against persisted codes in the database # @param [Boolean] success Result from Socure KYC API call # @param [Hash] errors Result from resolution proofing diff --git a/app/services/doc_auth/socure/requests/document_request.rb b/app/services/doc_auth/socure/requests/document_request.rb index f214f8867c6..3fa0a99b10d 100644 --- a/app/services/doc_auth/socure/requests/document_request.rb +++ b/app/services/doc_auth/socure/requests/document_request.rb @@ -16,13 +16,6 @@ def initialize( @language = language end - private - - def lang(language) - return 'zh-cn' if language == :zh - language - end - def body redirect = { method: 'GET', @@ -40,6 +33,13 @@ def body }.to_json end + private + + def lang(language) + return 'zh-cn' if language == :zh + language + end + def handle_http_response(http_response) JSON.parse(http_response.body, symbolize_names: true) end diff --git a/app/services/idv/analytics_events_enhancer.rb b/app/services/idv/analytics_events_enhancer.rb index 810e933438d..2b713d57d8d 100644 --- a/app/services/idv/analytics_events_enhancer.rb +++ b/app/services/idv/analytics_events_enhancer.rb @@ -31,7 +31,6 @@ module AnalyticsEventsEnhancer idv_doc_auth_ssn_visited idv_doc_auth_submitted_image_upload_form idv_doc_auth_submitted_image_upload_vendor - idv_socure_verification_data_requested idv_doc_auth_submitted_pii_validation idv_doc_auth_verify_proofing_results idv_doc_auth_verify_submitted @@ -97,6 +96,8 @@ module AnalyticsEventsEnhancer idv_sdk_selfie_image_capture_opened idv_selfie_image_added idv_session_error_visited + idv_socure_document_request_submitted + idv_socure_verification_data_requested idv_threatmetrix_response_body idv_usps_auth_token_refresh_job_completed idv_usps_auth_token_refresh_job_network_error diff --git a/spec/controllers/idv/hybrid_mobile/socure/document_capture_controller_spec.rb b/spec/controllers/idv/hybrid_mobile/socure/document_capture_controller_spec.rb index faab1251e0d..c9cfce2b570 100644 --- a/spec/controllers/idv/hybrid_mobile/socure/document_capture_controller_spec.rb +++ b/spec/controllers/idv/hybrid_mobile/socure/document_capture_controller_spec.rb @@ -143,6 +143,12 @@ ) end + it 'logs correct info' do + expect(@analytics).to have_logged_event( + :idv_socure_document_request_submitted, + ) + end + it 'sets DocumentCaptureSession socure_docv_capture_app_url value' do document_capture_session.reload expect(document_capture_session.socure_docv_capture_app_url).to eq(socure_capture_app_url) diff --git a/spec/controllers/idv/socure/document_capture_controller_spec.rb b/spec/controllers/idv/socure/document_capture_controller_spec.rb index 132d570b24f..7d494be9516 100644 --- a/spec/controllers/idv/socure/document_capture_controller_spec.rb +++ b/spec/controllers/idv/socure/document_capture_controller_spec.rb @@ -155,6 +155,12 @@ ) end + it 'logs correct info' do + expect(@analytics).to have_logged_event( + :idv_socure_document_request_submitted, + ) + end + it 'sets DocumentCaptureSession socure_docv_capture_app_url value' do document_capture_session.reload expect(document_capture_session.socure_docv_capture_app_url).to eq(socure_capture_app_url) diff --git a/spec/features/idv/doc_auth/socure_document_capture_spec.rb b/spec/features/idv/doc_auth/socure_document_capture_spec.rb index 0c3a39c5a03..7b49d706609 100644 --- a/spec/features/idv/doc_auth/socure_document_capture_spec.rb +++ b/spec/features/idv/doc_auth/socure_document_capture_spec.rb @@ -29,7 +29,7 @@ and_return(socure_docv_verification_data_test_mode) end - context 'happy path' do + context 'happy path', allow_browser_log: true do before do @pass_stub = stub_docv_verification_data_pass(docv_transaction_token: @docv_transaction_token) end @@ -63,6 +63,9 @@ 'Rate Limit Reached', limiter_type: :idv_doc_auth, ) + expect(fake_analytics).to have_logged_event( + :idv_socure_document_request_submitted, + ) end context 'successfully processes image on last attempt' do @@ -88,7 +91,7 @@ end end - context 'network connection errors' do + context 'network connection errors', allow_browser_log: true do context 'getting the capture path' do before do allow_any_instance_of(Faraday::Connection).to receive(:post). @@ -103,6 +106,9 @@ expect(page).to have_content(t('doc_auth.headers.general.network_error')) expect(page).to have_content(t('doc_auth.errors.general.new_network_error')) + expect(fake_analytics).to have_logged_event( + :idv_socure_document_request_submitted, + ) end end @@ -113,6 +119,22 @@ end end + context 'invalid request', allow_browser_log: true do + context 'getting the capture path w wrong api key' do + before do + DocAuth::Mock::DocAuthMockClient.reset! + stub_docv_document_request(status: 401) + end + + it 'correctly logs event', js: true do + visit idv_socure_document_capture_path + expect(fake_analytics).to have_logged_event( + :idv_socure_document_request_submitted, + ) + end + end + end + it 'does not track state if state tracking is disabled' do allow(IdentityConfig.store).to receive(:state_tracking_enabled).and_return(false) socure_docv_upload_documents( @@ -203,6 +225,9 @@ expect(page).to have_current_path(idv_ssn_url) expect(DocAuthLog.find_by(user_id: @user.id).state).to eq('NY') + expect(fake_analytics).to have_logged_event( + :idv_socure_document_request_submitted, + ) fill_out_ssn_form_ok click_idv_continue @@ -234,6 +259,9 @@ it 'shows the correct error page' do expect(page).to have_content(t(expected_header_key)) + expect(fake_analytics).to have_logged_event( + :idv_socure_document_request_submitted, + ) end end diff --git a/spec/features/idv/hybrid_mobile/hybrid_socure_mobile_spec.rb b/spec/features/idv/hybrid_mobile/hybrid_socure_mobile_spec.rb index 6bb6e0f8445..4560fa0d52e 100644 --- a/spec/features/idv/hybrid_mobile/hybrid_socure_mobile_spec.rb +++ b/spec/features/idv/hybrid_mobile/hybrid_socure_mobile_spec.rb @@ -10,6 +10,7 @@ let(:fake_socure_document_capture_app_url) { 'https://verify.fake-socure.test/something' } let(:fake_socure_docv_document_request_endpoint) { 'https://fake-socure.test/document-request' } let(:socure_docv_verification_data_test_mode) { false } + let(:fake_analytics) { FakeAnalytics.new } before do allow(FeatureManagement).to receive(:doc_capture_polling_enabled?).and_return(true) @@ -27,9 +28,10 @@ allow(IdentityConfig.store).to receive(:socure_docv_verification_data_test_mode). and_return(socure_docv_verification_data_test_mode) @docv_transaction_token = stub_docv_document_request + stub_analytics end - context 'happy path' do + context 'happy path', allow_browser_log: true do before do @pass_stub = stub_docv_verification_data_pass(docv_transaction_token: @docv_transaction_token) end @@ -81,7 +83,6 @@ visit idv_hybrid_mobile_socure_document_capture_url expect(page).to have_current_path(idv_hybrid_mobile_socure_document_capture_url) - click_idv_continue expect(page).to have_current_path(fake_socure_document_capture_app_url) socure_docv_upload_documents(docv_transaction_token: @docv_transaction_token) @@ -101,7 +102,7 @@ perform_in_browser(:desktop) do expect(page).to_not have_content(t('doc_auth.headings.text_message'), wait: 10) expect(page).to have_current_path(idv_ssn_path) - + expect(@analytics).to have_logged_event(:idv_socure_document_request_submitted) fill_out_ssn_form_ok click_idv_continue @@ -441,6 +442,7 @@ expect(page).to have_text(t('doc_auth.headers.general.network_error')) expect(page).to have_text(t('doc_auth.errors.general.new_network_error')) + expect(@analytics).to have_logged_event(:idv_socure_document_request_submitted) end perform_in_browser(:desktop) do @@ -448,4 +450,25 @@ end end end + + context 'invalid request', allow_browser_log: true do + context 'getting the capture path w wrong api key' do + before do + user = user_with_2fa + visit_idp_from_oidc_sp_with_ial2 + sign_in_and_2fa_user(user) + complete_doc_auth_steps_before_document_capture_step + click_idv_continue + DocAuth::Mock::DocAuthMockClient.reset! + stub_docv_document_request(status: 401) + end + + it 'correctly logs event', js: true do + visit idv_socure_document_capture_path + expect(@analytics).to have_logged_event( + :idv_socure_document_request_submitted, + ) + end + end + end end