diff --git a/Gemfile b/Gemfile index ada4d9e22..92790bce2 100644 --- a/Gemfile +++ b/Gemfile @@ -54,7 +54,7 @@ gem 'puma' # Use Puma as the app server gem 'pundit' gem 'rack-attack' gem 'rack-mini-profiler' -gem 'rails' +gem 'rails', '= 5.2.4.2' gem 'rails-i18n' # Locales par défaut gem 'rake-progressbar', require: false gem 'react-rails' diff --git a/Gemfile.lock b/Gemfile.lock index 224b5f9a5..425c59161 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -20,25 +20,25 @@ GEM specs: aasm (5.0.1) concurrent-ruby (~> 1.0) - actioncable (5.2.4.1) - actionpack (= 5.2.4.1) + actioncable (5.2.4.2) + actionpack (= 5.2.4.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.4.1) - actionpack (= 5.2.4.1) - actionview (= 5.2.4.1) - activejob (= 5.2.4.1) + actionmailer (5.2.4.2) + actionpack (= 5.2.4.2) + actionview (= 5.2.4.2) + activejob (= 5.2.4.2) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.4.1) - actionview (= 5.2.4.1) - activesupport (= 5.2.4.1) + actionpack (5.2.4.2) + actionview (= 5.2.4.2) + activesupport (= 5.2.4.2) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.4.1) - activesupport (= 5.2.4.1) + actionview (5.2.4.2) + activesupport (= 5.2.4.2) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) @@ -53,25 +53,25 @@ GEM jsonapi-renderer (>= 0.1.1.beta1, < 0.3) active_storage_validations (0.8.7) rails (>= 5.2.0) - activejob (5.2.4.1) - activesupport (= 5.2.4.1) + activejob (5.2.4.2) + activesupport (= 5.2.4.2) globalid (>= 0.3.6) - activemodel (5.2.4.1) - activesupport (= 5.2.4.1) - activerecord (5.2.4.1) - activemodel (= 5.2.4.1) - activesupport (= 5.2.4.1) + activemodel (5.2.4.2) + activesupport (= 5.2.4.2) + activerecord (5.2.4.2) + activemodel (= 5.2.4.2) + activesupport (= 5.2.4.2) arel (>= 9.0) - activestorage (5.2.4.1) - actionpack (= 5.2.4.1) - activerecord (= 5.2.4.1) + activestorage (5.2.4.2) + actionpack (= 5.2.4.2) + activerecord (= 5.2.4.2) marcel (~> 0.3.1) activestorage-openstack (1.4.1) fog-openstack (~> 1.0) marcel mime-types rails (>= 5.2.2) - activesupport (5.2.4.1) + activesupport (5.2.4.2) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -469,18 +469,18 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (5.2.4.1) - actioncable (= 5.2.4.1) - actionmailer (= 5.2.4.1) - actionpack (= 5.2.4.1) - actionview (= 5.2.4.1) - activejob (= 5.2.4.1) - activemodel (= 5.2.4.1) - activerecord (= 5.2.4.1) - activestorage (= 5.2.4.1) - activesupport (= 5.2.4.1) + rails (5.2.4.2) + actioncable (= 5.2.4.2) + actionmailer (= 5.2.4.2) + actionpack (= 5.2.4.2) + actionview (= 5.2.4.2) + activejob (= 5.2.4.2) + activemodel (= 5.2.4.2) + activerecord (= 5.2.4.2) + activestorage (= 5.2.4.2) + activesupport (= 5.2.4.2) bundler (>= 1.3.0) - railties (= 5.2.4.1) + railties (= 5.2.4.2) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.4) actionpack (>= 5.0.1.x) @@ -494,9 +494,9 @@ GEM rails-i18n (5.1.2) i18n (>= 0.7, < 2) railties (>= 5.0, < 6) - railties (5.2.4.1) - actionpack (= 5.2.4.1) - activesupport (= 5.2.4.1) + railties (5.2.4.2) + actionpack (= 5.2.4.2) + activesupport (= 5.2.4.2) method_source rake (>= 0.8.7) thor (>= 0.19.0, < 2.0) @@ -782,7 +782,7 @@ DEPENDENCIES pundit rack-attack rack-mini-profiler - rails + rails (= 5.2.4.2) rails-controller-testing rails-i18n rake-progressbar diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b78fe1b90..b146affec 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,7 @@ class ApplicationController < ActionController::Base include TrustedDeviceConcern include Pundit + include Devise::StoreLocationExtension MAINTENANCE_MESSAGE = 'Le site est actuellement en maintenance. Il sera à nouveau disponible dans un court instant.' @@ -198,7 +199,9 @@ class ApplicationController < ActionController::Base # return at this location # after the device is trusted - store_location_for(:user, request.fullpath) + if get_stored_location_for(:user).blank? + store_location_for(:user, request.fullpath) + end send_login_token_or_bufferize(current_instructeur) redirect_to link_sent_path(email: current_instructeur.email) diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 646c3505c..29412c102 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -1,6 +1,4 @@ class InvitesController < ApplicationController - include Devise::StoreLocationExtension - before_action :authenticate_user!, only: [:create] before_action :store_user_location!, only: [:show] diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index 2e70cd862..8d4ffd26a 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -1,6 +1,5 @@ module Users class DossiersController < UserController - include Devise::StoreLocationExtension include DossierHelper layout 'procedure_context', only: [:identite, :update_identite, :siret, :update_siret] diff --git a/app/javascript/shared/utils.js b/app/javascript/shared/utils.js index 0921b6d68..e74ddd78e 100644 --- a/app/javascript/shared/utils.js +++ b/app/javascript/shared/utils.js @@ -3,7 +3,7 @@ import $ from 'jquery'; import debounce from 'debounce'; export { debounce }; -export const { fire, ajax } = Rails; +export const { fire } = Rails; export function show(el) { el && el.classList.remove('hidden'); @@ -45,6 +45,22 @@ export function delegate(eventNames, selector, callback) { ); } +export function ajax(options) { + return new Promise((resolve, reject) => { + Object.assign(options, { + success: (response, statusText, xhr) => { + resolve({ response, statusText, xhr }); + }, + error: (response, statusText, xhr) => { + let error = new Error(`Erreur ${xhr.status} : ${statusText}`); + Object.assign(error, { response, statusText, xhr }); + reject(error); + } + }); + Rails.ajax(options); + }); +} + export function getJSON(url, data, method = 'get') { incrementActiveRequestsCount(); data = method !== 'get' ? JSON.stringify(data) : data; diff --git a/app/jobs/expired_dossiers_deletion_job.rb b/app/jobs/expired_dossiers_deletion_job.rb new file mode 100644 index 000000000..f269d595a --- /dev/null +++ b/app/jobs/expired_dossiers_deletion_job.rb @@ -0,0 +1,7 @@ +class ExpiredDossiersDeletionJob < ApplicationJob + queue_as :cron + + def perform(*args) + ExpiredDossiersDeletionService.process_expired_dossiers_brouillon + end +end diff --git a/app/jobs/seek_and_destroy_expired_dossiers_job.rb b/app/jobs/seek_and_destroy_expired_dossiers_job.rb deleted file mode 100644 index d720873bf..000000000 --- a/app/jobs/seek_and_destroy_expired_dossiers_job.rb +++ /dev/null @@ -1,8 +0,0 @@ -class SeekAndDestroyExpiredDossiersJob < ApplicationJob - queue_as :cron - - def perform(*args) - Dossier.send_brouillon_expiration_notices - Dossier.destroy_brouillons_and_notify - end -end diff --git a/app/jobs/warn_expiring_dossiers_job.rb b/app/jobs/warn_expiring_dossiers_job.rb index c20789133..b8926662d 100644 --- a/app/jobs/warn_expiring_dossiers_job.rb +++ b/app/jobs/warn_expiring_dossiers_job.rb @@ -3,8 +3,7 @@ class WarnExpiringDossiersJob < ApplicationJob def perform(*args) expiring, expired = Dossier - .includes(:procedure) - .nearing_end_of_retention + .en_instruction_close_to_expiration .partition(&:retention_expired?) AdministrationMailer.dossier_expiration_summary(expiring, expired).deliver_later diff --git a/app/mailers/dossier_mailer.rb b/app/mailers/dossier_mailer.rb index c2294ee67..b3fcd9a94 100644 --- a/app/mailers/dossier_mailer.rb +++ b/app/mailers/dossier_mailer.rb @@ -29,20 +29,6 @@ class DossierMailer < ApplicationMailer end end - def notify_deletion_to_user(deleted_dossier, to_email) - @deleted_dossier = deleted_dossier - subject = "Votre dossier nº #{@deleted_dossier.dossier_id} a bien été supprimé" - - mail(to: to_email, subject: subject) - end - - def notify_deletion_to_administration(deleted_dossier, to_email) - @deleted_dossier = deleted_dossier - subject = "Le dossier nº #{@deleted_dossier.dossier_id} a été supprimé à la demande de l'usager" - - mail(to: to_email, subject: subject) - end - def notify_revert_to_instruction(dossier) @dossier = dossier @service = dossier.procedure.service @@ -55,40 +41,60 @@ class DossierMailer < ApplicationMailer end end - def notify_brouillon_near_deletion(user, dossiers) + def notify_brouillon_near_deletion(dossiers, to_email) @subject = default_i18n_subject(count: dossiers.count) @dossiers = dossiers - mail(to: user.email, subject: @subject) + mail(to: to_email, subject: @subject) end - def notify_brouillon_deletion(user, dossier_hashes) + def notify_brouillon_deletion(dossier_hashes, to_email) @subject = default_i18n_subject(count: dossier_hashes.count) @dossier_hashes = dossier_hashes - mail(to: user.email, subject: @subject) + mail(to: to_email, subject: @subject) end - def notify_automatic_deletion_to_user(user, dossier_hashes) - @subject = default_i18n_subject(count: dossier_hashes.count) - @dossier_hashes = dossier_hashes + def notify_deletion_to_user(deleted_dossier, to_email) + @subject = default_i18n_subject(dossier_id: deleted_dossier.dossier_id) + @deleted_dossier = deleted_dossier - mail(to: user.email, subject: @subject) + mail(to: to_email, subject: @subject) end - def notify_automatic_deletion_to_administration(user, dossier_hashes) - @subject = default_i18n_subject(count: dossier_hashes.count) - @dossier_hashes = dossier_hashes + def notify_deletion_to_administration(deleted_dossier, to_email) + @subject = default_i18n_subject(dossier_id: deleted_dossier.dossier_id) + @deleted_dossier = deleted_dossier - mail(to: user.email, subject: @subject) + mail(to: to_email, subject: @subject) end - def notify_en_construction_near_deletion(user, dossiers, for_user) + def notify_automatic_deletion_to_user(deleted_dossiers, to_email) + @subject = default_i18n_subject(count: deleted_dossiers.count) + @deleted_dossiers = deleted_dossiers + + mail(to: to_email, subject: @subject) + end + + def notify_automatic_deletion_to_administration(deleted_dossiers, to_email) + @subject = default_i18n_subject(count: deleted_dossiers.count) + @deleted_dossiers = deleted_dossiers + + mail(to: to_email, subject: @subject) + end + + def notify_en_construction_near_deletion_to_user(dossiers, to_email) @subject = default_i18n_subject(count: dossiers.count) @dossiers = dossiers - @for_user = for_user - mail(to: user.email, subject: @subject) + mail(to: to_email, subject: @subject) + end + + def notify_en_construction_near_deletion_to_administration(dossiers, to_email) + @subject = default_i18n_subject(count: dossiers.count) + @dossiers = dossiers + + mail(to: to_email, subject: @subject) end def notify_groupe_instructeur_changed(instructeur, dossier) diff --git a/app/models/attestation_template.rb b/app/models/attestation_template.rb index 69056789b..87accde3c 100644 --- a/app/models/attestation_template.rb +++ b/app/models/attestation_template.rb @@ -10,9 +10,8 @@ class AttestationTemplate < ApplicationRecord has_one_attached :signature validates :footer, length: { maximum: 190 } - - validates :logo, content_type: [:png, :jpg, :jpeg] - validates :signature, content_type: [:png, :jpg, :jpeg] + validates :logo, content_type: ['image/png', 'image/jpg', 'image/jpeg'], size: { less_than: 1.megabytes } + validates :signature, content_type: ['image/png', 'image/jpg', 'image/jpeg'], size: { less_than: 1.megabytes } DOSSIER_STATE = Dossier.states.fetch(:accepte) diff --git a/app/models/avis.rb b/app/models/avis.rb index fae8f3a35..bf468b96a 100644 --- a/app/models/avis.rb +++ b/app/models/avis.rb @@ -10,6 +10,8 @@ class Avis < ApplicationRecord validates :email, format: { with: Devise.email_regexp, message: "n'est pas valide" }, allow_nil: true validates :claimant, presence: true + validates :piece_justificative_file, size: { less_than: 20.megabytes } + validates :introduction_file, size: { less_than: 20.megabytes } before_validation -> { sanitize_email(:email) } before_create :try_to_assign_instructeur diff --git a/app/models/commentaire.rb b/app/models/commentaire.rb index 9a93319d4..7d4a520ae 100644 --- a/app/models/commentaire.rb +++ b/app/models/commentaire.rb @@ -11,6 +11,7 @@ class Commentaire < ApplicationRecord has_one_attached :piece_jointe validates :body, presence: { message: "ne peut être vide" } + validates :piece_jointe, size: { less_than: 20.megabytes } default_scope { order(created_at: :asc) } scope :updated_since?, -> (date) { where('commentaires.updated_at > ?', date) } diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 8e3734e5b..f0eef0d1d 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -22,8 +22,6 @@ class Dossier < ApplicationRecord TAILLE_MAX_ZIP = 50.megabytes - DRAFT_EXPIRATION = 1.month + 5.days - has_one :etablissement, dependent: :destroy has_one :individual, validate: false, dependent: :destroy has_one :attestation, dependent: :destroy @@ -140,7 +138,6 @@ class Dossier < ApplicationRecord scope :en_cours, -> { not_archived.state_en_construction_ou_instruction } scope :without_followers, -> { left_outer_joins(:follows).where(follows: { id: nil }) } scope :with_champs, -> { includes(champs: :type_de_champ) } - scope :nearing_end_of_retention, -> (duration = '1 month') { joins(:procedure).where("en_instruction_at + (duree_conservation_dossiers_dans_ds * interval '1 month') - now() < interval ?", duration) } scope :for_api, -> { includes(commentaires: { piece_jointe_attachment: :blob }, champs: [ @@ -170,10 +167,24 @@ class Dossier < ApplicationRecord scope :brouillon_close_to_expiration, -> do brouillon .joins(:procedure) - .where("dossiers.created_at + (duree_conservation_dossiers_dans_ds * interval '1 month') - (1 * interval '1 month') <= now()") + .where("dossiers.created_at + (duree_conservation_dossiers_dans_ds * interval '1 month') - INTERVAL '1 month' <= now()") end - scope :expired_brouillon, -> { brouillon.where("brouillon_close_to_expiration_notice_sent_at < ?", (Time.zone.now - (DRAFT_EXPIRATION))) } - scope :without_notice_sent, -> { where(brouillon_close_to_expiration_notice_sent_at: nil) } + scope :en_construction_close_to_expiration, -> do + en_construction + .joins(:procedure) + .where("dossiers.en_construction_at + (duree_conservation_dossiers_dans_ds * interval '1 month') - INTERVAL '1 month' <= now()") + end + scope :en_instruction_close_to_expiration, -> do + en_instruction + .joins(:procedure) + .where("dossiers.en_instruction_at + (duree_conservation_dossiers_dans_ds * interval '1 month') - INTERVAL '1 month' <= now()") + end + + scope :brouillon_expired, -> { brouillon.where("brouillon_close_to_expiration_notice_sent_at < (now() - INTERVAL '1 month 5 days')") } + scope :en_construction_expired, -> { en_construction.where("en_construction_close_to_expiration_notice_sent_at < (now() - INTERVAL '1 month 5 days')") } + + scope :without_brouillon_expiration_notice_sent, -> { where(brouillon_close_to_expiration_notice_sent_at: nil) } + scope :without_en_construction_expiration_notice_sent, -> { where(en_construction_close_to_expiration_notice_sent_at: nil) } scope :for_procedure, -> (procedure) { includes(:user, :groupe_instructeur).where(groupe_instructeurs: { procedure: procedure }) } scope :for_api_v2, -> { includes(procedure: [:administrateurs], etablissement: [], individual: []) } @@ -669,36 +680,4 @@ class Dossier < ApplicationRecord end end end - - def self.send_brouillon_expiration_notices - brouillons = Dossier - .brouillon_close_to_expiration - .without_notice_sent - - brouillons - .includes(:user) - .group_by(&:user) - .each do |(user, dossiers)| - DossierMailer.notify_brouillon_near_deletion(user, dossiers).deliver_later - end - - brouillons.update_all(brouillon_close_to_expiration_notice_sent_at: Time.zone.now) - end - - def self.destroy_brouillons_and_notify - expired_brouillons = Dossier.expired_brouillon - - expired_brouillons - .includes(:procedure, :user) - .group_by(&:user) - .each do |(user, dossiers)| - dossier_hashes = dossiers.map(&:hash_for_deletion_mail) - DossierMailer.notify_brouillon_deletion(user, dossier_hashes).deliver_later - - dossiers.each do |dossier| - DeletedDossier.create_from_dossier(dossier) - dossier.destroy - end - end - end end diff --git a/app/models/instructeur.rb b/app/models/instructeur.rb index d580694ae..bb55fe36a 100644 --- a/app/models/instructeur.rb +++ b/app/models/instructeur.rb @@ -163,11 +163,13 @@ class Instructeur < ApplicationRecord acc << h end - [["en_instruction", h[:nb_en_instruction]], ["accepte", h[:nb_accepted]]].each do |state, count| - if procedure.declarative_with_state == state && count > 0 - h[:procedure_id] = procedure.id - h[:procedure_libelle] = procedure.libelle - acc << h + if h[:nb_en_instruction] > 0 || h[:nb_accepted] > 0 + [["en_instruction", h[:nb_en_instruction]], ["accepte", h[:nb_accepted]]].each do |state, count| + if procedure&.declarative_with_state == state && count > 0 + h[:procedure_id] = procedure.id + h[:procedure_libelle] = procedure.libelle + acc << h + end end end diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 807899628..3c3a72fca 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -84,6 +84,26 @@ class Procedure < ApplicationRecord validates :duree_conservation_dossiers_dans_ds, allow_nil: true, numericality: { only_integer: true, greater_than_or_equal_to: 1, less_than_or_equal_to: MAX_DUREE_CONSERVATION }, unless: :durees_conservation_required validates :duree_conservation_dossiers_hors_ds, allow_nil: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, unless: :durees_conservation_required validates_with MonAvisEmbedValidator + validates :notice, content_type: [ + "application/msword", + "application/pdf", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "application/vnd.ms-powerpoint", + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "application/vnd.oasis.opendocument.text", + "application/vnd.oasis.opendocument.presentation", + "text/plain" + ], size: { less_than: 20.megabytes } + + validates :deliberation, content_type: [ + "application/msword", + "application/pdf", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "text/plain", + "application/vnd.oasis.opendocument.text" + ], size: { less_than: 20.megabytes } + + validates :logo, content_type: ['image/png', 'image/jpg', 'image/jpeg'], size: { less_than: 5.megabytes } before_save :update_juridique_required before_save :update_durees_conservation_required after_initialize :ensure_path_exists diff --git a/app/services/expired_dossiers_deletion_service.rb b/app/services/expired_dossiers_deletion_service.rb new file mode 100644 index 000000000..6129b5331 --- /dev/null +++ b/app/services/expired_dossiers_deletion_service.rb @@ -0,0 +1,110 @@ +class ExpiredDossiersDeletionService + def self.process_expired_dossiers_brouillon + send_brouillon_expiration_notices + delete_expired_brouillons_and_notify + end + + def self.process_expired_dossiers_en_construction + send_en_construction_expiration_notices + delete_expired_en_construction_and_notify + end + + def self.send_brouillon_expiration_notices + dossiers_close_to_expiration = Dossier + .brouillon_close_to_expiration + .without_brouillon_expiration_notice_sent + + dossiers_close_to_expiration + .includes(:user, :procedure) + .group_by(&:user) + .each do |(user, dossiers)| + DossierMailer.notify_brouillon_near_deletion( + dossiers, + user.email + ).deliver_later + end + + dossiers_close_to_expiration.update_all(brouillon_close_to_expiration_notice_sent_at: Time.zone.now) + end + + def self.send_en_construction_expiration_notices + dossiers_close_to_expiration = Dossier + .en_construction_close_to_expiration + .without_en_construction_expiration_notice_sent + + dossiers_close_to_expiration + .includes(:user) + .group_by(&:user) + .each do |(user, dossiers)| + DossierMailer.notify_en_construction_near_deletion_to_user( + dossiers, + user.email + ).deliver_later + end + + group_by_fonctionnaire_email(dossiers_close_to_expiration).each do |(email, dossiers)| + DossierMailer.notify_en_construction_near_deletion_to_administration( + dossiers, + email + ).deliver_later + end + + dossiers_close_to_expiration.update_all(en_construction_close_to_expiration_notice_sent_at: Time.zone.now) + end + + def self.delete_expired_brouillons_and_notify + dossiers_to_remove = Dossier.brouillon_expired + + dossiers_to_remove + .includes(:user, :procedure) + .group_by(&:user) + .each do |(user, dossiers)| + DossierMailer.notify_brouillon_deletion( + dossiers.map(&:hash_for_deletion_mail), + user.email + ).deliver_later + end + + dossiers_to_remove.each do |dossier| + DeletedDossier.create_from_dossier(dossier) + dossier.destroy + end + end + + def self.delete_expired_en_construction_and_notify + dossiers_to_remove = Dossier.en_construction_expired + + dossiers_to_remove.each do |dossier| + DeletedDossier.create_from_dossier(dossier) + end + + dossiers_to_remove + .includes(:user) + .group_by(&:user) + .each do |(user, dossiers)| + DossierMailer.notify_automatic_deletion_to_user( + DeletedDossier.where(dossier_id: dossiers.map(&:id)), + user.email + ).deliver_later + end + + self.group_by_fonctionnaire_email(dossiers_to_remove).each do |(email, dossiers)| + DossierMailer.notify_automatic_deletion_to_administration( + DeletedDossier.where(dossier_id: dossiers.map(&:id)), + email + ).deliver_later + end + + dossiers_to_remove.destroy_all + end + + private + + def self.group_by_fonctionnaire_email(dossiers) + dossiers + .includes(:followers_instructeurs, procedure: [:administrateurs]) + .each_with_object(Hash.new { |h, k| h[k] = Set.new }) do |dossier, h| + (dossier.followers_instructeurs + dossier.procedure.administrateurs).each { |destinataire| h[destinataire.email] << dossier } + end + end +end diff --git a/app/views/dossier_mailer/notify_automatic_deletion_to_administration.html.haml b/app/views/dossier_mailer/notify_automatic_deletion_to_administration.html.haml index e466b459b..373b78d11 100644 --- a/app/views/dossier_mailer/notify_automatic_deletion_to_administration.html.haml +++ b/app/views/dossier_mailer/notify_automatic_deletion_to_administration.html.haml @@ -3,10 +3,10 @@ %p Bonjour, -%p= t('.automatic_dossier_deletion', count: @dossier_hashes.count) - -%ul - - @dossier_hashes.each do |d| - %li= "n° #{d[:id]} (#{d[:procedure_libelle]})" +%p + = t('.header', count: @deleted_dossiers.count) + %ul + - @deleted_dossiers.each do |d| + %li n° #{d.dossier_id} (#{d.procedure.libelle}) = render partial: "layouts/mailers/signature" diff --git a/app/views/dossier_mailer/notify_automatic_deletion_to_user.html.haml b/app/views/dossier_mailer/notify_automatic_deletion_to_user.html.haml index 337151682..8a824675c 100644 --- a/app/views/dossier_mailer/notify_automatic_deletion_to_user.html.haml +++ b/app/views/dossier_mailer/notify_automatic_deletion_to_user.html.haml @@ -3,12 +3,12 @@ %p Bonjour, -%p= t('.automatic_dossier_deletion', count: @dossier_hashes.count) +%p + = t('.header', count: @deleted_dossiers.count) + %ul + - @deleted_dossiers.each do |d| + %li n° #{d.dossier_id} (#{d.procedure.libelle}) -%ul - - @dossier_hashes.each do |d| - %li= link_to("n° #{d[:id]} (#{d[:procedure_libelle]})", dossier_url(d)) - -%p= t('.dossier_will_not_be_processed', count: @dossier_hashes.count) +%p= t('.footer', count: @deleted_dossiers.count) = render partial: "layouts/mailers/signature" diff --git a/app/views/dossier_mailer/notify_brouillon_deletion.html.haml b/app/views/dossier_mailer/notify_brouillon_deletion.html.haml index 7a28ec3f7..a621b7009 100644 --- a/app/views/dossier_mailer/notify_brouillon_deletion.html.haml +++ b/app/views/dossier_mailer/notify_brouillon_deletion.html.haml @@ -3,10 +3,10 @@ %p Bonjour, -%p= t('.automatic_dossier_deletion', count: @dossier_hashes.count) - -%ul - - @dossier_hashes.each do |d| - %li n° #{d[:id]} (#{d[:procedure_libelle]}) +%p + = t('.header', count: @dossier_hashes.count) + %ul + - @dossier_hashes.each do |d| + %li n° #{d[:id]} (#{d[:procedure_libelle]}) = render partial: "layouts/mailers/signature" diff --git a/app/views/dossier_mailer/notify_brouillon_near_deletion.html.haml b/app/views/dossier_mailer/notify_brouillon_near_deletion.html.haml index fc972ddd0..bce0ad8dc 100644 --- a/app/views/dossier_mailer/notify_brouillon_near_deletion.html.haml +++ b/app/views/dossier_mailer/notify_brouillon_near_deletion.html.haml @@ -4,13 +4,11 @@ Bonjour, %p - Afin de limiter la conservation de vos données personnelles, - = t('.automatic_dossier_deletion', count: @dossiers.count) + = t('.header', count: @dossiers.count) %ul - @dossiers.each do |d| %li= link_to("n° #{d.id} (#{d.procedure.libelle})", dossier_url(d)) -%p - #{sanitize(t('.send_your_draft', count: @dossiers.count))}. Et sinon, vous n'avez rien à faire. +%p= sanitize(t('.footer', count: @dossiers.count)) = render partial: "layouts/mailers/signature" diff --git a/app/views/dossier_mailer/notify_deletion_to_administration.html.haml b/app/views/dossier_mailer/notify_deletion_to_administration.html.haml index d53e295e5..e64cab4b6 100644 --- a/app/views/dossier_mailer/notify_deletion_to_administration.html.haml +++ b/app/views/dossier_mailer/notify_deletion_to_administration.html.haml @@ -1,11 +1,9 @@ -- content_for(:title, "Suppression du dossier n° #{@deleted_dossier.dossier_id}") +- content_for(:title, "#{@subject}") %p Bonjour, %p - À la demande de l'usager, le dossier n° #{@deleted_dossier.dossier_id} - (sur la démarche « #{@deleted_dossier.procedure.libelle} ») - a été supprimé. + = t('.body', dossier_id: @deleted_dossier.dossier_id, procedure: @deleted_dossier.procedure.libelle) = render partial: "layouts/mailers/signature" diff --git a/app/views/dossier_mailer/notify_deletion_to_user.html.haml b/app/views/dossier_mailer/notify_deletion_to_user.html.haml index 293994ca1..e64cab4b6 100644 --- a/app/views/dossier_mailer/notify_deletion_to_user.html.haml +++ b/app/views/dossier_mailer/notify_deletion_to_user.html.haml @@ -1,11 +1,9 @@ -- content_for(:title, "Suppression du dossier n° #{@deleted_dossier.dossier_id}") +- content_for(:title, "#{@subject}") %p Bonjour, %p - Votre dossier n° #{@deleted_dossier.dossier_id} - (« #{@deleted_dossier.procedure.libelle} ») a bien été supprimé. - Une trace anonyme de ce traitement sera conservée pour l’administration. + = t('.body', dossier_id: @deleted_dossier.dossier_id, procedure: @deleted_dossier.procedure.libelle) = render partial: "layouts/mailers/signature" diff --git a/app/views/dossier_mailer/notify_en_construction_near_deletion.html.haml b/app/views/dossier_mailer/notify_en_construction_near_deletion.html.haml deleted file mode 100644 index 896138408..000000000 --- a/app/views/dossier_mailer/notify_en_construction_near_deletion.html.haml +++ /dev/null @@ -1,27 +0,0 @@ -- content_for(:title, "#{@subject}") - -%p - Bonjour, - -%p - - if !@for_user - Afin de limiter la conservation de vos données personnelles, - - = t('.automatic_dossier_deletion', count: @dossiers.count) - - %ul - - @dossiers.each do |d| - - if !@for_user - %li - #{link_to("n° #{d.id} (#{d.procedure.libelle})", dossier_url(d))}. Retrouvez le dossier au format #{link_to("PDF", instructeur_dossier_url(d.procedure, d, format: :pdf))} - - else - %li - #{link_to("n° #{d.id} (#{d.procedure.libelle})", dossier_url(d))}. Retrouvez le dossier au format #{link_to("PDF", dossier_url(d, format: :pdf))} - -%p - - if @for_user - = sanitize(t('.send_user_draft', count: @dossiers.count)) - - else - = sanitize(t('.send_other_draft', count: @dossiers.count)) - -= render partial: "layouts/mailers/signature" diff --git a/app/views/dossier_mailer/notify_en_construction_near_deletion_to_administration.html.haml b/app/views/dossier_mailer/notify_en_construction_near_deletion_to_administration.html.haml new file mode 100644 index 000000000..b89f885f9 --- /dev/null +++ b/app/views/dossier_mailer/notify_en_construction_near_deletion_to_administration.html.haml @@ -0,0 +1,16 @@ +- content_for(:title, "#{@subject}") + +%p + Bonjour, + +%p + = t('.header', count: @dossiers.count) + %ul + - @dossiers.each do |d| + %li + #{link_to("n° #{d.id} (#{d.procedure.libelle})", dossier_url(d))}. Retrouvez le dossier au format #{link_to("PDF", instructeur_dossier_url(d.procedure, d, format: :pdf))} + +%p + = sanitize(t('.footer', count: @dossiers.count)) + += render partial: "layouts/mailers/signature" diff --git a/app/views/dossier_mailer/notify_en_construction_near_deletion_to_user.html.haml b/app/views/dossier_mailer/notify_en_construction_near_deletion_to_user.html.haml new file mode 100644 index 000000000..30dd62ad6 --- /dev/null +++ b/app/views/dossier_mailer/notify_en_construction_near_deletion_to_user.html.haml @@ -0,0 +1,16 @@ +- content_for(:title, "#{@subject}") + +%p + Bonjour, + +%p + = t('.header', count: @dossiers.count) + %ul + - @dossiers.each do |d| + %li + #{link_to("n° #{d.id} (#{d.procedure.libelle})", dossier_url(d))}. Retrouvez le dossier au format #{link_to("PDF", dossier_url(d, format: :pdf))} + +%p + = sanitize(t('.footer', count: @dossiers.count)) + += render partial: "layouts/mailers/signature" diff --git a/app/views/new_administrateur/procedures/_informations.html.haml b/app/views/new_administrateur/procedures/_informations.html.haml index 9a3385173..db14b75a1 100644 --- a/app/views/new_administrateur/procedures/_informations.html.haml +++ b/app/views/new_administrateur/procedures/_informations.html.haml @@ -70,6 +70,8 @@ Une notice explicative est un document destiné à guider l’usager dans sa démarche. C’est un document que vous avez élaboré et qui peut prendre la forme d’un fichier doc, d’un pdf ou encore de diapositives. Le bouton pour télécharger cette notice apparaît en haut du formulaire pour l’usager. = f.label :notice, 'Notice' +%p.notice + Formats acceptés : .doc, .odt, .pdf, .ppt, .pptx - notice = @procedure.notice = render 'shared/attachment/edit', { form: f, diff --git a/config/locales/views/dossier_mailer/notify_automatic_deletion_to_administration/fr.yml b/config/locales/views/dossier_mailer/notify_automatic_deletion_to_administration/fr.yml index c0f77813f..1fcfd6198 100644 --- a/config/locales/views/dossier_mailer/notify_automatic_deletion_to_administration/fr.yml +++ b/config/locales/views/dossier_mailer/notify_automatic_deletion_to_administration/fr.yml @@ -4,6 +4,6 @@ fr: subject: one: "Un dossier a été supprimé automatiquement" other: "Des dossiers ont été supprimés automatiquement" - automatic_dossier_deletion: + header: one: "Le délai maximum de conservation du dossier suivant a été atteint, il a donc été supprimé :" other: "Le délai maximum de conservation des dossiers suivants a été atteint, ils ont donc été supprimés :" diff --git a/config/locales/views/dossier_mailer/notify_automatic_deletion_to_user/fr.yml b/config/locales/views/dossier_mailer/notify_automatic_deletion_to_user/fr.yml index 7f5aef939..0f082b5ab 100644 --- a/config/locales/views/dossier_mailer/notify_automatic_deletion_to_user/fr.yml +++ b/config/locales/views/dossier_mailer/notify_automatic_deletion_to_user/fr.yml @@ -4,9 +4,9 @@ fr: subject: one: "Un dossier a été supprimé automatiquement" other: "Des dossiers ont été supprimés automatiquement" - automatic_dossier_deletion: + header: one: "Le délai maximum de conservation du dossier suivant a été atteint, il a donc été supprimé :" other: "Le délai maximum de conservation des dossiers suivants a été atteint, ils ont donc été supprimés :" - dossier_will_not_be_processed: + footer: one: "Le dossier ne sera pas traité, nous nous excusons de la gène occasionnée." other: "Les dossiers ne seront pas traités, nous nous excusons de la gène occasionnée." diff --git a/config/locales/views/dossier_mailer/notify_brouillon_deletion/fr.yml b/config/locales/views/dossier_mailer/notify_brouillon_deletion/fr.yml index 291dffc23..bcb8ce439 100644 --- a/config/locales/views/dossier_mailer/notify_brouillon_deletion/fr.yml +++ b/config/locales/views/dossier_mailer/notify_brouillon_deletion/fr.yml @@ -4,6 +4,6 @@ fr: subject: one: "Un dossier en brouillon a été supprimé automatiquement" other: "Des dossiers en brouillon ont été supprimés automatiquement" - automatic_dossier_deletion: + header: one: "Le délai maximum de conservation du dossier en brouillon suivant a été atteint, il a donc été supprimé :" other: "Le délai maximum de conservation des dossiers en brouillon suivants a été atteint, ils ont donc été supprimés :" diff --git a/config/locales/views/dossier_mailer/notify_brouillon_near_deletion/fr.yml b/config/locales/views/dossier_mailer/notify_brouillon_near_deletion/fr.yml index a3cbf01dc..f4ccef4e0 100644 --- a/config/locales/views/dossier_mailer/notify_brouillon_near_deletion/fr.yml +++ b/config/locales/views/dossier_mailer/notify_brouillon_near_deletion/fr.yml @@ -4,9 +4,9 @@ fr: subject: one: Un dossier en brouillon va bientôt être supprimé other: Des dossiers en brouillon vont bientôt être supprimés - automatic_dossier_deletion: - one: "le dossier en brouillon suivant sera bientôt automatiquement supprimé :" - other: "les dossiers en brouillon suivant seront bientôt automatiquement supprimés :" - send_your_draft: - one: "Si vous souhaitez toujours déposer ce dossier, vous pouvez retrouver votre brouillon pendant encore un mois" - other: "Si vous souhaitez toujours déposer ces dossiers, vous pouvez retrouver vos brouillons pendant encore un mois" + header: + one: "Afin de limiter la conservation de vos données personnelles, le dossier en brouillon suivant sera bientôt automatiquement supprimé :" + other: "Afin de limiter la conservation de vos données personnelles, les dossiers en brouillon suivant seront bientôt automatiquement supprimés :" + footer: + one: "Si vous souhaitez toujours déposer ce dossier, vous pouvez retrouver votre brouillon pendant encore un mois. Et sinon, vous n’avez rien à faire." + other: "Si vous souhaitez toujours déposer ces dossiers, vous pouvez retrouver vos brouillons pendant encore un mois. Et sinon, vous n’avez rien à faire." diff --git a/config/locales/views/dossier_mailer/notify_deletion_to_administration/fr.yml b/config/locales/views/dossier_mailer/notify_deletion_to_administration/fr.yml new file mode 100644 index 000000000..b31847d64 --- /dev/null +++ b/config/locales/views/dossier_mailer/notify_deletion_to_administration/fr.yml @@ -0,0 +1,5 @@ +fr: + dossier_mailer: + notify_deletion_to_administration: + subject: Le dossier nº %{dossier_id} a été supprimé à la demande de l’usager + body: À la demande de l’usager, le dossier n° %{dossier_id} (%{procedure}) a été supprimé. diff --git a/config/locales/views/dossier_mailer/notify_deletion_to_user/fr.yml b/config/locales/views/dossier_mailer/notify_deletion_to_user/fr.yml new file mode 100644 index 000000000..5d8caecf7 --- /dev/null +++ b/config/locales/views/dossier_mailer/notify_deletion_to_user/fr.yml @@ -0,0 +1,5 @@ +fr: + dossier_mailer: + notify_deletion_to_user: + subject: Votre dossier nº %{dossier_id} a bien été supprimé + body: Votre dossier n° %{dossier_id} (%{procedure}) a bien été supprimé. Une trace de ce traitement sera conservée pour l’administration. diff --git a/config/locales/views/dossier_mailer/notify_en_construction_near_deletion/fr.yml b/config/locales/views/dossier_mailer/notify_en_construction_near_deletion/fr.yml deleted file mode 100644 index 6a4955e0b..000000000 --- a/config/locales/views/dossier_mailer/notify_en_construction_near_deletion/fr.yml +++ /dev/null @@ -1,15 +0,0 @@ -fr: - dossier_mailer: - notify_en_construction_near_deletion: - subject: - one: Un dossier en construction va bientôt être supprimé - other: Des dossiers en construction vont bientôt être supprimés - automatic_dossier_deletion: - one: "le dossier en construction suivant sera bientôt automatiquement supprimé :" - other: "les dossiers en construction suivant seront bientôt automatiquement supprimés :" - send_user_draft: - one: "Vous pouvez retrouver votre dossier pendant encore un mois. Vous n'avez rien à faire." - other: "Vous pouvez retrouver vos dossiers pendant encore un mois. Vous n'avez rien à faire." - send_other_draft: - one: "Vous avez un mois pour traiter le dossier." - other: "Vous avez un mois pour traiter les dossiers." diff --git a/config/locales/views/dossier_mailer/notify_en_construction_near_deletion_to_administration/fr.yml b/config/locales/views/dossier_mailer/notify_en_construction_near_deletion_to_administration/fr.yml new file mode 100644 index 000000000..43bf63ded --- /dev/null +++ b/config/locales/views/dossier_mailer/notify_en_construction_near_deletion_to_administration/fr.yml @@ -0,0 +1,12 @@ +fr: + dossier_mailer: + notify_en_construction_near_deletion_to_administration: + subject: + one: Un dossier en construction va bientôt être supprimé + other: Des dossiers en construction vont bientôt être supprimés + header: + one: "Le dossier en construction suivant sera bientôt automatiquement supprimé :" + other: "Les dossiers en construction suivant seront bientôt automatiquement supprimés :" + footer: + one: "Vous avez un mois pour commencer l'instruction du dossier." + other: "Vous avez un mois pour commencer l'instruction des dossiers." diff --git a/config/locales/views/dossier_mailer/notify_en_construction_near_deletion_to_user/fr.yml b/config/locales/views/dossier_mailer/notify_en_construction_near_deletion_to_user/fr.yml new file mode 100644 index 000000000..d9c58d97b --- /dev/null +++ b/config/locales/views/dossier_mailer/notify_en_construction_near_deletion_to_user/fr.yml @@ -0,0 +1,12 @@ +fr: + dossier_mailer: + notify_en_construction_near_deletion_to_user: + subject: + one: Un dossier en construction va bientôt être supprimé + other: Des dossiers en construction vont bientôt être supprimés + header: + one: "Afin de limiter la conservation de vos données personnelles, le dossier en construction suivant sera bientôt automatiquement supprimé :" + other: "Afin de limiter la conservation de vos données personnelles, les dossiers en construction suivant seront bientôt automatiquement supprimés :" + footer: + one: "Vous pouvez retrouver votre dossier pendant encore un mois. Vous n’avez rien à faire." + other: "Vous pouvez retrouver vos dossiers pendant encore un mois. Vous n’avez rien à faire." diff --git a/db/migrate/20191211153436_add_en_construction_close_to_expiration_to_dossiers.rb b/db/migrate/20191211153436_add_en_construction_close_to_expiration_to_dossiers.rb new file mode 100644 index 000000000..4fba9525d --- /dev/null +++ b/db/migrate/20191211153436_add_en_construction_close_to_expiration_to_dossiers.rb @@ -0,0 +1,5 @@ +class AddEnConstructionCloseToExpirationToDossiers < ActiveRecord::Migration[5.2] + def change + add_column :dossiers, :en_construction_close_to_expiration_notice_sent_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index fe75b1601..a7a596376 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -250,9 +250,10 @@ ActiveRecord::Schema.define(version: 2020_03_04_155418) do t.text "private_search_terms" t.bigint "groupe_instructeur_id" t.datetime "brouillon_close_to_expiration_notice_sent_at" + t.datetime "groupe_instructeur_updated_at" + t.datetime "en_construction_close_to_expiration_notice_sent_at" 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.datetime "groupe_instructeur_updated_at" t.index ["archived"], name: "index_dossiers_on_archived" t.index ["groupe_instructeur_id"], name: "index_dossiers_on_groupe_instructeur_id" t.index ["hidden_at"], name: "index_dossiers_on_hidden_at" diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 990c55961..8289c3482 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -164,6 +164,7 @@ describe ApplicationController, type: :controller do allow(@controller).to receive(:instructeur_signed_in?).and_return(instructeur_signed_in) allow(@controller).to receive(:sensitive_path).and_return(sensitive_path) allow(@controller).to receive(:send_login_token_or_bufferize) + allow(@controller).to receive(:get_stored_location_for).and_return(nil) allow(@controller).to receive(:store_location_for) allow(IPService).to receive(:ip_trusted?).and_return(ip_trusted) end diff --git a/spec/features/users/dossier_creation_spec.rb b/spec/features/users/dossier_creation_spec.rb index 662d02918..e54228974 100644 --- a/spec/features/users/dossier_creation_spec.rb +++ b/spec/features/users/dossier_creation_spec.rb @@ -110,4 +110,16 @@ feature 'Creating a new dossier:' do end end end + + context 'when the user is not signed in' do + let(:instructeur) { create(:instructeur) } + let(:procedure) { create(:procedure, :published) } + scenario 'the user is an instructeur with untrusted device' do + visit commencer_path(path: procedure.path) + click_on "J’ai déjà un compte" + sign_in_with(instructeur.email, instructeur.user.password, true) + + expect(page).to have_current_path(commencer_path(path: procedure.path)) + end + end end diff --git a/spec/mailers/dossier_mailer_spec.rb b/spec/mailers/dossier_mailer_spec.rb index c18b2ebb4..c277461c8 100644 --- a/spec/mailers/dossier_mailer_spec.rb +++ b/spec/mailers/dossier_mailer_spec.rb @@ -55,8 +55,8 @@ RSpec.describe DossierMailer, type: :mailer do subject { described_class.notify_deletion_to_administration(deleted_dossier, to_email) } - it { expect(subject.subject).to eq("Le dossier nº #{deleted_dossier.dossier_id} a été supprimé à la demande de l'usager") } - it { expect(subject.body).to include("À la demande de l'usager") } + it { expect(subject.subject).to eq("Le dossier nº #{deleted_dossier.dossier_id} a été supprimé à la demande de l’usager") } + it { expect(subject.body).to include("À la demande de l’usager") } it { expect(subject.body).to include(deleted_dossier.dossier_id) } it { expect(subject.body).to include(deleted_dossier.procedure.libelle) } end @@ -81,7 +81,7 @@ RSpec.describe DossierMailer, type: :mailer do @date_suppression = dossier.created_at + duree.months end - subject { described_class.notify_brouillon_near_deletion(dossier.user, [dossier]) } + subject { described_class.notify_brouillon_near_deletion([dossier], dossier.user.email) } it { expect(subject.body).to include("n° #{dossier.id} ") } it { expect(subject.body).to include(dossier.procedure.libelle) } @@ -90,7 +90,7 @@ RSpec.describe DossierMailer, type: :mailer do describe '.notify_brouillon_deletion' do let(:dossier) { create(:dossier) } - subject { described_class.notify_brouillon_deletion(dossier.user, [dossier.hash_for_deletion_mail]) } + subject { described_class.notify_brouillon_deletion([dossier.hash_for_deletion_mail], dossier.user.email) } it { expect(subject.subject).to eq("Un dossier en brouillon a été supprimé automatiquement") } it { expect(subject.body).to include("n° #{dossier.id} (#{dossier.procedure.libelle})") } @@ -98,14 +98,16 @@ RSpec.describe DossierMailer, type: :mailer do describe '.notify_automatic_deletion_to_user' do let(:dossier) { create(:dossier) } + let(:deleted_dossier) { DeletedDossier.create_from_dossier(dossier) } before do duree = dossier.procedure.duree_conservation_dossiers_dans_ds @date_suppression = dossier.created_at + duree.months end - subject { described_class.notify_automatic_deletion_to_user(dossier.user, [dossier.hash_for_deletion_mail]) } + subject { described_class.notify_automatic_deletion_to_user([deleted_dossier], dossier.user.email) } + it { expect(subject.to).to eq([dossier.user.email]) } it { expect(subject.subject).to eq("Un dossier a été supprimé automatiquement") } it { expect(subject.body).to include("n° #{dossier.id} ") } it { expect(subject.body).to include(dossier.procedure.libelle) } @@ -114,8 +116,9 @@ RSpec.describe DossierMailer, type: :mailer do describe '.notify_automatic_deletion_to_administration' do let(:dossier) { create(:dossier) } + let(:deleted_dossier) { DeletedDossier.create_from_dossier(dossier) } - subject { described_class.notify_automatic_deletion_to_administration(dossier.user, [dossier.hash_for_deletion_mail]) } + subject { described_class.notify_automatic_deletion_to_administration([deleted_dossier], dossier.user.email) } it { expect(subject.subject).to eq("Un dossier a été supprimé automatiquement") } it { expect(subject.body).to include("n° #{dossier.id} (#{dossier.procedure.libelle})") } @@ -129,13 +132,13 @@ RSpec.describe DossierMailer, type: :mailer do @date_suppression = dossier.created_at + duree.months end - subject { described_class.notify_en_construction_near_deletion(dossier.user, [dossier], true) } + subject { described_class.notify_en_construction_near_deletion_to_administration([dossier], dossier.user.email) } it { expect(subject.subject).to eq("Un dossier en construction va bientôt être supprimé") } it { expect(subject.body).to include("n° #{dossier.id} ") } it { expect(subject.body).to include(dossier.procedure.libelle) } it { expect(subject.body).to include("PDF") } - it { expect(subject.body).to include("Vous pouvez retrouver votre dossier pendant encore un mois. Vous n'avez rien à faire.") } + it { expect(subject.body).to include("Vous avez un mois pour commencer l'instruction du dossier.") } end describe '.notify_en_construction_near_deletion_to_user' do @@ -146,13 +149,14 @@ RSpec.describe DossierMailer, type: :mailer do @date_suppression = dossier.created_at + duree.months end - subject { described_class.notify_en_construction_near_deletion(dossier.user, [dossier], false) } + subject { described_class.notify_en_construction_near_deletion_to_user([dossier], dossier.user.email) } + it { expect(subject.to).to eq([dossier.user.email]) } it { expect(subject.subject).to eq("Un dossier en construction va bientôt être supprimé") } it { expect(subject.body).to include("n° #{dossier.id} ") } it { expect(subject.body).to include(dossier.procedure.libelle) } it { expect(subject.body).to include("PDF") } - it { expect(subject.body).to include("Vous avez un mois pour traiter le dossier.") } + it { expect(subject.body).to include("Vous pouvez retrouver votre dossier pendant encore un mois. Vous n’avez rien à faire.") } end describe '.notify_groupe_instructeur_changed_to_instructeur' do diff --git a/spec/mailers/previews/dossier_mailer_preview.rb b/spec/mailers/previews/dossier_mailer_preview.rb index f1fc2dab7..55c1fd562 100644 --- a/spec/mailers/previews/dossier_mailer_preview.rb +++ b/spec/mailers/previews/dossier_mailer_preview.rb @@ -8,37 +8,61 @@ class DossierMailerPreview < ActionMailer::Preview DossierMailer.notify_new_answer(dossier) end - def notify_deletion_to_user - DossierMailer.notify_deletion_to_user(deleted_dossier, "user@ds.fr") - end - - def notify_deletion_to_administration - DossierMailer.notify_deletion_to_administration(deleted_dossier, "admin@ds.fr") - end - def notify_revert_to_instruction DossierMailer.notify_revert_to_instruction(dossier) end def notify_brouillon_near_deletion - DossierMailer.notify_brouillon_near_deletion(User.new(email: "usager@example.com"), [dossier]) + DossierMailer.notify_brouillon_near_deletion([dossier], usager_email) end def notify_brouillons_near_deletion - DossierMailer.notify_brouillon_near_deletion(User.new(email: "usager@example.com"), [dossier, dossier]) + DossierMailer.notify_brouillon_near_deletion([dossier, dossier], usager_email) + end + + def notify_en_construction_near_deletion_to_user + DossierMailer.notify_en_construction_near_deletion_to_user([dossier], usager_email) + end + + def notify_en_construction_near_deletion_to_administration + DossierMailer.notify_en_construction_near_deletion_to_administration([dossier, dossier], administration_email) end def notify_brouillon_deletion - DossierMailer.notify_brouillon_deletion(User.new(email: "usager@example.com"), [dossier.hash_for_deletion_mail]) + DossierMailer.notify_brouillon_deletion([dossier.hash_for_deletion_mail], usager_email) end def notify_brouillons_deletion dossier_hashes = [dossier, dossier].map(&:hash_for_deletion_mail) - DossierMailer.notify_brouillon_deletion(User.new(email: "usager@example.com"), dossier_hashes) + DossierMailer.notify_brouillon_deletion(dossier_hashes, usager_email) + end + + def notify_deletion_to_user + DossierMailer.notify_deletion_to_user(deleted_dossier, usager_email) + end + + def notify_deletion_to_administration + DossierMailer.notify_deletion_to_administration(deleted_dossier, administration_email) + end + + def notify_automatic_deletion_to_user + DossierMailer.notify_automatic_deletion_to_user([deleted_dossier, deleted_dossier], usager_email) + end + + def notify_automatic_deletion_to_administration + DossierMailer.notify_automatic_deletion_to_administration([deleted_dossier, deleted_dossier], administration_email) end private + def usager_email + "usager@example.com" + end + + def administration_email + "administration@example.com" + end + def deleted_dossier DeletedDossier.new(dossier_id: 1, procedure: procedure) end @@ -52,7 +76,7 @@ class DossierMailerPreview < ActionMailer::Preview end def procedure - Procedure.new(libelle: 'Dotation d’Équipement des Territoires Ruraux - Exercice 2019', service: service, logo: Rack::Test::UploadedFile.new("./spec/fixtures/files/logo_test_procedure.png", 'image/png')) + Procedure.new(id: 1234, libelle: 'Dotation d’Équipement des Territoires Ruraux - Exercice 2019', service: service, logo: Rack::Test::UploadedFile.new("./spec/fixtures/files/logo_test_procedure.png", 'image/png')) end def service diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb index f1cad93d2..b620ad968 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -45,29 +45,54 @@ describe Dossier do end end - describe 'nearing_end_of_retention' do + describe 'brouillon_close_to_expiration' do + let(:procedure) { create(:procedure, duree_conservation_dossiers_dans_ds: 6) } + let!(:young_dossier) { create(:dossier, :en_construction, procedure: procedure) } + let!(:expiring_dossier) { create(:dossier, created_at: 170.days.ago, procedure: procedure) } + let!(:just_expired_dossier) { create(:dossier, created_at: (6.months + 1.hour + 10.seconds).ago, procedure: procedure) } + let!(:long_expired_dossier) { create(:dossier, created_at: 1.year.ago, procedure: procedure) } + + subject { Dossier.brouillon_close_to_expiration } + + it do + is_expected.not_to include(young_dossier) + is_expected.to include(expiring_dossier) + is_expected.to include(just_expired_dossier) + is_expected.to include(long_expired_dossier) + end + end + + describe 'en_construction_close_to_expiration' do + let(:procedure) { create(:procedure, duree_conservation_dossiers_dans_ds: 6) } + let!(:young_dossier) { create(:dossier, procedure: procedure) } + let!(:expiring_dossier) { create(:dossier, :en_construction, en_construction_at: 170.days.ago, procedure: procedure) } + let!(:just_expired_dossier) { create(:dossier, :en_construction, en_construction_at: (6.months + 1.hour + 10.seconds).ago, procedure: procedure) } + let!(:long_expired_dossier) { create(:dossier, :en_construction, en_construction_at: 1.year.ago, procedure: procedure) } + + subject { Dossier.en_construction_close_to_expiration } + + it do + is_expected.not_to include(young_dossier) + is_expected.to include(expiring_dossier) + is_expected.to include(just_expired_dossier) + is_expected.to include(long_expired_dossier) + end + end + + describe 'en_instruction_close_to_expiration' do let(:procedure) { create(:procedure, duree_conservation_dossiers_dans_ds: 6) } let!(:young_dossier) { create(:dossier, procedure: procedure) } let!(:expiring_dossier) { create(:dossier, :en_instruction, en_instruction_at: 170.days.ago, procedure: procedure) } let!(:just_expired_dossier) { create(:dossier, :en_instruction, en_instruction_at: (6.months + 1.hour + 10.seconds).ago, procedure: procedure) } let!(:long_expired_dossier) { create(:dossier, :en_instruction, en_instruction_at: 1.year.ago, procedure: procedure) } - context 'with default delay to end of retention' do - subject { Dossier.nearing_end_of_retention } + subject { Dossier.en_instruction_close_to_expiration } - it { is_expected.not_to include(young_dossier) } - it { is_expected.to include(expiring_dossier) } - it { is_expected.to include(just_expired_dossier) } - it { is_expected.to include(long_expired_dossier) } - end - - context 'with custom delay to end of retention' do - subject { Dossier.nearing_end_of_retention('0') } - - it { is_expected.not_to include(young_dossier) } - it { is_expected.not_to include(expiring_dossier) } - it { is_expected.to include(just_expired_dossier) } - it { is_expected.to include(long_expired_dossier) } + it do + is_expected.not_to include(young_dossier) + is_expected.to include(expiring_dossier) + is_expected.to include(just_expired_dossier) + is_expected.to include(long_expired_dossier) end end @@ -1072,60 +1097,6 @@ describe Dossier do it { expect(Dossier.for_procedure(procedure_2)).to contain_exactly(dossier_2_1) } end - describe '#send_brouillon_expiration_notices' do - before { Timecop.freeze(Time.zone.parse('12/12/2012 15:00:00')) } - - let!(:procedure) { create(:procedure, duree_conservation_dossiers_dans_ds: 6) } - let!(:date_close_to_expiration) { Time.zone.now - procedure.duree_conservation_dossiers_dans_ds.months + 1.month } - let!(:date_expired) { Time.zone.now - procedure.duree_conservation_dossiers_dans_ds.months - 6.days } - let!(:date_not_expired) { Time.zone.now - procedure.duree_conservation_dossiers_dans_ds.months + 2.months } - - after { Timecop.return } - - context "Envoi de message pour les dossiers expirant dans - d'un mois" do - let!(:expired_brouillon) { create(:dossier, procedure: procedure, created_at: date_expired) } - let!(:brouillon_close_to_expiration) { create(:dossier, procedure: procedure, created_at: date_close_to_expiration) } - let!(:brouillon_close_but_with_notice_sent) { create(:dossier, procedure: procedure, created_at: date_close_to_expiration, brouillon_close_to_expiration_notice_sent_at: Time.zone.now) } - let!(:valid_brouillon) { create(:dossier, procedure: procedure, created_at: date_not_expired) } - - before do - allow(DossierMailer).to receive(:notify_brouillon_near_deletion).and_return(double(deliver_later: nil)) - Dossier.send_brouillon_expiration_notices - end - - it 'verification de la creation de mail' do - expect(DossierMailer).to have_received(:notify_brouillon_near_deletion).with(brouillon_close_to_expiration.user, [brouillon_close_to_expiration]) - expect(DossierMailer).to have_received(:notify_brouillon_near_deletion).with(expired_brouillon.user, [expired_brouillon]) - end - - it 'Verification du changement d etat du champ' do - expect(brouillon_close_to_expiration.reload.brouillon_close_to_expiration_notice_sent_at).not_to be_nil - end - end - end - - describe '#destroy_brouillons_and_notify' do - let!(:today) { Time.zone.now.at_midnight } - - let!(:expired_brouillon) { create(:dossier, brouillon_close_to_expiration_notice_sent_at: today - (Dossier::DRAFT_EXPIRATION + 1.day)) } - let!(:other_brouillon) { create(:dossier, brouillon_close_to_expiration_notice_sent_at: today - (Dossier::DRAFT_EXPIRATION - 1.day)) } - - before do - allow(DossierMailer).to receive(:notify_brouillon_deletion).and_return(double(deliver_later: nil)) - Dossier.destroy_brouillons_and_notify - end - - it 'notifies deletion' do - expect(DossierMailer).to have_received(:notify_brouillon_deletion).once - expect(DossierMailer).to have_received(:notify_brouillon_deletion).with(expired_brouillon.user, [expired_brouillon.hash_for_deletion_mail]) - end - - it 'deletes the expired brouillon' do - expect(DeletedDossier.find_by(dossier_id: expired_brouillon.id)).to be_present - expect { expired_brouillon.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - end - describe '#geo_position' do let(:lat) { "46.538192" } let(:lon) { "2.428462" } diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index 080d753a5..0d3b220df 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -193,12 +193,19 @@ describe Procedure do context 'when the deliberation is uploaded ' do before do - allow(procedure).to receive(:deliberation) - .and_return(double('attached?': true)) + procedure.deliberation = Rack::Test::UploadedFile.new('spec/fixtures/files/file.pdf', 'application/pdf') end it { expect(procedure.valid?).to eq(true) } end + + context 'when the deliberation is uploaded with an unauthorized format' do + before do + procedure.deliberation = Rack::Test::UploadedFile.new('spec/fixtures/files/french-flag.gif', 'image/gif') + end + + it { expect(procedure.valid?).to eq(false) } + end end end @@ -925,8 +932,9 @@ describe Procedure do p.reload expect(p.juridique_required).to be_falsey - allow(p).to receive(:deliberation).and_return(double('attached?': true)) - p.save + @deliberation = Rack::Test::UploadedFile.new('spec/fixtures/files/file.pdf', 'application/pdf') + p.update(deliberation: @deliberation) + p.reload expect(p.juridique_required).to be_truthy end end diff --git a/spec/services/expired_dossiers_deletion_service_spec.rb b/spec/services/expired_dossiers_deletion_service_spec.rb new file mode 100644 index 000000000..1b7c1088f --- /dev/null +++ b/spec/services/expired_dossiers_deletion_service_spec.rb @@ -0,0 +1,280 @@ +require 'spec_helper' + +describe ExpiredDossiersDeletionService do + describe '#process_expired_dossiers_brouillon' do + let(:draft_expiration) { 1.month + 5.days } + let!(:today) { Time.zone.now.at_midnight } + let!(:procedure) { create(:procedure, duree_conservation_dossiers_dans_ds: 6) } + let!(:date_close_to_expiration) { Date.today - procedure.duree_conservation_dossiers_dans_ds.months + 1.month } + let!(:date_expired) { Date.today - procedure.duree_conservation_dossiers_dans_ds.months - 6.days } + let!(:date_not_expired) { Date.today - procedure.duree_conservation_dossiers_dans_ds.months + 2.months } + + context 'send messages for dossiers expiring soon and delete expired' do + let!(:expired_brouillon) { create(:dossier, procedure: procedure, created_at: date_expired, brouillon_close_to_expiration_notice_sent_at: today - (draft_expiration + 1.day)) } + let!(:brouillon_close_to_expiration) { create(:dossier, procedure: procedure, created_at: date_close_to_expiration) } + let!(:brouillon_close_but_with_notice_sent) { create(:dossier, procedure: procedure, created_at: date_close_to_expiration, brouillon_close_to_expiration_notice_sent_at: Time.zone.now) } + let!(:valid_brouillon) { create(:dossier, procedure: procedure, created_at: date_not_expired) } + + before do + allow(DossierMailer).to receive(:notify_brouillon_near_deletion).and_return(double(deliver_later: nil)) + allow(DossierMailer).to receive(:notify_brouillon_deletion).and_return(double(deliver_later: nil)) + + ExpiredDossiersDeletionService.process_expired_dossiers_brouillon + end + + it 'emails should be sent' do + expect(DossierMailer).to have_received(:notify_brouillon_near_deletion).once + expect(DossierMailer).to have_received(:notify_brouillon_near_deletion).with([brouillon_close_to_expiration], brouillon_close_to_expiration.user.email) + end + + it 'dossier state should change' do + expect(brouillon_close_to_expiration.reload.brouillon_close_to_expiration_notice_sent_at).not_to be_nil + end + + it 'deletes and notify expired brouillon' do + expect(DossierMailer).to have_received(:notify_brouillon_deletion).once + expect(DossierMailer).to have_received(:notify_brouillon_deletion).with([expired_brouillon.hash_for_deletion_mail], expired_brouillon.user.email) + expect(DeletedDossier.find_by(dossier_id: expired_brouillon.id)).to be_present + expect { expired_brouillon.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end + + describe '#send_brouillon_expiration_notices' do + let!(:conservation_par_defaut) { 3.months } + + before { Timecop.freeze(Time.zone.now) } + after { Timecop.return } + + before do + allow(DossierMailer).to receive(:notify_brouillon_near_deletion).and_return(double(deliver_later: nil)) + end + + context 'with a single dossier' do + let!(:dossier) { create(:dossier, created_at: created_at) } + + before { ExpiredDossiersDeletionService.send_brouillon_expiration_notices } + + context 'when the dossier is not closed to expiration' do + let(:created_at) { (conservation_par_defaut - 1.month - 1.day).ago } + + it { expect(dossier.reload.brouillon_close_to_expiration_notice_sent_at).to be_nil } + it { expect(DossierMailer).not_to have_received(:notify_brouillon_near_deletion) } + end + + context 'when the dossier is closed to expiration' do + let(:created_at) { (conservation_par_defaut - 1.month + 1.day).ago } + + it { expect(dossier.reload.brouillon_close_to_expiration_notice_sent_at).not_to be_nil } + it { expect(DossierMailer).to have_received(:notify_brouillon_near_deletion).once } + it { expect(DossierMailer).to have_received(:notify_brouillon_near_deletion).with([dossier], dossier.user.email) } + end + end + + context 'with 2 dossiers to notice' do + let!(:user) { create(:user) } + let!(:dossier_1) { create(:dossier, user: user, created_at: (conservation_par_defaut - 1.month + 1.day).ago) } + let!(:dossier_2) { create(:dossier, user: user, created_at: (conservation_par_defaut - 1.month + 1.day).ago) } + + before { ExpiredDossiersDeletionService.send_brouillon_expiration_notices } + + it { expect(DossierMailer).to have_received(:notify_brouillon_near_deletion).once } + it { expect(DossierMailer).to have_received(:notify_brouillon_near_deletion).with(match_array([dossier_1, dossier_2]), user.email) } + end + end + + describe '#delete_expired_brouillons_and_notify' do + let!(:warning_period) { 1.month + 5.days } + + before { Timecop.freeze(Time.zone.now) } + after { Timecop.return } + + before do + allow(DossierMailer).to receive(:notify_brouillon_deletion).and_return(double(deliver_later: nil)) + end + + context 'with a single dossier' do + let!(:dossier) { create(:dossier, brouillon_close_to_expiration_notice_sent_at: notice_sent_at) } + + before { ExpiredDossiersDeletionService.delete_expired_brouillons_and_notify } + + context 'when no notice has been sent' do + let(:notice_sent_at) { nil } + + it { expect { dossier.reload }.not_to raise_error } + it { expect(DossierMailer).not_to have_received(:notify_brouillon_deletion) } + end + + context 'when a notice has been sent not so long ago' do + let(:notice_sent_at) { (warning_period - 1.day).ago } + + it { expect { dossier.reload }.not_to raise_error } + it { expect(DossierMailer).not_to have_received(:notify_brouillon_deletion) } + end + + context 'when a notice has been sent a long time ago' do + let(:notice_sent_at) { (warning_period + 1.day).ago } + + it { expect { dossier.reload }.to raise_error(ActiveRecord::RecordNotFound) } + + it { expect(DossierMailer).to have_received(:notify_brouillon_deletion).once } + it { expect(DossierMailer).to have_received(:notify_brouillon_deletion).with([dossier.hash_for_deletion_mail], dossier.user.email) } + end + end + + context 'with 2 dossiers to delete' do + let!(:user) { create(:user) } + let!(:dossier_1) { create(:dossier, user: user, brouillon_close_to_expiration_notice_sent_at: (warning_period + 1.day).ago) } + let!(:dossier_2) { create(:dossier, user: user, brouillon_close_to_expiration_notice_sent_at: (warning_period + 1.day).ago) } + + before { ExpiredDossiersDeletionService.delete_expired_brouillons_and_notify } + + it { expect(DossierMailer).to have_received(:notify_brouillon_deletion).once } + it { expect(DossierMailer).to have_received(:notify_brouillon_deletion).with(match_array([dossier_1.hash_for_deletion_mail, dossier_2.hash_for_deletion_mail]), user.email) } + end + end + + describe '#send_en_construction_expiration_notices' do + let!(:conservation_par_defaut) { 3.months } + + before { Timecop.freeze(Time.zone.now) } + after { Timecop.return } + + before do + allow(DossierMailer).to receive(:notify_en_construction_near_deletion_to_user).and_return(double(deliver_later: nil)) + allow(DossierMailer).to receive(:notify_en_construction_near_deletion_to_administration).and_return(double(deliver_later: nil)) + end + + context 'with a single dossier' do + let!(:dossier) { create(:dossier, :en_construction, :followed, en_construction_at: en_construction_at) } + + before { ExpiredDossiersDeletionService.send_en_construction_expiration_notices } + + context 'when the dossier is not near deletion' do + let(:en_construction_at) { (conservation_par_defaut - 1.month - 1.day).ago } + + it { expect(dossier.reload.en_construction_close_to_expiration_notice_sent_at).to be_nil } + it { expect(DossierMailer).not_to have_received(:notify_en_construction_near_deletion_to_user) } + it { expect(DossierMailer).not_to have_received(:notify_en_construction_near_deletion_to_administration) } + end + + context 'when the dossier is near deletion' do + let(:en_construction_at) { (conservation_par_defaut - 1.month + 1.day).ago } + + it { expect(dossier.reload.en_construction_close_to_expiration_notice_sent_at).not_to be_nil } + + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_user).once } + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_administration).twice } + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_user).with([dossier], dossier.user.email) } + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_administration).with([dossier], dossier.procedure.administrateurs.first.email) } + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_administration).with([dossier], dossier.followers_instructeurs.first.email) } + end + end + + context 'with 2 dossiers to notice' do + let!(:user) { create(:user) } + let!(:dossier_1) { create(:dossier, :en_construction, user: user, en_construction_at: (conservation_par_defaut - 1.month + 1.day).ago) } + let!(:dossier_2) { create(:dossier, :en_construction, user: user, en_construction_at: (conservation_par_defaut - 1.month + 1.day).ago) } + + let!(:instructeur) { create(:instructeur) } + + before do + instructeur.followed_dossiers << dossier_1 << dossier_2 + ExpiredDossiersDeletionService.send_en_construction_expiration_notices + end + + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_user).once } + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_administration).exactly(3).times } + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_user).with(match_array([dossier_1, dossier_2]), user.email) } + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_administration).with(match_array([dossier_1, dossier_2]), instructeur.email) } + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_administration).with([dossier_1], dossier_1.procedure.administrateurs.first.email) } + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_administration).with([dossier_2], dossier_2.procedure.administrateurs.first.email) } + end + + context 'when an instructeur is also administrateur' do + let!(:procedure) { create(:procedure) } + let!(:administrateur) { procedure.administrateurs.first } + let!(:dossier) { create(:dossier, :en_construction, procedure: procedure, en_construction_at: (conservation_par_defaut - 1.month + 1.day).ago) } + + before do + administrateur.instructeur.followed_dossiers << dossier + ExpiredDossiersDeletionService.send_en_construction_expiration_notices + end + + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_user).once } + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_user).with([dossier], dossier.user.email) } + it { expect(DossierMailer).to have_received(:notify_en_construction_near_deletion_to_administration).with([dossier], administrateur.email) } + end + end + + describe '#delete_expired_en_construction_and_notify' do + let!(:warning_period) { 1.month + 5.days } + + before { Timecop.freeze(Time.zone.now) } + after { Timecop.return } + + before do + allow(DossierMailer).to receive(:notify_automatic_deletion_to_user).and_return(double(deliver_later: nil)) + allow(DossierMailer).to receive(:notify_automatic_deletion_to_administration).and_return(double(deliver_later: nil)) + end + + context 'with a single dossier' do + let!(:dossier) { create(:dossier, :en_construction, :followed, en_construction_close_to_expiration_notice_sent_at: notice_sent_at) } + let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier.id) } + + before { ExpiredDossiersDeletionService.delete_expired_en_construction_and_notify } + + context 'when no notice has been sent' do + let(:notice_sent_at) { nil } + + it { expect { dossier.reload }.not_to raise_error } + it { expect(DossierMailer).not_to have_received(:notify_automatic_deletion_to_user) } + it { expect(DossierMailer).not_to have_received(:notify_automatic_deletion_to_administration) } + end + + context 'when a notice has been sent not so long ago' do + let(:notice_sent_at) { (warning_period - 1.day).ago } + + it { expect { dossier.reload }.not_to raise_error } + it { expect(DossierMailer).not_to have_received(:notify_automatic_deletion_to_user) } + it { expect(DossierMailer).not_to have_received(:notify_automatic_deletion_to_administration) } + end + + context 'when a notice has been sent a long time ago' do + let(:notice_sent_at) { (warning_period + 1.day).ago } + + it { expect { dossier.reload }.to raise_error(ActiveRecord::RecordNotFound) } + + it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_user).once } + it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_user).with([deleted_dossier], dossier.user.email) } + + it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).twice } + it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([deleted_dossier], dossier.procedure.administrateurs.first.email) } + it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([deleted_dossier], dossier.followers_instructeurs.first.email) } + end + end + + context 'with 2 dossiers to delete' do + let!(:user) { create(:user) } + let!(:dossier_1) { create(:dossier, :en_construction, user: user, en_construction_close_to_expiration_notice_sent_at: (warning_period + 1.day).ago) } + let!(:dossier_2) { create(:dossier, :en_construction, user: user, en_construction_close_to_expiration_notice_sent_at: (warning_period + 1.day).ago) } + let(:deleted_dossier_1) { DeletedDossier.find_by(dossier_id: dossier_1.id) } + let(:deleted_dossier_2) { DeletedDossier.find_by(dossier_id: dossier_2.id) } + + let!(:instructeur) { create(:instructeur) } + + before do + instructeur.followed_dossiers << dossier_1 << dossier_2 + ExpiredDossiersDeletionService.delete_expired_en_construction_and_notify + end + + it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_user).once } + it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_user).with(match_array([deleted_dossier_1, deleted_dossier_2]), user.email) } + + it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).thrice } + it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with(match_array([deleted_dossier_1, deleted_dossier_2]), instructeur.email) } + it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([deleted_dossier_1], dossier_1.procedure.administrateurs.first.email) } + it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_administration).with([deleted_dossier_2], dossier_2.procedure.administrateurs.first.email) } + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f5e6de454..97fca6426 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -44,7 +44,7 @@ Capybara.register_driver :headless_chrome do |app| options.add_argument('--window-size=1440,900') capabilities = Selenium::WebDriver::Remote::Capabilities.chrome( - chromeOptions: { args: ['headless', 'disable-dev-shm-usage', 'disable-software-rasterizer', 'mute-audio', 'window-size=1440,900'] } + chromeOptions: { args: ['disable-dev-shm-usage', 'disable-software-rasterizer', 'mute-audio', 'window-size=1440,900'] } ) Capybara::Selenium::Driver.new app,