Skip to content

Commit

Permalink
Add task for deleting a user
Browse files Browse the repository at this point in the history
Adds a new task for deleting an individual user, and a dry run task for
checking it in advance.

Doesn't delete any associated forms or groups - this complicates things
quite a lot and it's less risky for live forms if we delete or reassign
those form/group associations prior to running this task to delete the
user.
  • Loading branch information
DavidBiddle committed Dec 13, 2024
1 parent 29873b7 commit f60705a
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
25 changes: 25 additions & 0 deletions lib/tasks/users.rake
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ namespace :users do
task update_user_roles_to_standard: :environment do
update_user_roles
end

desc "Delete user (dry run)"
task :delete_user_dry_run, %i[user_id] => :environment do |_, args|
run_deletion_task("delete_user_dry_run", args, rollback: true)
end

desc "Delete user"
task :delete_user, %i[user_id] => :environment do |_, args|
# This task doesn't check whether the user is associated with any forms or groups.
# Before running the task, remove the user from any groups and reassign their forms to another user.
run_deletion_task("delete_user", args, rollback: false)
end
end

def update_user_roles
Expand All @@ -29,3 +41,16 @@ def update_user_roles
Rails.logger.info("Number of organisation_admin users: #{User.where(role: 'organisation_admin').count}")
Rails.logger.info("Number of super_admin users: #{User.where(role: 'super_admin').count}")
end

def run_deletion_task(task_name, args, rollback:)
usage_message = "usage: rake #{task_name}[<user_id>]".freeze
abort usage_message if args[:user_id].blank?

ActiveRecord::Base.transaction do
user = User.find(args[:user_id])
user.destroy!
Rails.logger.info("Deleted user: #{args[:user_id]}")
Rails.logger.info("users:delete_user_dry_run: rollback deletion of user #{args[:user_id]}") if rollback
raise ActiveRecord::Rollback if rollback
end
end
67 changes: 67 additions & 0 deletions spec/lib/tasks/users.rake_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,71 @@
expect(org_admin_user.reload.role).to eq("organisation_admin")
end
end

describe "users:delete_user_dry_run" do
subject(:task) do
Rake::Task["users:delete_user_dry_run"]
.tap(&:reenable) # make sure task is invoked every time
end

let!(:user_to_delete) { create(:user) }

context "when a user ID is provided" do
it "does not delete the user" do
expect {
task.invoke(user_to_delete.id)

user_to_delete.reload
}.not_to raise_error(ActiveRecord::RecordNotFound)
end

it "logs the deletion and the rollback" do
expect(Rails.logger).to receive(:info).with("Deleted user: #{user_to_delete.id}")
expect(Rails.logger).to receive(:info).with("users:delete_user_dry_run: rollback deletion of user #{user_to_delete.id}")
task.invoke(user_to_delete.id)
end
end

context "when a user ID is not provided" do
it "aborts with a usage message" do
expect {
task.invoke
}.to raise_error(SystemExit)
.and output("usage: rake delete_user_dry_run[<user_id>]\n").to_stderr
end
end
end

describe "users:delete_user" do
subject(:task) do
Rake::Task["users:delete_user"]
.tap(&:reenable) # make sure task is invoked every time
end

let!(:user_to_delete) { create(:user) }

context "when a user ID is provided" do
it "deletes the user" do
expect {
task.invoke(user_to_delete.id)

user_to_delete.reload
}.to raise_error(ActiveRecord::RecordNotFound)
end

it "logs the deletion" do
expect(Rails.logger).to receive(:info).with("Deleted user: #{user_to_delete.id}")
task.invoke(user_to_delete.id)
end
end

context "when a user ID is not provided" do
it "aborts with a usage message" do
expect {
task.invoke
}.to raise_error(SystemExit)
.and output("usage: rake delete_user[<user_id>]\n").to_stderr
end
end
end
end

0 comments on commit f60705a

Please sign in to comment.