98 lines
3.5 KiB
Ruby
98 lines
3.5 KiB
Ruby
# frozen_string_literal: true
|
|
# rubocop:disable Style/Documentation
|
|
|
|
module Gitlab
|
|
module BackgroundMigration
|
|
class WrongfullyConfirmedEmailUnconfirmer
|
|
class UserModel < ActiveRecord::Base
|
|
alias_method :reset, :reload
|
|
|
|
self.table_name = 'users'
|
|
|
|
scope :active, -> { where(state: 'active', user_type: nil) } # only humans, skip bots
|
|
|
|
devise :confirmable
|
|
end
|
|
|
|
class EmailModel < ActiveRecord::Base
|
|
alias_method :reset, :reload
|
|
|
|
self.table_name = 'emails'
|
|
|
|
belongs_to :user
|
|
|
|
devise :confirmable
|
|
|
|
def self.wrongfully_confirmed_emails(start_id, stop_id)
|
|
joins(:user)
|
|
.merge(UserModel.active)
|
|
.where(id: (start_id..stop_id))
|
|
.where.not('emails.confirmed_at' => nil)
|
|
.where('emails.confirmed_at = users.confirmed_at')
|
|
.where('emails.email <> users.email')
|
|
.where('NOT EXISTS (SELECT 1 FROM user_synced_attributes_metadata WHERE user_id=users.id AND email_synced IS true)')
|
|
end
|
|
end
|
|
|
|
def perform(start_id, stop_id)
|
|
email_records = EmailModel
|
|
.wrongfully_confirmed_emails(start_id, stop_id)
|
|
.to_a
|
|
|
|
user_ids = email_records.map(&:user_id).uniq
|
|
|
|
ActiveRecord::Base.transaction do
|
|
update_email_records(start_id, stop_id)
|
|
update_user_records(user_ids)
|
|
end
|
|
|
|
# Refind the records with the "real" Email model so devise will notice that the user / email is unconfirmed
|
|
unconfirmed_email_records = ::Email.where(id: email_records.map(&:id))
|
|
ActiveRecord::Associations::Preloader.new.preload(unconfirmed_email_records, [:user])
|
|
|
|
send_emails(unconfirmed_email_records)
|
|
end
|
|
|
|
private
|
|
|
|
def update_email_records(start_id, stop_id)
|
|
EmailModel.connection.execute <<-SQL
|
|
WITH md5_strings as #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
|
|
#{email_query_for_update(start_id, stop_id).to_sql}
|
|
)
|
|
UPDATE #{EmailModel.connection.quote_table_name(EmailModel.table_name)}
|
|
SET confirmed_at = NULL,
|
|
confirmation_token = md5_strings.md5_string,
|
|
confirmation_sent_at = NOW()
|
|
FROM md5_strings
|
|
WHERE id = md5_strings.email_id
|
|
SQL
|
|
end
|
|
|
|
def update_user_records(user_ids)
|
|
UserModel
|
|
.where(id: user_ids)
|
|
.update_all("confirmed_at = NULL, confirmation_sent_at = NOW(), unconfirmed_email = NULL, confirmation_token=md5(users.id::varchar || users.created_at || users.encrypted_password || '#{Integer(Time.now.to_i)}')")
|
|
end
|
|
|
|
def email_query_for_update(start_id, stop_id)
|
|
EmailModel
|
|
.wrongfully_confirmed_emails(start_id, stop_id)
|
|
.select('emails.id as email_id', "md5(emails.id::varchar || emails.created_at || users.encrypted_password || '#{Integer(Time.now.to_i)}') as md5_string")
|
|
end
|
|
|
|
def send_emails(email_records)
|
|
user_records = email_records.map(&:user).uniq
|
|
|
|
user_records.each do |user|
|
|
Gitlab::BackgroundMigration::Mailers::UnconfirmMailer.unconfirm_notification_email(user).deliver_later
|
|
DeviseMailer.confirmation_instructions(user, user.confirmation_token).deliver_later(wait: 1.minute)
|
|
end
|
|
|
|
email_records.each do |email|
|
|
DeviseMailer.confirmation_instructions(email, email.confirmation_token).deliver_later(wait: 1.minute)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|