mirror of
https://github.com/discourse/discourse.git
synced 2024-11-26 17:43:42 +08:00
9bd436c20b
The user and an admin could create multiple email change requests for the same user. If any of the requests was validated and it became primary, the other request could not be deleted anymore.
142 lines
4.5 KiB
Ruby
142 lines
4.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class EmailUpdater
|
|
include HasErrors
|
|
|
|
attr_reader :user
|
|
|
|
def self.human_attribute_name(name, options = {})
|
|
User.human_attribute_name(name, options)
|
|
end
|
|
|
|
def initialize(guardian: nil, user: nil)
|
|
@guardian = guardian
|
|
@user = user
|
|
end
|
|
|
|
def change_to(email, add: false)
|
|
@guardian.ensure_can_edit_email!(@user)
|
|
|
|
email = Email.downcase(email.strip)
|
|
EmailValidator.new(attributes: :email).validate_each(self, :email, email)
|
|
return if errors.present?
|
|
|
|
if existing_user = User.find_by_email(email)
|
|
if SiteSetting.hide_email_address_taken
|
|
Jobs.enqueue(:critical_user_email, type: :account_exists, user_id: existing_user.id)
|
|
else
|
|
error_message = +'change_email.error'
|
|
error_message << '_staged' if existing_user.staged?
|
|
errors.add(:base, I18n.t(error_message))
|
|
end
|
|
end
|
|
|
|
return if errors.present? || existing_user.present?
|
|
|
|
old_email = @user.email if !add
|
|
|
|
if @guardian.is_staff? && @guardian.user != @user
|
|
StaffActionLogger.new(@guardian.user).log_add_email(@user)
|
|
else
|
|
UserHistory.create!(action: UserHistory.actions[:add_email], acting_user_id: @user.id)
|
|
end
|
|
|
|
change_req = EmailChangeRequest.find_or_initialize_by(user_id: @user.id, new_email: email)
|
|
|
|
if change_req.new_record?
|
|
change_req.requested_by = @guardian.user
|
|
change_req.old_email = old_email
|
|
change_req.new_email = email
|
|
end
|
|
|
|
if change_req.change_state.blank? || change_req.change_state == EmailChangeRequest.states[:complete]
|
|
change_req.change_state = if @user.staff?
|
|
# Staff users must confirm their old email address first.
|
|
EmailChangeRequest.states[:authorizing_old]
|
|
else
|
|
EmailChangeRequest.states[:authorizing_new]
|
|
end
|
|
end
|
|
|
|
if change_req.change_state == EmailChangeRequest.states[:authorizing_old]
|
|
change_req.old_email_token = @user.email_tokens.create!(email: @user.email)
|
|
send_email(add ? :confirm_old_email_add : :confirm_old_email, change_req.old_email_token)
|
|
elsif change_req.change_state == EmailChangeRequest.states[:authorizing_new]
|
|
change_req.new_email_token = @user.email_tokens.create!(email: email)
|
|
send_email(:confirm_new_email, change_req.new_email_token)
|
|
end
|
|
|
|
change_req.save!
|
|
end
|
|
|
|
def confirm(token)
|
|
confirm_result = nil
|
|
|
|
User.transaction do
|
|
result = EmailToken.atomic_confirm(token)
|
|
if result[:success]
|
|
token = result[:email_token]
|
|
@user = token.user
|
|
|
|
change_req = @user.email_change_requests
|
|
.where('old_email_token_id = :token_id OR new_email_token_id = :token_id', token_id: token.id)
|
|
.first
|
|
|
|
case change_req.try(:change_state)
|
|
when EmailChangeRequest.states[:authorizing_old]
|
|
change_req.update!(
|
|
change_state: EmailChangeRequest.states[:authorizing_new],
|
|
new_email_token: @user.email_tokens.create(email: change_req.new_email)
|
|
)
|
|
send_email(:confirm_new_email, change_req.new_email_token)
|
|
confirm_result = :authorizing_new
|
|
when EmailChangeRequest.states[:authorizing_new]
|
|
change_req.update!(change_state: EmailChangeRequest.states[:complete])
|
|
if !@user.staff?
|
|
# Send an email notification only to users who did not confirm old
|
|
# email.
|
|
send_email_notification(change_req.old_email, change_req.new_email)
|
|
end
|
|
update_user_email(change_req.old_email, change_req.new_email)
|
|
confirm_result = :complete
|
|
end
|
|
else
|
|
errors.add(:base, I18n.t('change_email.already_done'))
|
|
confirm_result = :error
|
|
end
|
|
end
|
|
|
|
confirm_result || :error
|
|
end
|
|
|
|
def update_user_email(old_email, new_email)
|
|
if old_email.present?
|
|
@user.user_emails.find_by(email: old_email).update!(email: new_email)
|
|
else
|
|
@user.user_emails.create!(email: new_email)
|
|
end
|
|
@user.reload
|
|
|
|
DiscourseEvent.trigger(:user_updated, @user)
|
|
@user.set_automatic_groups
|
|
end
|
|
|
|
protected
|
|
|
|
def send_email(type, email_token)
|
|
Jobs.enqueue :critical_user_email,
|
|
to_address: email_token.email,
|
|
type: type,
|
|
user_id: @user.id,
|
|
email_token: email_token.token
|
|
end
|
|
|
|
def send_email_notification(old_email, new_email)
|
|
Jobs.enqueue :critical_user_email,
|
|
to_address: @user.email,
|
|
type: old_email ? :notify_old_email : :notify_old_email_add,
|
|
user_id: @user.id,
|
|
new_email: new_email
|
|
end
|
|
end
|