diff --git a/lib/tasks/users.rake b/lib/tasks/users.rake index ae1383a26..95952be29 100644 --- a/lib/tasks/users.rake +++ b/lib/tasks/users.rake @@ -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 @@ -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}[]".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 diff --git a/spec/lib/tasks/users.rake_spec.rb b/spec/lib/tasks/users.rake_spec.rb index ecda97fcb..1b182a37a 100644 --- a/spec/lib/tasks/users.rake_spec.rb +++ b/spec/lib/tasks/users.rake_spec.rb @@ -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[]\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[]\n").to_stderr + end + end + end end