Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f2f2f44
refactor true id response to represent selfie_status with symbols
eileen-nava Jan 18, 2024
fd30f4a
changelog: Internal, DocAuth, refactor how we represent selfie outcomes
eileen-nava Jan 18, 2024
2c437fd
refactor document_capture_session & document_capture_session_result t…
eileen-nava Jan 18, 2024
9ec4c57
include selfie_status method in both Mock::ResultResponse and DocAuth…
eileen-nava Jan 19, 2024
032a7a5
update image uploads controller spec to use selfie_status. Maintain D…
eileen-nava Jan 19, 2024
0411d6a
remove selfie_status from DocAuth::Response, keep it in Mock::ResultR…
eileen-nava Jan 19, 2024
43eff2c
Merge branch 'main' into em/12159-refactor-selfie-success
eileen-nava Jan 19, 2024
26d53f5
fix tests
eileen-nava Jan 19, 2024
ddd5443
fix more tests
eileen-nava Jan 19, 2024
7341f69
add selfie_passed? & continue selfie_success to selfie_status refactor
eileen-nava Jan 22, 2024
594ca5a
fix failing test
eileen-nava Jan 22, 2024
9f65bd0
Merge branch 'main' into em/12159-refactor-selfie-success
eileen-nava Jan 22, 2024
9c79595
revert doc capture session spec to pre-refactor expectations
eileen-nava Jan 22, 2024
d261e54
ensure that DocCaptureSessionResult will return a symbol for selfie_s…
eileen-nava Jan 23, 2024
b7e797a
handle 50/50 state in DocCaptureSessionResult
eileen-nava Jan 24, 2024
3dcfc7e
change approach to ensuring that selfie_status returns a symbol
eileen-nava Jan 24, 2024
1a6c532
extract selfie_status_from_response method into ApplicationHelper
eileen-nava Jan 24, 2024
d88acb2
test selfie_status return type
eileen-nava Jan 24, 2024
19da555
Merge branch 'main' into em/12159-refactor-selfie-success
eileen-nava Jan 24, 2024
d964cb9
Merge branch 'main' into em/12159-refactor-selfie-success
eileen-nava Jan 24, 2024
169c5c6
lint
eileen-nava Jan 24, 2024
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
5 changes: 3 additions & 2 deletions app/forms/idv/api_image_upload_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Idv
class ApiImageUploadForm
include ActiveModel::Model
include ActionView::Helpers::TranslationHelper
include ApplicationHelper

validates_presence_of :front
validates_presence_of :back
Expand Down Expand Up @@ -459,14 +460,14 @@ def store_failed_images(client_response, doc_pii_response)
front_image_fingerprint: failed_front_fingerprint,
back_image_fingerprint: failed_back_fingerprint,
doc_auth_success: client_response.doc_auth_success?,
selfie_success: client_response.selfie_success,
selfie_status: selfie_status_from_response(client_response),
)
elsif doc_pii_response && !doc_pii_response.success?
document_capture_session.store_failed_auth_data(
front_image_fingerprint: extra_attributes[:front_image_fingerprint],
back_image_fingerprint: extra_attributes[:back_image_fingerprint],
doc_auth_success: client_response.doc_auth_success?,
selfie_success: client_response.selfie_success,
selfie_status: selfie_status_from_response(client_response),
)
end
# retrieve updated data from session
Expand Down
6 changes: 6 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,10 @@ def cancel_link_text
def desktop_device?
!BrowserCache.parse(request.user_agent).mobile?
end

def selfie_status_from_response(client_response)
return client_response.selfie_status if client_response.respond_to?(:selfie_status)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is the respond_to? check how we are managing the 50-50 state?

If this code is running, it will be on a new box, so in that context, the selfie_status property will exist no matter what. I think we need to check the return values of the properties (because we really want to check the keys of the serialized JSON but that's hidden at this layer) so all we can see is which values are nil

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Is the respond_to? check how we are managing the 50-50 state?

No, it is not.

I referred to the existing documentation for renaming a field in a data structure in Redis, which states that in the first deploy, you add the new name and write to the new name everywhere the old name is written. I added selfie_success back to DocumentCaptureSessionResult in this commit and we will remove it when working on this ticket LG-12200

Please let me know if a different approach would be preferable.

Also, selfie_status_from_response takes a Response object like DocAuth::Response or Mock::ResultResponse. I thought the greatest risk around a 50/50 state error for this PR related to the change of a session field?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ah yup that's right, I lost track of which objects were deserialized from redis and which were just in-memory


:not_processed
end
Comment on lines +64 to +68
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why was this helper added here? this is a very generic helper, but this is a specific method? What if we made a mixin just for this?

end
8 changes: 4 additions & 4 deletions app/models/document_capture_session.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
class DocumentCaptureSession < ApplicationRecord
include NonNullUuid
include ApplicationHelper

belongs_to :user

Expand All @@ -18,8 +19,7 @@ def store_result_from_response(doc_auth_response)
session_result.attention_with_barcode = doc_auth_response.attention_with_barcode?
session_result.selfie_check_performed = doc_auth_response.selfie_check_performed?
session_result.doc_auth_success = doc_auth_response.doc_auth_success?
# nil(selfie not required) or true/false
session_result.selfie_success = doc_auth_response.selfie_success
session_result.selfie_status = selfie_status_from_response(doc_auth_response)
EncryptedRedisStructStorage.store(
session_result,
expires_in: IdentityConfig.store.doc_capture_request_valid_for_minutes.minutes.seconds.to_i,
Expand All @@ -29,14 +29,14 @@ def store_result_from_response(doc_auth_response)
end

def store_failed_auth_data(front_image_fingerprint:, back_image_fingerprint:, doc_auth_success:,
selfie_success:)
selfie_status:)
session_result = load_result || DocumentCaptureSessionResult.new(
id: generate_result_id,
)
session_result.success = false
session_result.captured_at = Time.zone.now
session_result.doc_auth_success = doc_auth_success
session_result.selfie_success = selfie_success
session_result.selfie_status = selfie_status
session_result.add_failed_front_image!(front_image_fingerprint) if front_image_fingerprint
session_result.add_failed_back_image!(back_image_fingerprint) if back_image_fingerprint
EncryptedRedisStructStorage.store(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def create_response_info
classification_info: classification_info,
address_line2_present: !pii_from_doc[:address2].blank?,
doc_auth_success: doc_auth_success?,
selfie_success: nil,
selfie_status: :not_processed,
}
end

Expand Down
20 changes: 12 additions & 8 deletions app/services/doc_auth/lexis_nexis/responses/true_id_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,18 @@ def doc_auth_success?
doc_auth_result_passed?
end

# @return [Boolean, nil]
# When selfie result is missing, return nil
# @return [:success, :fail, :not_processed]
# When selfie result is missing, return :not_processed
# Otherwise:
# return true if selfie check result == 'Pass'
# return false
def selfie_success
return selfie_result if selfie_result.nil?
selfie_result == 'Pass'
# return :success if selfie check result == 'Pass'
# return :fail
def selfie_status
return :not_processed if selfie_result.nil?
selfie_result == 'Pass' ? :success : :fail
end

def selfie_passed?
selfie_status == :success
end

private
Expand Down Expand Up @@ -248,7 +252,7 @@ def all_passed?
true_id_product.present? &&
product_status_passed? &&
doc_auth_result_passed? &&
(@liveness_checking_enabled ? selfie_success : true)
(@liveness_checking_enabled ? selfie_passed? : true)
end

def selfie_result
Expand Down
14 changes: 9 additions & 5 deletions app/services/doc_auth/mock/result_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ class ResultResponse < DocAuth::Response

def initialize(uploaded_file, selfie_check_performed, config)
@uploaded_file = uploaded_file.to_s
@config = config
@selfie_check_performed = selfie_check_performed
@config = config
super(
success: success?,
errors: errors,
Expand Down Expand Up @@ -136,9 +136,9 @@ def doc_auth_success?
doc_auth_result_from_uploaded_file == 'Passed' || errors.blank?
end

def selfie_success
return nil if portrait_match_results&.dig(:FaceMatchResult).nil?
portrait_match_results[:FaceMatchResult] == 'Pass'
def selfie_status
return :not_processed if portrait_match_results&.dig(:FaceMatchResult).nil?
portrait_match_results[:FaceMatchResult] == 'Pass' ? :success : :fail
end

private
Expand Down Expand Up @@ -183,7 +183,11 @@ def doc_auth_result_from_success
def all_doc_capture_values_passing?(doc_auth_result, id_type_supported)
doc_auth_result == 'Passed' &&
id_type_supported &&
(@selfie_check_performed ? selfie_success : true)
(@selfie_check_performed ? selfie_passed? : true)
end

def selfie_passed?
selfie_status == :success
end

def parse_uri
Expand Down
12 changes: 5 additions & 7 deletions app/services/doc_auth/response.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module DocAuth
class Response
attr_reader :errors, :exception, :extra, :pii_from_doc, :doc_type_supported, :selfie_live,
:selfie_quality_good
include ApplicationHelper

attr_reader :errors, :exception, :extra, :pii_from_doc, :doc_type_supported,
:selfie_live, :selfie_quality_good

ID_TYPE_SLUGS = {
'Identification Card' => 'state_id_card',
Expand Down Expand Up @@ -74,7 +76,7 @@ def to_h
selfie_live: selfie_live?,
selfie_quality_good: selfie_quality_good?,
doc_auth_success: doc_auth_success?,
selfie_success: selfie_success,
selfie_status: selfie_status_from_response(self),
}.merge(extra)
end

Expand All @@ -97,10 +99,6 @@ def selfie_check_performed?
@selfie_check_performed
end

def selfie_success
# to be implemented by concrete subclass
end

def doc_auth_success?
# to be implemented by concrete subclass
false
Expand Down
8 changes: 6 additions & 2 deletions app/services/document_capture_session_result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,20 @@
:failed_back_image_fingerprints,
:captured_at,
:selfie_check_performed,
:doc_auth_success, :selfie_success,
:doc_auth_success, :selfie_status, :selfie_success,
keyword_init: true,
allowed_members: [:id, :success, :attention_with_barcode, :failed_front_image_fingerprints,
:failed_back_image_fingerprints, :captured_at, :selfie_check_performed,
:doc_auth_success, :selfie_success]
:doc_auth_success, :selfie_status, :selfie_success]
) do
def self.redis_key_prefix
'dcs:result'
end

def selfie_status
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

similarly , result[:selfie_status] or result['selfie_status'] may have problem. But not critical.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Are there any scenarios in which we read session_result[:selfie_status] or session_result['selfie_status']? I thought we always used session_result.selfie_status.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@eileen-nava , no just for completeness purpose.

self[:selfie_status].to_sym
end

alias_method :success?, :success
alias_method :attention_with_barcode?, :attention_with_barcode
alias_method :pii_from_doc, :pii
Expand Down
14 changes: 7 additions & 7 deletions spec/controllers/idv/image_uploads_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@
back_image_fingerprint: an_instance_of(String),
doc_type_supported: boolean,
doc_auth_success: boolean,
selfie_success: nil,
selfie_status: :not_processed,
liveness_checking_required: boolean,
selfie_live: boolean,
selfie_quality_good: boolean,
Expand Down Expand Up @@ -621,7 +621,7 @@
back_image_fingerprint: an_instance_of(String),
doc_type_supported: boolean,
doc_auth_success: boolean,
selfie_success: nil,
selfie_status: :not_processed,
liveness_checking_required: boolean,
selfie_live: true,
selfie_quality_good: true,
Expand Down Expand Up @@ -717,7 +717,7 @@
back_image_fingerprint: an_instance_of(String),
doc_type_supported: boolean,
doc_auth_success: boolean,
selfie_success: nil,
selfie_status: :not_processed,
liveness_checking_required: boolean,
selfie_live: true,
selfie_quality_good: true,
Expand Down Expand Up @@ -813,7 +813,7 @@
back_image_fingerprint: an_instance_of(String),
doc_type_supported: boolean,
doc_auth_success: boolean,
selfie_success: nil,
selfie_status: :not_processed,
liveness_checking_required: boolean,
selfie_live: true,
selfie_quality_good: true,
Expand Down Expand Up @@ -906,7 +906,7 @@
back_image_fingerprint: an_instance_of(String),
doc_type_supported: boolean,
doc_auth_success: boolean,
selfie_success: nil,
selfie_status: :not_processed,
liveness_checking_required: boolean,
selfie_live: true,
selfie_quality_good: true,
Expand Down Expand Up @@ -1024,8 +1024,8 @@
back_image_fingerprint: an_instance_of(String),
doc_type_supported: boolean,
doc_auth_success: boolean,
selfie_status: :not_processed,
liveness_checking_required: boolean,
selfie_success: nil,
selfie_live: true,
selfie_quality_good: true,
)
Expand Down Expand Up @@ -1100,7 +1100,7 @@
back_image_fingerprint: an_instance_of(String),
doc_type_supported: boolean,
doc_auth_success: boolean,
selfie_success: nil,
selfie_status: :not_processed,
liveness_checking_required: boolean,
selfie_live: boolean,
selfie_quality_good: boolean,
Expand Down
6 changes: 1 addition & 5 deletions spec/forms/idv/api_image_upload_form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@
selfie_live: boolean,
selfie_quality_good: boolean,
doc_auth_success: boolean,
selfie_success: anything,
selfie_status: anything,
)
end

Expand Down Expand Up @@ -491,7 +491,6 @@
allow(client_response).to receive(:network_error?).and_return(false)
allow(client_response).to receive(:errors).and_return(errors)
allow(client_response).to receive(:doc_auth_success?).and_return(false)
allow(client_response).to receive(:selfie_success).and_return(nil)
form.send(:validate_form)
capture_result = form.send(:store_failed_images, client_response, doc_pii_response)
expect(capture_result[:front]).not_to be_empty
Expand All @@ -505,7 +504,6 @@
allow(client_response).to receive(:network_error?).and_return(false)
allow(client_response).to receive(:errors).and_return(errors)
allow(client_response).to receive(:doc_auth_success?).and_return(false)
allow(client_response).to receive(:selfie_success).and_return(nil)
form.send(:validate_form)
capture_result = form.send(:store_failed_images, client_response, doc_pii_response)
expect(capture_result[:front]).not_to be_empty
Expand All @@ -519,7 +517,6 @@
allow(client_response).to receive(:network_error?).and_return(false)
allow(client_response).to receive(:errors).and_return(errors)
allow(client_response).to receive(:doc_auth_success?).and_return(false)
allow(client_response).to receive(:selfie_success).and_return(nil)
form.send(:validate_form)
capture_result = form.send(:store_failed_images, client_response, doc_pii_response)
expect(capture_result[:front]).not_to be_empty
Expand Down Expand Up @@ -548,7 +545,6 @@
allow(client_response).to receive(:network_error?).and_return(true)
allow(client_response).to receive(:errors).and_return(errors)
allow(client_response).to receive(:doc_auth_success?).and_return(false)
allow(client_response).to receive(:selfie_success).and_return(nil)
allow(doc_pii_response).to receive(:success?).and_return(false)
form.send(:validate_form)
capture_result = form.send(:store_failed_images, client_response, doc_pii_response)
Expand Down
23 changes: 23 additions & 0 deletions spec/helpers/application_helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,27 @@
end
end
end

describe '#selfie_status_from_response' do
context 'the response does not have selfie_status method defined on it' do
let(:success) { true }
let(:errors) { {} }
let(:exception) { nil }
let(:pii_from_doc) { {} }
let(:attention_with_barcode) { false }
let(:response) do
DocAuth::Response.new(
success: success,
errors: errors,
exception: exception,
pii_from_doc: pii_from_doc,
attention_with_barcode: attention_with_barcode,
)
end

it 'returns :not_processed' do
expect(selfie_status_from_response(response)).to eq(:not_processed)
end
end
end
end
12 changes: 6 additions & 6 deletions spec/models/document_capture_session_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
front_image_fingerprint: 'fingerprint1',
back_image_fingerprint: nil,
doc_auth_success: false,
selfie_success: nil,
selfie_status: :not_processed,
)
result_id = record.result_id
key = EncryptedRedisStructStorage.key(result_id, type: DocumentCaptureSessionResult)
Expand All @@ -107,7 +107,7 @@
expect(result.failed_front_image?(nil)).to eq(false)
expect(result.failed_back_image?(nil)).to eq(false)
expect(result.doc_auth_success).to eq(false)
expect(result.selfie_success).to be_nil
expect(result.selfie_status).to eq(:not_processed)
end

it 'saves failed image finterprints' do
Expand All @@ -117,29 +117,29 @@
front_image_fingerprint: 'fingerprint1',
back_image_fingerprint: nil,
doc_auth_success: false,
selfie_success: nil,
selfie_status: :not_processed,
)
old_result = record.load_result

record.store_failed_auth_data(
front_image_fingerprint: 'fingerprint2',
back_image_fingerprint: 'fingerprint3',
doc_auth_success: false,
selfie_success: nil,
selfie_status: :not_processed,
)
new_result = record.load_result

expect(old_result.failed_front_image?('fingerprint1')).to eq(true)
expect(old_result.failed_front_image?('fingerprint2')).to eq(false)
expect(old_result.failed_back_image?('fingerprint3')).to eq(false)
expect(old_result.doc_auth_success).to eq(false)
expect(old_result.selfie_success).to be_nil
expect(old_result.selfie_status).to eq(:not_processed)

expect(new_result.failed_front_image?('fingerprint1')).to eq(true)
expect(new_result.failed_front_image?('fingerprint2')).to eq(true)
expect(new_result.failed_back_image?('fingerprint3')).to eq(true)
expect(new_result.doc_auth_success).to eq(false)
expect(new_result.selfie_success).to be_nil
expect(new_result.selfie_status).to eq(:not_processed)
end
end
end
Loading