diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index e6a64f2cd..592f16f2c 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -149,6 +149,8 @@ module Users @no_description = true if @dossier.update(dossier_params) && @dossier.individual.valid? + # TODO: remove this after proper mandat email validation + @dossier.individual.update!(email_verified_at: Time.zone.now) @dossier.update!(autorisation_donnees: true, identity_updated_at: Time.zone.now) flash.notice = t('.identity_saved') diff --git a/app/models/user.rb b/app/models/user.rb index 3a9aebfb2..d047ab1d1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -63,6 +63,7 @@ class User < ApplicationRecord # Callback provided by Devise def after_confirmation + update!(email_verified_at: Time.zone.now) link_invites! end @@ -98,7 +99,7 @@ class User < ApplicationRecord def self.create_or_promote_to_instructeur(email, password, administrateurs: []) user = User - .create_with(password: password, confirmed_at: Time.zone.now) + .create_with(password: password, confirmed_at: Time.zone.now, email_verified_at: Time.zone.now) .find_or_create_by(email: email) if user.valid? @@ -137,7 +138,7 @@ class User < ApplicationRecord def self.create_or_promote_to_expert(email, password) user = User - .create_with(password: password, confirmed_at: Time.zone.now) + .create_with(password: password, confirmed_at: Time.zone.now, email_verified_at: Time.zone.now) .find_or_create_by(email: email) if user.valid? diff --git a/app/tasks/maintenance/prefill_individual_email_verified_at_task.rb b/app/tasks/maintenance/prefill_individual_email_verified_at_task.rb new file mode 100644 index 000000000..fa6e045d2 --- /dev/null +++ b/app/tasks/maintenance/prefill_individual_email_verified_at_task.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# We are going to confirm the various email addresses of the users in the system. +# Individual model (mandant) needs their email_verified_at attribute to be set in order to receive emails. +# This task sets the email_verified_at attribute to the current time for all the individual to be backward compatible +# See https://github.com/demarches-simplifiees/demarches-simplifiees.fr/issues/10450 +module Maintenance + class PrefillIndividualEmailVerifiedAtTask < MaintenanceTasks::Task + def collection + Individual.in_batches + end + + def process(batch_of_individuals) + batch_of_individuals.update_all(email_verified_at: Time.zone.now) + end + end +end diff --git a/app/tasks/maintenance/prefill_user_email_verified_at_task.rb b/app/tasks/maintenance/prefill_user_email_verified_at_task.rb new file mode 100644 index 000000000..ad3ba6f5b --- /dev/null +++ b/app/tasks/maintenance/prefill_user_email_verified_at_task.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# We are going to confirm the various email addresses of the users in the system. +# User model needs their email_verified_at attribute to be set in order to receive emails. +# This task sets the email_verified_at attribute to the current time for all users to be backward compatible +# See https://github.com/demarches-simplifiees/demarches-simplifiees.fr/issues/10450 +module Maintenance + class PrefillUserEmailVerifiedAtTask < MaintenanceTasks::Task + def collection + User.in_batches + end + + def process(batch_of_users) + batch_of_users.update_all(email_verified_at: Time.zone.now) + end + end +end diff --git a/db/migrate/20240524120336_add_email_verified_at_column_to_users.rb b/db/migrate/20240524120336_add_email_verified_at_column_to_users.rb new file mode 100644 index 000000000..176b9d2ab --- /dev/null +++ b/db/migrate/20240524120336_add_email_verified_at_column_to_users.rb @@ -0,0 +1,5 @@ +class AddEmailVerifiedAtColumnToUsers < ActiveRecord::Migration[7.0] + def change + add_column :users, :email_verified_at, :datetime + end +end diff --git a/db/migrate/20240527090508_add_email_verified_at_column_to_individuals.rb b/db/migrate/20240527090508_add_email_verified_at_column_to_individuals.rb new file mode 100644 index 000000000..b77aea273 --- /dev/null +++ b/db/migrate/20240527090508_add_email_verified_at_column_to_individuals.rb @@ -0,0 +1,5 @@ +class AddEmailVerifiedAtColumnToIndividuals < ActiveRecord::Migration[7.0] + def change + add_column :individuals, :email_verified_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 22ee0febd..74b41f6c7 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[7.0].define(version: 2024_04_17_053843) do +ActiveRecord::Schema[7.0].define(version: 2024_05_27_090508) do # These are extensions that must be enabled in order to support this database enable_extension "pg_buffercache" enable_extension "pg_stat_statements" @@ -752,6 +752,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_04_17_053843) do t.datetime "created_at", precision: nil t.integer "dossier_id" t.string "email" + t.datetime "email_verified_at" t.string "gender" t.string "nom" t.string "notification_method" @@ -1137,6 +1138,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_04_17_053843) do t.datetime "current_sign_in_at", precision: nil t.string "current_sign_in_ip" t.string "email", default: "", null: false + t.datetime "email_verified_at" t.string "encrypted_password", default: "", null: false t.integer "failed_attempts", default: 0, null: false t.datetime "inactive_close_to_expiration_notice_sent_at" diff --git a/db/seeds.rb b/db/seeds.rb index 52f97d02f..1a021ad23 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -13,7 +13,8 @@ SuperAdmin.create!(email: default_user, password: default_password) user = User.create!( email: default_user, password: default_password, - confirmed_at: Time.zone.now + confirmed_at: Time.zone.now, + email_verified_at: Time.zone.now ) user.create_instructeur! user.create_administrateur! diff --git a/spec/controllers/users/dossiers_controller_spec.rb b/spec/controllers/users/dossiers_controller_spec.rb index 8dd165c01..8d3b702f9 100644 --- a/spec/controllers/users/dossiers_controller_spec.rb +++ b/spec/controllers/users/dossiers_controller_spec.rb @@ -211,6 +211,7 @@ describe Users::DossiersController, type: :controller do expect(individual.errors.full_messages).to be_empty expect(individual.notification_method).to eq('email') expect(individual.email).to eq('mickey@gmail.com') + expect(individual.email_verified_at).to be_present expect(response).to redirect_to(brouillon_dossier_path(dossier)) end diff --git a/spec/models/france_connect_information_spec.rb b/spec/models/france_connect_information_spec.rb index 621c729b3..1dcb149cc 100644 --- a/spec/models/france_connect_information_spec.rb +++ b/spec/models/france_connect_information_spec.rb @@ -19,6 +19,7 @@ describe FranceConnectInformation, type: :model do it do subject expect(fci.user.email).to eq('a@email.com') + expect(fci.user.email_verified_at).to be_present end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 336d78886..409507d37 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -16,6 +16,12 @@ describe User, type: :model do user.confirm expect(user.reload.invites.size).to eq(2) end + + it 'verifies its email' do + expect(user.email_verified_at).to be_nil + user.confirm + expect(user.email_verified_at).to be_present + end end describe '#owns?' do @@ -111,6 +117,7 @@ describe User, type: :model do user = subject expect(user.valid_password?(password)).to be true expect(user.confirmed_at).to be_present + expect(user.email_verified_at).to be_present expect(user.instructeur).to be_present end @@ -184,6 +191,7 @@ describe User, type: :model do user = subject expect(user.valid_password?(password)).to be true expect(user.confirmed_at).to be_present + expect(user.email_verified_at).to be_present expect(user.expert).to be_present end end @@ -214,6 +222,18 @@ describe User, type: :model do end end + describe '.create_or_promote_to_gestionnaire' do + let(:email) { 'inst1@gmail.com' } + let(:password) { 'un super password !' } + + subject { User.create_or_promote_to_gestionnaire(email, password) } + + it 'verifies its email' do + user = subject + expect(user.email_verified_at).to be_present + end + end + describe 'invite_administrateur!' do let(:super_admin) { create(:super_admin) } let(:administrateur) { create(:administrateur) }