Merge pull request #6108 from tchak/enable-user-destruction

Enable user destruction
This commit is contained in:
Paul Chavard 2021-05-04 12:31:02 +02:00 committed by GitHub
commit 71a48c99bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 246 additions and 157 deletions

View file

@ -41,7 +41,7 @@ module Manager
def export_mail_brouillons def export_mail_brouillons
dossiers = procedure.dossiers.state_brouillon.includes(:user) dossiers = procedure.dossiers.state_brouillon.includes(:user)
emails = dossiers.map { |d| d.user.email }.sort.uniq emails = dossiers.map { |dossier| dossier.user_email_for(:display) }.sort.uniq
date = Time.zone.now.strftime('%d-%m-%Y') date = Time.zone.now.strftime('%d-%m-%Y')
send_data(emails.join("\n"), :filename => "brouillons-#{procedure.id}-au-#{date}.csv") send_data(emails.join("\n"), :filename => "brouillons-#{procedure.id}-au-#{date}.csv")
end end

View file

@ -143,7 +143,7 @@ module Users
if passage_en_construction? && errors.blank? if passage_en_construction? && errors.blank?
@dossier.passer_en_construction! @dossier.passer_en_construction!
NotificationMailer.send_initiated_notification(@dossier).deliver_later NotificationMailer.send_en_construction_notification(@dossier).deliver_later
@dossier.groupe_instructeur.instructeurs.with_instant_email_dossier_notifications.each do |instructeur| @dossier.groupe_instructeur.instructeurs.with_instant_email_dossier_notifications.each do |instructeur|
DossierMailer.notify_new_dossier_depose_to_instructeur(@dossier, instructeur.email).deliver_later DossierMailer.notify_new_dossier_depose_to_instructeur(@dossier, instructeur.email).deliver_later
end end

View file

@ -54,8 +54,12 @@ module Types
end end
def usager def usager
if object.user_deleted?
{ email: object.user_email_for(:display), id: -1 }
else
Loaders::Record.for(User).load(object.user_id) Loaders::Record.for(User).load(object.user_id)
end end
end
def groupe_instructeur def groupe_instructeur
Loaders::Record.for(GroupeInstructeur).load(object.groupe_instructeur_id) Loaders::Record.for(GroupeInstructeur).load(object.groupe_instructeur_id)

View file

@ -13,7 +13,7 @@ class DossierMailer < ApplicationMailer
subject = "Retrouvez votre brouillon pour la démarche « #{dossier.procedure.libelle} »" subject = "Retrouvez votre brouillon pour la démarche « #{dossier.procedure.libelle} »"
mail(from: NO_REPLY_EMAIL, to: dossier.user.email, subject: subject) do |format| mail(from: NO_REPLY_EMAIL, to: dossier.user_email_for(:notification), subject: subject) do |format|
format.html { render layout: 'mailers/notifications_layout' } format.html { render layout: 'mailers/notifications_layout' }
end end
end end
@ -25,7 +25,7 @@ class DossierMailer < ApplicationMailer
subject = "Nouveau message pour votre dossier nº #{dossier.id} (#{dossier.procedure.libelle})" subject = "Nouveau message pour votre dossier nº #{dossier.id} (#{dossier.procedure.libelle})"
mail(from: NO_REPLY_EMAIL, to: dossier.user.email, subject: subject) do |format| mail(from: NO_REPLY_EMAIL, to: dossier.user_email_for(:notification), subject: subject) do |format|
format.html { render layout: 'mailers/notifications_layout' } format.html { render layout: 'mailers/notifications_layout' }
end end
end end
@ -49,7 +49,7 @@ class DossierMailer < ApplicationMailer
subject = "Votre dossier nº #{@dossier.id} est en train d'être réexaminé" subject = "Votre dossier nº #{@dossier.id} est en train d'être réexaminé"
mail(from: NO_REPLY_EMAIL, to: dossier.user.email, subject: subject) do |format| mail(from: NO_REPLY_EMAIL, to: dossier.user_email_for(:notification), subject: subject) do |format|
format.html { render layout: 'mailers/notifications_layout' } format.html { render layout: 'mailers/notifications_layout' }
end end
end end
@ -139,7 +139,7 @@ class DossierMailer < ApplicationMailer
@subject = "Attention : votre dossier n'est pas déposé." @subject = "Attention : votre dossier n'est pas déposé."
@dossier = dossier @dossier = dossier
mail(to: dossier.user.email, subject: @subject) mail(to: dossier.user_email_for(:notification), subject: @subject)
end end
protected protected

View file

@ -1,32 +0,0 @@
# Preview all emails at http://localhost:3000/rails/mailers/new_attestation_mailer
class NewAttestationMailer < ApplicationMailer
include Rails.application.routes.url_helpers
def new_attestation(dossier)
to = dossier.user.email
subject = "Nouvelle attestation pour votre dossier nº #{dossier.id}"
mail(to: to, subject: subject, body: body(dossier))
end
private
def body(dossier)
<<~HEREDOC
Bonjour,
Votre dossier  #{dossier.id} (démarche "#{dossier.procedure.libelle}") a subi, à un moment, un "aller-retour" :
- Acceptation de votre dossier
- Passage en instruction du dossier car besoin de le modifier
- Seconde acceptation de votre dossier
Suite à cette opération, l'attestation liée à votre dossier n'a pas é regénérée.
Ce problème est désormais reglé, votre nouvelle attestation est disponible à l'adresse suivante :
#{attestation_dossier_url(dossier)}
Cordialement,
Léquipe #{APPLICATION_NAME}
HEREDOC
end
end

View file

@ -8,54 +8,63 @@
class NotificationMailer < ApplicationMailer class NotificationMailer < ApplicationMailer
include ActionView::Helpers::SanitizeHelper include ActionView::Helpers::SanitizeHelper
before_action :set_dossier
after_action :create_commentaire_for_notification
helper ServiceHelper helper ServiceHelper
helper MailerHelper helper MailerHelper
layout 'mailers/notifications_layout' layout 'mailers/notifications_layout'
default from: NO_REPLY_EMAIL default from: NO_REPLY_EMAIL
def send_dossier_received(dossier) def send_notification
send_notification(dossier, dossier.procedure.received_mail_template) @service = @dossier.procedure.service
@logo_url = attach_logo(@dossier.procedure)
@rendered_template = sanitize(@body)
mail(subject: @subject, to: @email, template_name: 'send_notification')
end end
def send_initiated_notification(dossier) def self.send_en_construction_notification(dossier)
send_notification(dossier, dossier.procedure.initiated_mail_template) with(dossier: dossier, state: Dossier.states.fetch(:en_construction)).send_notification
end end
def send_closed_notification(dossier) def self.send_en_instruction_notification(dossier)
send_notification(dossier, dossier.procedure.closed_mail_template) with(dossier: dossier, state: Dossier.states.fetch(:en_instruction)).send_notification
end end
def send_refused_notification(dossier) def self.send_accepte_notification(dossier)
send_notification(dossier, dossier.procedure.refused_mail_template) with(dossier: dossier, state: Dossier.states.fetch(:accepte)).send_notification
end end
def send_without_continuation_notification(dossier) def self.send_refuse_notification(dossier)
send_notification(dossier, dossier.procedure.without_continuation_mail_template) with(dossier: dossier, state: Dossier.states.fetch(:refuse)).send_notification
end
def self.send_sans_suite_notification(dossier)
with(dossier: dossier, state: Dossier.states.fetch(:sans_suite)).send_notification
end end
private private
def send_notification(dossier, mail_template) def set_dossier
email = dossier.user.email @dossier = params[:dossier]
subject = mail_template.subject_for_dossier(dossier) if @dossier.user_deleted?
body = mail_template.body_for_dossier(dossier) mail.perform_deliveries = false
else
mail_template = @dossier.procedure.mail_template_for(params[:state])
create_commentaire_for_notification(dossier, subject, body) @email = @dossier.user_email_for(:notification)
@subject = mail_template.subject_for_dossier(@dossier)
@dossier = dossier @body = mail_template.body_for_dossier(@dossier)
@service = dossier.procedure.service @actions = mail_template.actions_for_dossier(@dossier)
@logo_url = attach_logo(dossier.procedure) end
@rendered_template = sanitize(body)
@actions = mail_template.actions_for_dossier(dossier)
mail(subject: subject, to: email, template_name: 'send_notification')
end end
def create_commentaire_for_notification(dossier, subject, body) def create_commentaire_for_notification
params = { body: ["[#{subject}]", body].join("<br><br>") } body = ["[#{@subject}]", @body].join("<br><br>")
commentaire = CommentaireService.build_with_email(CONTACT_EMAIL, dossier, params) commentaire = CommentaireService.build_with_email(CONTACT_EMAIL, @dossier, body: body)
commentaire.save! commentaire.save!
end end
end end

View file

@ -8,6 +8,7 @@
# autorisation_donnees :boolean # autorisation_donnees :boolean
# brouillon_close_to_expiration_notice_sent_at :datetime # brouillon_close_to_expiration_notice_sent_at :datetime
# conservation_extension :interval default(0 seconds) # conservation_extension :interval default(0 seconds)
# deleted_user_email_never_send :string
# en_construction_at :datetime # en_construction_at :datetime
# en_construction_close_to_expiration_notice_sent_at :datetime # en_construction_close_to_expiration_notice_sent_at :datetime
# en_construction_conservation_extension :interval default(0 seconds) # en_construction_conservation_extension :interval default(0 seconds)
@ -137,9 +138,9 @@ class Dossier < ApplicationRecord
end end
event :repasser_en_instruction, after: :after_repasser_en_instruction do event :repasser_en_instruction, after: :after_repasser_en_instruction do
transitions from: :refuse, to: :en_instruction transitions from: :refuse, to: :en_instruction, guard: :can_repasser_en_instruction?
transitions from: :sans_suite, to: :en_instruction transitions from: :sans_suite, to: :en_instruction, guard: :can_repasser_en_instruction?
transitions from: :accepte, to: :en_instruction transitions from: :accepte, to: :en_instruction, guard: :can_repasser_en_instruction?
end end
end end
@ -249,6 +250,7 @@ class Dossier < ApplicationRecord
states = opts[:notify_on_closed] ? [:publiee, :close, :depubliee] : [:publiee, :depubliee] states = opts[:notify_on_closed] ? [:publiee, :close, :depubliee] : [:publiee, :depubliee]
joins(:procedure) joins(:procedure)
.where(procedures: { aasm_state: states }) .where(procedures: { aasm_state: states })
.where.not(user_id: nil)
end end
scope :brouillon_close_to_expiration, -> do scope :brouillon_close_to_expiration, -> do
@ -342,7 +344,7 @@ class Dossier < ApplicationRecord
before_save :build_default_champs, if: Proc.new { revision_id_was.nil? } before_save :build_default_champs, if: Proc.new { revision_id_was.nil? }
before_save :update_search_terms before_save :update_search_terms
after_save :send_dossier_received after_save :send_dossier_en_instruction
after_save :send_web_hook after_save :send_web_hook
after_create_commit :send_draft_notification_email after_create_commit :send_draft_notification_email
@ -350,6 +352,22 @@ class Dossier < ApplicationRecord
validates :individual, presence: true, if: -> { revision.procedure.for_individual? } validates :individual, presence: true, if: -> { revision.procedure.for_individual? }
validates :groupe_instructeur, presence: true, if: -> { !brouillon? } validates :groupe_instructeur, presence: true, if: -> { !brouillon? }
def user_deleted?
user_id.nil?
end
def user_email_for(use)
if user_deleted?
if use == :display
deleted_user_email_never_send
else
raise "Can not send email to discarded user"
end
else
user.email
end
end
def motivation def motivation
return nil if !termine? return nil if !termine?
traitements.any? ? traitements.last.motivation : read_attribute(:motivation) traitements.any? ? traitements.last.motivation : read_attribute(:motivation)
@ -416,6 +434,10 @@ class Dossier < ApplicationRecord
brouillon? && procedure.dossier_can_transition_to_en_construction? brouillon? && procedure.dossier_can_transition_to_en_construction?
end end
def can_repasser_en_instruction?
termine? && !user_deleted?
end
def can_be_updated_by_user? def can_be_updated_by_user?
brouillon? || en_construction? brouillon? || en_construction?
end end
@ -429,7 +451,7 @@ class Dossier < ApplicationRecord
end end
def messagerie_available? def messagerie_available?
!brouillon? && !archived !brouillon? && !user_deleted? && !archived
end end
def en_construction_close_to_expiration? def en_construction_close_to_expiration?
@ -590,13 +612,18 @@ class Dossier < ApplicationRecord
administration_emails.each do |email| administration_emails.each do |email|
DossierMailer.notify_deletion_to_administration(deleted_dossier, email).deliver_later DossierMailer.notify_deletion_to_administration(deleted_dossier, email).deliver_later
end end
DossierMailer.notify_deletion_to_user(deleted_dossier, user.email).deliver_later
if !user_deleted?
DossierMailer.notify_deletion_to_user(deleted_dossier, user_email_for(:notification)).deliver_later
end
log_dossier_operation(author, :supprimer, self) log_dossier_operation(author, :supprimer, self)
elsif termine? elsif termine?
deleted_dossier = DeletedDossier.create_from_dossier(self, reason) deleted_dossier = DeletedDossier.create_from_dossier(self, reason)
DossierMailer.notify_instructeur_deletion_to_user(deleted_dossier, user.email).deliver_later if !user_deleted?
DossierMailer.notify_instructeur_deletion_to_user(deleted_dossier, user_email_for(:notification)).deliver_later
end
log_dossier_operation(author, :supprimer, self) log_dossier_operation(author, :supprimer, self)
end end
@ -663,7 +690,7 @@ class Dossier < ApplicationRecord
save! save!
remove_titres_identite! remove_titres_identite!
NotificationMailer.send_closed_notification(self).deliver_later NotificationMailer.send_accepte_notification(self).deliver_later
send_dossier_decision_to_experts(self) send_dossier_decision_to_experts(self)
log_dossier_operation(instructeur, :accepter, self) log_dossier_operation(instructeur, :accepter, self)
end end
@ -678,7 +705,7 @@ class Dossier < ApplicationRecord
save! save!
remove_titres_identite! remove_titres_identite!
NotificationMailer.send_closed_notification(self).deliver_later NotificationMailer.send_accepte_notification(self).deliver_later
log_automatic_dossier_operation(:accepter, self) log_automatic_dossier_operation(:accepter, self)
end end
@ -691,7 +718,7 @@ class Dossier < ApplicationRecord
save! save!
remove_titres_identite! remove_titres_identite!
NotificationMailer.send_refused_notification(self).deliver_later NotificationMailer.send_refuse_notification(self).deliver_later
send_dossier_decision_to_experts(self) send_dossier_decision_to_experts(self)
log_dossier_operation(instructeur, :refuser, self) log_dossier_operation(instructeur, :refuser, self)
end end
@ -705,7 +732,7 @@ class Dossier < ApplicationRecord
save! save!
remove_titres_identite! remove_titres_identite!
NotificationMailer.send_without_continuation_notification(self).deliver_later NotificationMailer.send_sans_suite_notification(self).deliver_later
send_dossier_decision_to_experts(self) send_dossier_decision_to_experts(self)
log_dossier_operation(instructeur, :classer_sans_suite, self) log_dossier_operation(instructeur, :classer_sans_suite, self)
end end
@ -751,7 +778,7 @@ class Dossier < ApplicationRecord
def spreadsheet_columns(with_etablissement: false, types_de_champ:, types_de_champ_private:) def spreadsheet_columns(with_etablissement: false, types_de_champ:, types_de_champ_private:)
columns = [ columns = [
['ID', id.to_s], ['ID', id.to_s],
['Email', user.email] ['Email', user_email_for(:display)]
] ]
if procedure.for_individual? if procedure.for_individual?
@ -922,9 +949,9 @@ class Dossier < ApplicationRecord
end end
end end
def send_dossier_received def send_dossier_en_instruction
if saved_change_to_state? && en_instruction? && !procedure.declarative_accepte? if saved_change_to_state? && en_instruction? && !procedure.declarative_accepte?
NotificationMailer.send_dossier_received(self).deliver_later NotificationMailer.send_en_instruction_notification(self).deliver_later
end end
end end

View file

@ -500,6 +500,23 @@ class Procedure < ApplicationRecord
without_continuation_mail || Mails::WithoutContinuationMail.default_for_procedure(self) without_continuation_mail || Mails::WithoutContinuationMail.default_for_procedure(self)
end end
def mail_template_for(state)
case state
when Dossier.states.fetch(:en_construction)
initiated_mail_template
when Dossier.states.fetch(:en_instruction)
received_mail_template
when Dossier.states.fetch(:accepte)
closed_mail_template
when Dossier.states.fetch(:refuse)
refused_mail_template
when Dossier.states.fetch(:sans_suite)
without_continuation_mail_template
else
raise "Unknown dossier state: #{state}"
end
end
def self.default_sort def self.default_sort
{ {
'table' => 'self', 'table' => 'self',

View file

@ -170,18 +170,24 @@ class User < ApplicationRecord
end end
def can_be_deleted? def can_be_deleted?
!administrateur? && !instructeur? && !expert? && dossiers.with_discarded.state_instruction_commencee.empty? !administrateur? && !instructeur? && !expert?
end end
def delete_and_keep_track_dossiers(administration) def delete_and_keep_track_dossiers(administration)
if !can_be_deleted? if !can_be_deleted?
raise "Cannot delete this user because instruction has started for some dossiers" raise "Cannot delete this user because they are also instructeur, expert or administrateur"
end end
dossiers.each do |dossier| Invite.where(dossier: dossiers.with_discarded).destroy_all
dossiers.state_en_construction.each do |dossier|
dossier.discard_and_keep_track!(administration, :user_removed) dossier.discard_and_keep_track!(administration, :user_removed)
end end
dossiers.with_discarded.destroy_all DossierOperationLog
.where(dossier: dossiers.with_discarded.discarded)
.where.not(operation: DossierOperationLog.operations.fetch(:supprimer))
.destroy_all
dossiers.with_discarded.discarded.destroy_all
dossiers.update_all(deleted_user_email_never_send: email, user_id: nil)
destroy! destroy!
end end

View file

@ -174,7 +174,7 @@ def add_message(pdf, message)
if message.sent_by_system? if message.sent_by_system?
sender = 'Email automatique' sender = 'Email automatique'
elsif message.sent_by?(@dossier.user) elsif message.sent_by?(@dossier.user)
sender = @dossier.user.email sender = @dossier.user_email_for(:display)
end end
format_in_2_lines(pdf, "#{sender}, #{try_format_date(message.created_at)}", format_in_2_lines(pdf, "#{sender}, #{try_format_date(message.created_at)}",
@ -233,7 +233,7 @@ prawn_document(page_size: "A4") do |pdf|
format_in_2_columns(pdf, 'Informations France Connect', "Le dossier a été déposé par le compte de #{@dossier.france_connect_information.given_name} #{@dossier.france_connect_information.family_name}, authentifié par France Connect le #{@dossier.france_connect_information.updated_at.strftime('%d/%m/%Y')}") format_in_2_columns(pdf, 'Informations France Connect', "Le dossier a été déposé par le compte de #{@dossier.france_connect_information.given_name} #{@dossier.france_connect_information.family_name}, authentifié par France Connect le #{@dossier.france_connect_information.updated_at.strftime('%d/%m/%Y')}")
end end
format_in_2_columns(pdf, "Email", @dossier.user.email) format_in_2_columns(pdf, "Email", @dossier.user_email_for(:display))
if @dossier.individual.present? if @dossier.individual.present?
add_identite_individual(pdf, @dossier.individual) add_identite_individual(pdf, @dossier.individual)

View file

@ -38,7 +38,7 @@
= link_to(instructeur_avis_path(avis.procedure, avis), class: 'cell-link') do = link_to(instructeur_avis_path(avis.procedure, avis), class: 'cell-link') do
%span.icon.folder %span.icon.folder
#{avis.dossier.id} #{avis.dossier.id}
%td= link_to(avis.dossier.user.email, instructeur_avis_path(avis.procedure, avis), class: 'cell-link') %td= link_to(avis.dossier.user_email_for(:display), instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
%td= link_to(avis.procedure.libelle, instructeur_avis_path(avis.procedure, avis), class: 'cell-link') %td= link_to(avis.procedure.libelle, instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
= paginate(@avis) = paginate(@avis)
- else - else

View file

@ -38,7 +38,7 @@
= link_to(instructeur_avis_path(avis.procedure, avis), class: 'cell-link') do = link_to(instructeur_avis_path(avis.procedure, avis), class: 'cell-link') do
%span.icon.folder %span.icon.folder
#{avis.dossier.id} #{avis.dossier.id}
%td= link_to(avis.dossier.user.email, instructeur_avis_path(avis.procedure, avis), class: 'cell-link') %td= link_to(avis.dossier.user_email_for(:display), instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
%td= link_to(avis.procedure.libelle, instructeur_avis_path(avis.procedure, avis), class: 'cell-link') %td= link_to(avis.procedure.libelle, instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
= paginate(@avis) = paginate(@avis)
- else - else

View file

@ -99,13 +99,20 @@
%h4 Voir lattestation %h4 Voir lattestation
%p Cette attestation a été envoyée automatiquement au demandeur. %p Cette attestation a été envoyée automatiquement au demandeur.
- if dossier.can_repasser_en_instruction?
%li %li
= link_to repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), method: :post, data: { remote:true, confirm: "Voulez vous remettre le dossier #{dossier.id} en instruction ?" } do = link_to repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), method: :post, data: { remote:true, confirm: "Voulez vous remettre le dossier #{dossier.id} en instruction ?" } do
%span.icon.in-progress %span.icon.in-progress
.dropdown-description .dropdown-description
%h4 Repasser en instruction %h4 Repasser en instruction
Lusager sera notifié que son dossier est réexaminé. Lusager sera notifié que son dossier est réexaminé.
- if dossier.termine? - elsif dossier.user_deleted?
%li
%span.icon.info
.dropdown-description
%h4 En attente darchivage
L'usager a supprimé son compte. Vous pouvez archiver puis supprimer le dossier.
%li %li
= link_to supprimer_dossier_instructeur_dossier_path(dossier.procedure, dossier), method: :patch, data: { confirm: "Voulez vous vraiment supprimer le dossier #{dossier.id} ? Cette action est irréversible. \nNous vous suggérons de télécharger le dossier au format PDF au préalable." } do = link_to supprimer_dossier_instructeur_dossier_path(dossier.procedure, dossier), method: :patch, data: { confirm: "Voulez vous vraiment supprimer le dossier #{dossier.id} ? Cette action est irréversible. \nNous vous suggérons de télécharger le dossier au format PDF au préalable." } do
%span.icon.delete %span.icon.delete

View file

@ -27,7 +27,7 @@
= link_to(dossier_linked_path(current_instructeur, dossier), class: 'cell-link') do = link_to(dossier_linked_path(current_instructeur, dossier), class: 'cell-link') do
= dossier.id = dossier.id
%td= link_to(dossier.procedure.libelle, dossier_linked_path(current_instructeur, dossier), class: 'cell-link') %td= link_to(dossier.procedure.libelle, dossier_linked_path(current_instructeur, dossier), class: 'cell-link')
%td= link_to(dossier.user.email, dossier_linked_path(current_instructeur, dossier), class: 'cell-link') %td= link_to(dossier.user_email_for(:display), dossier_linked_path(current_instructeur, dossier), class: 'cell-link')
%td.status-col %td.status-col
= link_to(dossier_linked_path(current_instructeur, dossier), class: 'cell-link') do = link_to(dossier_linked_path(current_instructeur, dossier), class: 'cell-link') do
= status_badge(dossier.state) = status_badge(dossier.state)

View file

@ -0,0 +1,5 @@
class AddDeletedUserEmailNeverSendToDossiers < ActiveRecord::Migration[6.1]
def change
add_column :dossiers, :deleted_user_email_never_send, :string
end
end

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2021_04_28_104228) do ActiveRecord::Schema.define(version: 2021_04_28_114228) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -275,6 +275,7 @@ ActiveRecord::Schema.define(version: 2021_04_28_104228) do
t.datetime "last_commentaire_updated_at" t.datetime "last_commentaire_updated_at"
t.string "api_entreprise_job_exceptions", array: true t.string "api_entreprise_job_exceptions", array: true
t.interval "conservation_extension", default: "PT0S" t.interval "conservation_extension", default: "PT0S"
t.string "deleted_user_email_never_send"
t.index "to_tsvector('french'::regconfig, (search_terms || private_search_terms))", name: "index_dossiers_on_search_terms_private_search_terms", using: :gin t.index "to_tsvector('french'::regconfig, (search_terms || private_search_terms))", name: "index_dossiers_on_search_terms_private_search_terms", using: :gin
t.index "to_tsvector('french'::regconfig, search_terms)", name: "index_dossiers_on_search_terms", using: :gin t.index "to_tsvector('french'::regconfig, search_terms)", name: "index_dossiers_on_search_terms", using: :gin
t.index ["archived"], name: "index_dossiers_on_archived" t.index ["archived"], name: "index_dossiers_on_archived"

View file

@ -210,7 +210,7 @@ describe Instructeurs::DossiersController, type: :controller do
end end
it 'Notification email is sent' do it 'Notification email is sent' do
expect(NotificationMailer).to receive(:send_refused_notification) expect(NotificationMailer).to receive(:send_refuse_notification)
.with(dossier).and_return(NotificationMailer) .with(dossier).and_return(NotificationMailer)
expect(NotificationMailer).to receive(:deliver_later) expect(NotificationMailer).to receive(:deliver_later)
@ -250,7 +250,7 @@ describe Instructeurs::DossiersController, type: :controller do
end end
it 'Notification email is sent' do it 'Notification email is sent' do
expect(NotificationMailer).to receive(:send_without_continuation_notification) expect(NotificationMailer).to receive(:send_sans_suite_notification)
.with(dossier).and_return(NotificationMailer) .with(dossier).and_return(NotificationMailer)
expect(NotificationMailer).to receive(:deliver_later) expect(NotificationMailer).to receive(:deliver_later)
@ -280,7 +280,7 @@ describe Instructeurs::DossiersController, type: :controller do
dossier.passer_en_instruction!(instructeur) dossier.passer_en_instruction!(instructeur)
sign_in(instructeur.user) sign_in(instructeur.user)
expect(NotificationMailer).to receive(:send_closed_notification) expect(NotificationMailer).to receive(:send_accepte_notification)
.with(dossier) .with(dossier)
.and_return(NotificationMailer) .and_return(NotificationMailer)

View file

@ -476,12 +476,12 @@ describe Users::DossiersController, type: :controller do
delivery = double delivery = double
expect(delivery).to receive(:deliver_later).with(no_args) expect(delivery).to receive(:deliver_later).with(no_args)
expect(NotificationMailer).to receive(:send_initiated_notification) expect(NotificationMailer).to receive(:send_en_construction_notification)
.and_return(delivery) .and_return(delivery)
subject subject
expect(NotificationMailer).not_to receive(:send_initiated_notification) expect(NotificationMailer).not_to receive(:send_en_construction_notification)
subject subject
end end
@ -499,7 +499,7 @@ describe Users::DossiersController, type: :controller do
it { expect(flash.alert).to eq(['nop']) } it { expect(flash.alert).to eq(['nop']) }
it 'does not send an email' do it 'does not send an email' do
expect(NotificationMailer).not_to receive(:send_initiated_notification) expect(NotificationMailer).not_to receive(:send_en_construction_notification)
subject subject
end end
@ -687,7 +687,7 @@ describe Users::DossiersController, type: :controller do
end end
it 'does not send an email' do it 'does not send an email' do
expect(NotificationMailer).not_to receive(:send_initiated_notification) expect(NotificationMailer).not_to receive(:send_en_construction_notification)
subject subject
end end

View file

@ -1,19 +1,21 @@
RSpec.describe NotificationMailer, type: :mailer do RSpec.describe NotificationMailer, type: :mailer do
let(:administrateur) { create(:administrateur) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:procedure) { create(:simple_procedure) } let(:procedure) { create(:simple_procedure) }
let(:dossier) { create(:dossier, :en_construction, :with_individual, :with_service, user: user, procedure: procedure) }
describe '.send_dossier_received' do describe 'send_en_instruction_notification' do
let(:dossier) { create(:dossier, :en_construction, :with_individual, :with_service, user: user, procedure: procedure) }
let(:email_template) { create(:received_mail, subject: 'Email subject', body: 'Your dossier was processed. Thanks.') } let(:email_template) { create(:received_mail, subject: 'Email subject', body: 'Your dossier was processed. Thanks.') }
before do before do
dossier.procedure.received_mail = email_template dossier.procedure.received_mail = email_template
end end
subject(:mail) { described_class.send_dossier_received(dossier) } subject(:mail) { described_class.send_en_instruction_notification(dossier) }
it 'creates a commentaire in the messagerie' do it 'creates a commentaire in the messagerie' do
expect { subject.deliver_now }.to change { Commentaire.count }.by(1) expect { subject.deliver_now }.to change { Commentaire.count }.by(1)
expect(subject.perform_deliveries).to be_truthy
commentaire = Commentaire.last commentaire = Commentaire.last
expect(commentaire.body).to include(email_template.subject_for_dossier(dossier), email_template.body_for_dossier(dossier)) expect(commentaire.body).to include(email_template.subject_for_dossier(dossier), email_template.body_for_dossier(dossier))
@ -59,4 +61,27 @@ RSpec.describe NotificationMailer, type: :mailer do
expect(subject.from.first).to eq(Mail::Address.new(NO_REPLY_EMAIL).address) expect(subject.from.first).to eq(Mail::Address.new(NO_REPLY_EMAIL).address)
end end
end end
describe 'send_accepte_notification' do
let(:dossier) { create(:dossier, :en_instruction, :with_individual, :with_service, user: user, procedure: procedure) }
let(:email_template) { create(:closed_mail, subject: 'Email subject', body: 'Your dossier was accepted. Thanks.') }
before do
dossier.procedure.closed_mail = email_template
end
subject(:mail) { described_class.send_accepte_notification(dossier) }
context 'when dossier user is deleted' do
before do
dossier.user.delete_and_keep_track_dossiers(administrateur)
dossier.reload
end
it 'should not send notification' do
expect { subject.deliver_now }.not_to change { Commentaire.count }
expect(subject.perform_deliveries).to be_falsey
end
end
end
end end

View file

@ -1,23 +1,36 @@
class NotificationMailerPreview < ActionMailer::Preview class NotificationMailerPreview < ActionMailer::Preview
def send_initiated_notification def send_en_construction_notification
p = Procedure.where(id: Mails::InitiatedMail.where("body like ?", "%<img%").pluck(:procedure_id).uniq).order("RANDOM()").first NotificationMailer.send_en_construction_notification(dossier_with_image)
NotificationMailer.send_initiated_notification(p.dossiers.last)
end end
def send_dossier_received def send_en_instruction_notification
NotificationMailer.send_dossier_received(Dossier.last) NotificationMailer.send_en_instruction_notification(dossier)
end end
def send_closed_notification def send_accepte_notification
NotificationMailer.send_closed_notification(Dossier.last) NotificationMailer.send_accepte_notification(dossier)
end end
def send_refused_notification def send_refuse_notification
dossier = Dossier.last.tap { |d| d.assign_attributes(motivation: 'Le montant demandé dépasse le plafond autorisé') } NotificationMailer.send_refuse_notification(dossier_with_motivation)
NotificationMailer.send_refused_notification(dossier)
end end
def send_without_continuation_notification def send_sans_suite_notification
NotificationMailer.send_without_continuation_notification(Dossier.last) NotificationMailer.send_sans_suite_notification(dossier)
end
private
def dossier
Dossier.last
end
def dossier_with_image
procedure = Procedure.where(id: Mails::InitiatedMail.where("body like ?", "%<img%").pluck(:procedure_id).uniq).order("RANDOM()").first
procedure.dossiers.last
end
def dossier_with_motivation
Dossier.last.tap { |d| d.assign_attributes(motivation: 'Le montant demandé dépasse le plafond autorisé') }
end end
end end

View file

@ -512,17 +512,17 @@ describe Dossier do
let(:instructeur) { create(:instructeur) } let(:instructeur) { create(:instructeur) }
before do before do
allow(NotificationMailer).to receive(:send_dossier_received).and_return(double(deliver_later: nil)) allow(NotificationMailer).to receive(:send_en_instruction_notification).and_return(double(deliver_later: nil))
end end
it "sends an email when the dossier becomes en_instruction" do it "sends an email when the dossier becomes en_instruction" do
dossier.passer_en_instruction!(instructeur) dossier.passer_en_instruction!(instructeur)
expect(NotificationMailer).to have_received(:send_dossier_received).with(dossier) expect(NotificationMailer).to have_received(:send_en_instruction_notification).with(dossier)
end end
it "does not an email when the dossier becomes accepte" do it "does not an email when the dossier becomes accepte" do
dossier.accepte! dossier.accepte!
expect(NotificationMailer).to_not have_received(:send_dossier_received) expect(NotificationMailer).to_not have_received(:send_en_instruction_notification)
end end
end end
@ -935,7 +935,7 @@ describe Dossier do
let(:attestation) { Attestation.new } let(:attestation) { Attestation.new }
before do before do
allow(NotificationMailer).to receive(:send_closed_notification).and_return(double(deliver_later: true)) allow(NotificationMailer).to receive(:send_accepte_notification).and_return(double(deliver_later: true))
allow(dossier).to receive(:build_attestation).and_return(attestation) allow(dossier).to receive(:build_attestation).and_return(attestation)
Timecop.freeze(now) Timecop.freeze(now)
@ -957,7 +957,7 @@ describe Dossier do
it { expect(operation_serialized['operation']).to eq('accepter') } it { expect(operation_serialized['operation']).to eq('accepter') }
it { expect(operation_serialized['dossier_id']).to eq(dossier.id) } it { expect(operation_serialized['dossier_id']).to eq(dossier.id) }
it { expect(operation_serialized['executed_at']).to eq(last_operation.executed_at.iso8601) } it { expect(operation_serialized['executed_at']).to eq(last_operation.executed_at.iso8601) }
it { expect(NotificationMailer).to have_received(:send_closed_notification).with(dossier) } it { expect(NotificationMailer).to have_received(:send_accepte_notification).with(dossier) }
it { expect(dossier.attestation).to eq(attestation) } it { expect(dossier.attestation).to eq(attestation) }
end end
@ -968,7 +968,7 @@ describe Dossier do
let(:attestation) { Attestation.new } let(:attestation) { Attestation.new }
before do before do
allow(NotificationMailer).to receive(:send_closed_notification).and_return(double(deliver_later: true)) allow(NotificationMailer).to receive(:send_accepte_notification).and_return(double(deliver_later: true))
allow(dossier).to receive(:build_attestation).and_return(attestation) allow(dossier).to receive(:build_attestation).and_return(attestation)
Timecop.freeze(now) Timecop.freeze(now)
@ -984,7 +984,7 @@ describe Dossier do
it { expect(dossier.state).to eq('accepte') } it { expect(dossier.state).to eq('accepte') }
it { expect(last_operation.operation).to eq('accepter') } it { expect(last_operation.operation).to eq('accepter') }
it { expect(last_operation.automatic_operation?).to be_truthy } it { expect(last_operation.automatic_operation?).to be_truthy }
it { expect(NotificationMailer).to have_received(:send_closed_notification).with(dossier) } it { expect(NotificationMailer).to have_received(:send_accepte_notification).with(dossier) }
it { expect(dossier.attestation).to eq(attestation) } it { expect(dossier.attestation).to eq(attestation) }
end end

View file

@ -263,13 +263,16 @@ describe User, type: :model do
describe '#can_be_deleted?' do describe '#can_be_deleted?' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:administrateur) { create(:administrateur) }
let(:instructeur) { create(:instructeur) }
let(:expert) { create(:expert) }
subject { user.can_be_deleted? } subject { user.can_be_deleted? }
context 'when the user has a dossier in instruction' do context 'when the user has a dossier in instruction' do
let!(:dossier) { create(:dossier, :en_instruction, user: user) } let!(:dossier) { create(:dossier, :en_instruction, user: user) }
it { is_expected.to be false } it { is_expected.to be true }
end end
context 'when the user has no dossier in instruction' do context 'when the user has no dossier in instruction' do
@ -278,19 +281,19 @@ describe User, type: :model do
context 'when the user is an administrateur' do context 'when the user is an administrateur' do
it 'cannot be deleted' do it 'cannot be deleted' do
administrateur = create(:administrateur) expect(administrateur.user.can_be_deleted?).to be_falsy
user = administrateur.user
expect(user.can_be_deleted?).to be_falsy
end end
end end
context 'when the user is an instructeur' do context 'when the user is an instructeur' do
it 'cannot be deleted' do it 'cannot be deleted' do
instructeur = create(:instructeur) expect(instructeur.user.can_be_deleted?).to be_falsy
user = instructeur.user end
end
expect(user.can_be_deleted?).to be_falsy context 'when the user is an expert' do
it 'cannot be deleted' do
expect(expert.user.can_be_deleted?).to be_falsy
end end
end end
end end
@ -299,14 +302,7 @@ describe User, type: :model do
let(:super_admin) { create(:super_admin) } let(:super_admin) { create(:super_admin) }
let(:user) { create(:user) } let(:user) { create(:user) }
context 'with a dossier in instruction' do context 'without a dossier with processing strted' do
let!(:dossier_en_instruction) { create(:dossier, :en_instruction, user: user) }
it 'raises' do
expect { user.delete_and_keep_track_dossiers(super_admin) }.to raise_error(RuntimeError)
end
end
context 'without a dossier in instruction' do
let!(:dossier_en_construction) { create(:dossier, :en_construction, user: user) } let!(:dossier_en_construction) { create(:dossier, :en_construction, user: user) }
let!(:dossier_brouillon) { create(:dossier, user: user) } let!(:dossier_brouillon) { create(:dossier, user: user) }
@ -321,28 +317,39 @@ describe User, type: :model do
end end
context 'with a discarded dossier' do context 'with a discarded dossier' do
let!(:dossier_cache) do let(:dossier_to_discard) { create(:dossier, :en_construction, user: user) }
create(:dossier, :en_construction, user: user) let!(:dossier_from_another_user) { create(:dossier, :en_construction, user: create(:user)) }
end
let!(:dossier_from_another_user) do
create(:dossier, :en_construction, user: create(:user))
end
it "keep track of dossiers and delete user" do it "keep track of dossiers and delete user" do
dossier_cache.discard_and_keep_track!(super_admin, :user_request) dossier_to_discard.discard_and_keep_track!(super_admin, :user_request)
user.delete_and_keep_track_dossiers(super_admin) user.delete_and_keep_track_dossiers(super_admin)
expect(DeletedDossier.find_by(dossier_id: dossier_en_construction)).to be_present expect(DeletedDossier.find_by(dossier_id: dossier_en_construction)).to be_present
expect(DeletedDossier.find_by(dossier_id: dossier_brouillon)).to be_nil expect(DeletedDossier.find_by(dossier_id: dossier_brouillon)).to be_nil
expect(Dossier.find_by(id: dossier_from_another_user.id)).to be_present
expect(User.find_by(id: user.id)).to be_nil expect(User.find_by(id: user.id)).to be_nil
end end
end
end
it "doesn't destroy dossiers of another user" do context 'with dossiers with processing strted' do
dossier_cache.discard_and_keep_track!(super_admin, :user_request) let!(:dossier_en_instruction) { create(:dossier, :en_instruction, user: user) }
let!(:dossier_termine) { create(:dossier, :accepte, user: user) }
it "keep track of dossiers and delete user" do
user.delete_and_keep_track_dossiers(super_admin) user.delete_and_keep_track_dossiers(super_admin)
expect(Dossier.find_by(id: dossier_from_another_user.id)).to be_present expect(dossier_en_instruction.reload).to be_present
end expect(dossier_en_instruction.user).to be_nil
expect(dossier_en_instruction.user_email_for(:display)).to eq(user.email)
expect { dossier_en_instruction.user_email_for(:notification) }.to raise_error(RuntimeError)
expect(dossier_termine.reload).to be_present
expect(dossier_termine.user).to be_nil
expect(dossier_termine.user_email_for(:display)).to eq(user.email)
expect { dossier_termine.user_email_for(:notification) }.to raise_error(RuntimeError)
expect(User.find_by(id: user.id)).to be_nil
end end
end end
end end