diff options
Diffstat (limited to 'app/services/users/destroy_service.rb')
-rw-r--r-- | app/services/users/destroy_service.rb | 51 |
1 files changed, 34 insertions, 17 deletions
diff --git a/app/services/users/destroy_service.rb b/app/services/users/destroy_service.rb index dfa9316889e..a378cb09854 100644 --- a/app/services/users/destroy_service.rb +++ b/app/services/users/destroy_service.rb @@ -23,6 +23,11 @@ module Users # `hard_delete: true` implies `delete_solo_owned_groups: true`. To perform # a hard deletion without destroying solo-owned groups, pass # `delete_solo_owned_groups: false, hard_delete: true` in +options+. + # + # To make the service asynchronous, a new behaviour is being introduced + # behind the user_destroy_with_limited_execution_time_worker feature flag. + # Migrating the associated user records, and post-migration cleanup is + # handled by the Users::MigrateRecordsToGhostUserWorker cron worker. def execute(user, options = {}) delete_solo_owned_groups = options.fetch(:delete_solo_owned_groups, options[:hard_delete]) @@ -35,12 +40,14 @@ module Users return user end - # Calling all before/after_destroy hooks for the user because - # there is no dependent: destroy in the relationship. And the removal - # is done by a foreign_key. Otherwise they won't be called - user.members.find_each { |member| member.run_callbacks(:destroy) } + user.block + + # Load the records. Groups are unavailable after membership is destroyed. + solo_owned_groups = user.solo_owned_groups.load + + user.members.each_batch { |batch| batch.destroy_all } # rubocop:disable Style/SymbolProc, Cop/DestroyAll - user.solo_owned_groups.each do |group| + solo_owned_groups.each do |group| Groups::DestroyService.new(group, current_user).execute end @@ -54,22 +61,32 @@ module Users yield(user) if block_given? - MigrateToGhostUserService.new(user).execute(hard_delete: options[:hard_delete]) + hard_delete = options.fetch(:hard_delete, false) - response = Snippets::BulkDestroyService.new(current_user, user.snippets).execute(options) - raise DestroyError, response.message if response.error? + if Feature.enabled?(:user_destroy_with_limited_execution_time_worker) + Users::GhostUserMigration.create!(user: user, + initiator_user: current_user, + hard_delete: hard_delete) - # Rails attempts to load all related records into memory before - # destroying: https://github.com/rails/rails/issues/22510 - # This ensures we delete records in batches. - user.destroy_dependent_associations_in_batches(exclude: [:snippets]) - user.nullify_dependent_associations_in_batches + else + MigrateToGhostUserService.new(user).execute(hard_delete: options[:hard_delete]) - # Destroy the namespace after destroying the user since certain methods may depend on the namespace existing - user_data = user.destroy - namespace.destroy + response = Snippets::BulkDestroyService.new(current_user, user.snippets) + .execute(skip_authorization: hard_delete) + raise DestroyError, response.message if response.error? - user_data + # Rails attempts to load all related records into memory before + # destroying: https://github.com/rails/rails/issues/22510 + # This ensures we delete records in batches. + user.destroy_dependent_associations_in_batches(exclude: [:snippets]) + user.nullify_dependent_associations_in_batches + + # Destroy the namespace after destroying the user since certain methods may depend on the namespace existing + user_data = user.destroy + namespace.destroy + + user_data + end end end end |