diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb index bbcf408650d3bf29afa29e8b48be2c59ccf95dcb..93db454dafc51d8967cb6bbff4db1a048782de1b 100644 --- a/app/helpers/form_helper.rb +++ b/app/helpers/form_helper.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true module FormHelper - def form_errors(model, type: 'form', truncate: [], custom_message: []) + def form_errors(model, type: 'form', truncate: [], custom_message: [], custom_headline: nil) errors = model.errors return unless errors.any? - headline = n_( + headline = custom_headline || n_( 'The %{type} contains the following error:', 'The %{type} contains the following errors:', errors.count diff --git a/app/models/user.rb b/app/models/user.rb index 00c338b6f2735e4ef85dd3bf84057bad150ee86d..35b0a73049ee74c9a978528a87906b150799ef6c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1188,10 +1188,23 @@ def will_save_change_to_login? end def unique_email - return if errors.added?(:email, _('has already been taken')) + email_taken = errors.added?(:email, _('has already been taken')) - if !emails.exists?(email: email) && Email.exists?(email: email) + if !email_taken && !emails.exists?(email: email) && Email.exists?(email: email) errors.add(:email, _('has already been taken')) + email_taken = true + end + + if email_taken && + ::Feature.enabled?(:delay_delete_own_user) && + User.find_by_any_email(email)&.deleted_own_account? + + help_page_url = Rails.application.routes.url_helpers.help_page_url( + 'user/profile/account/delete_account', + anchor: 'delete-your-own-account' + ) + + errors.add(:email, _('is linked to an account pending deletion.'), help_page_url: help_page_url) end end diff --git a/app/views/devise/shared/_error_messages.html.haml b/app/views/devise/shared/_error_messages.html.haml index caebda72b9cee22f1f140dff06f8850add013140..c1c73a1b753a5fd596242e86ebdaa7912d9164ae 100644 --- a/app/views/devise/shared/_error_messages.html.haml +++ b/app/views/devise/shared/_error_messages.html.haml @@ -1,9 +1,2 @@ -- if resource.errors.any? - = render Pajamas::AlertComponent.new(title: I18n.t("errors.messages.not_saved", count: resource.errors.count, resource: resource.class.model_name.human.downcase), - variant: :danger, - dismissible: false, - alert_options: { id: 'error_explanation', class: 'gl-mb-3'}) do |c| - - c.with_body do - %ul.gl-pl-4 - - resource.errors.full_messages.each do |message| - %li= message +- headline = I18n.t("errors.messages.not_saved", count: resource.errors.count, resource: resource.class.model_name.human.downcase) += form_errors(resource, custom_headline: headline) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 1e9facaa8a9558690511d438fb7e8038a885131f..f196be6b97c81ee7aa71a3fa206041c243f0d5c3 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -60769,6 +60769,9 @@ msgstr "" msgid "is invalid because there is upstream lock" msgstr "" +msgid "is linked to an account pending deletion." +msgstr "" + msgid "is not" msgstr "" diff --git a/spec/helpers/form_helper_spec.rb b/spec/helpers/form_helper_spec.rb index 0db48dfc28eeeddf7eb4e0b34ab842593b22c5ee..1048b58d1e4959a02ae1caaac149831f0e9c6f2d 100644 --- a/spec/helpers/form_helper_spec.rb +++ b/spec/helpers/form_helper_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe FormHelper do +RSpec.describe FormHelper, feature_category: :shared do include Devise::Test::ControllerHelpers describe '#dropdown_max_select' do @@ -83,6 +83,14 @@ .to include('The form contains the following errors:') end + it 'uses passed custom headline' do + resource = double(errors: errors_stub('A')) + + result = helper.form_errors(resource, custom_headline: 'There were errors:') + expect(result).to include('There were errors:') + expect(result).not_to include('The form contains the following error:') + end + it 'renders each message' do model = double(errors: errors_stub('Error 1', 'Error 2', 'Error 3')) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 86cfb1c35cfdddf392eff0bba9631c32f99d1d5a..861ab5341b67054b49a005405744cd530de4ed55 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -8501,4 +8501,39 @@ def owner_class_attribute_default; end end end end + + context 'when email is not unique' do + let_it_be(:existing_user) { create(:user) } + + subject(:new_user) { build(:user, email: existing_user.email).tap { |user| user.valid? } } + + shared_examples 'it does not add account pending deletion error message' do + it 'does not add account pending deletion error message' do + expect(new_user.errors.full_messages).to include('Email has already been taken') + expect(new_user.errors.full_messages).not_to include('Email is linked to an account pending deletion') + end + end + + context 'when existing account is pending deletion' do + before do + UserCustomAttribute.set_deleted_own_account_at(existing_user) + end + + it 'adds expected error messages' do + expect(new_user.errors.full_messages).to include('Email has already been taken', 'Email is linked to an account pending deletion.') + end + + context 'when delay_delete_own_user feature flag is disabled' do + before do + stub_feature_flags(delay_delete_own_user: false) + end + + it_behaves_like 'it does not add account pending deletion error message' + end + end + + context 'when existing account is not pending deletion' do + it_behaves_like 'it does not add account pending deletion error message' + end + end end