Merge pull request #10595 from demarches-simplifiees/email-mandant-need-confirmation-ldu
ETQ Mandant, je dois confirmer mon mail avant de recevoir des notifs
This commit is contained in:
commit
7630cc39fa
9 changed files with 153 additions and 8 deletions
|
@ -30,6 +30,24 @@ class Users::ActivateController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def confirm_email
|
||||||
|
user = User.find_by(confirmation_token: params[:token])
|
||||||
|
if user && user.email_verified_at
|
||||||
|
flash[:notice] = "Votre email est déjà vérifié"
|
||||||
|
elsif user && 2.days.ago < user.confirmation_sent_at
|
||||||
|
user.update!(email_verified_at: Time.zone.now)
|
||||||
|
flash[:notice] = 'Votre email a bien été vérifié'
|
||||||
|
else
|
||||||
|
if user.present?
|
||||||
|
flash[:alert] = "Ce lien n'est plus valable, un nouveau lien a été envoyé à l'adresse #{user.email}"
|
||||||
|
User.create_or_promote_to_tiers(user.email, SecureRandom.hex)
|
||||||
|
else
|
||||||
|
flash[:alert] = "Un problème est survenu, vous pouvez nous contacter sur #{Current.contact_email}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
redirect_to root_path(user)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def user_params
|
def user_params
|
||||||
|
|
|
@ -147,10 +147,14 @@ module Users
|
||||||
def update_identite
|
def update_identite
|
||||||
@dossier = dossier
|
@dossier = dossier
|
||||||
@no_description = true
|
@no_description = true
|
||||||
|
email = dossier_params.dig('individual_attributes', 'email')
|
||||||
|
|
||||||
if @dossier.update(dossier_params) && @dossier.individual.valid?
|
if @dossier.update(dossier_params) && @dossier.individual.valid?
|
||||||
# TODO: remove this after proper mandat email validation
|
# verify for_tiers email
|
||||||
@dossier.individual.update!(email_verified_at: Time.zone.now)
|
if email.present?
|
||||||
|
User.create_or_promote_to_tiers(email, SecureRandom.hex, @dossier)
|
||||||
|
end
|
||||||
|
|
||||||
@dossier.update!(autorisation_donnees: true, identity_updated_at: Time.zone.now)
|
@dossier.update!(autorisation_donnees: true, identity_updated_at: Time.zone.now)
|
||||||
flash.notice = t('.identity_saved')
|
flash.notice = t('.identity_saved')
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,21 @@ class UserMailer < ApplicationMailer
|
||||||
reply_to: Current.contact_email)
|
reply_to: Current.contact_email)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def invite_tiers(user, token, dossier)
|
||||||
|
@token = token
|
||||||
|
@user = user
|
||||||
|
@dossier = dossier
|
||||||
|
subject = "Vérification de votre mail"
|
||||||
|
|
||||||
|
configure_defaults_for_user(user)
|
||||||
|
|
||||||
|
bypass_unverified_mail_protection!
|
||||||
|
|
||||||
|
mail(to: user.email,
|
||||||
|
subject: subject,
|
||||||
|
reply_to: Current.contact_email)
|
||||||
|
end
|
||||||
|
|
||||||
def invite_gestionnaire(user, reset_password_token, groupe_gestionnaire)
|
def invite_gestionnaire(user, reset_password_token, groupe_gestionnaire)
|
||||||
@reset_password_token = reset_password_token
|
@reset_password_token = reset_password_token
|
||||||
@user = user
|
@user = user
|
||||||
|
|
|
@ -83,6 +83,12 @@ class User < ApplicationRecord
|
||||||
UserMailer.invite_instructeur(self, set_reset_password_token).deliver_later
|
UserMailer.invite_instructeur(self, set_reset_password_token).deliver_later
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def invite_tiers!(dossier)
|
||||||
|
token = SecureRandom.hex(10)
|
||||||
|
self.update!(confirmation_token: token, confirmation_sent_at: Time.zone.now)
|
||||||
|
UserMailer.invite_tiers(self, token, dossier).deliver_later
|
||||||
|
end
|
||||||
|
|
||||||
def invite_gestionnaire!(groupe_gestionnaire)
|
def invite_gestionnaire!(groupe_gestionnaire)
|
||||||
UserMailer.invite_gestionnaire(self, set_reset_password_token, groupe_gestionnaire).deliver_later
|
UserMailer.invite_gestionnaire(self, set_reset_password_token, groupe_gestionnaire).deliver_later
|
||||||
end
|
end
|
||||||
|
@ -130,6 +136,17 @@ class User < ApplicationRecord
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.create_or_promote_to_tiers(email, password, dossier = nil)
|
||||||
|
user = User
|
||||||
|
.create_with(password: password, confirmed_at: Time.zone.now)
|
||||||
|
.find_or_create_by(email: email)
|
||||||
|
|
||||||
|
if user.valid? && user.unverified_email?
|
||||||
|
user.invite_tiers!(dossier)
|
||||||
|
end
|
||||||
|
user
|
||||||
|
end
|
||||||
|
|
||||||
def self.create_or_promote_to_administrateur(email, password)
|
def self.create_or_promote_to_administrateur(email, password)
|
||||||
user = User.create_or_promote_to_instructeur(email, password)
|
user = User.create_or_promote_to_instructeur(email, password)
|
||||||
|
|
||||||
|
|
27
app/views/user_mailer/invite_tiers.html.haml
Normal file
27
app/views/user_mailer/invite_tiers.html.haml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
- content_for(:title, "Vérification de votre mail sur #{Current.application_name}")
|
||||||
|
|
||||||
|
%p
|
||||||
|
Bonjour,
|
||||||
|
|
||||||
|
%p
|
||||||
|
- if @dossier.present?
|
||||||
|
Un dossier sur la démarche : #{@dossier.procedure.libelle} a été démarré en votre nom par #{@dossier.user.email}.
|
||||||
|
- else
|
||||||
|
Un dossier a été démarré en votre nom sur #{Current.application_name}"
|
||||||
|
|
||||||
|
%p
|
||||||
|
Pour continuer à recevoir les mails concernant votre dossier, vous devez confirmer votre adresse email en cliquant sur ce bouton :
|
||||||
|
= round_button 'Je confirme', users_confirm_email_url(token: @token), :primary
|
||||||
|
|
||||||
|
%p
|
||||||
|
Vous pouvez aussi utiliser ce lien :
|
||||||
|
= link_to(users_confirm_email_url(token: @token), users_confirm_email_url(token: @token))
|
||||||
|
|
||||||
|
%p
|
||||||
|
- if @dossier.present?
|
||||||
|
Pour en savoir plus, veuillez vous rapprocher de #{@dossier.user.email}.
|
||||||
|
- else
|
||||||
|
Nous restons à votre disposition si vous avez besoin d’accompagnement à l'adresse #{link_to CONTACT_EMAIL, "mailto:#{CONTACT_EMAIL}"}.
|
||||||
|
|
||||||
|
|
||||||
|
= render partial: "layouts/mailers/signature"
|
|
@ -277,6 +277,7 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
get 'activate' => '/users/activate#new'
|
get 'activate' => '/users/activate#new'
|
||||||
patch 'activate' => '/users/activate#create'
|
patch 'activate' => '/users/activate#create'
|
||||||
|
get 'confirm_email/:token' => '/users/activate#confirm_email', as: :confirm_email
|
||||||
end
|
end
|
||||||
|
|
||||||
# order matters: we don't want those routes to match /admin/procedures/:id
|
# order matters: we don't want those routes to match /admin/procedures/:id
|
||||||
|
|
|
@ -37,4 +37,54 @@ describe Users::ActivateController, type: :controller do
|
||||||
it { expect(response).to redirect_to(users_activate_path(token: token)) }
|
it { expect(response).to redirect_to(users_activate_path(token: token)) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#confirm_email' do
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
let(:dossier) { create(:dossier, user: user) }
|
||||||
|
|
||||||
|
before { user.invite_tiers!(dossier) }
|
||||||
|
|
||||||
|
context 'when the confirmation token is valid' do
|
||||||
|
before do
|
||||||
|
get :confirm_email, params: { token: user.confirmation_token }
|
||||||
|
user.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates the email_verified_at' do
|
||||||
|
expect(user.email_verified_at).to be_present
|
||||||
|
expect(user.confirmation_token).to be_present
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'redirects to root path with a success notice' do
|
||||||
|
expect(response).to redirect_to(root_path(user))
|
||||||
|
expect(flash[:notice]).to eq('Votre email a bien été vérifié')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the confirmation token is valid but already used' do
|
||||||
|
before do
|
||||||
|
get :confirm_email, params: { token: user.confirmation_token }
|
||||||
|
get :confirm_email, params: { token: user.confirmation_token }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'redirects to root path with an explanation notice' do
|
||||||
|
expect(response).to redirect_to(root_path(user))
|
||||||
|
expect(flash[:notice]).to eq('Votre email est déjà vérifié')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the confirmation token is too old or not valid' do
|
||||||
|
subject { get :confirm_email, params: { token: user.confirmation_token } }
|
||||||
|
|
||||||
|
before do
|
||||||
|
user.update!(confirmation_sent_at: 3.days.ago)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'redirects to root path with an explanation notice and it send a new link if user present' do
|
||||||
|
expect { subject }.to have_enqueued_mail(UserMailer, :invite_tiers)
|
||||||
|
expect(response).to redirect_to(root_path(user))
|
||||||
|
expect(flash[:alert]).to eq("Ce lien n'est plus valable, un nouveau lien a été envoyé à l'adresse #{user.email}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -162,19 +162,21 @@ describe Users::DossiersController, type: :controller do
|
||||||
describe 'update_identite' do
|
describe 'update_identite' do
|
||||||
let(:procedure) { create(:procedure, :for_individual) }
|
let(:procedure) { create(:procedure, :for_individual) }
|
||||||
let(:dossier) { create(:dossier, user: user, procedure: procedure) }
|
let(:dossier) { create(:dossier, user: user, procedure: procedure) }
|
||||||
let(:now) { Time.zone.parse('01/01/2100') }
|
|
||||||
|
|
||||||
subject { post :update_identite, params: { id: dossier.id, dossier: dossier_params } }
|
subject { post :update_identite, params: { id: dossier.id, dossier: dossier_params } }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
Timecop.freeze(now) do
|
|
||||||
subject
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with correct individual and dossier params' do
|
context 'with correct individual and dossier params' do
|
||||||
let(:dossier_params) { { individual_attributes: { gender: 'M', nom: 'Mouse', prenom: 'Mickey' } } }
|
let(:dossier_params) { { individual_attributes: { gender: 'M', nom: 'Mouse', prenom: 'Mickey' } } }
|
||||||
|
let(:now) { Time.zone.parse('01/01/2100') }
|
||||||
|
before do
|
||||||
|
Timecop.freeze(now) do
|
||||||
|
subject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it do
|
it do
|
||||||
expect(response).to redirect_to(brouillon_dossier_path(dossier))
|
expect(response).to redirect_to(brouillon_dossier_path(dossier))
|
||||||
|
@ -185,6 +187,7 @@ describe Users::DossiersController, type: :controller do
|
||||||
context 'when the identite cannot be updated by the user' do
|
context 'when the identite cannot be updated by the user' do
|
||||||
let(:dossier) { create(:dossier, :with_individual, :en_instruction, user: user, procedure: procedure) }
|
let(:dossier) { create(:dossier, :with_individual, :en_instruction, user: user, procedure: procedure) }
|
||||||
let(:dossier_params) { { individual_attributes: { gender: 'M', nom: 'Mouse', prenom: 'Mickey' } } }
|
let(:dossier_params) { { individual_attributes: { gender: 'M', nom: 'Mouse', prenom: 'Mickey' } } }
|
||||||
|
before { subject }
|
||||||
|
|
||||||
it 'redirects to the dossiers list' do
|
it 'redirects to the dossiers list' do
|
||||||
expect(response).to redirect_to(dossier_path(dossier))
|
expect(response).to redirect_to(dossier_path(dossier))
|
||||||
|
@ -194,6 +197,7 @@ describe Users::DossiersController, type: :controller do
|
||||||
|
|
||||||
context 'with incorrect individual and dossier params' do
|
context 'with incorrect individual and dossier params' do
|
||||||
let(:dossier_params) { { individual_attributes: { gender: '', nom: '', prenom: '' } } }
|
let(:dossier_params) { { individual_attributes: { gender: '', nom: '', prenom: '' } } }
|
||||||
|
before { subject }
|
||||||
|
|
||||||
it do
|
it do
|
||||||
expect(response).not_to have_http_status(:redirect)
|
expect(response).not_to have_http_status(:redirect)
|
||||||
|
@ -201,17 +205,20 @@ describe Users::DossiersController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a dossier is in broullon, for_tiers and we want to update the individual' do
|
context 'when a dossier is in brouillon, for_tiers and we want to update the individual' do
|
||||||
let(:dossier) { create(:dossier, :for_tiers_without_notification, state: "brouillon", user: user, procedure: procedure) }
|
let(:dossier) { create(:dossier, :for_tiers_without_notification, state: "brouillon", user: user, procedure: procedure) }
|
||||||
let(:dossier_params) { { individual_attributes: { gender: 'M', nom: 'Mouse', prenom: 'Mickey', email: 'mickey@gmail.com', notification_method: 'email' } } }
|
let(:dossier_params) { { individual_attributes: { gender: 'M', nom: 'Mouse', prenom: 'Mickey', email: 'mickey@gmail.com', notification_method: 'email' } } }
|
||||||
|
|
||||||
it 'updates the individual with valid notification_method' do
|
it 'updates the individual with valid notification_method' do
|
||||||
|
expect { subject }.to have_enqueued_mail(UserMailer, :invite_tiers)
|
||||||
|
.and change(User, :count).by(1)
|
||||||
|
|
||||||
dossier.reload
|
dossier.reload
|
||||||
individual = dossier.individual.reload
|
individual = dossier.individual.reload
|
||||||
expect(individual.errors.full_messages).to be_empty
|
expect(individual.errors.full_messages).to be_empty
|
||||||
expect(individual.notification_method).to eq('email')
|
expect(individual.notification_method).to eq('email')
|
||||||
expect(individual.email).to eq('mickey@gmail.com')
|
expect(individual.email).to eq('mickey@gmail.com')
|
||||||
expect(individual.email_verified_at).to be_present
|
expect(individual.email_verified_at).to eq nil
|
||||||
expect(response).to redirect_to(brouillon_dossier_path(dossier))
|
expect(response).to redirect_to(brouillon_dossier_path(dossier))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -219,6 +226,8 @@ describe Users::DossiersController, type: :controller do
|
||||||
let(:dossier_params) { { mandataire_first_name: "Jean", mandataire_last_name: "Dupont" } }
|
let(:dossier_params) { { mandataire_first_name: "Jean", mandataire_last_name: "Dupont" } }
|
||||||
|
|
||||||
it 'updates the dossier mandataire first and last name' do
|
it 'updates the dossier mandataire first and last name' do
|
||||||
|
expect { subject }.not_to have_enqueued_mail(UserMailer, :invite_tiers)
|
||||||
|
|
||||||
dossier.reload
|
dossier.reload
|
||||||
individual = dossier.individual.reload
|
individual = dossier.individual.reload
|
||||||
expect(dossier.errors.full_messages).to be_empty
|
expect(dossier.errors.full_messages).to be_empty
|
||||||
|
|
|
@ -24,6 +24,10 @@ class UserMailerPreview < ActionMailer::Preview
|
||||||
UserMailer.invite_instructeur(user, 'aedfa0d0')
|
UserMailer.invite_instructeur(user, 'aedfa0d0')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def invite_tiers
|
||||||
|
UserMailer.invite_tiers(user, 'aedfa0d0', Dossier.first)
|
||||||
|
end
|
||||||
|
|
||||||
def invite_gestionnaire
|
def invite_gestionnaire
|
||||||
groupe_gestionnaire = GroupeGestionnaire.new(name: 'Root admins group')
|
groupe_gestionnaire = GroupeGestionnaire.new(name: 'Root admins group')
|
||||||
UserMailer.invite_gestionnaire(user, 'aedfa0d0', groupe_gestionnaire)
|
UserMailer.invite_gestionnaire(user, 'aedfa0d0', groupe_gestionnaire)
|
||||||
|
|
Loading…
Reference in a new issue