discourse/app/controllers/users_email_controller.rb
Ted Johansson d63f1826fe
FEATURE: User fields required for existing users - Part 2 (#27172)
We want to allow admins to make new required fields apply to existing users. In order for this to work we need to have a way to make those users fill up the fields on their next page load. This is very similar to how adding a 2FA requirement post-fact works. Users will be redirected to a page where they can fill up the remaining required fields, and until they do that they won't be able to do anything else.
2024-06-25 19:32:18 +08:00

131 lines
3.9 KiB
Ruby

# frozen_string_literal: true
class UsersEmailController < ApplicationController
requires_login only: %i[index update]
skip_before_action :check_xhr, only: %i[show_confirm_old_email show_confirm_new_email]
skip_before_action :redirect_to_login_if_required,
:redirect_to_profile_if_required,
only: %i[
show_confirm_old_email
show_confirm_new_email
confirm_old_email
confirm_new_email
]
def index
end
def create
return render json: failed_json, status: 410 if !SiteSetting.enable_secondary_emails
params.require(:email)
user = fetch_user_from_params
RateLimiter.new(user, "email-hr-#{request.remote_ip}", 6, 1.hour).performed!
RateLimiter.new(user, "email-min-#{request.remote_ip}", 3, 1.minute).performed!
updater = EmailUpdater.new(guardian: guardian, user: user)
updater.change_to(params[:email], add: true)
return render_json_error(updater.errors.full_messages) if updater.errors.present?
render body: nil
rescue RateLimiter::LimitExceeded
render_json_error(I18n.t("rate_limiter.slow_down"))
end
def update
params.require(:email)
user = fetch_user_from_params
RateLimiter.new(user, "email-hr-#{request.remote_ip}", 6, 1.hour).performed!
RateLimiter.new(user, "email-min-#{request.remote_ip}", 3, 1.minute).performed!
updater = EmailUpdater.new(guardian: guardian, user: user)
updater.change_to(params[:email])
return render_json_error(updater.errors.full_messages) if updater.errors.present?
render body: nil
rescue RateLimiter::LimitExceeded
render_json_error(I18n.t("rate_limiter.slow_down"))
end
def confirm_new_email
change_request = load_change_request(:new)
result =
run_second_factor!(SecondFactor::Actions::ConfirmEmail, target_user: change_request.user)
if result.no_second_factors_enabled? || result.second_factor_auth_completed?
updater = EmailUpdater.new
if updater.confirm(params[:token]) == :complete
updater.user.user_stat.reset_bounce_score!
render json: success_json
else
render json: { error: I18n.t("change_email.already_done") }, status: 400
end
end
end
def show_confirm_new_email
return render "default/empty" if request.format.html?
change_request = load_change_request(:new)
render json: {
new_email: change_request.new_email,
old_email: change_request.old_email,
token: params[:token],
}
end
def confirm_old_email
load_change_request(:old)
updater = EmailUpdater.new
if updater.confirm(params[:token]) == :authorizing_new
render json: success_json
else
render json: { error: I18n.t("change_email.already_done") }, status: 400
end
end
def show_confirm_old_email
return render "default/empty" if request.format.html?
change_request = load_change_request(:old)
render json: {
new_email: change_request.new_email,
old_email: change_request.old_email,
token: params[:token],
}
end
private
def load_change_request(type)
expires_now
token = EmailToken.confirmable(params[:token], scope: EmailToken.scopes[:email_update])
raise Discourse::NotFound if !token || !token.user
if current_user && token.user.id != current_user.id
raise Discourse::InvalidAccess.new "You are logged in, but this email change link belongs to another user account. Please log out and try again."
end
change_request_params =
if type == :old
{ old_email_token_id: token.id, change_state: EmailChangeRequest.states[:authorizing_old] }
elsif type == :new
{ new_email_token_id: token.id, change_state: EmailChangeRequest.states[:authorizing_new] }
end
token.user&.email_change_requests&.find_by!(**change_request_params)
end
end