2019-04-29 20:27:42 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-07-27 22:27:38 -04:00
|
|
|
RSpec.describe EmailUpdater do
|
2016-03-07 14:40:11 -05:00
|
|
|
let(:old_email) { 'old.email@example.com' }
|
|
|
|
let(:new_email) { 'new.email@example.com' }
|
|
|
|
|
2016-03-21 14:36:26 -04:00
|
|
|
it "provides better error message when a staged user has the same email" do
|
|
|
|
Fabricate(:user, staged: true, email: new_email)
|
|
|
|
|
|
|
|
user = Fabricate(:user, email: old_email)
|
2020-02-19 18:52:21 -05:00
|
|
|
updater = EmailUpdater.new(guardian: user.guardian, user: user)
|
2016-03-21 14:36:26 -04:00
|
|
|
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
|
|
|
|
|
2021-03-10 07:49:26 -05:00
|
|
|
it "does not create multiple email change requests" do
|
|
|
|
user = Fabricate(:user)
|
|
|
|
|
|
|
|
EmailUpdater.new(guardian: Fabricate(:admin).guardian, user: user).change_to(new_email)
|
|
|
|
EmailUpdater.new(guardian: Fabricate(:admin).guardian, user: user).change_to(new_email)
|
|
|
|
|
|
|
|
expect(user.email_change_requests.count).to eq(1)
|
|
|
|
end
|
|
|
|
|
2020-02-19 18:52:21 -05:00
|
|
|
context "when an admin is changing the email of another user" do
|
|
|
|
let(:admin) { Fabricate(:admin) }
|
2020-06-04 01:09:10 -04:00
|
|
|
let(:updater) { EmailUpdater.new(guardian: admin.guardian, user: user) }
|
2020-02-19 18:52:21 -05:00
|
|
|
|
|
|
|
def expect_old_email_job
|
2020-07-24 05:16:52 -04:00
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { to_address: old_email, type: :notify_old_email, user_id: user.id }) do
|
|
|
|
yield
|
|
|
|
end
|
2020-02-19 18:52:21 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
context "for a regular user" do
|
|
|
|
let(:user) { Fabricate(:user, email: old_email) }
|
|
|
|
|
2020-10-06 23:02:24 -04:00
|
|
|
it "sends an email to the user for them to confirm the email change" do
|
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :confirm_new_email, to_address: new_email }) do
|
|
|
|
updater.change_to(new_email)
|
2020-07-24 05:16:52 -04:00
|
|
|
end
|
2020-02-19 18:52:21 -05:00
|
|
|
end
|
|
|
|
|
2022-09-29 17:49:17 -04:00
|
|
|
it "sends an email to confirm old email first if require_change_email_confirmation is enabled" do
|
|
|
|
SiteSetting.require_change_email_confirmation = true
|
|
|
|
|
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :confirm_old_email, to_address: old_email }) do
|
|
|
|
updater.change_to(new_email)
|
|
|
|
end
|
|
|
|
|
|
|
|
expect(updater.change_req).to be_present
|
|
|
|
expect(updater.change_req.old_email).to eq(old_email)
|
|
|
|
expect(updater.change_req.new_email).to eq(new_email)
|
|
|
|
expect(updater.change_req.change_state).to eq(EmailChangeRequest.states[:authorizing_old])
|
|
|
|
expect(updater.change_req.old_email_token.email).to eq(old_email)
|
|
|
|
expect(updater.change_req.new_email_token).to be_blank
|
|
|
|
end
|
|
|
|
|
2020-10-06 23:02:24 -04:00
|
|
|
it "logs the admin user as the requester" do
|
2020-02-19 18:52:21 -05:00
|
|
|
updater.change_to(new_email)
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.requested_by).to eq(admin)
|
2020-02-19 18:52:21 -05:00
|
|
|
end
|
|
|
|
|
2020-10-06 23:02:24 -04:00
|
|
|
it "starts the new confirmation process" do
|
|
|
|
updater.change_to(new_email)
|
|
|
|
expect(updater.errors).to be_blank
|
2020-09-28 19:45:45 -04:00
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req).to be_present
|
|
|
|
expect(updater.change_req.change_state).to eq(EmailChangeRequest.states[:authorizing_new])
|
2020-10-06 23:02:24 -04:00
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.old_email).to eq(old_email)
|
|
|
|
expect(updater.change_req.new_email).to eq(new_email)
|
|
|
|
expect(updater.change_req.old_email_token).to be_blank
|
|
|
|
expect(updater.change_req.new_email_token.email).to eq(new_email)
|
2020-02-19 18:52:21 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "for a staff user" do
|
|
|
|
let(:user) { Fabricate(:moderator, email: old_email) }
|
|
|
|
|
2020-02-19 22:42:57 -05:00
|
|
|
before do
|
2020-07-24 05:16:52 -04:00
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :confirm_old_email, to_address: old_email }) do
|
|
|
|
updater.change_to(new_email)
|
|
|
|
end
|
2020-02-19 18:52:21 -05:00
|
|
|
end
|
|
|
|
|
2020-02-19 22:42:57 -05:00
|
|
|
it "starts the old confirmation process" do
|
|
|
|
expect(updater.errors).to be_blank
|
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.old_email).to eq(old_email)
|
|
|
|
expect(updater.change_req.new_email).to eq(new_email)
|
|
|
|
expect(updater.change_req).to be_present
|
|
|
|
expect(updater.change_req.change_state).to eq(EmailChangeRequest.states[:authorizing_old])
|
2020-02-19 22:42:57 -05:00
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.old_email_token.email).to eq(old_email)
|
|
|
|
expect(updater.change_req.new_email_token).to be_blank
|
2020-02-19 18:52:21 -05:00
|
|
|
end
|
|
|
|
|
2020-02-19 22:42:57 -05:00
|
|
|
it "does not immediately confirm the request" do
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.change_state).not_to eq(EmailChangeRequest.states[:complete])
|
2020-02-19 18:52:21 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when changing their own email" do
|
|
|
|
let(:user) { admin }
|
|
|
|
|
|
|
|
before do
|
|
|
|
admin.update(email: old_email)
|
2020-07-24 05:16:52 -04:00
|
|
|
|
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :confirm_old_email, to_address: old_email }) do
|
|
|
|
updater.change_to(new_email)
|
|
|
|
end
|
2020-02-19 18:52:21 -05:00
|
|
|
end
|
|
|
|
|
2020-10-06 23:02:24 -04:00
|
|
|
it "logs the user as the requester" do
|
|
|
|
updater.change_to(new_email)
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.requested_by).to eq(user)
|
2020-10-06 23:02:24 -04:00
|
|
|
end
|
|
|
|
|
2020-02-19 18:52:21 -05:00
|
|
|
it "starts the old confirmation process" do
|
|
|
|
expect(updater.errors).to be_blank
|
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.old_email).to eq(old_email)
|
|
|
|
expect(updater.change_req.new_email).to eq(new_email)
|
|
|
|
expect(updater.change_req).to be_present
|
|
|
|
expect(updater.change_req.change_state).to eq(EmailChangeRequest.states[:authorizing_old])
|
2020-02-19 18:52:21 -05:00
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.old_email_token.email).to eq(old_email)
|
|
|
|
expect(updater.change_req.new_email_token).to be_blank
|
2020-02-19 18:52:21 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it "does not immediately confirm the request" do
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.change_state).not_to eq(EmailChangeRequest.states[:complete])
|
2020-02-19 18:52:21 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-07 14:40:11 -05:00
|
|
|
context 'as a regular user' do
|
|
|
|
let(:user) { Fabricate(:user, email: old_email) }
|
2020-02-19 18:52:21 -05:00
|
|
|
let(:updater) { EmailUpdater.new(guardian: user.guardian, user: user) }
|
2016-03-07 14:40:11 -05:00
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context "when changing primary email" do
|
2020-06-10 12:11:49 -04:00
|
|
|
before do
|
2020-07-24 05:16:52 -04:00
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :confirm_new_email, to_address: new_email }) do
|
|
|
|
updater.change_to(new_email)
|
|
|
|
end
|
2020-06-10 12:11:49 -04:00
|
|
|
end
|
2016-03-07 14:40:11 -05:00
|
|
|
|
2020-06-10 12:11:49 -04:00
|
|
|
it "starts the new confirmation process" do
|
|
|
|
expect(updater.errors).to be_blank
|
2016-03-07 14:40:11 -05:00
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req).to be_present
|
|
|
|
expect(updater.change_req.change_state).to eq(EmailChangeRequest.states[:authorizing_new])
|
2016-03-07 14:40:11 -05:00
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.old_email).to eq(old_email)
|
|
|
|
expect(updater.change_req.new_email).to eq(new_email)
|
|
|
|
expect(updater.change_req.old_email_token).to be_blank
|
|
|
|
expect(updater.change_req.new_email_token.email).to eq(new_email)
|
2020-06-10 12:11:49 -04:00
|
|
|
end
|
2016-03-07 14:40:11 -05:00
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context 'when confirming an invalid token' do
|
2020-06-10 12:11:49 -04:00
|
|
|
it "produces an error" do
|
|
|
|
updater.confirm('random')
|
|
|
|
expect(updater.errors).to be_present
|
|
|
|
expect(user.reload.email).not_to eq(new_email)
|
|
|
|
end
|
2016-03-07 14:40:11 -05:00
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context 'when confirming a valid token' do
|
2020-06-10 12:11:49 -04:00
|
|
|
it "updates the user's email" do
|
2020-07-16 08:51:30 -04:00
|
|
|
event = DiscourseEvent.track_events {
|
2020-07-24 05:16:52 -04:00
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :notify_old_email, to_address: old_email }) do
|
2021-11-25 02:34:39 -05:00
|
|
|
updater.confirm(updater.change_req.new_email_token.token)
|
2020-07-24 05:16:52 -04:00
|
|
|
end
|
2020-07-16 08:51:30 -04:00
|
|
|
}.last
|
|
|
|
|
2020-06-10 12:11:49 -04:00
|
|
|
expect(updater.errors).to be_blank
|
|
|
|
expect(user.reload.email).to eq(new_email)
|
2016-03-07 14:40:11 -05:00
|
|
|
|
2020-07-16 08:51:30 -04:00
|
|
|
expect(event[:event_name]).to eq(:user_updated)
|
|
|
|
expect(event[:params].first).to eq(user)
|
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
updater.change_req.reload
|
|
|
|
expect(updater.change_req.change_state).to eq(EmailChangeRequest.states[:complete])
|
2020-06-10 12:11:49 -04:00
|
|
|
end
|
2016-03-07 14:40:11 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context "when adding an email" do
|
2020-06-10 12:11:49 -04:00
|
|
|
before do
|
2020-07-24 05:16:52 -04:00
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :confirm_new_email, to_address: new_email }) do
|
|
|
|
updater.change_to(new_email, add: true)
|
|
|
|
end
|
2020-06-10 12:11:49 -04:00
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context 'when confirming a valid token' do
|
2020-06-10 12:11:49 -04:00
|
|
|
it "adds a user email" do
|
2020-06-17 14:41:16 -04:00
|
|
|
expect(UserHistory.where(action: UserHistory.actions[:add_email], acting_user_id: user.id).last).to be_present
|
|
|
|
|
2020-07-16 08:51:30 -04:00
|
|
|
event = DiscourseEvent.track_events {
|
2020-07-24 05:16:52 -04:00
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :notify_old_email_add, to_address: old_email }) do
|
2021-11-25 02:34:39 -05:00
|
|
|
updater.confirm(updater.change_req.new_email_token.token)
|
2020-07-24 05:16:52 -04:00
|
|
|
end
|
2020-07-16 08:51:30 -04:00
|
|
|
}.last
|
|
|
|
|
2020-06-10 12:11:49 -04:00
|
|
|
expect(updater.errors).to be_blank
|
|
|
|
expect(UserEmail.where(user_id: user.id).pluck(:email)).to contain_exactly(user.email, new_email)
|
|
|
|
|
2020-07-16 08:51:30 -04:00
|
|
|
expect(event[:event_name]).to eq(:user_updated)
|
|
|
|
expect(event[:params].first).to eq(user)
|
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
updater.change_req.reload
|
|
|
|
expect(updater.change_req.change_state).to eq(EmailChangeRequest.states[:complete])
|
2020-06-10 12:11:49 -04:00
|
|
|
end
|
|
|
|
end
|
2020-06-11 07:53:41 -04:00
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context 'when it was deleted before' do
|
2020-06-11 07:53:41 -04:00
|
|
|
it 'works' do
|
2020-07-24 05:16:52 -04:00
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :notify_old_email_add, to_address: old_email }) do
|
2021-11-25 02:34:39 -05:00
|
|
|
updater.confirm(updater.change_req.new_email_token.token)
|
2020-07-24 05:16:52 -04:00
|
|
|
end
|
|
|
|
|
2020-06-11 07:53:41 -04:00
|
|
|
expect(user.reload.user_emails.pluck(:email)).to contain_exactly(old_email, new_email)
|
|
|
|
|
|
|
|
user.user_emails.where(email: new_email).delete_all
|
|
|
|
expect(user.reload.user_emails.pluck(:email)).to contain_exactly(old_email)
|
|
|
|
|
2020-07-24 05:16:52 -04:00
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :confirm_new_email, to_address: new_email }) do
|
|
|
|
updater.change_to(new_email, add: true)
|
|
|
|
end
|
|
|
|
|
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :notify_old_email_add, to_address: old_email }) do
|
2021-11-25 02:34:39 -05:00
|
|
|
updater.confirm(updater.change_req.new_email_token.token)
|
2020-07-24 05:16:52 -04:00
|
|
|
end
|
|
|
|
|
2020-06-11 07:53:41 -04:00
|
|
|
expect(user.reload.user_emails.pluck(:email)).to contain_exactly(old_email, new_email)
|
|
|
|
end
|
|
|
|
end
|
2020-06-10 12:11:49 -04:00
|
|
|
end
|
2021-04-05 11:01:42 -04:00
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context "with max_allowed_secondary_emails" do
|
2021-04-05 11:01:42 -04:00
|
|
|
let(:secondary_email_1) { "secondary_1@email.com" }
|
|
|
|
let(:secondary_email_2) { "secondary_2@email.com" }
|
|
|
|
|
|
|
|
before do
|
|
|
|
SiteSetting.max_allowed_secondary_emails = 2
|
|
|
|
Fabricate(:secondary_email, user: user, primary: false, email: secondary_email_1)
|
|
|
|
Fabricate(:secondary_email, user: user, primary: false, email: secondary_email_2)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "max secondary_emails limit reached" do
|
|
|
|
updater.change_to(new_email, add: true)
|
|
|
|
expect(updater.errors).to be_present
|
|
|
|
expect(updater.errors.messages[:base].first).to be I18n.t("change_email.max_secondary_emails_error")
|
|
|
|
end
|
|
|
|
end
|
2016-03-07 14:40:11 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'as a staff user' do
|
|
|
|
let(:user) { Fabricate(:moderator, email: old_email) }
|
2020-02-19 18:52:21 -05:00
|
|
|
let(:updater) { EmailUpdater.new(guardian: user.guardian, user: user) }
|
2016-03-07 14:40:11 -05:00
|
|
|
|
|
|
|
before do
|
2020-07-24 05:16:52 -04:00
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :confirm_old_email, to_address: old_email }) do
|
|
|
|
updater.change_to(new_email)
|
|
|
|
end
|
2016-03-07 14:40:11 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it "starts the old confirmation process" do
|
|
|
|
expect(updater.errors).to be_blank
|
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.old_email).to eq(old_email)
|
|
|
|
expect(updater.change_req.new_email).to eq(new_email)
|
|
|
|
expect(updater.change_req).to be_present
|
|
|
|
expect(updater.change_req.change_state).to eq(EmailChangeRequest.states[:authorizing_old])
|
2016-03-07 14:40:11 -05:00
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.old_email_token.email).to eq(old_email)
|
|
|
|
expect(updater.change_req.new_email_token).to be_blank
|
2016-03-07 14:40:11 -05:00
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context 'when confirming an invalid token' do
|
2016-03-07 14:40:11 -05:00
|
|
|
it "produces an error" do
|
|
|
|
updater.confirm('random')
|
|
|
|
expect(updater.errors).to be_present
|
|
|
|
expect(user.reload.email).not_to eq(new_email)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context 'when confirming a valid token' do
|
2016-03-07 14:40:11 -05:00
|
|
|
before do
|
2020-07-24 05:16:52 -04:00
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :confirm_new_email, to_address: new_email }) do
|
2021-11-25 02:34:39 -05:00
|
|
|
@old_token = updater.change_req.old_email_token.token
|
|
|
|
updater.confirm(@old_token)
|
2020-07-24 05:16:52 -04:00
|
|
|
end
|
2016-03-07 14:40:11 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it "starts the new update process" do
|
|
|
|
expect(updater.errors).to be_blank
|
|
|
|
expect(user.reload.email).to eq(old_email)
|
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
expect(updater.change_req.change_state).to eq(EmailChangeRequest.states[:authorizing_new])
|
|
|
|
expect(updater.change_req.new_email_token).to be_present
|
2016-03-07 14:40:11 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it "cannot be confirmed twice" do
|
2021-11-25 02:34:39 -05:00
|
|
|
updater.confirm(@old_token)
|
2016-03-07 14:40:11 -05:00
|
|
|
expect(updater.errors).to be_present
|
|
|
|
expect(user.reload.email).to eq(old_email)
|
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
updater.change_req.reload
|
|
|
|
expect(updater.change_req.change_state).to eq(EmailChangeRequest.states[:authorizing_new])
|
|
|
|
expect(updater.change_req.new_email_token.email).to eq(new_email)
|
2016-03-07 14:40:11 -05:00
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context "when completing the new update process" do
|
2016-03-07 14:40:11 -05:00
|
|
|
before do
|
2020-07-24 05:16:52 -04:00
|
|
|
expect_not_enqueued_with(job: :critical_user_email, args: { type: :notify_old_email, to_address: old_email }) do
|
2021-11-25 02:34:39 -05:00
|
|
|
updater.confirm(updater.change_req.new_email_token.token)
|
2020-07-24 05:16:52 -04:00
|
|
|
end
|
2016-03-07 14:40:11 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it "updates the user's email" do
|
|
|
|
expect(updater.errors).to be_blank
|
|
|
|
expect(user.reload.email).to eq(new_email)
|
|
|
|
|
2021-11-25 02:34:39 -05:00
|
|
|
updater.change_req.reload
|
|
|
|
expect(updater.change_req.change_state).to eq(EmailChangeRequest.states[:complete])
|
2016-03-07 14:40:11 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-10-04 11:41:08 -04:00
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context 'when hide_email_address_taken is enabled' do
|
2017-10-04 11:41:08 -04:00
|
|
|
before do
|
|
|
|
SiteSetting.hide_email_address_taken = true
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:user) { Fabricate(:user, email: old_email) }
|
|
|
|
let(:existing) { Fabricate(:user, email: new_email) }
|
2020-02-19 18:52:21 -05:00
|
|
|
let(:updater) { EmailUpdater.new(guardian: user.guardian, user: user) }
|
2017-10-04 11:41:08 -04:00
|
|
|
|
|
|
|
it "doesn't error if user exists with new email" do
|
|
|
|
updater.change_to(existing.email)
|
|
|
|
expect(updater.errors).to be_blank
|
|
|
|
expect(user.email_change_requests).to be_empty
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'sends an email to the owner of the account with the new email' do
|
2020-07-24 05:16:52 -04:00
|
|
|
expect_enqueued_with(job: :critical_user_email, args: { type: :account_exists, user_id: existing.id }) do
|
|
|
|
updater.change_to(existing.email)
|
|
|
|
end
|
2017-10-04 11:41:08 -04:00
|
|
|
end
|
|
|
|
end
|
2016-03-07 14:40:11 -05:00
|
|
|
end
|