feat: automate account deletion (#11406)
- Automate the deletion of accounts that have requested deletion via account settings. - Add a Sidekiq job that runs daily to find accounts that have requested deletion and have passed the 7-day window. - This job deletes the account and then soft-deletes users if they do not belong to any other account. - This job also sends an email to the Chatwoot instance admin for compliance purposes. - The Chatwoot instance admin's email is configurable via the `CHATWOOT_INSTANCE_ADMIN_EMAIL` global config. --------- Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
44
spec/jobs/internal/delete_accounts_job_spec.rb
Normal file
44
spec/jobs/internal/delete_accounts_job_spec.rb
Normal file
@@ -0,0 +1,44 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Internal::DeleteAccountsJob do
|
||||
subject(:job) { described_class.perform_later }
|
||||
|
||||
let!(:account_marked_for_deletion) { create(:account) }
|
||||
let!(:future_deletion_account) { create(:account) }
|
||||
let!(:active_account) { create(:account) }
|
||||
let(:account_deletion_service) { instance_double(AccountDeletionService, perform: true) }
|
||||
|
||||
before do
|
||||
account_marked_for_deletion.update!(
|
||||
custom_attributes: {
|
||||
'marked_for_deletion_at' => 1.day.ago.iso8601,
|
||||
'marked_for_deletion_reason' => 'user_requested'
|
||||
}
|
||||
)
|
||||
|
||||
future_deletion_account.update!(
|
||||
custom_attributes: {
|
||||
'marked_for_deletion_at' => 3.days.from_now.iso8601,
|
||||
'marked_for_deletion_reason' => 'user_requested'
|
||||
}
|
||||
)
|
||||
|
||||
allow(AccountDeletionService).to receive(:new).and_return(account_deletion_service)
|
||||
end
|
||||
|
||||
it 'enqueues the job' do
|
||||
expect { job }.to have_enqueued_job(described_class)
|
||||
.on_queue('scheduled_jobs')
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
it 'calls AccountDeletionService for accounts past deletion date' do
|
||||
described_class.new.perform
|
||||
|
||||
expect(AccountDeletionService).to have_received(:new).with(account: account_marked_for_deletion)
|
||||
expect(AccountDeletionService).not_to have_received(:new).with(account: future_deletion_account)
|
||||
expect(AccountDeletionService).not_to have_received(:new).with(account: active_account)
|
||||
expect(account_deletion_service).to have_received(:perform)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AdministratorNotifications::AccountComplianceMailer do
|
||||
let(:account) do
|
||||
create(:account, custom_attributes: { 'marked_for_deletion_at' => 1.day.ago.iso8601, 'marked_for_deletion_reason' => 'user_requested' })
|
||||
end
|
||||
let(:soft_deleted_users) do
|
||||
[
|
||||
{ id: 1, original_email: 'user1@example.com' },
|
||||
{ id: 2, original_email: 'user2@example.com' }
|
||||
]
|
||||
end
|
||||
|
||||
describe 'account_deleted' do
|
||||
it 'has the right subject format' do
|
||||
subject = described_class.new.send(:subject_for, account)
|
||||
expect(subject).to eq("Account Deletion Notice for #{account.id} - #{account.name}")
|
||||
end
|
||||
|
||||
it 'includes soft deleted users in meta when provided' do
|
||||
mailer_instance = described_class.new
|
||||
allow(mailer_instance).to receive(:params).and_return(
|
||||
{ soft_deleted_users: soft_deleted_users }
|
||||
)
|
||||
|
||||
meta = mailer_instance.send(:build_meta, account)
|
||||
|
||||
expect(meta['deleted_user_count']).to eq(2)
|
||||
expect(meta['soft_deleted_users'].size).to eq(2)
|
||||
expect(meta['soft_deleted_users'].first['user_id']).to eq('1')
|
||||
expect(meta['soft_deleted_users'].first['user_email']).to eq('user1@example.com')
|
||||
end
|
||||
end
|
||||
end
|
||||
63
spec/services/account_deletion_service_spec.rb
Normal file
63
spec/services/account_deletion_service_spec.rb
Normal file
@@ -0,0 +1,63 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AccountDeletionService do
|
||||
let(:account) { create(:account) }
|
||||
let(:mailer) { instance_double(ActionMailer::MessageDelivery, deliver_later: nil) }
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
allow(DeleteObjectJob).to receive(:perform_later)
|
||||
allow(AdministratorNotifications::AccountComplianceMailer).to receive(:with).and_return(
|
||||
instance_double(AdministratorNotifications::AccountComplianceMailer, account_deleted: mailer)
|
||||
)
|
||||
end
|
||||
|
||||
it 'enqueues DeleteObjectJob with the account' do
|
||||
described_class.new(account: account).perform
|
||||
|
||||
expect(DeleteObjectJob).to have_received(:perform_later).with(account)
|
||||
end
|
||||
|
||||
it 'sends a compliance notification email' do
|
||||
described_class.new(account: account).perform
|
||||
|
||||
expect(AdministratorNotifications::AccountComplianceMailer).to have_received(:with) do |args|
|
||||
expect(args[:account]).to eq(account)
|
||||
expect(args).to include(:soft_deleted_users)
|
||||
end
|
||||
expect(mailer).to have_received(:deliver_later)
|
||||
end
|
||||
|
||||
context 'when handling users' do
|
||||
let(:user_with_one_account) { create(:user) }
|
||||
let(:user_with_multiple_accounts) { create(:user) }
|
||||
let(:second_account) { create(:account) }
|
||||
|
||||
before do
|
||||
create(:account_user, user: user_with_one_account, account: account)
|
||||
create(:account_user, user: user_with_multiple_accounts, account: account)
|
||||
create(:account_user, user: user_with_multiple_accounts, account: second_account)
|
||||
end
|
||||
|
||||
it 'soft deletes users who only belong to the deleted account' do
|
||||
original_email = user_with_one_account.email
|
||||
|
||||
described_class.new(account: account).perform
|
||||
|
||||
# Reload the user to get the updated email
|
||||
user_with_one_account.reload
|
||||
expect(user_with_one_account.email).to eq("#{original_email}-deleted.com")
|
||||
end
|
||||
|
||||
it 'does not modify emails for users belonging to multiple accounts' do
|
||||
original_email = user_with_multiple_accounts.email
|
||||
|
||||
described_class.new(account: account).perform
|
||||
|
||||
# Reload the user to get the updated email
|
||||
user_with_multiple_accounts.reload
|
||||
expect(user_with_multiple_accounts.email).to eq(original_email)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user