Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 1 addition & 5 deletions app/forms/gpo_verify_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def submit
UspsInPersonProofing::EnrollmentHelper.schedule_in_person_enrollment(user, pii)
pending_profile&.deactivate(:in_person_verification_pending)
elsif fraud_review_checker.fraud_check_failed? && threatmetrix_enabled?
bump_fraud_review_pending_timestamps
pending_profile&.deactivate_for_fraud_review
elsif fraud_review_checker.fraud_check_failed?
pending_profile&.activate_after_fraud_review_unnecessary
else
Expand Down Expand Up @@ -57,10 +57,6 @@ def gpo_confirmation_code
pending_profile.gpo_confirmation_codes.first_with_otp(otp)
end

def bump_fraud_review_pending_timestamps
pending_profile&.bump_fraud_review_pending_timestamps
end

def validate_otp_not_expired
return unless gpo_confirmation_code.present? && gpo_confirmation_code.expired?

Expand Down
23 changes: 21 additions & 2 deletions app/models/profile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,29 @@ def deactivate_for_gpo_verification
update!(active: false, gpo_verification_pending_at: Time.zone.now)
end

def deactivate_for_fraud_review(fraud_pending_reason:)
def deactivate_for_fraud_review
##
# This is temporary. We are working on changing the way fraud review status
# is computed. The goal is that a profile is only in fraud review when
# `fraud_review_pending_at` is set. We will set this immediatly if a user
# verifies with phone and when a user enters their GPO code.
#
# We currently look at `fraud_pending_reason` to determine if a user is in
# fraud review. This allows us to change the writes on
# `fraud_review_pending_at` without side-effects.
#
# Once the writes on `fraud_review_pending_at` are correct we can move the
# reads to determine a user is fraud review pending to that column. At that
# point we can set `fraud_pending_reason` when we create a profile and
# deactivate the profile at the appropriate time for the given context
# (i.e. immediatly for phone and after GPO code entry for GPO).
#
if fraud_pending_reason.nil?
raise 'Attempting to deactivate a profile with a nil fraud pending reason'
end

update!(
active: false,
fraud_pending_reason: fraud_pending_reason,
fraud_review_pending_at: Time.zone.now,
fraud_rejection_at: nil,
)
Expand Down
5 changes: 3 additions & 2 deletions app/services/idv/profile_maker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ def save_profile(
profile.initiating_service_provider = initiating_service_provider
profile.encrypt_pii(pii_attributes, user_password)
profile.proofing_components = current_proofing_components
profile.fraud_pending_reason = fraud_pending_reason
profile.save!
profile.deactivate_for_gpo_verification if gpo_verification_needed
if fraud_pending_reason.present?
profile.deactivate_for_fraud_review(fraud_pending_reason: fraud_pending_reason)
if fraud_pending_reason.present? && !gpo_verification_needed

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.

I did some tracing through the code and couldn't find where deactivate_for_fraud_review will be called once the user enters their gpo code.

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.

That occurs in GpoVerifyForm#submit.

profile.deactivate_for_fraud_review
end
profile
end
Expand Down
70 changes: 70 additions & 0 deletions lib/tasks/backfill_fraud_review_pending_at.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
namespace :profiles do
desc 'If a profile is in GPO and fraud pending state, move it out of fraud pending state'

##
# Usage:
#
# Print pending updates
# bundle exec rake profiles:backfill_fraud_review_pending_at
#
# Commit updates
# bundle exec rake profiles:backfill_fraud_review_pending_at UPDATE_PROFILES=true
#
task backfill_fraud_review_pending_at: :environment do |_task, _args|
ActiveRecord::Base.connection.execute('SET statement_timeout = 60000')

update_profiles = ENV['UPDATE_PROFILES'] == 'true'

profiles = Profile.where(
'fraud_review_pending_at IS NOT NULL OR fraud_rejection_at IS NOT NULL',
).where.not(
gpo_verification_pending_at: nil,
)

profiles.each do |profile|
warn "#{profile.id},#{profile.fraud_review_pending_at},#{profile.fraud_rejection_at}"
profile.update!(fraud_review_pending_at: nil) if update_profiles

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.

Should this confirm that fraud_pending_reason is set? And, should it set fraud_rejection_at to 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.

Yeah, I'll add a warn if fraud_pending_reason is not set and we definitely want to nil fraud_rejection_at.

end
end

##
# Usage:
#
# Rollback the above:
#
# export BACKFILL_OUTPUT='<backfill_output>'
# bundle exec rake profiles:rollback_backfill_fraud_review_pending_at
#
task rollback_backfill_fraud_review_pending_at: :environment do |_task, _args|
ActiveRecord::Base.connection.execute('SET statement_timeout = 60000')

profile_data = ENV['BACKFILL_OUTPUT'].split("\n").map do |profile_row|
profile_row.split(',')
end

warn "Updating #{profile_data.count} records"
profile_data.each do |profile_datum|
profile_id, fraud_review_pending_at, fraud_rejection_at = profile_datum
Profile.where(id: profile_id).update!(
fraud_review_pending_at: fraud_review_pending_at,
fraud_rejection_at: fraud_rejection_at,
)
end
end

##
# Usage:
# bundle exec rake profiles:validate_backfill_fraud_review_pending_at
#
task validate_backfill_fraud_review_pending_at: :environment do |_task, _args|
ActiveRecord::Base.connection.execute('SET statement_timeout = 60000')

profiles = Profile.where(
'fraud_review_pending_at IS NOT NULL OR fraud_rejection_at IS NOT NULL',
).where.not(
gpo_verification_pending_at: nil,
)

warn "fraud_pending_reason backfill left #{profiles.count} rows"
end
end
6 changes: 4 additions & 2 deletions spec/controllers/idv/personal_key_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ def index
context 'profile is pending from a different session' do
context 'profile is pending due to fraud review' do
before do
profile.deactivate_for_fraud_review(fraud_pending_reason: 'threatmetrix_review')
profile.fraud_pending_reason = 'threatmetrix_review'
profile.deactivate_for_fraud_review
subject.idv_session.profile_id = nil
end

Expand Down Expand Up @@ -290,7 +291,8 @@ def index

context 'profile is in fraud_review' do
before do
profile.deactivate_for_fraud_review(fraud_pending_reason: 'threatmetrix_review')
profile.fraud_pending_reason = 'threatmetrix_review'
profile.deactivate_for_fraud_review
end

it 'redirects to idv please call path' do
Expand Down
3 changes: 2 additions & 1 deletion spec/models/profile_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,8 @@
expect(profile.initiating_service_provider).to be_nil
expect(profile.verified_at).to be_nil

profile.deactivate_for_fraud_review(fraud_pending_reason: 'threatmetrix_review')
profile.fraud_pending_reason = 'threatmetrix_review'
profile.deactivate_for_fraud_review

expect(profile.activated_at).to be_nil
expect(profile.active).to eq(false)
Expand Down