debian-mirror-gitlab/app/services/users/migrate_to_ghost_user_service.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

114 lines
3.2 KiB
Ruby
Raw Normal View History

2018-11-18 11:00:15 +05:30
# frozen_string_literal: true
2017-08-17 22:00:37 +05:30
# When a user is destroyed, some of their associated records are
# moved to a "Ghost User", to prevent these associated records from
# being destroyed.
#
# For example, all the issues/MRs a user has created are _not_ destroyed
# when the user is destroyed.
module Users
class MigrateToGhostUserService
extend ActiveSupport::Concern
2022-04-04 11:22:00 +05:30
attr_reader :ghost_user, :user, :hard_delete
2017-08-17 22:00:37 +05:30
def initialize(user)
@user = user
2021-11-11 11:23:49 +05:30
@ghost_user = User.ghost
2017-08-17 22:00:37 +05:30
end
2022-04-04 11:22:00 +05:30
# If an admin attempts to hard delete a user, in some cases associated
# records may have a NOT NULL constraint on the user ID that prevent that record
# from being destroyed. In such situations we must assign the record to the ghost user.
# Passing in `hard_delete: true` will ensure these records get assigned to
# the ghost user before the user is destroyed. Other associated records will be destroyed.
# letting the other associated records be destroyed.
def execute(hard_delete: false)
@hard_delete = hard_delete
2017-08-17 22:00:37 +05:30
transition = user.block_transition
2021-11-11 11:23:49 +05:30
# Block the user before moving records to prevent a data race.
# For example, if the user creates an issue after `migrate_issues`
# runs and before the user is destroyed, the destroy will fail with
# an exception.
user.block
2017-08-17 22:00:37 +05:30
2021-11-11 11:23:49 +05:30
begin
user.transaction do
migrate_records
end
rescue Exception # rubocop:disable Lint/RescueException
2017-08-17 22:00:37 +05:30
# Reverse the user block if record migration fails
2021-11-11 11:23:49 +05:30
if transition
2017-08-17 22:00:37 +05:30
transition.rollback
user.save!
end
2021-11-11 11:23:49 +05:30
raise
2017-08-17 22:00:37 +05:30
end
2019-07-31 22:56:46 +05:30
user.reset
2017-08-17 22:00:37 +05:30
end
private
2018-03-17 18:26:18 +05:30
def migrate_records
2022-04-04 11:22:00 +05:30
return if hard_delete
2018-03-17 18:26:18 +05:30
migrate_issues
migrate_merge_requests
migrate_notes
migrate_abuse_reports
2018-10-15 14:42:47 +05:30
migrate_award_emoji
2020-05-24 23:13:21 +05:30
migrate_snippets
2020-06-23 00:09:42 +05:30
migrate_reviews
2018-03-17 18:26:18 +05:30
end
2018-12-05 23:21:45 +05:30
# rubocop: disable CodeReuse/ActiveRecord
2017-08-17 22:00:37 +05:30
def migrate_issues
2022-05-07 20:08:51 +05:30
batched_migrate(Issue, :author_id)
batched_migrate(Issue, :last_edited_by_id)
2017-08-17 22:00:37 +05:30
end
2018-12-05 23:21:45 +05:30
# rubocop: enable CodeReuse/ActiveRecord
2017-08-17 22:00:37 +05:30
2018-12-05 23:21:45 +05:30
# rubocop: disable CodeReuse/ActiveRecord
2017-08-17 22:00:37 +05:30
def migrate_merge_requests
2022-05-07 20:08:51 +05:30
batched_migrate(MergeRequest, :author_id)
batched_migrate(MergeRequest, :merge_user_id)
2017-08-17 22:00:37 +05:30
end
2018-12-05 23:21:45 +05:30
# rubocop: enable CodeReuse/ActiveRecord
2017-08-17 22:00:37 +05:30
def migrate_notes
2022-05-07 20:08:51 +05:30
batched_migrate(Note, :author_id)
2017-08-17 22:00:37 +05:30
end
def migrate_abuse_reports
user.reported_abuse_reports.update_all(reporter_id: ghost_user.id)
end
2018-10-15 14:42:47 +05:30
def migrate_award_emoji
2017-08-17 22:00:37 +05:30
user.award_emoji.update_all(user_id: ghost_user.id)
end
2020-05-24 23:13:21 +05:30
def migrate_snippets
snippets = user.snippets.only_project_snippets
snippets.update_all(author_id: ghost_user.id)
end
2020-06-23 00:09:42 +05:30
def migrate_reviews
2022-05-07 20:08:51 +05:30
batched_migrate(Review, :author_id)
2020-06-23 00:09:42 +05:30
end
2022-05-07 20:08:51 +05:30
# rubocop:disable CodeReuse/ActiveRecord
2022-06-21 17:19:12 +05:30
def batched_migrate(base_scope, column, batch_size: 50)
2022-05-07 20:08:51 +05:30
loop do
2022-06-21 17:19:12 +05:30
update_count = base_scope.where(column => user.id).limit(batch_size).update_all(column => ghost_user.id)
2022-05-07 20:08:51 +05:30
break if update_count == 0
end
end
# rubocop:enable CodeReuse/ActiveRecord
2017-08-17 22:00:37 +05:30
end
end
2019-12-04 20:38:33 +05:30
2021-06-08 01:23:25 +05:30
Users::MigrateToGhostUserService.prepend_mod_with('Users::MigrateToGhostUserService')