FIX: When admin changes another user's email auto-confirm the change (#9001)

When admin changes a user's email from the preferences page of that user:

* The user will not be sent an email to confirm that their
  email is changing. They will be sent a reset password email
  so they can set the password for their account at the new
  email address.
* The user will still be sent an email to their old email to inform
  them that it was changed.
* Admin and staff users still need to follow the same old + new
  confirm process, as do users changing their own email.
This commit is contained in:
Martin Brennan
2020-02-20 09:52:21 +10:00
committed by GitHub
parent 20b90afad9
commit 97d8f19387
5 changed files with 131 additions and 21 deletions

View File

@@ -10,16 +10,102 @@ describe EmailUpdater do
Fabricate(:user, staged: true, email: new_email)
user = Fabricate(:user, email: old_email)
updater = EmailUpdater.new(user.guardian, user)
updater = EmailUpdater.new(guardian: user.guardian, user: user)
updater.change_to(new_email)
expect(updater.errors).to be_present
expect(updater.errors.messages[:base].first).to be I18n.t("change_email.error_staged")
end
context "when an admin is changing the email of another user" do
let(:admin) { Fabricate(:admin) }
let(:updater) { EmailUpdater.new(guardian: user.guardian, user: user, initiating_user: admin) }
def expect_old_email_job
Jobs.expects(:enqueue).with(:critical_user_email, has_entries(to_address: old_email, type: :notify_old_email, user_id: user.id))
end
def expect_forgot_password_job
Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :forgot_password, user_id: user.id))
end
context "for a regular user" do
let(:user) { Fabricate(:user, email: old_email) }
it "does not send an email to the user for them to confirm their new email but still sends the notification to the old email" do
Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :confirm_new_email, to_address: new_email)).never
expect_old_email_job
expect_forgot_password_job
updater.change_to(new_email)
end
it "creates a change request authorizing the new email and immediately confirms it " do
updater.change_to(new_email)
change_req = user.email_change_requests.first
expect(change_req.change_state).to eq(EmailChangeRequest.states[:complete])
end
it "sends a reset password email to the user so they can set a password for their new email" do
expect_old_email_job
expect_forgot_password_job
updater.change_to(new_email)
end
end
context "for a staff user" do
let(:user) { Fabricate(:moderator, email: old_email) }
it "does not send an email to the user for them to confirm their new email but still sends the notification to the old email" do
Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :confirm_new_email, to_address: new_email)).never
expect_old_email_job
expect_forgot_password_job
updater.change_to(new_email)
end
it "creates a change request authorizing the new email and immediately confirms it " do
updater.change_to(new_email)
change_req = user.email_change_requests.first
expect(change_req.change_state).to eq(EmailChangeRequest.states[:complete])
end
it "sends a reset password email to the user so they can set a password for their new email" do
expect_old_email_job
expect_forgot_password_job
updater.change_to(new_email)
end
end
context "when changing their own email" do
let(:user) { admin }
before do
admin.update(email: old_email)
Jobs.expects(:enqueue).once.with(:critical_user_email, has_entries(type: :confirm_old_email, to_address: old_email))
updater.change_to(new_email)
@change_req = user.email_change_requests.first
end
it "starts the old confirmation process" do
expect(updater.errors).to be_blank
expect(@change_req.old_email).to eq(old_email)
expect(@change_req.new_email).to eq(new_email)
expect(@change_req).to be_present
expect(@change_req.change_state).to eq(EmailChangeRequest.states[:authorizing_old])
expect(@change_req.old_email_token.email).to eq(old_email)
expect(@change_req.new_email_token).to be_blank
end
it "does not immediately confirm the request" do
expect(@change_req.change_state).not_to eq(EmailChangeRequest.states[:complete])
end
end
end
context 'as a regular user' do
let(:user) { Fabricate(:user, email: old_email) }
let(:updater) { EmailUpdater.new(user.guardian, user) }
let(:updater) { EmailUpdater.new(guardian: user.guardian, user: user) }
before do
Jobs.expects(:enqueue).once.with(:critical_user_email, has_entries(type: :confirm_new_email, to_address: new_email))
@@ -63,7 +149,7 @@ describe EmailUpdater do
context 'as a staff user' do
let(:user) { Fabricate(:moderator, email: old_email) }
let(:updater) { EmailUpdater.new(user.guardian, user) }
let(:updater) { EmailUpdater.new(guardian: user.guardian, user: user) }
before do
Jobs.expects(:enqueue).once.with(:critical_user_email, has_entries(type: :confirm_old_email, to_address: old_email))
@@ -140,7 +226,7 @@ describe EmailUpdater do
let(:user) { Fabricate(:user, email: old_email) }
let(:existing) { Fabricate(:user, email: new_email) }
let(:updater) { EmailUpdater.new(user.guardian, user) }
let(:updater) { EmailUpdater.new(guardian: user.guardian, user: user) }
it "doesn't error if user exists with new email" do
updater.change_to(existing.email)

View File

@@ -655,7 +655,7 @@ RSpec.describe Users::OmniauthCallbacksController do
username: 'boguslaw',
email: new_email }
updater = EmailUpdater.new(user.guardian, user)
updater = EmailUpdater.new(guardian: user.guardian, user: user)
updater.change_to(new_email)
user.reload

View File

@@ -26,7 +26,7 @@ describe UsersEmailController do
end
it 'does not change email if accounts mismatch' do
updater = EmailUpdater.new(user.guardian, user)
updater = EmailUpdater.new(guardian: user.guardian, user: user)
updater.change_to('new.n.cool@example.com')
old_email = user.email
@@ -42,7 +42,7 @@ describe UsersEmailController do
end
context "with a valid user" do
let(:updater) { EmailUpdater.new(user.guardian, user) }
let(:updater) { EmailUpdater.new(guardian: user.guardian, user: user) }
before do
sign_in(user)
@@ -221,7 +221,7 @@ describe UsersEmailController do
it 'bans change when accounts do not match' do
sign_in(user)
updater = EmailUpdater.new(moderator.guardian, moderator)
updater = EmailUpdater.new(guardian: moderator.guardian, user: moderator)
updater.change_to('new.n.cool@example.com')
get "/u/confirm-old-email/#{moderator.email_tokens.last.token}"
@@ -235,7 +235,7 @@ describe UsersEmailController do
it 'confirms with a correct token' do
# NOTE: only moderators need to confirm both old and new
sign_in(moderator)
updater = EmailUpdater.new(moderator.guardian, moderator)
updater = EmailUpdater.new(guardian: moderator.guardian, user: moderator)
updater.change_to('new.n.cool@example.com')
get "/u/confirm-old-email/#{moderator.email_tokens.last.token}"