diff --git a/app/controllers/profile_controller.rb b/app/controllers/profile_controller.rb index a1ee71bf..878831d5 100644 --- a/app/controllers/profile_controller.rb +++ b/app/controllers/profile_controller.rb @@ -9,7 +9,12 @@ class ProfileController < ApplicationController def update_contact if current_user.update(contact_params) - redirect_to settings_profile_index_path, notice: I18n.t('contact_information_has_been_update') + if current_user.try(:pending_reconfirmation?) && current_user.previous_changes.key?(:unconfirmed_email) + redirect_to settings_profile_index_path, + notice: I18n.t('a_confirmation_email_has_been_sent_to_the_new_email_address') + else + redirect_to settings_profile_index_path, notice: I18n.t('contact_information_has_been_update') + end else render :index, status: :unprocessable_content end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 39555b59..9ab9ca68 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -65,7 +65,12 @@ class UsersController < ApplicationController end if @user.update(attrs.except(*(current_user == @user ? %i[password otp_required_for_login role] : %i[password]))) - redirect_back fallback_location: settings_users_path, notice: I18n.t('user_has_been_updated') + if @user.try(:pending_reconfirmation?) && @user.previous_changes.key?(:unconfirmed_email) + redirect_back fallback_location: settings_users_path, + notice: I18n.t('a_confirmation_email_has_been_sent_to_the_new_email_address') + else + redirect_back fallback_location: settings_users_path, notice: I18n.t('user_has_been_updated') + end else render turbo_stream: turbo_stream.replace(:modal, template: 'users/edit'), status: :unprocessable_content end diff --git a/app/models/user.rb b/app/models/user.rb index 83e88f08..7eabb059 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -6,6 +6,9 @@ # # id :bigint not null, primary key # archived_at :datetime +# confirmation_sent_at :datetime +# confirmation_token :string +# confirmed_at :datetime # consumed_timestep :integer # current_sign_in_at :datetime # current_sign_in_ip :string @@ -24,8 +27,9 @@ # reset_password_token :string # role :string not null # sign_in_count :integer default(0), not null +# unconfirmed_email :string # unlock_token :string -# uuid :text not null +# uuid :string not null # created_at :datetime not null # updated_at :datetime not null # account_id :bigint not null diff --git a/app/views/profile/index.html.erb b/app/views/profile/index.html.erb index c5422b00..9f1ec645 100644 --- a/app/views/profile/index.html.erb +++ b/app/views/profile/index.html.erb @@ -18,6 +18,11 @@
<%= f.label :email, t('email'), class: 'label' %> <%= f.email_field :email, autocomplete: 'off', class: 'base-input' %> + <% if current_user.try(:pending_reconfirmation?) %> + + <% end %>
<%= f.button button_title(title: t('update'), disabled_with: t('updating')), class: 'base-button' %> diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb index 5ceaeabc..c7652916 100644 --- a/app/views/users/_form.html.erb +++ b/app/views/users/_form.html.erb @@ -13,6 +13,11 @@
<%= f.label :email, t('email'), class: 'label' %> <%= f.email_field :email, required: true, class: 'base-input' %> + <% if user.try(:pending_reconfirmation?) %> + + <% end %> <% if user.persisted? && Accounts.can_send_emails?(current_account) %> <%= t('click_here_to_send_a_reset_password_email_html') %> diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb index a0849cec..e49a8563 100644 --- a/app/views/users/index.html.erb +++ b/app/views/users/index.html.erb @@ -52,7 +52,13 @@ <%= user.full_name %> - <%= user.email %> + <% if user.try(:pending_reconfirmation?) %> + <%= user.unconfirmed_email %> +
+ (<%= t('unconfirmed') %>) + <% else %> + <%= user.email %> + <% end %> diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index d7b80f1a..1329ce87 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -31,6 +31,7 @@ end # # Use this hook to configure devise mailer, warden hooks and so forth. # Many of these configuration options can be set straight in your model. +# rubocop:disable Metrics/BlockLength Devise.setup do |config| config.warden do |manager| manager.default_strategies(scope: :user).unshift(:two_factor_authenticatable) @@ -166,7 +167,7 @@ Devise.setup do |config| # without confirming their account. # Default is 0.days, meaning the user cannot access the website without # confirming their account. - # config.allow_unconfirmed_access_for = 2.days + config.allow_unconfirmed_access_for = nil # A period that the user is allowed to confirm their account before their # token becomes invalid. For example, if set to 3.days, the user can confirm @@ -332,3 +333,4 @@ Devise.setup do |config| ActiveSupport.run_load_hooks(:devise_config, config) end +# rubocop:enable Metrics/BlockLength diff --git a/config/locales/i18n.yml b/config/locales/i18n.yml index b9784c04..0d47623a 100644 --- a/config/locales/i18n.yml +++ b/config/locales/i18n.yml @@ -71,7 +71,7 @@ en: &en team_access: Team access document_download_filename_format: Document download filename format docuseal_trusted_signature: DocuSeal Trusted Signature - hello_name: Hello %{name} + hello_name: Hi %{name} you_are_invited_to_product_name: You are invited to %{product_name} you_have_been_invited_to_account_name_product_name_please_sign_up_using_the_link_below_: 'You have been invited to %{account_name} %{product_name}. Please sign up using the link below:' sent_using_product_name_in_testing_mode_html: 'Sent using %{product_name} in testing mode' @@ -861,6 +861,19 @@ en: &en reports: Reports completed_submissions: Completed submissions sms: SMS + a_confirmation_email_has_been_sent_to_the_new_email_address: A confirmation email has been sent to the new email address. + email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} email address is awaiting confirmation. Follow the link in the email to confirm." + please_confirm_your_email_address_using_the_link_below_: 'Please confirm your email address using the link below:' + confirm_email: Confirm email + unconfirmed: Unconfirmed + devise: + confirmations: + confirmed: Your email address has been successfully confirmed. + failure: + unconfirmed: You have to confirm your email address before continuing. + mailer: + confirmation_instructions: + subject: Confirm your email address submission_sources: api: API bulk: Bulk Send @@ -1808,6 +1821,19 @@ es: &es reports: Informes completed_submissions: Envíos completados sms: SMS + a_confirmation_email_has_been_sent_to_the_new_email_address: Se ha enviado un correo electrónico de confirmación a la nueva dirección de correo electrónico. + email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} está pendiente de confirmación. Sigue el enlace en el correo para confirmarla." + please_confirm_your_email_address_using_the_link_below_: 'Por favor, confirma tu dirección de correo electrónico utilizando el enlace a continuación:' + confirm_email: Confirmar correo + unconfirmed: No confirmado + devise: + confirmations: + confirmed: Tu dirección de correo electrónico ha sido confirmada correctamente. + failure: + unconfirmed: Debes confirmar tu dirección de correo electrónico antes de continuar. + mailer: + confirmation_instructions: + subject: Confirma tu dirección de correo electrónico submission_sources: api: API bulk: Envío masivo @@ -2756,6 +2782,19 @@ it: &it reports: Rapporti completed_submissions: Invii completati sms: SMS + a_confirmation_email_has_been_sent_to_the_new_email_address: È stata inviata un'email di conferma al nuovo indirizzo email. + email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} è in attesa di conferma. Segui il link nell'email per confermare." + please_confirm_your_email_address_using_the_link_below_: 'Conferma il tuo indirizzo email utilizzando il link qui sotto:' + confirm_email: Conferma email + unconfirmed: Non confermato + devise: + confirmations: + confirmed: Il tuo indirizzo email è stato confermato con successo. + failure: + unconfirmed: Devi confermare il tuo indirizzo email prima di continuare. + mailer: + confirmation_instructions: + subject: Conferma il tuo indirizzo email submission_sources: api: API bulk: Invio massivo @@ -3700,6 +3739,19 @@ fr: &fr reports: Rapports completed_submissions: Soumissions terminées sms: SMS + a_confirmation_email_has_been_sent_to_the_new_email_address: Un e-mail de confirmation a été envoyé à la nouvelle adresse e-mail. + email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} est en attente de confirmation. Suivez le lien dans l'e-mail pour la confirmer." + please_confirm_your_email_address_using_the_link_below_: 'Veuillez confirmer votre adresse e-mail en utilisant le lien ci-dessous :' + confirm_email: "Confirmer l'e-mail" + unconfirmed: Non confirmé + devise: + confirmations: + confirmed: Votre adresse e-mail a été confirmée avec succès. + failure: + unconfirmed: Vous devez confirmer votre adresse e-mail avant de continuer. + mailer: + confirmation_instructions: + subject: Confirmez votre adresse e-mail submission_sources: api: API bulk: Envoi en masse @@ -4647,6 +4699,19 @@ pt: &pt reports: Relatórios completed_submissions: Envios concluídos sms: SMS + a_confirmation_email_has_been_sent_to_the_new_email_address: Um e-mail de confirmação foi enviado para o novo endereço de e-mail. + email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} está aguardando confirmação. Siga o link enviado para esse endereço de e-mail para confirmar." + please_confirm_your_email_address_using_the_link_below_: 'Por favor, confirme seu endereço de e-mail usando o link abaixo:' + confirm_email: Confirmar e-mail + unconfirmed: Não confirmado + devise: + confirmations: + confirmed: Seu endereço de e-mail foi confirmado com sucesso. + failure: + unconfirmed: Você deve confirmar seu endereço de e-mail antes de continuar. + mailer: + confirmation_instructions: + subject: Confirme seu endereço de e-mail submission_sources: api: API bulk: Envio em massa @@ -5594,6 +5659,19 @@ de: &de reports: Berichte completed_submissions: Abgeschlossene Übermittlungen sms: SMS + a_confirmation_email_has_been_sent_to_the_new_email_address: Eine Bestätigungs-E-Mail wurde an die neue E-Mail-Adresse gesendet. + email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} wartet auf Bestätigung. Folgen Sie dem Link in der E-Mail, um sie zu bestätigen." + please_confirm_your_email_address_using_the_link_below_: 'Bitte bestätigen Sie Ihre E-Mail-Adresse über den folgenden Link:' + confirm_email: E-Mail bestätigen + unconfirmed: Unbestätigt + devise: + confirmations: + confirmed: Ihre E-Mail-Adresse wurde erfolgreich bestätigt. + failure: + unconfirmed: Sie müssen Ihre E-Mail-Adresse bestätigen, bevor Sie fortfahren. + mailer: + confirmation_instructions: + subject: Bestätigen Sie Ihre E-Mail-Adresse submission_sources: api: API bulk: Massenversand @@ -6902,6 +6980,19 @@ nl: &nl reports: Rapporten completed_submissions: Voltooide inzendingen sms: SMS + a_confirmation_email_has_been_sent_to_the_new_email_address: Er is een bevestigingsmail verzonden naar het nieuwe e-mailadres. + email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} wacht op bevestiging. Volg de link in de e-mail om te bevestigen." + please_confirm_your_email_address_using_the_link_below_: 'Bevestig je e-mailadres via de onderstaande link:' + confirm_email: E-mailadres bevestigen + unconfirmed: Onbevestigd + devise: + confirmations: + confirmed: Je e-mailadres is succesvol bevestigd. + failure: + unconfirmed: Je moet je e-mailadres bevestigen voordat je verdergaat. + mailer: + confirmation_instructions: + subject: Bevestig je e-mailadres submission_sources: api: API bulk: Bulkverzending diff --git a/db/migrate/20251125194305_add_confirmable_to_users.rb b/db/migrate/20251125194305_add_confirmable_to_users.rb new file mode 100644 index 00000000..ca946854 --- /dev/null +++ b/db/migrate/20251125194305_add_confirmable_to_users.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class AddConfirmableToUsers < ActiveRecord::Migration[8.0] + def change + add_column :users, :confirmation_token, :string + add_column :users, :confirmed_at, :datetime + add_column :users, :confirmation_sent_at, :datetime + add_column :users, :unconfirmed_email, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 5ceb1f31..ea115d78 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_11_21_113910) do +ActiveRecord::Schema[8.0].define(version: 2025_11_25_194305) do # These are extensions that must be enabled in order to support this database enable_extension "btree_gin" enable_extension "plpgsql" @@ -451,6 +451,10 @@ ActiveRecord::Schema[8.0].define(version: 2025_11_21_113910) do t.string "otp_secret" t.integer "consumed_timestep" t.boolean "otp_required_for_login", default: false, null: false + t.string "confirmation_token" + t.datetime "confirmed_at" + t.datetime "confirmation_sent_at" + t.string "unconfirmed_email" t.index ["account_id"], name: "index_users_on_account_id" t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true