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
30 changes: 30 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,32 @@ def gpo_verification_pending_profile?
gpo_verification_pending_profile.present?
end

def suspended?
suspended_at.to_s > reinstated_at.to_s
Comment thread
olatifflexion marked this conversation as resolved.
end

def reinstated?
reinstated_at.to_s > suspended_at.to_s
end
Comment thread
olatifflexion marked this conversation as resolved.

def suspend!
if suspended?
analytics.user_suspended(success: false, error_message: :user_already_suspended)
raise 'user_already_suspended'
end
update!(suspended_at: Time.zone.now)
analytics.user_suspended(success: true)
end

def reinstate!
if !suspended?
analytics.user_reinstated(success: false, error_message: :user_is_not_suspended)
raise 'user_is_not_suspended'
end
update!(reinstated_at: Time.zone.now)
analytics.user_reinstated(success: true)
end

def pending_profile
return @pending_profile if defined?(@pending_profile)

Expand Down Expand Up @@ -403,6 +429,10 @@ def send_confirmation_instructions

add_method_tracer :send_devise_notification, "Custom/#{name}/send_devise_notification"

def analytics
@analytics ||= Analytics.new(user: self, request: nil, session: {}, sp: nil)
end

def send_email_to_all_addresses(user_mailer_template)
confirmed_email_addresses.each do |email_address|
UserMailer.with(
Expand Down
36 changes: 36 additions & 0 deletions app/services/analytics_events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3876,6 +3876,42 @@ def user_registration_user_fully_registered(
)
end

# Tracks when user reinstated
# @param [Boolean] success
# @param [String] error_message
def user_reinstated(
success:,
error_message: nil,
**extra
)
track_event(
'User Suspension: Reinstated',
{
success: success,
error_message: error_message,
**extra,
}.compact,
)
end

# Tracks when user suspended
# @param [Boolean] success
# @param [String] error_message
def user_suspended(
success:,
error_message: nil,
**extra
)
track_event(
'User Suspension: Suspended',
{
success: success,
error_message: error_message,
**extra,
}.compact,
)
end

# Tracks when USPS in-person proofing enrollment is created
# @param [String] enrollment_code
# @param [Integer] enrollment_id
Expand Down
10 changes: 10 additions & 0 deletions spec/factories/users.rb
Original file line number Diff line number Diff line change
Expand Up @@ -259,5 +259,15 @@
create(:profile, :password_reset, :with_pii, user: user)
end
end

trait :suspended do
suspended_at { Time.zone.now }
reinstated_at { nil }
end

trait :reinstated do
suspended_at { Time.zone.now }
reinstated_at { Time.zone.now + 1.hour }
end
Comment thread
olatifflexion marked this conversation as resolved.
end
end
126 changes: 126 additions & 0 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,132 @@
end
end

describe 'user suspension' do
let(:user) { User.new }
let(:cannot_reinstate_message) { :user_is_not_suspended }
let(:cannot_suspend_message) { :user_already_suspended }

describe '#suspended?' do
context 'when suspended_at is after reinstated_at' do
before do
user.suspended_at = Time.zone.now
user.reinstated_at = Time.zone.now - 1.day
end
it 'returns true' do
expect(user.suspended?).to be true
end
end

context 'when suspended_at is before reinstated_at' do
before do
user.suspended_at = Time.zone.now - 1.day
user.reinstated_at = Time.zone.now
end

it 'returns false' do
expect(user.suspended?).to be false
end
end

context 'when suspended_at is nil' do
before do
user.suspended_at = nil
user.reinstated_at = nil
end

it 'returns false' do
expect(user.suspended?).to be false
end
end
end

describe '#reinstated?' do
context 'when reinstated_at is after suspended_at' do
before do
user.suspended_at = Time.zone.now - 1.day
user.reinstated_at = Time.zone.now
end

it 'returns true' do
expect(user.reinstated?).to be true
end
end

context 'when reinstated_at is before suspended_at' do
before do
user.suspended_at = Time.zone.now
user.reinstated_at = Time.zone.now - 1.day
end

it 'returns false' do
expect(user.reinstated?).to be false
end
end

context 'when reinstated_at is nil' do
before do
user.suspended_at = nil
user.reinstated_at = nil
end
it 'returns false' do
expect(user.reinstated?).to be false
end
end
end

describe '#suspend!' do
it 'updates the suspended_at attribute with the current time' do
expect do
user.suspend!
end.to change(user, :suspended_at).from(nil).to(be_within(1.second).of(Time.zone.now))
end

it 'tracks the user suspension' do
expect(user.analytics).to receive(:user_suspended).with(success: true)
user.suspend!
end

it 'raises an error if the user is already suspended' do
user.suspended_at = Time.zone.now
expect(user.analytics).to receive(:user_suspended).with(
success: false,
error_message: cannot_suspend_message,
)
expect do
user.suspend!
end.to raise_error(cannot_suspend_message.to_s)
end
end

describe '#reinstate!' do
before do
user.suspended_at = Time.zone.now
user.reinstated_at = nil
end
it 'updates the reinstated_at attribute with the current time' do
expect do
user.reinstate!
end.to change(user, :reinstated_at).from(nil).to(be_within(1.second).of(Time.zone.now))
end

it 'tracks the user reinstatement' do
expect(user.analytics).to receive(:user_reinstated).with(success: true)
user.reinstate!
end

it 'raises an error if the user is not currently suspended' do
user.suspended_at = nil
expect(user.analytics).to receive(:user_reinstated).with(
success: false,
error_message: cannot_reinstate_message,
)
expect do
user.reinstate!
end.to raise_error(cannot_reinstate_message.to_s)
end
end
end

describe '#should_receive_in_person_completion_survey?' do
let!(:user) { create(:user) }
let(:service_provider) { create(:service_provider) }
Expand Down