Skip to content
Open

NRMI-41 #1284

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
20 changes: 20 additions & 0 deletions app/controllers/v1/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,24 @@ def user_auth_logs

render jsonapi: objects, class: { OpenStruct: SerializableUserAuthLog }, status: :ok
end

def deactivate
user = User.find_by!(auth_id: current_auth_id)

unless user.can_deactivate?
# rubocop:disable Layout/LineLength
return render jsonapi_errors: { user: ['Cannot be deactivated because they are the only user associated with their suppliers'] },
status: :unprocessable_entity
# rubocop:enable Layout/LineLength
end

result = DeactivateUser.new(user: user).call

if result.success?
render jsonapi: user, status: :ok
else
render jsonapi_errors: { user: ['Could not be deactivated'] },
status: :unprocessable_entity
end
end
end
6 changes: 6 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,10 @@ def multiple_suppliers?
def active?
!auth_id.nil?
end

def can_deactivate?
suppliers.all? do |supplier|
supplier.active_users.where.not(id: id).exists?
end
end
end
2 changes: 1 addition & 1 deletion app/serializable/serializable_user.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class SerializableUser < JSONAPI::Serializable::Resource
type 'users'
attributes :multiple_suppliers?, :name, :email, :created_at
attributes :multiple_suppliers?, :can_deactivate?, :name, :email, :created_at
end
19 changes: 18 additions & 1 deletion app/services/deactivate_user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,33 @@ def call
result = Result.new(true)

User.transaction do
lock_linked_suppliers!

unless user.can_deactivate?
result.success = false
raise ActiveRecord::Rollback
end

begin
DeleteUserInAuth0.new(user: user).call
rescue Auth0::Exception
result.success = false
Rails.logger.error("Error adding user #{user.email} to Auth0 during DeactivateUser")
raise ActiveRecord::Rollback
end
user.update(auth_id: nil)

unless user.update(auth_id: nil)
result.success = false
raise ActiveRecord::Rollback
end
end

result
end

private

def lock_linked_suppliers!
user.suppliers.lock.load
end
end
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
collection do
patch :update_name
patch :update_email
patch :deactivate
get :user_auth_logs
end
end
Expand Down
1 change: 1 addition & 0 deletions spec/models/offboard/deactivate_users_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
end

let!(:user) { FactoryBot.create(:user, name: 'User One', email: 'email_one@ccs.co.uk', suppliers: [supplier]) }
let!(:user_two) { FactoryBot.create(:user, name: 'User Two', email: 'email_two@ccs.co.uk', suppliers: [supplier]) }

before do
stub_auth0_token_request
Expand Down
51 changes: 51 additions & 0 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,57 @@
end
end

describe '#can_deactivate?' do
subject(:can_deactivate?) { user.can_deactivate? }

let(:user) { FactoryBot.create(:user) }

context 'when the user is the only active user for a supplier' do
before do
supplier = FactoryBot.create(:supplier)
user.suppliers << supplier
end

it { is_expected.to be_falsy }
end

context 'when the user is not the only active user for a supplier' do
before do
supplier = FactoryBot.create(:supplier)
user.suppliers << supplier
other_user = FactoryBot.create(:user)
other_user.suppliers << supplier
end

it { is_expected.to be_truthy }
end

context 'when another linked user is inactive' do
before do
supplier = FactoryBot.create(:supplier)
user.suppliers << supplier
other_user = FactoryBot.create(:user, :inactive)
other_user.suppliers << supplier
end

it { is_expected.to be_falsy }
end

context 'when one supplier has multiple active users and another has only one' do
before do
supplier1 = FactoryBot.create(:supplier)
user.suppliers << supplier1
other_user1 = FactoryBot.create(:user)
other_user1.suppliers << supplier1

supplier2 = FactoryBot.create(:supplier)
user.suppliers << supplier2
end

it { is_expected.to be_falsy }
end
end

describe '.search' do
let!(:bob) { FactoryBot.create(:user, name: 'Bob Booker', email: 'bob@sheffield.com') }
let!(:bobby) { FactoryBot.create(:user, name: 'Bobby Brown', email: 'bobby_b_66@hotmail.com') }
Expand Down
57 changes: 57 additions & 0 deletions spec/requests/v1/users_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
expect(json['data'][0])
.to have_attribute(:multiple_suppliers?)
.with_value(false)
expect(json['data'][0])
.to have_attribute(:can_deactivate?)
end

it 'returns the details of the current user who belongs to more than one supplier' do
Expand All @@ -30,6 +32,22 @@
.to have_attribute(:multiple_suppliers?)
.with_value(true)
end

it 'returns that the user can be deactivated if they are not the only active user for a supplier' do
user = FactoryBot.create(:user)
supplier = FactoryBot.create(:supplier)
user.suppliers << supplier
other_user = FactoryBot.create(:user)
other_user.suppliers << supplier

get '/v1/users', headers: { 'X-Auth-Id' => JWT.encode(user.auth_id, 'test') }

expect(json['data'].size).to eql 1
expect(response).to be_successful
expect(json['data'][0])
.to have_attribute(:can_deactivate?)
.with_value(true)
end
end

describe 'PATCH /v1/users/update_name' do
Expand Down Expand Up @@ -125,4 +143,43 @@
expect(response.status).to eq 200
end
end

describe 'PATCH /v1/users/deactivate' do
let(:user) { FactoryBot.create(:user) }
let(:headers) { { 'X-Auth-Id' => JWT.encode(user.auth_id, 'test') } }

context 'when the user can be deactivated' do
before do
supplier = FactoryBot.create(:supplier)
user.suppliers << supplier
other_user = FactoryBot.create(:user)
other_user.suppliers << supplier
end

it 'deactivates the user' do
stub_auth0_token_request
stub_auth0_delete_user_request(user)

patch '/v1/users/deactivate', headers: headers

expect(response).to be_successful
expect(user.reload.auth_id).to be_nil
end
end

context 'when the user cannot be deactivated' do
before do
supplier = FactoryBot.create(:supplier)
user.suppliers << supplier
end

it 'returns an error' do
patch '/v1/users/deactivate', headers: headers

expect(response.status).to eq 422
expect(json['errors']).not_to be_empty
expect(user.reload.auth_id).not_to be_nil
end
end
end
end
25 changes: 25 additions & 0 deletions spec/services/deactivate_user_spec.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
require 'rails_helper'

RSpec.describe DeactivateUser do
let(:suppler) { create(:supplier) }
let(:user) { create(:user) }
let(:other_user) { create(:user) }

before(:each) do
user.suppliers << suppler
other_user.suppliers << suppler
stub_auth0_token_request
end

Expand All @@ -16,6 +21,26 @@
expect(result.failure?).to eq(false)
end

context 'when the user is the only active user for a supplier' do
let(:other_user) { create(:user, :inactive) }

it 'returns a failed result' do
result = described_class.new(user: user).call
expect(result).to be_failure
end

it 'does not delete the user in Auth0' do
expect_any_instance_of(DeleteUserInAuth0).not_to receive(:call)
described_class.new(user: user).call
end

it 'does not clear the auth_id of the user' do
original_auth_id = user.auth_id
described_class.new(user: user).call
expect(user.auth_id).to eql(original_auth_id)
end
end

context 'when Auth0 errors' do
before(:each) do
stub_auth0_delete_user_request_failure(user)
Expand Down
Loading