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,