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
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
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
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
75 changes: 75 additions & 0 deletions lib/tasks/backfill_fraud_review_pending_at.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
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|
if profile.fraud_pending_reason.blank?
warn "Profile ##{profile.id} does not have a fraud pending reason!"
break
end

warn "#{profile.id},#{profile.fraud_review_pending_at},#{profile.fraud_rejection_at}"
profile.update!(fraud_review_pending_at: nil, fraud_rejection_at: nil) if update_profiles
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