LG-12159: Refactor selfie_success to selfie_status and make it return a symbol#9953
LG-12159: Refactor selfie_success to selfie_status and make it return a symbol#9953eileen-nava merged 21 commits intomainfrom
Conversation
…o use selfie_status instead of selfie_success
…ocAuth::Response usage.
| :doc_auth_success, :selfie_success, | ||
| :doc_auth_success, :selfie_status, | ||
| 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] |
There was a problem hiding this comment.
this struct is serialized in redis, which means it will get persisted across hosts in a deploy. We need to add some 50-50 logic if we're renaming this, such as allowing both properties to be read, etc etc, then eventually dropping the old name
There was a problem hiding this comment.
Thanks, I'll make a follow-up ticket to remove the old field and read from both fields in this PR. 👍🏻
| 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 = doc_auth_response.respond_to?(:selfie_status) ? |
There was a problem hiding this comment.
@eileen-nava - whenever reading the selfie_status from DocumentCaptureResult, a string will be retrieved, yes? is there a way to return a symbol when retrieving the selfie_status attribute from DocumentCaptureResult?
There was a problem hiding this comment.
@eileen-nava and @amirbey , one thought is that it can be achieved with a kind of subclass, or some kind of call backs
For example subclassing with prepend
require 'redacted_struct'
module TestPropSymbolizer
def test_prop
super.to_sym
end
end
Result = RedactedStruct.new(
:test_prop,
allowed_members: [:test_prop],
) do
prepend TestPropSymbolizer
end
t = Result.new(test_prop: 'abc')
puts t.test_prop
puts t.test_prop.class
There was a problem hiding this comment.
Though it's debatable to include complex behaviors with struct, which basically a data holder.
Like hash in ruby, many cases it get overused it if not abuses.
There was a problem hiding this comment.
a bit simpler ... i tried defining the method #selfie_status as follows in DocumentCaptureSessionResult which seemed to work ...
def selfie_status
self[:selfie_status].to_sym
end
obs document_capture_session_result[:selfie_status] will still return a string, but using the member to fetch is not stylistically the way we're accessing attributes in this struct 🤔
There was a problem hiding this comment.
@dawei-nava @amirbey I implemented the first suggestion, then refreshed this thread and saw the second one. Is there a strong preference between the two? I agree that both work.
There was a problem hiding this comment.
@eileen-nava , we may need to consider accessing using result[:selfie_status] or result['selfie_status'] method calls
For example(draft):
def [](key)
return super.to_sym if key.to_s == :test_prop
super
endThere was a problem hiding this comment.
@dawei-nava @amirbey I implemented the first suggestion, then refreshed this thread and saw the second one. Is there a strong preference between the two? I agree that both work.
I agree both work ... i prefer the latter approach for reasons stated here ... https://github.com/18F/identity-idp/pull/9953/files#r1465155665
app/models/concerns/symbolizer.rb
Outdated
| @@ -0,0 +1,5 @@ | |||
| module Symbolizer | |||
There was a problem hiding this comment.
Other names considered: StringToSymbolConverter or FieldSymbolizer.
There was a problem hiding this comment.
would this concern be of use outside of DocumentCaptureSessionResult? I ask since Symbolizer doesn't seem closely tied to DocumentCaptureSessonResult; and, if other methods are added for use by other classes, the methods intended for use by other classes would be available to DocumentCaptureSessionResult and we would then maybe have to check the class of the caller. It almost seems like adding the #selfie_status method directly in DocumentCaptureSessionResult is a very simple solution and avoids this potential complication.
| selfie_status: client_response.respond_to?(:selfie_status) ? | ||
| client_response.selfie_status : :not_processed, |
There was a problem hiding this comment.
to help maintain consistency, this could be a private method reused on line 461:
...
selfie_status: selfie_status(client_response),
....
def selfie_status(client_response)
return client_response.selfie_status if client_response.respond_to?(:selfie_status)
:not_processed
end
There was a problem hiding this comment.
@amirbey I like this idea and took it one further by extracting the helper method into ApplicationHelper, so that we can use the method in ApiImageUploadForm, DocumentCaptureSession and DocAuth::Response.
| 'dcs:result' | ||
| end | ||
|
|
||
| def selfie_status |
There was a problem hiding this comment.
similarly , result[:selfie_status] or result['selfie_status'] may have problem. But not critical.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
@eileen-nava , no just for completeness purpose.
|
@eileen-nava - LGTM ... do we want to add a quick test to ensure that document_capture_session_result.selfie_status returns a symbol? so this doesn't get mistakenly changed at a later time |
| def selfie_status_from_response(client_response) | ||
| return client_response.selfie_status if client_response.respond_to?(:selfie_status) | ||
|
|
||
| :not_processed | ||
| end |
There was a problem hiding this comment.
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 | ||
|
|
||
| def selfie_status_from_response(client_response) | ||
| return client_response.selfie_status if client_response.respond_to?(:selfie_status) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
ah yup that's right, I lost track of which objects were deserialized from redis and which were just in-memory
🎫 Ticket
LG-12159: Change selfie_success to return a symbol
🛠 Summary of changes
selfie_successtoselfie_statusin the TrueIDResponse, AcuantResponse, Mock::ResultResponse, and DocAuth::Responseselfie_statusto return:success,:fail,:not_processedinstead oftrue,false, andnilall_passed?method introduced by LG-12038 to use this new logic