commit
4778eaaa9e
56 changed files with 433 additions and 427 deletions
|
@ -54,6 +54,10 @@
|
|||
font-size: 14px;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.mt-1 {
|
||||
margin-top: $default-spacer;
|
||||
}
|
||||
|
|
|
@ -3,12 +3,17 @@ module Administrateurs
|
|||
before_action :retrieve_procedure
|
||||
|
||||
def edit
|
||||
@attestation_template = @procedure.attestation_template || AttestationTemplate.new(procedure: @procedure)
|
||||
@attestation_template = build_attestation
|
||||
end
|
||||
|
||||
def update
|
||||
attestation_template = @procedure.attestation_template
|
||||
attestation_template = @procedure.draft_attestation_template.revise!
|
||||
|
||||
if attestation_template.update(activated_attestation_params)
|
||||
AttestationTemplate
|
||||
.where(id: @procedure.revisions.pluck(:attestation_template_id).compact)
|
||||
.update_all(activated: attestation_template.activated?)
|
||||
|
||||
flash.notice = "L'attestation a bien été modifiée"
|
||||
else
|
||||
flash.alert = attestation_template.errors.full_messages.join('<br>')
|
||||
|
@ -18,7 +23,7 @@ module Administrateurs
|
|||
end
|
||||
|
||||
def create
|
||||
attestation_template = AttestationTemplate.new(activated_attestation_params.merge(procedure_id: @procedure.id))
|
||||
attestation_template = build_attestation(activated_attestation_params)
|
||||
|
||||
if attestation_template.save
|
||||
flash.notice = "L'attestation a bien été sauvegardée"
|
||||
|
@ -30,14 +35,19 @@ module Administrateurs
|
|||
end
|
||||
|
||||
def preview
|
||||
attestation = @procedure.attestation_template || AttestationTemplate.new
|
||||
@attestation = attestation.render_attributes_for({})
|
||||
@attestation = build_attestation.render_attributes_for({})
|
||||
|
||||
render 'administrateurs/attestation_templates/show', formats: [:pdf]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build_attestation(attributes = {})
|
||||
attestation_template = @procedure.draft_attestation_template || @procedure.draft_revision.build_attestation_template
|
||||
attestation_template.attributes = attributes
|
||||
attestation_template
|
||||
end
|
||||
|
||||
def activated_attestation_params
|
||||
# cache result to avoid multiple uninterlaced computations
|
||||
if @activated_attestation_params.nil?
|
||||
|
|
|
@ -208,34 +208,33 @@ module Administrateurs
|
|||
end
|
||||
|
||||
def import
|
||||
if !CSV_ACCEPTED_CONTENT_TYPES.include?(group_csv_file.content_type) && !CSV_ACCEPTED_CONTENT_TYPES.include?(marcel_content_type)
|
||||
flash[:alert] = "Importation impossible : veuillez importer un fichier CSV"
|
||||
redirect_to admin_procedure_groupe_instructeurs_path(procedure)
|
||||
if procedure.publiee?
|
||||
if !CSV_ACCEPTED_CONTENT_TYPES.include?(group_csv_file.content_type) && !CSV_ACCEPTED_CONTENT_TYPES.include?(marcel_content_type)
|
||||
flash[:alert] = "Importation impossible : veuillez importer un fichier CSV"
|
||||
|
||||
elsif group_csv_file.size > CSV_MAX_SIZE
|
||||
flash[:alert] = "Importation impossible : le poids du fichier est supérieur à #{number_to_human_size(CSV_MAX_SIZE)}"
|
||||
redirect_to admin_procedure_groupe_instructeurs_path(procedure)
|
||||
elsif group_csv_file.size > CSV_MAX_SIZE
|
||||
flash[:alert] = "Importation impossible : le poids du fichier est supérieur à #{number_to_human_size(CSV_MAX_SIZE)}"
|
||||
|
||||
else
|
||||
file = group_csv_file.read
|
||||
base_encoding = CharlockHolmes::EncodingDetector.detect(file)
|
||||
groupes_emails = ACSV::CSV.new_for_ruby3(file.encode("UTF-8", base_encoding[:encoding], invalid: :replace, replace: ""), headers: true, header_converters: :downcase)
|
||||
.map { |r| r.to_h.slice('groupe', 'email') }
|
||||
|
||||
groupes_emails_has_keys = groupes_emails.first.has_key?("groupe") && groupes_emails.first.has_key?("email")
|
||||
|
||||
if groupes_emails_has_keys.blank?
|
||||
flash[:alert] = "Importation impossible, veuillez importer un csv #{view_context.link_to('suivant ce modèle', "/csv/#{I18n.locale}/import-groupe-test.csv")}"
|
||||
else
|
||||
add_instructeurs_and_get_errors = InstructeursImportService.import(procedure, groupes_emails)
|
||||
file = group_csv_file.read
|
||||
base_encoding = CharlockHolmes::EncodingDetector.detect(file)
|
||||
groupes_emails = ACSV::CSV.new_for_ruby3(file.encode("UTF-8", base_encoding[:encoding], invalid: :replace, replace: ""), headers: true, header_converters: :downcase)
|
||||
.map { |r| r.to_h.slice('groupe', 'email') }
|
||||
|
||||
if add_instructeurs_and_get_errors.empty?
|
||||
flash[:notice] = "La liste des instructeurs a été importée avec succès"
|
||||
groupes_emails_has_keys = groupes_emails.first.has_key?("groupe") && groupes_emails.first.has_key?("email")
|
||||
|
||||
if groupes_emails_has_keys.blank?
|
||||
flash[:alert] = "Importation impossible, veuillez importer un csv #{view_context.link_to('suivant ce modèle', "/csv/#{I18n.locale}/import-groupe-test.csv")}"
|
||||
else
|
||||
flash[:alert] = "Import terminé. Cependant les emails suivants ne sont pas pris en compte: #{add_instructeurs_and_get_errors.join(', ')}"
|
||||
add_instructeurs_and_get_errors = InstructeursImportService.import(procedure, groupes_emails)
|
||||
|
||||
if add_instructeurs_and_get_errors.empty?
|
||||
flash[:notice] = "La liste des instructeurs a été importée avec succès"
|
||||
else
|
||||
flash[:alert] = "Import terminé. Cependant les emails suivants ne sont pas pris en compte: #{add_instructeurs_and_get_errors.join(', ')}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
redirect_to admin_procedure_groupe_instructeurs_path(procedure)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -276,8 +276,9 @@ class ApplicationController < ActionController::Base
|
|||
matomo = Rails.application.secrets.matomo
|
||||
|
||||
{
|
||||
key: matomo[:client_key],
|
||||
enabled: matomo[:enabled]
|
||||
enabled: matomo[:enabled],
|
||||
host: matomo[:host],
|
||||
key: matomo[:client_key]
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ module Instructeurs
|
|||
.order(closed_at: :desc, unpublished_at: :desc, published_at: :desc, created_at: :desc)
|
||||
|
||||
dossiers = current_instructeur.dossiers.joins(:groupe_instructeur)
|
||||
@dossiers_count_per_procedure = dossiers.all_state.group('groupe_instructeurs.procedure_id').reorder(nil).count
|
||||
@dossiers_count_per_procedure = dossiers.all_state.visible_by_administration.group('groupe_instructeurs.procedure_id').reorder(nil).count
|
||||
@dossiers_a_suivre_count_per_procedure = dossiers.without_followers.en_cours.visible_by_administration.group('groupe_instructeurs.procedure_id').reorder(nil).count
|
||||
@dossiers_archived_count_per_procedure = dossiers.archived.group('groupe_instructeurs.procedure_id').count
|
||||
@dossiers_termines_count_per_procedure = dossiers.termine.visible_by_administration.group('groupe_instructeurs.procedure_id').reorder(nil).count
|
||||
|
@ -71,7 +71,7 @@ module Instructeurs
|
|||
@followed_dossiers_id = @followed_dossiers.pluck(:id)
|
||||
|
||||
@termines_dossiers = dossiers_visibles.termine.visible_by_administration
|
||||
@all_state_dossiers = dossiers_visibles.all_state
|
||||
@all_state_dossiers = dossiers_visibles.all_state.visible_by_administration
|
||||
@archived_dossiers = dossiers_visibles.archived
|
||||
@expirant_dossiers = dossiers_visibles.termine_or_en_construction_close_to_expiration
|
||||
|
||||
|
|
|
@ -16,39 +16,6 @@ module Manager
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Custom actions
|
||||
#
|
||||
|
||||
def discard
|
||||
dossier = Dossier.find(params[:id])
|
||||
dossier.discard_and_keep_track!(current_super_admin, :manager_request)
|
||||
|
||||
logger.info("Le dossier #{dossier.id} est supprimé par #{current_super_admin.email}")
|
||||
flash[:notice] = "Le dossier #{dossier.id} a été supprimé."
|
||||
|
||||
redirect_to manager_dossier_path(dossier)
|
||||
end
|
||||
|
||||
def restore
|
||||
dossier = Dossier.with_discarded.find(params[:id])
|
||||
dossier.restore(current_super_admin)
|
||||
|
||||
flash[:notice] = "Le dossier #{dossier.id} a été restauré."
|
||||
|
||||
redirect_to manager_dossier_path(dossier)
|
||||
end
|
||||
|
||||
def repasser_en_instruction
|
||||
dossier = Dossier.find(params[:id])
|
||||
dossier.repasser_en_instruction(instructeur: current_super_admin)
|
||||
|
||||
logger.info("Le dossier #{dossier.id} est repassé en instruction par #{current_super_admin.email}")
|
||||
flash[:notice] = "Le dossier #{dossier.id} est repassé en instruction."
|
||||
|
||||
redirect_to manager_dossier_path(dossier)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def unfiltered_list?
|
||||
|
|
|
@ -110,9 +110,17 @@ function ComboMultiple({
|
|||
extraOptions[0] &&
|
||||
extraOptions[0][0] == selectedValue
|
||||
) {
|
||||
setNewValues((newValues) => [...newValues, selectedValue]);
|
||||
setNewValues((newValues) => {
|
||||
const set = new Set(newValues);
|
||||
set.add(selectedValue);
|
||||
return [...set];
|
||||
});
|
||||
}
|
||||
saveSelection((selections) => [...selections, selectedValue]);
|
||||
saveSelection((selections) => {
|
||||
const set = new Set(selections);
|
||||
set.add(selectedValue);
|
||||
return [...set];
|
||||
});
|
||||
}
|
||||
setTerm('');
|
||||
awaitFormSubmit.done();
|
||||
|
@ -162,18 +170,17 @@ function ComboMultiple({
|
|||
};
|
||||
|
||||
const onBlur = () => {
|
||||
if (
|
||||
const shouldSelect =
|
||||
term &&
|
||||
[...extraOptions, ...options].map(([label]) => label).includes(term)
|
||||
) {
|
||||
awaitFormSubmit(() => {
|
||||
[...extraOptions, ...options].map(([label]) => label).includes(term);
|
||||
|
||||
awaitFormSubmit(() => {
|
||||
if (shouldSelect) {
|
||||
onSelect(term);
|
||||
});
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
} else {
|
||||
hidePopover();
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -232,17 +239,11 @@ function ComboMultiple({
|
|||
</button>
|
||||
</li>
|
||||
)}
|
||||
{results.map(([label, value], index) => {
|
||||
{results.map(([label], index) => {
|
||||
if (label.startsWith('--')) {
|
||||
return <ComboboxSeparator key={index} value={label} />;
|
||||
}
|
||||
return (
|
||||
<ComboboxOption
|
||||
key={index}
|
||||
value={label}
|
||||
data-option-value={value}
|
||||
/>
|
||||
);
|
||||
return <ComboboxOption key={index} value={label} />;
|
||||
})}
|
||||
</ComboboxList>
|
||||
</ComboboxPopover>
|
||||
|
|
|
@ -122,13 +122,7 @@ function ComboSearch({
|
|||
const label = getLabel(result);
|
||||
const [key, value] = transformResult(result);
|
||||
resultsMap.current[label] = { key, value, result };
|
||||
return (
|
||||
<ComboboxOption
|
||||
key={`${key}-${index}`}
|
||||
value={label}
|
||||
data-option-value={value}
|
||||
/>
|
||||
);
|
||||
return <ComboboxOption key={`${key}-${index}`} value={label} />;
|
||||
})}
|
||||
</ComboboxList>
|
||||
) : (
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
const { key, enabled } = gon.matomo || {};
|
||||
const { enabled, host, key } = gon.matomo || {};
|
||||
|
||||
if (enabled) {
|
||||
window._paq = window._paq || [];
|
||||
|
||||
const url = '//stats.data.gouv.fr/';
|
||||
const trackerUrl = `${url}piwik.php`;
|
||||
const jsUrl = `${url}piwik.js`;
|
||||
const jsUrl = `//${host}/piwik.js`;
|
||||
const trackerUrl = `//${host}/piwik.php`;
|
||||
|
||||
//
|
||||
// Configure Matomo analytics
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
class Cron::DiscardedProceduresDeletionJob < Cron::CronJob
|
||||
self.schedule_expression = "every day at 1 am"
|
||||
|
||||
def perform(*args)
|
||||
Procedure.discarded_expired.find_each do |procedure|
|
||||
procedure.dossiers.with_discarded.destroy_all
|
||||
procedure.destroy
|
||||
end
|
||||
def perform
|
||||
Procedure.purge_discarded
|
||||
end
|
||||
end
|
||||
|
|
|
@ -47,7 +47,7 @@ class ActiveJob::ApplicationLogSubscriber < ::ActiveJob::LogSubscriber
|
|||
end
|
||||
data[:tags] = tags
|
||||
data[:type] = 'tps'
|
||||
data[:source] = ENV['SOURCE']
|
||||
data[:source] = ENV['LOGRAGE_SOURCE']
|
||||
|
||||
log(data)
|
||||
end
|
||||
|
|
|
@ -84,22 +84,11 @@ class DossierMailer < ApplicationMailer
|
|||
mail(to: to_email, subject: @subject)
|
||||
end
|
||||
|
||||
def notify_deletion_to_user(deleted_dossier, to_email)
|
||||
I18n.with_locale(deleted_dossier.user_locale) do
|
||||
@subject = default_i18n_subject(dossier_id: deleted_dossier.dossier_id)
|
||||
@deleted_dossier = deleted_dossier
|
||||
def notify_en_construction_deletion_to_administration(dossier, to_email)
|
||||
@subject = default_i18n_subject(dossier_id: dossier.id)
|
||||
@dossier = dossier
|
||||
|
||||
mail(to: to_email, subject: @subject)
|
||||
end
|
||||
end
|
||||
|
||||
def notify_instructeur_deletion_to_user(deleted_dossier, to_email)
|
||||
I18n.with_locale(deleted_dossier.user_locale) do
|
||||
@subject = default_i18n_subject(libelle_demarche: deleted_dossier.procedure.libelle)
|
||||
@deleted_dossier = deleted_dossier
|
||||
|
||||
mail(to: to_email, subject: @subject)
|
||||
end
|
||||
mail(to: to_email, subject: @subject)
|
||||
end
|
||||
|
||||
def notify_deletion_to_administration(deleted_dossier, to_email)
|
||||
|
|
|
@ -15,7 +15,8 @@ class AttestationTemplate < ApplicationRecord
|
|||
include ActionView::Helpers::NumberHelper
|
||||
include TagsSubstitutionConcern
|
||||
|
||||
belongs_to :procedure, optional: false
|
||||
belongs_to :procedure, optional: true
|
||||
has_many :revisions, class_name: 'ProcedureRevision', inverse_of: :attestation_template, dependent: :nullify
|
||||
|
||||
has_one_attached :logo
|
||||
has_one_attached :signature
|
||||
|
@ -103,6 +104,25 @@ class AttestationTemplate < ApplicationRecord
|
|||
}
|
||||
end
|
||||
|
||||
def revise!
|
||||
if revisions.size > 1
|
||||
attestation_template = dup
|
||||
attestation_template.save!
|
||||
revisions
|
||||
.last
|
||||
.procedure
|
||||
.draft_revision
|
||||
.update!(attestation_template: attestation_template)
|
||||
attestation_template
|
||||
else
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
def procedure
|
||||
revisions.last&.procedure || super
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def used_tags
|
||||
|
|
|
@ -209,7 +209,7 @@ class Dossier < ApplicationRecord
|
|||
scope :hidden_by_user, -> { where.not(hidden_by_user_at: nil) }
|
||||
scope :hidden_by_administration, -> { where.not(hidden_by_administration_at: nil) }
|
||||
scope :visible_by_user, -> { where(hidden_by_user_at: nil) }
|
||||
scope :visible_by_administration, -> { where("hidden_by_administration_at IS NULL AND NOT (hidden_by_user_at IS NOT NULL AND state = 'en_construction')") }
|
||||
scope :visible_by_administration, -> { where("hidden_by_administration_at IS NULL AND NOT (hidden_by_user_at IS NOT NULL AND dossiers.state = 'en_construction')") }
|
||||
|
||||
scope :order_by_updated_at, -> (order = :desc) { order(updated_at: order) }
|
||||
scope :order_by_created_at, -> (order = :asc) { order(depose_at: order, created_at: order, id: order) }
|
||||
|
@ -539,10 +539,6 @@ class Dossier < ApplicationRecord
|
|||
en_construction? || termine?
|
||||
end
|
||||
|
||||
def can_be_deleted_by_manager?
|
||||
kept? && can_be_deleted_by_user?
|
||||
end
|
||||
|
||||
def messagerie_available?
|
||||
!brouillon? && !user_deleted? && !archived
|
||||
end
|
||||
|
@ -704,10 +700,6 @@ class Dossier < ApplicationRecord
|
|||
termine? && hidden_by_administration? && hidden_by_user?
|
||||
end
|
||||
|
||||
def can_be_restored_by_manager?
|
||||
hidden_by_administration? || discarded? && !procedure.discarded?
|
||||
end
|
||||
|
||||
def expose_legacy_carto_api?
|
||||
procedure.expose_legacy_carto_api?
|
||||
end
|
||||
|
@ -728,9 +720,11 @@ class Dossier < ApplicationRecord
|
|||
{ lon: lon, lat: lat, zoom: zoom }
|
||||
end
|
||||
|
||||
def unspecified_attestation_champs
|
||||
attestation_template = procedure.attestation_template
|
||||
def attestation_template
|
||||
revision.attestation_template
|
||||
end
|
||||
|
||||
def unspecified_attestation_champs
|
||||
if attestation_template&.activated?
|
||||
attestation_template.unspecified_champs_for_dossier(self)
|
||||
else
|
||||
|
@ -739,8 +733,8 @@ class Dossier < ApplicationRecord
|
|||
end
|
||||
|
||||
def build_attestation
|
||||
if procedure.attestation_template&.activated?
|
||||
procedure.attestation_template.attestation_for(self)
|
||||
if attestation_template&.activated?
|
||||
attestation_template.attestation_for(self)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -780,7 +774,6 @@ class Dossier < ApplicationRecord
|
|||
update(hidden_by_user_at: Time.zone.now, dossier_transfer_id: nil)
|
||||
end
|
||||
|
||||
user_email = user_deleted? ? nil : user_email_for(:notification)
|
||||
deleted_dossier = nil
|
||||
|
||||
transaction do
|
||||
|
@ -803,14 +796,6 @@ class Dossier < ApplicationRecord
|
|||
DossierMailer.notify_deletion_to_administration(deleted_dossier, email).deliver_later
|
||||
end
|
||||
end
|
||||
|
||||
if user_email.present?
|
||||
if reason == :user_request
|
||||
DossierMailer.notify_deletion_to_user(deleted_dossier, user_email).deliver_later
|
||||
else
|
||||
DossierMailer.notify_instructeur_deletion_to_user(deleted_dossier, user_email).deliver_later
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -97,7 +97,8 @@ class Export < ApplicationRecord
|
|||
end
|
||||
|
||||
def io(since: nil)
|
||||
dossiers = Dossier.where(groupe_instructeur: groupe_instructeurs)
|
||||
dossiers = Dossier.visible_by_administration
|
||||
.where(groupe_instructeur: groupe_instructeurs)
|
||||
if since.present?
|
||||
dossiers = dossiers.where('dossiers.depose_at > ?', since)
|
||||
end
|
||||
|
|
|
@ -235,7 +235,7 @@ class Instructeur < ApplicationRecord
|
|||
COUNT(DISTINCT dossiers.id) FILTER (where not archived AND NOT (dossiers.hidden_by_user_at IS NOT NULL AND state = 'en_construction') AND dossiers.state in ('en_construction', 'en_instruction') AND follows.id IS NULL) AS a_suivre,
|
||||
COUNT(DISTINCT dossiers.id) FILTER (where not archived AND dossiers.state in ('en_construction', 'en_instruction') AND follows.instructeur_id = :instructeur_id) AS suivis,
|
||||
COUNT(DISTINCT dossiers.id) FILTER (where not archived AND dossiers.state in ('accepte', 'refuse', 'sans_suite')) AS traites,
|
||||
COUNT(DISTINCT dossiers.id) FILTER (where not archived) AS tous,
|
||||
COUNT(DISTINCT dossiers.id) FILTER (where not archived AND NOT (dossiers.hidden_by_user_at IS NOT NULL AND state = 'en_construction')) AS tous,
|
||||
COUNT(DISTINCT dossiers.id) FILTER (where archived) AS archives,
|
||||
COUNT(DISTINCT dossiers.id) FILTER (where
|
||||
procedures.procedure_expires_when_termine_enabled
|
||||
|
|
|
@ -77,12 +77,15 @@ class Procedure < ApplicationRecord
|
|||
has_many :published_types_de_champ_private, through: :published_revision, source: :types_de_champ_private
|
||||
has_many :draft_types_de_champ, through: :draft_revision, source: :types_de_champ
|
||||
has_many :draft_types_de_champ_private, through: :draft_revision, source: :types_de_champ_private
|
||||
has_one :draft_attestation_template, through: :draft_revision, source: :attestation_template
|
||||
has_one :published_attestation_template, through: :published_revision, source: :attestation_template
|
||||
|
||||
has_many :experts_procedures, dependent: :destroy
|
||||
has_many :experts, through: :experts_procedures
|
||||
|
||||
has_one :module_api_carto, dependent: :destroy
|
||||
has_one :attestation_template, dependent: :destroy
|
||||
has_many :attestation_templates, through: :revisions, source: :attestation_template
|
||||
|
||||
belongs_to :parent_procedure, class_name: 'Procedure', optional: true
|
||||
belongs_to :canonical_procedure, class_name: 'Procedure', optional: true
|
||||
|
@ -373,7 +376,7 @@ class Procedure < ApplicationRecord
|
|||
end
|
||||
|
||||
def draft_changed?
|
||||
publiee? && published_revision.changed?(draft_revision) && revision_changes.present?
|
||||
publiee? && published_revision.different_from?(draft_revision) && revision_changes.present?
|
||||
end
|
||||
|
||||
def revision_changes
|
||||
|
@ -434,7 +437,8 @@ class Procedure < ApplicationRecord
|
|||
},
|
||||
revision_types_de_champ_private: {
|
||||
type_de_champ: :types_de_champ
|
||||
}
|
||||
},
|
||||
attestation_template: []
|
||||
}
|
||||
}
|
||||
include_list[:groupe_instructeurs] = :instructeurs if !is_different_admin
|
||||
|
@ -572,13 +576,17 @@ class Procedure < ApplicationRecord
|
|||
touch(:whitelisted_at)
|
||||
end
|
||||
|
||||
def active_attestation_template
|
||||
published_attestation_template || draft_attestation_template
|
||||
end
|
||||
|
||||
def closed_mail_template_attestation_inconsistency_state
|
||||
# As an optimization, don’t check the predefined templates (they are presumed correct)
|
||||
if closed_mail.present?
|
||||
tag_present = closed_mail.body.to_s.include?("--lien attestation--")
|
||||
if attestation_template&.activated? && !tag_present
|
||||
if active_attestation_template&.activated? && !tag_present
|
||||
:missing_tag
|
||||
elsif !attestation_template&.activated? && tag_present
|
||||
elsif !active_attestation_template&.activated? && tag_present
|
||||
:extraneous_tag
|
||||
end
|
||||
end
|
||||
|
@ -649,7 +657,7 @@ class Procedure < ApplicationRecord
|
|||
end
|
||||
|
||||
def can_be_deleted_by_administrateur?
|
||||
brouillon? || dossiers.state_instruction_commencee.empty?
|
||||
brouillon? || dossiers.state_en_instruction.empty?
|
||||
end
|
||||
|
||||
def can_be_deleted_by_manager?
|
||||
|
@ -663,18 +671,25 @@ class Procedure < ApplicationRecord
|
|||
close!
|
||||
end
|
||||
|
||||
dossiers.each do |dossier|
|
||||
dossiers.termine.visible_by_administration.each do |dossier|
|
||||
dossier.discard_and_keep_track!(author, :procedure_removed)
|
||||
end
|
||||
|
||||
discard!
|
||||
end
|
||||
|
||||
def purge_discarded
|
||||
if !dossiers.with_discarded.exists?
|
||||
destroy
|
||||
end
|
||||
end
|
||||
|
||||
def self.purge_discarded
|
||||
discarded_expired.find_each(&:purge_discarded)
|
||||
end
|
||||
|
||||
def restore(author)
|
||||
if discarded? && undiscard
|
||||
dossiers.with_discarded.discarded.find_each do |dossier|
|
||||
dossier.restore(author)
|
||||
end
|
||||
dossiers.hidden_by_administration.find_each do |dossier|
|
||||
dossier.restore(author)
|
||||
end
|
||||
|
|
|
@ -2,15 +2,17 @@
|
|||
#
|
||||
# Table name: procedure_revisions
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# published_at :datetime
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# procedure_id :bigint not null
|
||||
# id :bigint not null, primary key
|
||||
# published_at :datetime
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# attestation_template_id :bigint
|
||||
# procedure_id :bigint not null
|
||||
#
|
||||
class ProcedureRevision < ApplicationRecord
|
||||
self.implicit_order_column = :created_at
|
||||
belongs_to :procedure, -> { with_discarded }, inverse_of: :revisions, optional: false
|
||||
belongs_to :attestation_template, inverse_of: :revisions, optional: true, dependent: :destroy
|
||||
|
||||
has_many :dossiers, inverse_of: :revision, foreign_key: :revision_id
|
||||
|
||||
|
@ -105,7 +107,7 @@ class ProcedureRevision < ApplicationRecord
|
|||
!draft?
|
||||
end
|
||||
|
||||
def changed?(revision)
|
||||
def different_from?(revision)
|
||||
types_de_champ != revision.types_de_champ || types_de_champ_private != revision.types_de_champ_private
|
||||
end
|
||||
|
||||
|
@ -125,6 +127,10 @@ class ProcedureRevision < ApplicationRecord
|
|||
)
|
||||
end
|
||||
|
||||
def attestation_template
|
||||
super || procedure.attestation_template
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def compare_types_de_champ(from_tdc, to_tdc)
|
||||
|
|
|
@ -117,6 +117,7 @@ class ExpiredDossiersDeletionService
|
|||
|
||||
def self.group_by_user_email(dossiers, notify_on_closed_procedures_to_user: false)
|
||||
dossiers
|
||||
.visible_by_user
|
||||
.with_notifiable_procedure(notify_on_closed: notify_on_closed_procedures_to_user)
|
||||
.includes(:user, :procedure)
|
||||
.group_by(&:user)
|
||||
|
@ -125,6 +126,7 @@ class ExpiredDossiersDeletionService
|
|||
|
||||
def self.group_by_fonctionnaire_email(dossiers)
|
||||
dossiers
|
||||
.visible_by_administration
|
||||
.with_notifiable_procedure(notify_on_closed: true)
|
||||
.includes(:followers_instructeurs, procedure: [:administrateurs])
|
||||
.each_with_object(Hash.new { |h, k| h[k] = Set.new }) do |dossier, h|
|
||||
|
|
|
@ -24,11 +24,13 @@ class ProcedureArchiveService
|
|||
end
|
||||
|
||||
def new_collect_files_archive(archive, instructeur)
|
||||
## faux, ca ne doit prendre que certains groupe instructeur ?
|
||||
if archive.time_span_type == 'everything'
|
||||
dossiers = @procedure.dossiers.state_termine
|
||||
dossiers = Dossier.visible_by_administration
|
||||
.where(groupe_instructeur: archive.groupe_instructeurs)
|
||||
|
||||
dossiers = if archive.time_span_type == 'everything'
|
||||
dossiers.state_termine
|
||||
else
|
||||
dossiers = @procedure.dossiers.processed_in_month(archive.month)
|
||||
dossiers.processed_in_month(archive.month)
|
||||
end
|
||||
|
||||
attachments = create_list_of_attachments(dossiers)
|
||||
|
@ -44,10 +46,13 @@ class ProcedureArchiveService
|
|||
end
|
||||
|
||||
def old_collect_files_archive(archive, instructeur)
|
||||
if archive.time_span_type == 'everything'
|
||||
dossiers = @procedure.dossiers.state_termine
|
||||
dossiers = Dossier.visible_by_administration
|
||||
.where(groupe_instructeur: archive.groupe_instructeurs)
|
||||
|
||||
dossiers = if archive.time_span_type == 'everything'
|
||||
dossiers.state_termine
|
||||
else
|
||||
dossiers = @procedure.dossiers.processed_in_month(archive.month)
|
||||
dossiers.processed_in_month(archive.month)
|
||||
end
|
||||
|
||||
files = create_list_of_attachments(dossiers)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class MonAvisEmbedValidator < ActiveModel::Validator
|
||||
def validate(record)
|
||||
# We need to ensure the embed code is not any random string in order to avoid injections
|
||||
r = Regexp.new('<a href="https://monavis|voxusagers.numerique.gouv.fr/Demarches/\d+.*key=[[:alnum:]]+.*">\s*<img src="https://monavis|voxusagers.numerique.gouv.fr/(monavis-)?static/bouton-blanc|bleu.png|svg" alt="Je donne mon avis" title="Je donne mon avis sur cette démarche" />\s*</a>', Regexp::MULTILINE)
|
||||
r = Regexp.new('<a href="https://monavis|voxusagers.numerique.gouv.fr/Demarches/\d+.*key=[[:alnum:]]+.*">\s*<img src="https://monavis|voxusagers.numerique.gouv.fr/(monavis-)?static/bouton-blanc|bleu.png|svg" alt="Je donne mon avis" (title="Je donne mon avis sur cette démarche" )?/>\s*</a>', Regexp::MULTILINE)
|
||||
if record.monavis_embed.present? && !r.match?(record.monavis_embed)
|
||||
record.errors[:base] << "Le code fourni ne correspond pas au format des codes MonAvis reconnus par la plateforme."
|
||||
end
|
||||
|
|
|
@ -21,13 +21,17 @@
|
|||
= f.submit 'Ajouter le groupe', class: "button primary send"
|
||||
|
||||
- csv_max_size = Administrateurs::GroupeInstructeursController::CSV_MAX_SIZE
|
||||
= form_tag import_admin_procedure_groupe_instructeurs_path(procedure), method: :post, multipart: true, class: "mt-4 form" do
|
||||
= label_tag "Importer par fichier CSV"
|
||||
%p.notice Le fichier csv doit comporter 2 colonnes (Groupe, Email) et être séparé par des virgules. L'import n'écrase pas les groupes et les instructeurs existants.
|
||||
%p.notice Le poids du fichier doit être inférieur à #{number_to_human_size(csv_max_size)}
|
||||
%p.mt-2.mb-2= link_to "Télécharger l'exemple de fichier CSV", "/csv/#{I18n.locale}/import-groupe-test.csv"
|
||||
= file_field_tag :group_csv_file, required: true, accept: 'text/csv', size: "1"
|
||||
= submit_tag "Importer le fichier", class: 'button primary send', data: { disable_with: "Envoi..." }
|
||||
- if procedure.publiee?
|
||||
= form_tag import_admin_procedure_groupe_instructeurs_path(procedure), method: :post, multipart: true, class: "mt-4 form" do
|
||||
= label_tag "Importer par fichier CSV"
|
||||
%p.notice Le fichier csv doit comporter 2 colonnes (Groupe, Email) et être séparé par des virgules. L'import n'écrase pas les groupes et les instructeurs existants.
|
||||
%p.notice Le poids du fichier doit être inférieur à #{number_to_human_size(csv_max_size)}
|
||||
%p.mt-2.mb-2= link_to "Télécharger l'exemple de fichier CSV", "/csv/#{I18n.locale}/import-groupe-test.csv"
|
||||
= file_field_tag :group_csv_file, required: true, accept: 'text/csv', size: "1"
|
||||
= submit_tag "Importer le fichier", class: 'button primary send', data: { disable_with: "Envoi..." }
|
||||
- else
|
||||
%p.mt-4.form.bold.mb-2.text-lg Importer par fichier CSV
|
||||
%p.notice L’import d’instructeurs par fichier CSV est disponible une fois la démarche publiée
|
||||
|
||||
%table.table.mt-2
|
||||
%thead
|
||||
|
|
|
@ -138,7 +138,7 @@
|
|||
.procedure-grid
|
||||
|
||||
= link_to edit_admin_procedure_attestation_template_path(@procedure), class: 'card-admin' do
|
||||
- if @procedure.attestation_template.present? && @procedure.attestation_template.activated
|
||||
- if @procedure.draft_attestation_template&.activated?
|
||||
%div
|
||||
%span.icon.accept
|
||||
%p.card-admin-status-accept Activée
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
%p= t(:hello, scope: [:views, :shared, :greetings])
|
||||
|
||||
%p
|
||||
= t('.body', dossier_id: @deleted_dossier.dossier_id, procedure: @deleted_dossier.procedure.libelle)
|
||||
= t('.body', dossier_id: @dossier.id, procedure: @dossier.procedure.libelle)
|
||||
|
||||
= render partial: "layouts/mailers/signature"
|
|
@ -1,8 +0,0 @@
|
|||
- content_for(:title, "#{@subject}")
|
||||
|
||||
%p= t(:hello, scope: [:views, :shared, :greetings])
|
||||
|
||||
%p
|
||||
= t('.body_html', dossier_id: @deleted_dossier.dossier_id, libelle_demarche: @deleted_dossier.procedure.libelle, deleted_dossiers_link: dossiers_url(statut: 'dossiers-supprimes'))
|
||||
|
||||
= render partial: "layouts/mailers/signature"
|
|
@ -26,17 +26,6 @@ as well as a link to its edit page.
|
|||
(Supprimé)
|
||||
<% end %>
|
||||
</h1>
|
||||
|
||||
<div>
|
||||
<% if dossier.accepte? %>
|
||||
<%= link_to 'Repasser en instruction', repasser_en_instruction_manager_dossier_path(dossier), method: :post, class: 'button', data: { confirm: "Confirmez vous le passage en instruction du dossier ?" } %>
|
||||
<% end %>
|
||||
<% if dossier.can_be_deleted_by_manager? %>
|
||||
<%= link_to 'Supprimer le dossier', discard_manager_dossier_path(dossier), method: :post, class: 'button', data: { confirm: "Confirmez vous la suppression du dossier ?" } %>
|
||||
<% elsif dossier.can_be_restored_by_manager? %>
|
||||
<%= link_to 'Restaurer le dossier', restore_manager_dossier_path(dossier), method: :post, class: 'button', data: { confirm: "Confirmez vous la restauration du dossier ?" } %>
|
||||
<% end %>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="main-content__body">
|
||||
|
|
|
@ -1,126 +1,135 @@
|
|||
# Nom d'hôte de l'appli
|
||||
# * Pour du dev local: localhost:3000
|
||||
# * pour de la preprod: preprod.ds.organisme.fr (par exemple)
|
||||
# * pour de la prod: www.demarches-simplifiees.fr
|
||||
# Application host name
|
||||
#
|
||||
# Examples:
|
||||
# * For local development: localhost:3000
|
||||
# * For preproduction: staging.ds.organisme.fr
|
||||
# * For production: ds.organisme.fr
|
||||
APP_HOST="localhost:3000"
|
||||
|
||||
# Utilisé pour les logs LogRage
|
||||
SOURCE="tps_local"
|
||||
|
||||
# Clé de chiffrement de rails, cf https://api.rubyonrails.org/classes/Rails/Application.html
|
||||
# Rails key for signing sensitive data
|
||||
# See https://guides.rubyonrails.org/security.html
|
||||
#
|
||||
# For production you MUST generate a new key, and keep it secret.
|
||||
# Secrets must be long and random. Use bin/rails secret to get new unique secrets.
|
||||
SECRET_KEY_BASE="05a2d479d8e412198dabd08ef0eee9d6e180f5cbb48661a35fd1cae287f0a93d40b5f1da08f06780d698bbd458a0ea97f730f83ee780de5d4e31f649a0130cf0"
|
||||
SIGNING_KEY="aef3153a9829fa4ba10acb02927ac855df6b92795b1ad265d654443c4b14a017"
|
||||
|
||||
# Clé de chiffrement OTP, pour 2FA
|
||||
# Secret key for One-Time-Password codes, used for 2-factors authentication
|
||||
OTP_SECRET_KEY=""
|
||||
|
||||
# SAML IdP
|
||||
|
||||
# SAML_IDP_CERTIFICATE="billybop"
|
||||
# SAML_IDP_SECRET_KEY="-----BEGIN RSA PRIVATE KEY-----\nblabla+blabla\n-----END RSA PRIVATE KEY-----\n"
|
||||
# SENDINBLUE_LOGIN_URL="https://app.sendinblue.com/account/saml/login/truc"
|
||||
|
||||
# Database
|
||||
# Database credentials
|
||||
DB_DATABASE="tps_development"
|
||||
DB_HOST="localhost"
|
||||
DB_POOL=""
|
||||
DB_USERNAME="tps_development"
|
||||
DB_PASSWORD="tps_development"
|
||||
|
||||
# Protection simple de l'instance par mot de passe (utile pour la pre-prod)
|
||||
# Protect access to the instance with a static login/password (useful for staging environments)
|
||||
BASIC_AUTH_ENABLED="disabled"
|
||||
BASIC_AUTH_USERNAME=""
|
||||
BASIC_AUTH_PASSWORD=""
|
||||
|
||||
# Object Storage pour les pièces jointes
|
||||
# Object Storage for attachments
|
||||
FOG_ENABLED="disabled"
|
||||
FOG_OPENSTACK_API_KEY=""
|
||||
FOG_OPENSTACK_USERNAME=""
|
||||
FOG_OPENSTACK_URL=""
|
||||
FOG_OPENSTACK_REGION=""
|
||||
FOG_ENABLED="" # valeur attendue: enabled
|
||||
DS_PROXY_URL=""
|
||||
|
||||
# Service externe: authentification France Connect
|
||||
# External service: authentication through France Connect
|
||||
FC_PARTICULIER_ID=""
|
||||
FC_PARTICULIER_SECRET=""
|
||||
FC_PARTICULIER_BASE_URL=""
|
||||
|
||||
# Service externe: authentification Agent Connect
|
||||
# External service: authentication through Agent Connect
|
||||
AGENT_CONNECT_ID=""
|
||||
AGENT_CONNECT_SECRET=""
|
||||
AGENT_CONNECT_BASE_URL=""
|
||||
AGENT_CONNECT_JWKS=""
|
||||
AGENT_CONNECT_REDIRECT=""
|
||||
|
||||
# Service externe: Support Utilisateur HelpScout | Spécifique démarches-simplifiées.fr
|
||||
# External service: integration with HelpScout (optional)
|
||||
HELPSCOUT_MAILBOX_ID=""
|
||||
HELPSCOUT_CLIENT_ID=""
|
||||
HELPSCOUT_CLIENT_SECRET=""
|
||||
HELPSCOUT_WEBHOOK_SECRET=""
|
||||
|
||||
# Service externe: Supervision exterieure | Spécifique démarches-simplifiées.fr
|
||||
# External service: external supervision
|
||||
SENTRY_ENABLED="disabled"
|
||||
SENTRY_CURRENT_ENV="development"
|
||||
SENTRY_DSN_RAILS=""
|
||||
SENTRY_DSN_JS=""
|
||||
|
||||
# Statistiques web
|
||||
# External service: Matomo web analytics
|
||||
MATOMO_ENABLED="disabled"
|
||||
MATOMO_ID="73"
|
||||
# Missing MATOMO_HOST (thus hardcoded)
|
||||
MATOMO_ID=""
|
||||
MATOMO_HOST="matomo.organisme.fr"
|
||||
|
||||
# SMTP Provider: Send In Blue
|
||||
SENDINBLUE_ENABLED="disabled"
|
||||
SENDINBLUE_BALANCING=""
|
||||
SENDINBLUE_BALANCING_VALUE=""
|
||||
SENDINBLUE_ENABLED=""
|
||||
SENDINBLUE_CLIENT_KEY=""
|
||||
SENDINBLUE_SMTP_KEY=""
|
||||
SENDINBLUE_USER_NAME=""
|
||||
|
||||
# Service externe: Fournisseur de tchat pour administrateur | Spécifique démarches-simplifiées.fr
|
||||
CRISP_ENABLED="disabled"
|
||||
CRISP_CLIENT_KEY=""
|
||||
|
||||
# Service externe: rattrapage de mails envoyés, utile en préprod | Spécifique démarches-simplifiées.fr
|
||||
MAILTRAP_ENABLED="disabled"
|
||||
MAILTRAP_USERNAME=""
|
||||
MAILTRAP_PASSWORD=""
|
||||
# SENDINBLUE_LOGIN_URL="https://app.sendinblue.com/account/saml/login/truc"
|
||||
|
||||
# SMTP Provider: Mailjet
|
||||
MAILJET_API_KEY=""
|
||||
MAILJET_SECRET_KEY=""
|
||||
|
||||
# API Entreprise https://api.gouv.fr/api/api-entreprise.html
|
||||
# External service: live chat for admins (specific to démarches-simplifiées.fr)
|
||||
CRISP_ENABLED="disabled"
|
||||
CRISP_CLIENT_KEY=""
|
||||
|
||||
# External service: mail catcher for staging environments (specific to démarches-simplifiées.fr)
|
||||
MAILTRAP_ENABLED="disabled"
|
||||
MAILTRAP_USERNAME=""
|
||||
MAILTRAP_PASSWORD=""
|
||||
|
||||
# API Entreprise credentials
|
||||
# https://api.gouv.fr/api/api-entreprise.html
|
||||
API_ENTREPRISE_KEY=""
|
||||
|
||||
# Service externe: CRM de suivi de création d'administrateur | Spécifique démarches-simplifiées.fr
|
||||
# External service: CRM for following admin accounts pipeline (specific to démarches-simplifiées.fr)
|
||||
PIPEDRIVE_KEY=""
|
||||
|
||||
# Liste des réseaux qui passent outre la génération de token pour identifier un device, ainsi que le throttling par rack-attack
|
||||
# Networks bypassing the email login token that verifies new devices, and rack-attack throttling
|
||||
TRUSTED_NETWORKS=""
|
||||
|
||||
# Service externe: mesure de performance d'appli Rails | Spécifique démarches-simplifiées.fr
|
||||
# External service: mesuring performance of the Rails app (specific to démarches-simplifiées.fr)
|
||||
SKYLIGHT_AUTHENTICATION_KEY=""
|
||||
|
||||
# Activer ou non les logs LogRage
|
||||
# Enable or disable Lograge logs
|
||||
LOGRAGE_ENABLED="disabled"
|
||||
|
||||
# Service externe d'horodatage des changements de statut des dossiers (effectué quotidiennement)
|
||||
# Logs source for Lograge
|
||||
#
|
||||
# Examples:
|
||||
# * For local development: tps_local
|
||||
# * For preproduction: tps_staging
|
||||
# * For production: tps_prod
|
||||
LOGRAGE_SOURCE="tps_local"
|
||||
|
||||
# External service: timestamping a daily archive of dossiers status changes
|
||||
UNIVERSIGN_API_URL="https://ws.universign.eu/tsa/post/"
|
||||
UNIVERSIGN_USERPWD=""
|
||||
|
||||
# API Geo / Adresse
|
||||
# External service: API Geo / Adresse
|
||||
API_ADRESSE_URL="https://api-adresse.data.gouv.fr"
|
||||
API_GEO_URL="https://geo.api.gouv.fr"
|
||||
|
||||
# API Education
|
||||
# External service: API Education
|
||||
API_EDUCATION_URL="https://data.education.gouv.fr/api/records/1.0"
|
||||
|
||||
# Modifier le nb de tentatives de relance de job si echec
|
||||
# MAX_ATTEMPTS_JOBS=25
|
||||
# MAX_ATTEMPTS_API_ENTREPRISE_JOBS=5
|
||||
|
||||
# Clé de chriffrement des données sensibles en base
|
||||
# Encryption key for sensitive columns in the database
|
||||
ENCRYPTION_SERVICE_SALT=""
|
||||
|
||||
# Salt for invisible_captcha session data.
|
||||
# Must be the same value for all app instances behind a load-balancer.
|
||||
INVISIBLE_CAPTCHA_SECRET="kikooloool"
|
||||
|
|
|
@ -1,24 +1,28 @@
|
|||
# Optional environment variables
|
||||
|
||||
# Variables d'environnement optionnelles
|
||||
|
||||
# Les paramètres pour l'affichage du nom l'application, et pour la génération des liens
|
||||
# Application name, for display and generating links
|
||||
APPLICATION_NAME="demarches-simplifiees.fr"
|
||||
APPLICATION_SHORTNAME="d-s.fr"
|
||||
APPLICATION_BASE_URL="https://www.demarches-simplifiees.fr"
|
||||
|
||||
# If defined to "staging", tell the app that it's running on a staging instance
|
||||
DS_ENV="staging"
|
||||
|
||||
# Utilisation de France Connect
|
||||
# FRANCE_CONNECT_ENABLED="disabled" # "enabled" par défaut
|
||||
# France Connect usage
|
||||
# FRANCE_CONNECT_ENABLED="disabled" # "enabled" by default
|
||||
|
||||
# Utilisation de Agent Connect
|
||||
# AGENT_CONNECT_ENABLED="disabled" # "enabled" par défaut
|
||||
# Agent Connect usage
|
||||
# AGENT_CONNECT_ENABLED="disabled" # "enabled" by default
|
||||
|
||||
# Personnalisation d'instance - URLs des CGU et des mentions légales
|
||||
# Configure the maximum number of times a job is retried
|
||||
# MAX_ATTEMPTS_JOBS=25
|
||||
# MAX_ATTEMPTS_API_ENTREPRISE_JOBS=5
|
||||
|
||||
# Instance customization: URLs for GTS and legal mentions
|
||||
# CGU_URL=""
|
||||
# MENTIONS_LEGALES_URL=""
|
||||
|
||||
# Personnalisation d'instance - Adresses Email de l'application et téléphone
|
||||
# Instance customization: support emails addresses and phone
|
||||
# CONTACT_EMAIL=""
|
||||
# EQUIPE_EMAIL=""
|
||||
# TECH_EMAIL=""
|
||||
|
@ -26,61 +30,62 @@ DS_ENV="staging"
|
|||
# OLD_CONTACT_EMAIL=""
|
||||
# CONTACT_PHONE=""
|
||||
|
||||
# Personnalisation d'instance - Adresses postale de l'opérateur de l'instance
|
||||
# Instance customization: postal address of the instance operator
|
||||
# CONTACT_ADDRESS="Incubateur de Services Numériques / beta.gouv.fr\nServices du Premier Ministre, 20 avenue de Ségur, 75007 Paris"
|
||||
|
||||
# Personnalisation d'instance - URL pour la création de compte administrateur sur l'instance
|
||||
# Instance customization: URL for creating an admin account on the instance
|
||||
# DEMANDE_INSCRIPTION_ADMIN_PAGE_URL=""
|
||||
|
||||
# Personnalisation d'instance - URL du site web de documentation
|
||||
# Instance customization: URL of the documentation website
|
||||
# DOC_URL="https://doc.demarches-simplifiees.fr"
|
||||
|
||||
# Personnalisation d'instance - URL du site web FAQ
|
||||
# Instance customization: URL of the documentation support website
|
||||
# FAQ_URL="https://faq.demarches-simplifiees.fr"
|
||||
|
||||
# Personnalisation d'instance - URL de la déclaration d'accessibilité
|
||||
# Instance customization: URL of the accessibility statement
|
||||
# ACCESSIBILITE_URL=""
|
||||
|
||||
# Personnalisation d'instance - Page externe "Disponibilité" (status page)
|
||||
# Instance customization: URL of the availability/status webpage
|
||||
# STATUS_PAGE_URL=""
|
||||
|
||||
# Personnalisation d'instance - Favicons ---> à placer dans "app/assets/images"
|
||||
# Instance customization: Favicons ---> to be put in "app/assets/images"
|
||||
# FAVICON_16PX_SRC="favicons/16x16.png"
|
||||
# FAVICON_32PX_SRC="favicons/32x32.png"
|
||||
# FAVICON_96PX_SRC="favicons/96x96.png"
|
||||
|
||||
# Personnalisation d'instance - Logo de l'application ---> à placer dans "app/assets/images"
|
||||
# Instance customization: Application logo ---> to be put in "app/assets/images"
|
||||
# HEADER_LOGO_SRC="marianne.png"
|
||||
# HEADER_LOGO_ALT=""
|
||||
# HEADER_LOGO_WIDTH="65"
|
||||
# HEADER_LOGO_HEIGHT="56"
|
||||
|
||||
# Personnalisation d'instance - Logo dans l'entête des emails ---> à placer dans "app/assets/images"
|
||||
# Instance customization: Emails header logo ---> to be put in "app/assets/images"
|
||||
# MAILER_LOGO_SRC="mailer/instructeur_mailer/logo.png"
|
||||
|
||||
# Personnalisation d'instance - Logo dans le pied de page des emails ---> à placer dans "app/assets/images"
|
||||
# Instance customization: Emails footer logo ---> to be put in "app/assets/images"
|
||||
# MAILER_FOOTER_LOGO_SRC="mailer/instructeur_mailer/logo-beta-gouv-fr.png"
|
||||
|
||||
# Personnalisation d'instance - Logo par défaut d'une procédure ---> à placer dans "app/assets/images"
|
||||
# Instance customization: Procedure default logo ---> to be put in "app/assets/images"
|
||||
# PROCEDURE_DEFAULT_LOGO_SRC="republique-francaise-logo.svg"
|
||||
|
||||
# Personnalisation d'instance - Logo dans le PDF d'export d'un dossier ---> à placer dans "app/assets/images"
|
||||
# Instance customization: PDF export logo ---> to be put in "app/assets/images"
|
||||
# DOSSIER_PDF_EXPORT_LOGO_SRC="app/assets/images/header/logo-ds-wide.svg"
|
||||
|
||||
# Personnalisation d'instance - fichier utilisé pour poser un filigrane sur les pièces d'identité
|
||||
# Instance customization: watermark for identity documents
|
||||
# WATERMARK_FILE=""
|
||||
|
||||
# Active le mode maintenance
|
||||
# Enabling maintenance mode
|
||||
# MAINTENANCE_MODE="true"
|
||||
|
||||
# Active la localisation
|
||||
# Enabling localization
|
||||
# LOCALIZATION_ENABLED="true"
|
||||
|
||||
# Désactivé l'OTP pour SuperAdmin
|
||||
# Disabling 2FA for Super-Admins
|
||||
# SUPER_ADMIN_OTP_ENABLED = "disabled" # "enabled" par défaut
|
||||
|
||||
# API Particulier https://api.gouv.fr/les-api/api-particulier
|
||||
# API Particulier
|
||||
# https://api.gouv.fr/les-api/api-particulier
|
||||
# API_PARTICULIER_URL="https://particulier.api.gouv.fr/api"
|
||||
|
||||
# Les instructeurs et administrateurs peuvent changer leur email vers ces domaines
|
||||
# Admins and instructeurs can freely change their email to these domains
|
||||
# LEGIT_ADMIN_DOMAINS = "domaine_1.com;domaine_2.com"
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
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.
|
||||
notify_instructeur_deletion_to_user:
|
||||
subject: Votre dossier sur la démarche « %{libelle_demarche} » est supprimé
|
||||
body_html: |
|
||||
Afin de limiter la conservation de vos données personnelles, votre dossier n° %{dossier_id} concernant la démarche <b>« %{libelle_demarche} »</b> est <b>supprimé</b>.<br><br>
|
||||
Cette suppression ne modifie pas le statut final (accepté, refusé ou sans suite) de votre dossier.<br><br>
|
||||
Une trace de ce dossier est visible dans votre interface : <a href='%{deleted_dossiers_link}'>%{deleted_dossiers_link}</a>.
|
|
@ -0,0 +1,5 @@
|
|||
fr:
|
||||
dossier_mailer:
|
||||
notify_en_construction_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é.
|
|
@ -4,7 +4,7 @@ fr:
|
|||
subject:
|
||||
one: Une demande de transfert de dossier vous est adressée
|
||||
other: Une demande de transfert de dossiers vous est adressée
|
||||
transfer_link: demande de transfer
|
||||
transfer_link: demande de transfert
|
||||
body:
|
||||
one: |
|
||||
Accéder à la demande de transfert du dossier en cliquant sur le lien suivant :
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
defaults: &defaults
|
||||
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
|
||||
encryption_service_salt: <%= ENV["ENCRYPTION_SERVICE_SALT"] %>
|
||||
signing_key: <%= ENV["SIGNING_KEY"] %>
|
||||
otp_secret_key: <%= ENV["OTP_SECRET_KEY"] %>
|
||||
basic_auth:
|
||||
username: <%= ENV['BASIC_AUTH_USERNAME'] %>
|
||||
|
@ -25,7 +24,7 @@ defaults: &defaults
|
|||
token_endpoint: <%= ENV['FC_PARTICULIER_BASE_URL'] %>/api/v1/token
|
||||
userinfo_endpoint: <%= ENV['FC_PARTICULIER_BASE_URL'] %>/api/v1/userinfo
|
||||
logout_endpoint: <%= ENV['FC_PARTICULIER_BASE_URL'] %>/api/v1/logout
|
||||
agent_connect:
|
||||
agent_connect:
|
||||
identifier: <%= ENV['AGENT_CONNECT_ID'] %>
|
||||
secret: <%= ENV['AGENT_CONNECT_SECRET'] %>
|
||||
redirect_uri: <%= ENV['AGENT_CONNECT_REDIRECT'] %>
|
||||
|
@ -56,6 +55,7 @@ defaults: &defaults
|
|||
api_v3_key: <%= ENV['SENDINBLUE_API_V3_KEY'] %>
|
||||
matomo:
|
||||
enabled: <%= ENV['MATOMO_ENABLED'] == 'enabled' %>
|
||||
host: <%= ENV['MATOMO_HOST'] %>
|
||||
client_key: <%= ENV['MATOMO_ID'] %>
|
||||
sentry:
|
||||
enabled: <%= ENV['SENTRY_ENABLED'] == 'enabled' %>
|
||||
|
@ -85,7 +85,6 @@ test:
|
|||
<<: *defaults
|
||||
secret_key_base: aa52abc3f3a629d04a61e9899a24c12f52b24c679cbf45f8ec0cdcc64ab9526d673adca84212882dff3911ac98e0c32ec4729ca7b3429ba18ef4dfd1bd18bc7a
|
||||
encryption_service_salt: QUDyMoXyw2YXU8pHnpts3w9MyMpsMQ6BgP62obgCf7PQv
|
||||
signing_key: aef3153a9829fa4ba10acb02927ac855df6b92795b1ad265d654443c4b14a017
|
||||
otp_secret_key: 78ddda3679dc0ba2c99f50bcff04f49d862358dbeb7ead50368fdd6de14392be884ee10a204a0375b4b382e1a842fafe40d7858b7ab4796ec3a67c518d31112b
|
||||
api_entreprise:
|
||||
key: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik9oIHllYWgiLCJpYXQiOjE1MTYyMzkwMjJ9.f06sBo3q2Yxnw_TYPFUEs0CozBmcV-XniH_DeKNWzKE"
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class AddAttestationTemplateIdToProcedureRevisions < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_reference :procedure_revisions, :attestation_template, foreign_key: { to_table: :attestation_templates }, null: true, index: true
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2021_12_02_133139) do
|
||||
ActiveRecord::Schema.define(version: 2022_01_10_133139) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -593,6 +593,8 @@ ActiveRecord::Schema.define(version: 2021_12_02_133139) do
|
|||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "published_at"
|
||||
t.bigint "attestation_template_id"
|
||||
t.index ["attestation_template_id"], name: "index_procedure_revisions_on_attestation_template_id"
|
||||
t.index ["procedure_id"], name: "index_procedure_revisions_on_procedure_id"
|
||||
end
|
||||
|
||||
|
@ -872,6 +874,7 @@ ActiveRecord::Schema.define(version: 2021_12_02_133139) do
|
|||
add_foreign_key "procedure_revision_types_de_champ", "procedure_revision_types_de_champ", column: "parent_id"
|
||||
add_foreign_key "procedure_revision_types_de_champ", "procedure_revisions", column: "revision_id"
|
||||
add_foreign_key "procedure_revision_types_de_champ", "types_de_champ"
|
||||
add_foreign_key "procedure_revisions", "attestation_templates"
|
||||
add_foreign_key "procedure_revisions", "procedures"
|
||||
add_foreign_key "procedures", "procedure_revisions", column: "draft_revision_id"
|
||||
add_foreign_key "procedures", "procedure_revisions", column: "published_revision_id"
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
namespace :after_party do
|
||||
desc 'Deployment task: moving Attestations from Procedure to ProcedureRevision'
|
||||
task revise_attestation_templates: :environment do
|
||||
rake_puts "Running deploy task 'revise_attestation_templates'"
|
||||
|
||||
attestation_templates = AttestationTemplate.where.not(procedure_id: nil)
|
||||
progress = ProgressReport.new(attestation_templates.count)
|
||||
|
||||
attestation_templates.find_each do |attestation_template|
|
||||
ProcedureRevision
|
||||
.where(procedure_id: attestation_template.procedure_id, attestation_template_id: nil)
|
||||
.update_all(attestation_template_id: attestation_template)
|
||||
attestation_template.update_column(:procedure_id, nil)
|
||||
progress.inc
|
||||
end
|
||||
progress.finish
|
||||
|
||||
# Update task as completed. If you remove the line below, the task will
|
||||
# run with every deploy (or every time you call after_party:run).
|
||||
AfterParty::TaskRecord
|
||||
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||
end
|
||||
end
|
|
@ -1,8 +1,8 @@
|
|||
include ActionDispatch::TestProcess
|
||||
|
||||
describe Administrateurs::AttestationTemplatesController, type: :controller do
|
||||
let!(:attestation_template) { create(:attestation_template) }
|
||||
let(:admin) { create(:administrateur) }
|
||||
let(:attestation_template) { build(:attestation_template) }
|
||||
let!(:procedure) { create :procedure, administrateur: admin, attestation_template: attestation_template }
|
||||
let(:logo) { fixture_file_upload('spec/fixtures/files/white.png', 'image/png') }
|
||||
let(:logo2) { fixture_file_upload('spec/fixtures/files/white.png', 'image/png') }
|
||||
|
@ -41,7 +41,7 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do
|
|||
end
|
||||
|
||||
context 'if an attestation template exists on the procedure' do
|
||||
after { procedure.attestation_template.destroy }
|
||||
after { procedure.draft_revision.attestation_template&.destroy }
|
||||
|
||||
context 'with images' do
|
||||
let!(:attestation_template) do
|
||||
|
@ -115,14 +115,14 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do
|
|||
procedure.reload
|
||||
end
|
||||
|
||||
it { expect(procedure.attestation_template).to have_attributes(attestation_params) }
|
||||
it { expect(procedure.attestation_template.activated).to be true }
|
||||
it { expect(procedure.attestation_template.logo.download).to eq(logo2.read) }
|
||||
it { expect(procedure.attestation_template.signature.download).to eq(signature2.read) }
|
||||
it { expect(procedure.draft_attestation_template).to have_attributes(attestation_params) }
|
||||
it { expect(procedure.draft_attestation_template.activated).to be true }
|
||||
it { expect(procedure.draft_attestation_template.logo.download).to eq(logo2.read) }
|
||||
it { expect(procedure.draft_attestation_template.signature.download).to eq(signature2.read) }
|
||||
it { expect(response).to redirect_to edit_admin_procedure_attestation_template_path(procedure) }
|
||||
it { expect(flash.notice).to eq("L'attestation a bien été sauvegardée") }
|
||||
|
||||
after { procedure.attestation_template.destroy }
|
||||
after { procedure.draft_attestation_template.destroy }
|
||||
end
|
||||
|
||||
context 'when something wrong happens in the attestation template creation' do
|
||||
|
@ -140,7 +140,7 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do
|
|||
|
||||
it { expect(response).to redirect_to edit_admin_procedure_attestation_template_path(procedure) }
|
||||
it { expect(flash.alert).to be_present }
|
||||
it { expect(procedure.attestation_template).to be nil }
|
||||
it { expect(procedure.draft_attestation_template).to be nil }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -158,13 +158,13 @@ describe Administrateurs::AttestationTemplatesController, type: :controller do
|
|||
procedure.reload
|
||||
end
|
||||
|
||||
it { expect(procedure.attestation_template).to have_attributes(attestation_params) }
|
||||
it { expect(procedure.attestation_template.logo.download).to eq(logo2.read) }
|
||||
it { expect(procedure.attestation_template.signature.download).to eq(signature2.read) }
|
||||
it { expect(procedure.draft_attestation_template).to have_attributes(attestation_params) }
|
||||
it { expect(procedure.draft_attestation_template.logo.download).to eq(logo2.read) }
|
||||
it { expect(procedure.draft_attestation_template.signature.download).to eq(signature2.read) }
|
||||
it { expect(response).to redirect_to edit_admin_procedure_attestation_template_path(procedure) }
|
||||
it { expect(flash.notice).to eq("L'attestation a bien été modifiée") }
|
||||
|
||||
after { procedure.attestation_template.destroy }
|
||||
after { procedure.draft_attestation_template&.destroy }
|
||||
end
|
||||
|
||||
context 'when something wrong happens in the attestation template creation' do
|
||||
|
|
|
@ -411,9 +411,21 @@ describe Administrateurs::ProceduresController, type: :controller do
|
|||
context 'when dossier is en_construction' do
|
||||
let(:dossier) { create(:dossier, :en_construction, procedure: procedure_published) }
|
||||
|
||||
it { expect(procedure.reload.close?).to be_truthy }
|
||||
it { expect(procedure.reload.discarded?).to be_truthy }
|
||||
it { expect(dossier.reload.discarded?).to be_truthy }
|
||||
it do
|
||||
expect(procedure.reload.close?).to be_truthy
|
||||
expect(procedure.discarded?).to be_truthy
|
||||
expect(dossier.reload.kept?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'when dossier is accepte' do
|
||||
let(:dossier) { create(:dossier, :accepte, procedure: procedure_published) }
|
||||
|
||||
it do
|
||||
expect(procedure.reload.close?).to be_truthy
|
||||
expect(procedure.discarded?).to be_truthy
|
||||
expect(dossier.reload.hidden_by_administration?).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -427,8 +439,19 @@ describe Administrateurs::ProceduresController, type: :controller do
|
|||
context 'when dossier is en_construction' do
|
||||
let(:dossier) { create(:dossier, :en_construction, procedure: procedure_published) }
|
||||
|
||||
it { expect(procedure.reload.discarded?).to be_truthy }
|
||||
it { expect(dossier.reload.discarded?).to be_truthy }
|
||||
it do
|
||||
expect(procedure.reload.discarded?).to be_truthy
|
||||
expect(dossier.reload.kept?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'when dossier is accepte' do
|
||||
let(:dossier) { create(:dossier, :accepte, procedure: procedure_published) }
|
||||
|
||||
it do
|
||||
expect(procedure.reload.discarded?).to be_truthy
|
||||
expect(dossier.reload.hidden_by_administration?).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -766,7 +766,6 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
before do
|
||||
dossier.accepter!(instructeur: instructeur, motivation: "le dossier est correct")
|
||||
dossier.update!(hidden_by_user_at: Time.zone.now.beginning_of_day.utc)
|
||||
allow(DossierMailer).to receive(:notify_instructeur_deletion_to_user).and_return(double(deliver_later: nil))
|
||||
subject
|
||||
end
|
||||
|
||||
|
@ -775,10 +774,6 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
expect(DossierOperationLog.where(dossier_id: dossier.id).last.operation).to eq('supprimer')
|
||||
end
|
||||
|
||||
it 'send an email to the user' do
|
||||
expect(DossierMailer).to have_received(:notify_instructeur_deletion_to_user).with(DeletedDossier.where(dossier_id: dossier.id).first, dossier.user.email)
|
||||
end
|
||||
|
||||
it 'add a record into deleted_dossiers table' do
|
||||
expect(DeletedDossier.where(dossier_id: dossier.id).count).to eq(1)
|
||||
expect(DeletedDossier.where(dossier_id: dossier.id).first.revision_id).to eq(dossier.revision_id)
|
||||
|
@ -794,7 +789,6 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
context 'when the instructeur want to delete a dossier with a decision and not hidden by user' do
|
||||
before do
|
||||
dossier.accepter!(instructeur: instructeur, motivation: "le dossier est correct")
|
||||
allow(DossierMailer).to receive(:notify_instructeur_deletion_to_user).and_return(double(deliver_later: nil))
|
||||
subject
|
||||
end
|
||||
|
||||
|
@ -803,10 +797,6 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
expect(DossierOperationLog.where(dossier_id: dossier.id).last.operation).not_to eq('supprimer')
|
||||
end
|
||||
|
||||
it 'does not send an email to the user' do
|
||||
expect(DossierMailer).not_to have_received(:notify_instructeur_deletion_to_user).with(DeletedDossier.where(dossier_id: dossier.id).first, dossier.user.email)
|
||||
end
|
||||
|
||||
it 'add a record into deleted_dossiers table' do
|
||||
expect(DeletedDossier.where(dossier_id: dossier.id).count).to eq(0)
|
||||
end
|
||||
|
|
|
@ -107,6 +107,7 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
|
||||
before do
|
||||
create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction))
|
||||
create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction), hidden_by_user_at: 1.hour.ago)
|
||||
create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction))
|
||||
create(:dossier, procedure: procedure, state: Dossier.states.fetch(:sans_suite), archived: true)
|
||||
|
||||
|
@ -238,13 +239,26 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
let!(:new_unfollow_dossier) { create(:dossier, :en_instruction, procedure: procedure) }
|
||||
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:a_suivre_dossiers)).to match_array([new_unfollow_dossier]) }
|
||||
it { expect(assigns(:followed_dossiers)).to be_empty }
|
||||
it { expect(assigns(:termines_dossiers)).to be_empty }
|
||||
it { expect(assigns(:all_state_dossiers)).to match_array([new_unfollow_dossier]) }
|
||||
it { expect(assigns(:archived_dossiers)).to be_empty }
|
||||
|
||||
context 'with a dossier en contruction hidden by user' do
|
||||
let!(:hidden_dossier) { create(:dossier, groupe_instructeur: gi_2, state: Dossier.states.fetch(:en_construction), hidden_by_user_at: 1.hour.ago) }
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:all_state_dossiers)).to match_array([new_unfollow_dossier]) }
|
||||
end
|
||||
|
||||
context 'with a dossier en contruction not hidden by user' do
|
||||
let!(:en_construction_dossier) { create(:dossier, groupe_instructeur: gi_2, state: Dossier.states.fetch(:en_construction)) }
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:all_state_dossiers)).to match_array([new_unfollow_dossier, en_construction_dossier]) }
|
||||
end
|
||||
|
||||
context 'and dossiers without follower on each of the others groups' do
|
||||
let!(:new_unfollow_dossier_on_gi_2) { create(:dossier, groupe_instructeur: gi_2, state: Dossier.states.fetch(:en_instruction)) }
|
||||
let!(:new_unfollow_dossier_on_gi_3) { create(:dossier, groupe_instructeur: gi_3, state: Dossier.states.fetch(:en_instruction)) }
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
describe Manager::DossiersController, type: :controller do
|
||||
let(:super_admin) { create :super_admin }
|
||||
let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier) }
|
||||
let(:operations) { dossier.dossier_operation_logs.map(&:operation).map(&:to_sym) }
|
||||
|
||||
before { sign_in super_admin }
|
||||
|
||||
describe '#discard' do
|
||||
let(:dossier) { create(:dossier, :en_construction) }
|
||||
|
||||
before do
|
||||
post :discard, params: { id: dossier.id }
|
||||
dossier.reload
|
||||
end
|
||||
|
||||
it { expect(dossier.discarded?).to be_truthy }
|
||||
it { expect(deleted_dossier).not_to be_nil }
|
||||
it { expect(deleted_dossier.reason).to eq("manager_request") }
|
||||
it { expect(operations).to eq([:supprimer]) }
|
||||
end
|
||||
|
||||
describe '#restore' do
|
||||
let(:dossier) { create(:dossier, :en_construction, :with_individual) }
|
||||
|
||||
before do
|
||||
dossier.discard_and_keep_track!(super_admin, :manager_request)
|
||||
|
||||
post :restore, params: { id: dossier.id }
|
||||
dossier.reload
|
||||
end
|
||||
|
||||
it { expect(dossier.kept?).to be_truthy }
|
||||
it { expect(deleted_dossier).to be_nil }
|
||||
it { expect(operations).to eq([:supprimer, :restaurer]) }
|
||||
end
|
||||
|
||||
describe '#repasser_en_instruction' do
|
||||
let(:dossier) { create(:dossier, :accepte) }
|
||||
|
||||
before do
|
||||
post :repasser_en_instruction, params: { id: dossier.id }
|
||||
dossier.reload
|
||||
end
|
||||
|
||||
it { expect(dossier.en_instruction?).to be_truthy }
|
||||
end
|
||||
end
|
|
@ -27,10 +27,8 @@ describe Manager::ProceduresController, type: :controller do
|
|||
end
|
||||
|
||||
describe '#discard' do
|
||||
let(:dossier) { create(:dossier, :en_construction) }
|
||||
let(:dossier) { create(:dossier, :accepte) }
|
||||
let(:procedure) { dossier.procedure }
|
||||
let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier.id) }
|
||||
let(:operations) { dossier.dossier_operation_logs.map(&:operation).map(&:to_sym) }
|
||||
|
||||
before do
|
||||
post :discard, params: { id: procedure.id }
|
||||
|
@ -39,17 +37,12 @@ describe Manager::ProceduresController, type: :controller do
|
|||
end
|
||||
|
||||
it { expect(procedure.discarded?).to be_truthy }
|
||||
it { expect(dossier.discarded?).to be_truthy }
|
||||
it { expect(deleted_dossier).not_to be_nil }
|
||||
it { expect(deleted_dossier.reason).to eq("procedure_removed") }
|
||||
it { expect(operations).to eq([:supprimer]) }
|
||||
it { expect(dossier.hidden_by_administration?).to be_truthy }
|
||||
end
|
||||
|
||||
describe '#restore' do
|
||||
let(:dossier) { create(:dossier, :en_construction, :with_individual) }
|
||||
let(:dossier) { create(:dossier, :accepte, :with_individual) }
|
||||
let(:procedure) { dossier.procedure }
|
||||
let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier.id) }
|
||||
let(:operations) { dossier.dossier_operation_logs.map(&:operation).map(&:to_sym) }
|
||||
|
||||
before do
|
||||
procedure.discard_and_keep_track!(super_admin)
|
||||
|
@ -59,9 +52,7 @@ describe Manager::ProceduresController, type: :controller do
|
|||
end
|
||||
|
||||
it { expect(procedure.kept?).to be_truthy }
|
||||
it { expect(dossier.kept?).to be_truthy }
|
||||
it { expect(deleted_dossier).to be_nil }
|
||||
it { expect(operations).to eq([:supprimer, :restaurer]) }
|
||||
it { expect(dossier.hidden_by_administration?).to be_falsey }
|
||||
end
|
||||
|
||||
describe '#index' do
|
||||
|
|
|
@ -1008,7 +1008,6 @@ describe Users::DossiersController, type: :controller do
|
|||
shared_examples_for "the dossier can not be deleted" do
|
||||
it "doesn’t notify the deletion" do
|
||||
expect(DossierMailer).not_to receive(:notify_deletion_to_administration)
|
||||
expect(DossierMailer).not_to receive(:notify_deletion_to_user)
|
||||
subject
|
||||
end
|
||||
|
||||
|
@ -1024,7 +1023,6 @@ describe Users::DossiersController, type: :controller do
|
|||
|
||||
it "notifies the user and the admin of the deletion" do
|
||||
expect(DossierMailer).to receive(:notify_deletion_to_administration).with(kind_of(DeletedDossier), dossier.procedure.administrateurs.first.email).and_return(double(deliver_later: nil))
|
||||
expect(DossierMailer).to receive(:notify_deletion_to_user).with(kind_of(DeletedDossier), dossier.user.email).and_return(double(deliver_later: nil))
|
||||
subject
|
||||
end
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@ FactoryBot.define do
|
|||
body { 'body' }
|
||||
footer { 'footer' }
|
||||
activated { true }
|
||||
|
||||
association :procedure
|
||||
end
|
||||
|
||||
trait :with_files do
|
||||
|
|
|
@ -23,10 +23,11 @@ FactoryBot.define do
|
|||
types_de_champ { [] }
|
||||
types_de_champ_private { [] }
|
||||
updated_at { nil }
|
||||
attestation_template { }
|
||||
end
|
||||
|
||||
after(:build) do |procedure, evaluator|
|
||||
initial_revision = build(:procedure_revision, procedure: procedure)
|
||||
initial_revision = build(:procedure_revision, procedure: procedure, attestation_template: evaluator.attestation_template)
|
||||
add_types_de_champs(evaluator.types_de_champ, to: initial_revision, scope: :public)
|
||||
add_types_de_champs(evaluator.types_de_champ_private, to: initial_revision, scope: :private)
|
||||
|
||||
|
|
|
@ -60,16 +60,11 @@ RSpec.describe DossierMailer, type: :mailer do
|
|||
it { expect(subject.perform_deliveries).to be_falsy }
|
||||
end
|
||||
|
||||
describe '.notify_deletion_to_user' do
|
||||
let(:deleted_dossier) { build(:deleted_dossier) }
|
||||
def notify_deletion_to_administration(deleted_dossier, to_email)
|
||||
@subject = default_i18n_subject(dossier_id: deleted_dossier.dossier_id)
|
||||
@deleted_dossier = deleted_dossier
|
||||
|
||||
subject { described_class.notify_deletion_to_user(deleted_dossier, to_email) }
|
||||
|
||||
it { expect(subject.subject).to eq("Votre dossier nº #{deleted_dossier.dossier_id} a bien été supprimé") }
|
||||
it { expect(subject.body).to include("Votre dossier") }
|
||||
it { expect(subject.body).to include(deleted_dossier.dossier_id) }
|
||||
it { expect(subject.body).to include("a bien été supprimé") }
|
||||
it { expect(subject.body).to include(deleted_dossier.procedure.libelle) }
|
||||
mail(to: to_email, subject: @subject)
|
||||
end
|
||||
|
||||
describe '.notify_deletion_to_administration' do
|
||||
|
|
|
@ -45,10 +45,6 @@ class DossierMailerPreview < ActionMailer::Preview
|
|||
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_instructeur_deletion_to_user
|
||||
DossierMailer.notify_instructeur_deletion_to_user(deleted_dossier, usager_email)
|
||||
end
|
||||
|
|
|
@ -799,7 +799,6 @@ describe Dossier do
|
|||
let(:reason) { :user_request }
|
||||
|
||||
before do
|
||||
allow(DossierMailer).to receive(:notify_deletion_to_user).and_return(double(deliver_later: nil))
|
||||
allow(DossierMailer).to receive(:notify_deletion_to_administration).and_return(double(deliver_later: nil))
|
||||
end
|
||||
|
||||
|
@ -835,10 +834,6 @@ describe Dossier do
|
|||
expect(deleted_dossier.deleted_at).to be_present
|
||||
end
|
||||
|
||||
it 'notifies the user' do
|
||||
expect(DossierMailer).to have_received(:notify_deletion_to_user).with(deleted_dossier, dossier.user.email)
|
||||
end
|
||||
|
||||
it 'records the operation in the log' do
|
||||
expect(last_operation.operation).to eq("supprimer")
|
||||
expect(last_operation.automatic_operation?).to be_falsey
|
||||
|
@ -1327,29 +1322,31 @@ describe Dossier do
|
|||
end
|
||||
|
||||
describe 'discarded_brouillon_expired and discarded_en_construction_expired' do
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
let(:administrateur) { create(:administrateur) }
|
||||
let(:user) { administrateur.user }
|
||||
let(:reason) { DeletedDossier.reasons.fetch(:user_request) }
|
||||
|
||||
before do
|
||||
create(:dossier)
|
||||
create(:dossier, :en_construction)
|
||||
create(:dossier).discard!
|
||||
create(:dossier, :en_construction).discard!
|
||||
create(:dossier, user: user)
|
||||
create(:dossier, :en_construction, user: user)
|
||||
create(:dossier, user: user).discard_and_keep_track!(user, reason)
|
||||
create(:dossier, :en_construction, user: user).discard_and_keep_track!(user, reason)
|
||||
|
||||
Timecop.travel(2.months.ago) do
|
||||
create(:dossier).discard!
|
||||
create(:dossier, :en_construction).discard!
|
||||
create(:dossier, user: user).discard_and_keep_track!(user, reason)
|
||||
create(:dossier, :en_construction, user: user).discard_and_keep_track!(user, reason)
|
||||
|
||||
create(:dossier).procedure.discard_and_keep_track!(super_admin)
|
||||
create(:dossier, :en_construction).procedure.discard_and_keep_track!(super_admin)
|
||||
create(:dossier, user: user).procedure.discard_and_keep_track!(administrateur)
|
||||
create(:dossier, :en_construction, user: user).procedure.discard_and_keep_track!(administrateur)
|
||||
end
|
||||
Timecop.travel(1.week.ago) do
|
||||
create(:dossier).discard!
|
||||
create(:dossier, :en_construction).discard!
|
||||
create(:dossier, user: user).discard_and_keep_track!(user, reason)
|
||||
create(:dossier, :en_construction, user: user).discard_and_keep_track!(user, reason)
|
||||
end
|
||||
end
|
||||
|
||||
it { expect(Dossier.discarded_brouillon_expired.count).to eq(3) }
|
||||
it { expect(Dossier.discarded_en_construction_expired.count).to eq(3) }
|
||||
it { expect(Dossier.discarded_brouillon_expired.count).to eq(2) }
|
||||
it { expect(Dossier.discarded_en_construction_expired.count).to eq(0) }
|
||||
end
|
||||
|
||||
describe "discarded procedure dossier should be able to access it's procedure" do
|
||||
|
|
|
@ -169,7 +169,7 @@ describe ProcedureRevision do
|
|||
expect(new_revision.revision_types_de_champ.last.position).to eq(2)
|
||||
expect(new_revision.revision_types_de_champ.last.type_de_champ).to eq(new_type_de_champ)
|
||||
expect(new_revision.revision_types_de_champ.last.type_de_champ.revision).to eq(new_revision)
|
||||
expect(procedure.active_revision.changed?(new_revision)).to be_truthy
|
||||
expect(procedure.active_revision.different_from?(new_revision)).to be_truthy
|
||||
expect(procedure.active_revision.compare(new_revision)).to eq([
|
||||
{
|
||||
op: :add,
|
||||
|
|
|
@ -66,16 +66,12 @@ describe Procedure do
|
|||
end
|
||||
|
||||
describe '#closed_mail_template_attestation_inconsistency_state' do
|
||||
let(:procedure_without_attestation) { create(:procedure, closed_mail: closed_mail) }
|
||||
let(:procedure_without_attestation) { create(:procedure, closed_mail: closed_mail, attestation_template: nil) }
|
||||
let(:procedure_with_active_attestation) do
|
||||
procedure = create(:procedure, closed_mail: closed_mail)
|
||||
create(:attestation_template, procedure: procedure, activated: true)
|
||||
procedure
|
||||
create(:procedure, closed_mail: closed_mail, attestation_template: build(:attestation_template, activated: true))
|
||||
end
|
||||
let(:procedure_with_inactive_attestation) do
|
||||
procedure = create(:procedure, closed_mail: closed_mail)
|
||||
create(:attestation_template, procedure: procedure, activated: false)
|
||||
procedure
|
||||
create(:procedure, closed_mail: closed_mail, attestation_template: build(:attestation_template, activated: false))
|
||||
end
|
||||
|
||||
subject { procedure.closed_mail_template_attestation_inconsistency_state }
|
||||
|
@ -272,6 +268,16 @@ describe Procedure do
|
|||
let(:procedure) { build(:procedure, monavis_embed: monavis_issue_phillipe) }
|
||||
it { expect(procedure.valid?).to eq(true) }
|
||||
end
|
||||
|
||||
context 'Monavis embed code without title allowed' do
|
||||
monavis_issue_bouchra = <<-MSG
|
||||
<a href="https://voxusagers.numerique.gouv.fr/Demarches/3193?&view-mode=formulaire-avis&nd_mode=en-ligne-enti%C3%A8rement&nd_source=button&key=58e099a09c02abe629c14905ed2b055d">
|
||||
<img src="https://voxusagers.numerique.gouv.fr/static/bouton-bleu.svg" alt="Je donne mon avis" />
|
||||
</a>
|
||||
MSG
|
||||
let(:procedure) { build(:procedure, monavis_embed: monavis_issue_bouchra) }
|
||||
it { expect(procedure.valid?).to eq(true) }
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'duree de conservation' do
|
||||
|
|
|
@ -416,5 +416,26 @@ describe ExpiredDossiersDeletionService do
|
|||
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
|
||||
|
||||
context 'with 1 dossier deleted by user and 1 dossier deleted by administration' do
|
||||
let!(:dossier_1) { create(:dossier, :accepte, procedure: procedure, user: user, hidden_by_administration_at: 1.hour.ago, termine_close_to_expiration_notice_sent_at: (warning_period + 1.day).ago) }
|
||||
let!(:dossier_2) { create(:dossier, :refuse, procedure: procedure_2, user: user, hidden_by_user_at: 1.hour.ago, termine_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_termine_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]), 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(match_array([deleted_dossier_2]), instructeur.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
|
||||
|
|
|
@ -5,6 +5,11 @@ describe ProcedureArchiveService do
|
|||
let(:year) { 2020 }
|
||||
let(:month) { 3 }
|
||||
let(:date_month) { Date.strptime("#{year}-#{month}", "%Y-%m") }
|
||||
let(:groupe_instructeurs) { instructeur.groupe_instructeurs }
|
||||
|
||||
before do
|
||||
procedure.defaut_groupe_instructeur.add(instructeur)
|
||||
end
|
||||
|
||||
describe '#create_pending_archive' do
|
||||
context 'for a specific month' do
|
||||
|
@ -37,7 +42,7 @@ describe ProcedureArchiveService do
|
|||
after { Timecop.return }
|
||||
|
||||
context 'for a specific month' do
|
||||
let(:archive) { create(:archive, time_span_type: 'monthly', status: 'pending', month: date_month) }
|
||||
let(:archive) { create(:archive, time_span_type: 'monthly', status: 'pending', month: date_month, groupe_instructeurs: groupe_instructeurs) }
|
||||
let(:year) { 2021 }
|
||||
let(:mailer) { double('mailer', deliver_later: true) }
|
||||
|
||||
|
@ -99,7 +104,7 @@ describe ProcedureArchiveService do
|
|||
end
|
||||
|
||||
context 'for all months' do
|
||||
let(:archive) { create(:archive, time_span_type: 'everything', status: 'pending') }
|
||||
let(:archive) { create(:archive, time_span_type: 'everything', status: 'pending', groupe_instructeurs: groupe_instructeurs) }
|
||||
let(:mailer) { double('mailer', deliver_later: true) }
|
||||
|
||||
it 'collect files' do
|
||||
|
@ -125,7 +130,7 @@ describe ProcedureArchiveService do
|
|||
after { Timecop.return }
|
||||
|
||||
context 'for a specific month' do
|
||||
let(:archive) { create(:archive, time_span_type: 'monthly', status: 'pending', month: date_month) }
|
||||
let(:archive) { create(:archive, time_span_type: 'monthly', status: 'pending', month: date_month, groupe_instructeurs: groupe_instructeurs) }
|
||||
let(:year) { 2021 }
|
||||
let(:mailer) { double('mailer', deliver_later: true) }
|
||||
|
||||
|
@ -228,7 +233,7 @@ describe ProcedureArchiveService do
|
|||
end
|
||||
|
||||
context 'for all months' do
|
||||
let(:archive) { create(:archive, time_span_type: 'everything', status: 'pending') }
|
||||
let(:archive) { create(:archive, time_span_type: 'everything', status: 'pending', groupe_instructeurs: groupe_instructeurs) }
|
||||
let(:mailer) { double('mailer', deliver_later: true) }
|
||||
|
||||
it 'collect files' do
|
||||
|
|
|
@ -105,8 +105,7 @@ module SystemHelpers
|
|||
|
||||
def select_combobox(libelle, fill_with, value, check: true)
|
||||
fill_in libelle, with: fill_with
|
||||
selector = "li[data-option-value=\"#{value}\"]"
|
||||
find(selector).click
|
||||
find('li[role="option"]', text: value).click
|
||||
if check
|
||||
check_selected_value(libelle, with: value)
|
||||
end
|
||||
|
|
|
@ -165,8 +165,8 @@ describe 'Instructing a dossier:', js: true do
|
|||
|
||||
click_on 'Personnes impliquées'
|
||||
|
||||
select_combobox('Emails', instructeur_2.email, instructeur_2.id, check: false)
|
||||
select_combobox('Emails', instructeur_3.email, instructeur_3.id, check: false)
|
||||
select_combobox('Emails', instructeur_2.email, instructeur_2.email, check: false)
|
||||
select_combobox('Emails', instructeur_3.email, instructeur_3.email, check: false)
|
||||
|
||||
click_on 'Envoyer'
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ describe "procedure filters" do
|
|||
end
|
||||
|
||||
scenario "should add be able to add created_at column", js: true do
|
||||
add_column("Créé le", "self/created_at")
|
||||
add_column("Créé le")
|
||||
within ".dossiers-table" do
|
||||
expect(page).to have_link("Créé le")
|
||||
expect(page).to have_link(new_unfollow_dossier.created_at.strftime('%d/%m/%Y'))
|
||||
|
@ -40,7 +40,7 @@ describe "procedure filters" do
|
|||
end
|
||||
|
||||
scenario "should add be able to add and remove custom type_de_champ column", js: true do
|
||||
add_column(type_de_champ.libelle, "type_de_champ/#{type_de_champ.stable_id}")
|
||||
add_column(type_de_champ.libelle)
|
||||
within ".dossiers-table" do
|
||||
expect(page).to have_link(type_de_champ.libelle)
|
||||
expect(page).to have_link(champ.value)
|
||||
|
@ -123,9 +123,9 @@ describe "procedure filters" do
|
|||
click_button "Ajouter le filtre"
|
||||
end
|
||||
|
||||
def add_column(column_name, column_path)
|
||||
def add_column(column_name)
|
||||
click_on 'Personnaliser'
|
||||
select_combobox('Colonne à afficher', column_name, column_path, check: false)
|
||||
select_combobox('Colonne à afficher', column_name, column_name, check: false)
|
||||
click_button "Enregistrer"
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
describe 'admin/_closed_mail_template_attestation_inconsistency_alert.html.haml', type: :view do
|
||||
let(:procedure) { create(:procedure, closed_mail: closed_mail) }
|
||||
let(:procedure) { create(:procedure, closed_mail: closed_mail, attestation_template: attestation_template) }
|
||||
let(:attestation_template) { nil }
|
||||
|
||||
def alert
|
||||
assign(:procedure, procedure)
|
||||
|
@ -23,7 +24,7 @@ describe 'admin/_closed_mail_template_attestation_inconsistency_alert.html.haml'
|
|||
|
||||
context 'when there is an active attestation but the closed mail template does not mention it' do
|
||||
let(:closed_mail) { create(:closed_mail) }
|
||||
let!(:attestation_template) { create(:attestation_template, procedure: procedure, activated: true) }
|
||||
let(:attestation_template) { build(:attestation_template) }
|
||||
|
||||
it { expect(alert).to include("Cette démarche comporte une attestation, mais l’accusé d’acceptation ne la mentionne pas") }
|
||||
it { expect(alert).to include(edit_admin_procedure_mail_template_path(procedure, Mails::ClosedMail::SLUG)) }
|
||||
|
|
|
@ -8703,9 +8703,9 @@ nano-time@1.0.0:
|
|||
big-integer "^1.6.16"
|
||||
|
||||
nanoid@^3.1.30:
|
||||
version "3.1.30"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362"
|
||||
integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c"
|
||||
integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==
|
||||
|
||||
nanomatch@^1.2.9:
|
||||
version "1.2.13"
|
||||
|
|
Loading…
Reference in a new issue