FIX: Do not add same email multiple times (#12322)

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.
This commit is contained in:
Bianca Nenciu 2021-03-10 14:49:26 +02:00 committed by GitHub
parent 92ad2182f5
commit 9bd436c20b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 12 deletions

View File

@ -283,17 +283,14 @@ class UsersController < ApplicationController
user = fetch_user_from_params user = fetch_user_from_params
guardian.ensure_can_edit!(user) guardian.ensure_can_edit!(user)
user_email = user.user_emails.find_by(email: params[:email])
if user_email&.primary
return render json: failed_json, status: 428
end
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
if user_email if email = user.user_emails.find_by(email: params[:email], primary: false)
user_email.destroy email.destroy
DiscourseEvent.trigger(:user_updated, user) DiscourseEvent.trigger(:user_updated, user)
elsif elsif change_requests = user.email_change_requests.where(new_email: params[:email]).presence
user.email_change_requests.where(new_email: params[:email]).destroy_all change_requests.destroy_all
else
return render json: failed_json, status: 428
end end
if current_user.staff? && current_user != user if current_user.staff? && current_user != user

View File

@ -41,10 +41,10 @@ class EmailUpdater
UserHistory.create!(action: UserHistory.actions[:add_email], acting_user_id: @user.id) UserHistory.create!(action: UserHistory.actions[:add_email], acting_user_id: @user.id)
end end
change_req = EmailChangeRequest.find_or_initialize_by( change_req = EmailChangeRequest.find_or_initialize_by(user_id: @user.id, new_email: email)
user_id: @user.id, new_email: email, requested_by: @guardian.user
)
if change_req.new_record? if change_req.new_record?
change_req.requested_by = @guardian.user
change_req.old_email = old_email change_req.old_email = old_email
change_req.new_email = email change_req.new_email = email
end end

View File

@ -17,6 +17,15 @@ describe EmailUpdater do
expect(updater.errors.messages[:base].first).to be I18n.t("change_email.error_staged") expect(updater.errors.messages[:base].first).to be I18n.t("change_email.error_staged")
end end
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
context "when an admin is changing the email of another user" do context "when an admin is changing the email of another user" do
let(:admin) { Fabricate(:admin) } let(:admin) { Fabricate(:admin) }
let(:updater) { EmailUpdater.new(guardian: admin.guardian, user: user) } let(:updater) { EmailUpdater.new(guardian: admin.guardian, user: user) }

View File

@ -2852,6 +2852,18 @@ describe UsersController do
expect(event[:event_name]).to eq(:user_updated) expect(event[:event_name]).to eq(:user_updated)
expect(event[:params].first).to eq(user) expect(event[:params].first).to eq(user)
end end
it "can destroy duplicate emails" do
EmailChangeRequest.create!(
user: user,
new_email: user.email,
change_state: EmailChangeRequest.states[:authorizing_new]
)
delete "/u/#{user.username}/preferences/email.json", params: { email: user_email.email }
expect(user.email_change_requests).to be_empty
end
end end
describe '#is_local_username' do describe '#is_local_username' do