refactor(PiecesJustificativesService): stop passing flags, pass user_profile and manage ACL from the service itself

This commit is contained in:
Martin 2024-02-07 17:33:34 +01:00
parent 83690529ca
commit 32e8f34511
16 changed files with 355 additions and 277 deletions

View file

@ -159,9 +159,7 @@ module Experts
end
def telecharger_pjs
@dossier = dossier_with_champs
files = ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: @dossier.id), include_avis_for_expert: current_expert)
files = ActiveStorage::DownloadableFile.create_list_from_dossiers(user_profile: current_expert, dossiers: Dossier.where(id: @dossier.id))
cleaned_files = ActiveStorage::DownloadableFile.cleanup_list_from_dossier(files)
zipline(cleaned_files, "dossier-#{@dossier.id}.zip")

View file

@ -49,10 +49,9 @@ module Instructeurs
def show
@demande_seen_at = current_instructeur.follows.find_by(dossier: dossier_with_champs)&.demande_seen_at
@is_dossier_in_batch_operation = dossier.batch_operation.present?
respond_to do |format|
format.pdf do
@include_infos_administration = true
@acls = PiecesJustificativesService.new(user_profile: current_instructeur).acl_for_dossier_export
render(template: 'dossiers/show', formats: [:pdf])
end
format.all
@ -322,7 +321,7 @@ module Instructeurs
end
def telecharger_pjs
files = ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: dossier.id), with_champs_private: true, include_infos_administration: true)
files = ActiveStorage::DownloadableFile.create_list_from_dossiers(dossiers: Dossier.where(id: dossier.id), user_profile: current_instructeur)
cleaned_files = ActiveStorage::DownloadableFile.cleanup_list_from_dossier(files)
zipline(cleaned_files, "dossier-#{dossier.id}.zip")

View file

@ -88,10 +88,11 @@ module Users
end
def show
pj_service = PiecesJustificativesService.new(user_profile: current_user)
respond_to do |format|
format.pdf do
@dossier = dossier_with_champs(pj_template: false)
@include_infos_administration = false
@acls = pj_service.acl_for_dossier_export
render(template: 'dossiers/show', formats: [:pdf])
end
format.all do

View file

@ -1,15 +1,10 @@
require 'fog/openstack'
class ActiveStorage::DownloadableFile
def self.create_list_from_dossiers(
dossiers,
with_bills: false,
with_champs_private: false,
include_infos_administration: false,
include_avis_for_expert: false
)
PiecesJustificativesService.generate_dossier_export(dossiers, include_infos_administration:, include_avis_for_expert:) +
PiecesJustificativesService.liste_documents(dossiers, with_bills:, with_champs_private:, with_avis_piece_justificative: include_infos_administration)
def self.create_list_from_dossiers(dossiers:, user_profile:)
pj_service = PiecesJustificativesService.new(user_profile:)
pj_service.generate_dossiers_export(dossiers) + pj_service.liste_documents(dossiers)
end
def self.cleanup_list_from_dossier(files)

View file

@ -1,17 +1,18 @@
class PiecesJustificativesService
def self.liste_documents(dossiers,
with_bills:,
with_champs_private:,
with_avis_piece_justificative:)
def initialize(user_profile:)
@user_profile = user_profile
end
def liste_documents(dossiers)
bill_ids = []
docs = dossiers.in_batches.flat_map do |batch|
pjs = pjs_for_champs(batch, with_champs_private:) +
pjs = pjs_for_champs(batch) +
pjs_for_commentaires(batch) +
pjs_for_dossier(batch) +
pjs_for_avis(batch, with_avis_piece_justificative:)
pjs_for_avis(batch)
if with_bills
if liste_documents_allows?(:with_bills)
# some bills are shared among operations
# so first, all the bill_ids are fetched
operation_logs, some_bill_ids = operation_logs_and_signature_ids(batch)
@ -23,7 +24,7 @@ class PiecesJustificativesService
pjs
end
if with_bills
if liste_documents_allows?(:with_bills)
# then the bills are retrieved without duplication
docs += signatures(bill_ids.uniq)
end
@ -31,6 +32,38 @@ class PiecesJustificativesService
docs
end
def generate_dossiers_export(dossiers)
return [] if dossiers.empty?
pdfs = []
procedure = dossiers.first.procedure
dossiers = dossiers.includes(:individual, :traitement, :etablissement, user: :france_connect_information, avis: :expert, commentaires: [:instructeur, :expert])
dossiers = DossierPreloader.new(dossiers).in_batches
dossiers.each do |dossier|
dossier.association(:procedure).target = procedure
pdf = ApplicationController
.render(template: 'dossiers/show', formats: [:pdf],
assigns: {
acls: acl_for_dossier_export,
dossier: dossier
})
a = ActiveStorage::FakeAttachment.new(
file: StringIO.new(pdf),
filename: "export-#{dossier.id}.pdf",
name: 'pdf_export_for_instructeur',
id: dossier.id,
created_at: dossier.updated_at
)
pdfs << ActiveStorage::DownloadableFile.pj_and_path(dossier.id, a)
end
pdfs
end
def self.serialize_types_de_champ_as_type_pj(revision)
tdcs = revision.types_de_champ_public.filter { |type_champ| type_champ.old_pj.present? }
tdcs.map.with_index do |type_champ, order_place|
@ -48,47 +81,52 @@ class PiecesJustificativesService
end
end
def self.generate_dossier_export(dossiers, include_infos_administration: false, include_avis_for_expert: false)
return [] if dossiers.empty?
pdfs = []
procedure = dossiers.first.procedure
dossiers = dossiers.includes(:individual, :traitement, :etablissement, user: :france_connect_information, avis: :expert, commentaires: [:instructeur, :expert])
dossiers = DossierPreloader.new(dossiers).in_batches
dossiers.each do |dossier|
dossier.association(:procedure).target = procedure
pdf = ApplicationController
.render(template: 'dossiers/show', formats: [:pdf],
assigns: {
include_infos_administration:,
include_avis_for_expert:,
dossier: dossier
})
a = ActiveStorage::FakeAttachment.new(
file: StringIO.new(pdf),
filename: "export-#{dossier.id}.pdf",
name: 'pdf_export_for_instructeur',
id: dossier.id,
created_at: dossier.updated_at
)
pdfs << ActiveStorage::DownloadableFile.pj_and_path(dossier.id, a)
def acl_for_dossier_export
case @user_profile
when Expert
{ include_infos_administration: true, include_avis_for_expert: true, only_for_expert: @user_profile }
when Instructeur, Administrateur
{ include_infos_administration: true, include_avis_for_expert: true, only_for_export: false }
when User
{ include_infos_administration: false, include_avis_for_expert: false, only_for_expert: false }
else
raise 'not supported'
end
pdfs
end
private
def self.pjs_for_champs(dossiers, with_champs_private:)
def liste_documents_allows?(scope)
case @user_profile
when Expert
{
with_bills: false,
with_champs_private: false,
with_avis_piece_justificative: false
}
when Instructeur
{
with_bills: false,
with_champs_private: true,
with_avis_piece_justificative: true
}
when Administrateur
{
with_bills: true,
with_champs_private: true,
with_avis_piece_justificative: true
}
else
raise 'not supported'
end.fetch(scope)
end
def pjs_for_champs(dossiers)
champs = Champ
.joins(:piece_justificative_file_attachments)
.where(type: "Champs::PieceJustificativeChamp", dossier: dossiers)
if !with_champs_private
if !liste_documents_allows?(:with_champs_private)
champs = champs.where(private: false)
end
@ -106,7 +144,7 @@ class PiecesJustificativesService
end
end
def self.pjs_for_commentaires(dossiers)
def pjs_for_commentaires(dossiers)
commentaire_id_dossier_id = Commentaire
.joins(:piece_jointe_attachment)
.where(dossier: dossiers)
@ -123,13 +161,13 @@ class PiecesJustificativesService
end
end
def self.pjs_for_dossier(dossiers)
def pjs_for_dossier(dossiers)
motivations(dossiers) +
attestations(dossiers) +
etablissements(dossiers)
end
def self.etablissements(dossiers)
def etablissements(dossiers)
etablissement_id_dossier_id = Etablissement
.where(dossier: dossiers)
.pluck(:id, :dossier_id)
@ -144,7 +182,7 @@ class PiecesJustificativesService
end
end
def self.motivations(dossiers)
def motivations(dossiers)
ActiveStorage::Attachment
.includes(:blob)
.where(record_type: "Dossier", name: "justificatif_motivation", record_id: dossiers)
@ -155,7 +193,7 @@ class PiecesJustificativesService
end
end
def self.attestations(dossiers)
def attestations(dossiers)
attestation_id_dossier_id = Attestation
.joins(:pdf_attachment)
.where(dossier: dossiers)
@ -171,10 +209,9 @@ class PiecesJustificativesService
end
end
def self.pjs_for_avis(dossiers, with_avis_piece_justificative:)
avis_ids_dossier_id_query = Avis.joins(:dossier)
.where(dossier: dossiers)
avis_ids_dossier_id_query = avis_ids_dossier_id_query.where(confidentiel: false) if !with_avis_piece_justificative
def pjs_for_avis(dossiers)
avis_ids_dossier_id_query = Avis.joins(:dossier).where(dossier: dossiers)
avis_ids_dossier_id_query = avis_ids_dossier_id_query.where(confidentiel: false) if !liste_documents_allows?(:with_avis_piece_justificative)
avis_ids_dossier_id = avis_ids_dossier_id_query.pluck(:id, :dossier_id).to_h
ActiveStorage::Attachment
@ -187,7 +224,7 @@ class PiecesJustificativesService
end
end
def self.operation_logs_and_signature_ids(dossiers)
def operation_logs_and_signature_ids(dossiers)
dol_id_dossier_id_bill_id = DossierOperationLog
.where(dossier: dossiers, data: nil)
.pluck(:bill_signature_id, :id, :dossier_id)
@ -227,14 +264,14 @@ class PiecesJustificativesService
[serialized_dols, bill_ids]
end
def self.signatures(bill_ids)
def signatures(bill_ids)
ActiveStorage::Attachment
.includes(:blob)
.where(record_type: "BillSignature", record_id: bill_ids)
.map { |bill| ActiveStorage::DownloadableFile.bill_and_path(bill) }
end
def self.safe_attachment(attachment)
def safe_attachment(attachment)
attachment
.blob
.virus_scan_result == ActiveStorage::VirusScanner::SAFE

View file

@ -36,7 +36,7 @@ class ProcedureExportService
end
def to_zip
attachments = ActiveStorage::DownloadableFile.create_list_from_dossiers(dossiers, with_champs_private: true, include_infos_administration: true)
attachments = ActiveStorage::DownloadableFile.create_list_from_dossiers(dossiers:, user_profile: @user_profile)
DownloadableFileService.download_and_zip(procedure, attachments, base_filename) do |zip_filepath|
ArchiveUploader.new(procedure: procedure, filename: filename(:zip), filepath: zip_filepath).blob

View file

@ -110,7 +110,7 @@ def add_identite_etablissement(pdf, etablissement)
format_in_2_columns(pdf, "État administratif", humanized_entreprise_etat_administratif(etablissement))
end
if @include_infos_administration
if @acls[:include_infos_administration]
if etablissement.entreprise_effectif_mensuel.present?
format_in_2_columns(pdf, "Effectif mensuel #{try_format_mois_effectif(etablissement)} de l'établissement (URSSAF ou MSA) ", number_with_delimiter(etablissement.entreprise_effectif_mensuel.to_s))
end
@ -349,22 +349,28 @@ prawn_document(page_size: "A4") do |pdf|
add_title(pdf, 'Formulaire')
add_champs(pdf, @dossier.champs_public)
if @include_infos_administration && @dossier.champs_private.present?
if @acls[:include_infos_administration] && @dossier.champs_private.present?
add_title(pdf, "Annotations privées")
add_champs(pdf, @dossier.champs_private)
end
if @include_infos_administration && @dossier.avis.present?
if @acls[:include_infos_administration] && @dossier.avis.present?
add_title(pdf, "Avis")
@dossier.avis.each do |avis|
add_avis(pdf, avis)
end
end
if @include_avis_for_expert && @dossier.avis.present?
if @acls[:include_avis_for_expert] && @dossier.avis.present?
add_title(pdf, "Avis")
@dossier.avis_for_expert(@include_avis_for_expert).each do |avis|
add_avis(pdf, avis)
if @acls[:only_for_expert]
@dossier.avis_for_expert(@acls[:only_for_expert]).each do |avis|
add_avis(pdf, avis)
end
else
@dossier.avis.each do |avis|
add_avis(pdf, avis)
end
end
end

View file

@ -4,8 +4,8 @@ namespace :benchmarks do
p_45964 = Procedure.find(45964)
p_55824 = Procedure.find(55824)
Benchmark.bm do |x|
x.report("Démarche 45964") { ProcedureExportService.new(p_45964, p_45964.dossiers).to_xlsx }
x.report("Démarche 55824") { ProcedureExportService.new(p_55824, p_55824.dossiers).to_xlsx }
x.report("Démarche 45964") { ProcedureExportService.new(p_45964, p_45964.dossiers, p_45964.administrateurs.first).to_xlsx }
x.report("Démarche 55824") { ProcedureExportService.new(p_55824, p_55824.dossiers, p_55824.administrateurs.first).to_xlsx }
end
end
@ -25,8 +25,8 @@ namespace :benchmarks do
p_45964 = Procedure.find(45964)
p_55824 = Procedure.find(55824)
Benchmark.bm do |x|
x.report("Démarche 45964") { PiecesJustificativesService.generate_dossier_export(p_45964.dossiers) }
x.report("Démarche 55824") { PiecesJustificativesService.generate_dossier_export(p_55824.dossiers.limit(10_000)) }
x.report("Démarche 45964") { PiecesJustificativesService.new(user_profile: p_45964.administrateurs.first).generate_dossiers_export(p_45964.dossiers) }
x.report("Démarche 55824") { PiecesJustificativesService.new(user_profile: p_55824.administrateurs.first).generate_dossiers_export(p_55824.dossiers.limit(10_000)) }
end
end

View file

@ -116,17 +116,15 @@ describe Experts::AvisController, type: :controller do
describe '#telecharger_pjs' do
let(:avis) { avis_with_answer }
subject { get :telecharger_pjs, params: { id: avis.id, procedure_id: } }
before do
allow(PiecesJustificativesService).to receive(:generate_dossier_export).and_return([]).with([dossier], include_infos_administration: false, include_avis_for_expert: expert)
end
context 'with a valid avis' do
it do
service = instance_double(PiecesJustificativesService)
expect(PiecesJustificativesService).to receive(:new).with(user_profile: expert).and_return(service)
expect(service).to receive(:generate_dossiers_export).with(Dossier.where(id: dossier)).and_return([])
expect(service).to receive(:liste_documents).with(Dossier.where(id: dossier)).and_return([])
is_expected.to have_http_status(:success)
expect(PiecesJustificativesService).to have_received(:generate_dossier_export)
end
end

View file

@ -910,7 +910,7 @@ describe Instructeurs::DossiersController, type: :controller do
subject
end
it { expect(assigns(:include_infos_administration)).to eq(true) }
it { expect(assigns(:acls)).to eq(PiecesJustificativesService.new(user_profile: instructeur).acl_for_dossier_export) }
it { expect(assigns(:is_dossier_in_batch_operation)).to eq(false) }
it { expect(response).to render_template 'dossiers/show' }
@ -1053,7 +1053,7 @@ describe Instructeurs::DossiersController, type: :controller do
end
before do
allow(PiecesJustificativesService).to receive(:generate_dossier_export).with([dossier], include_infos_administration: true, include_avis_for_expert: false).and_call_original
allow_any_instance_of(PiecesJustificativesService).to receive(:generate_dossiers_export).with([dossier]).and_call_original
end
it 'includes an attachment' do

View file

@ -1114,8 +1114,8 @@ describe Users::DossiersController, type: :controller do
end
context 'when the dossier has been submitted' do
it { expect(assigns(:include_infos_administration)).to eq(false) }
it { expect(response).to render_template 'dossiers/show' }
it { expect(assigns(:acls)).to eq(PiecesJustificativesService.new(user_profile: user).acl_for_dossier_export) }
it { expect(response).to render_template('dossiers/show') }
end
end
end

View file

@ -1,6 +1,6 @@
describe ExportJob do
let(:procedure) { create(:procedure, instructeurs: [instructeur]) }
let(:instructeur) { create(:instructeur) }
let(:procedure) { create(:procedure, instructeurs: [user_profile]) }
let(:user_profile) { create(:instructeur) }
let(:time_span_type) { :everything }
let(:status) { :tous }
let(:key) { '123' }
@ -8,7 +8,7 @@ describe ExportJob do
create(:export, format:,
time_span_type:,
key:,
instructeur:,
user_profile:,
groupe_instructeurs: procedure.groupe_instructeurs)
end

View file

@ -1,7 +1,8 @@
describe ActiveStorage::DownloadableFile do
let(:dossier) { create(:dossier, :en_construction) }
subject(:list) { ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: dossier.id), with_bills: true, with_champs_private: true) }
let(:user_profile) { create(:administrateur) }
let(:dossiers) { Dossier.where(id: dossier.id) }
subject(:list) { ActiveStorage::DownloadableFile.create_list_from_dossiers(user_profile:, dossiers:) }
describe 'create_list_from_dossiers' do
context 'when no piece_justificative is present' do

View file

@ -1,54 +1,129 @@
describe PiecesJustificativesService do
describe '.liste_documents' do
let(:with_champs_private) { true }
let(:with_bills) { true }
let(:with_avis_piece_justificative) { true }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:dossiers) { Dossier.where(id: dossier.id) }
subject do
PiecesJustificativesService
.liste_documents(Dossier.where(id: dossier.id), with_bills:, with_champs_private:, with_avis_piece_justificative:)
.map(&:first)
PiecesJustificativesService.new(user_profile:).liste_documents(dossiers).map(&:first)
end
context 'with a pj champ' do
context 'no acl' do
let(:user_profile) { build(:administrateur) }
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:witness) { create(:dossier, procedure: procedure) }
let(:pj_champ) { -> (d) { d.champs_public.find { |c| c.type == 'Champs::PieceJustificativeChamp' } } }
before do
attach_file_to_champ(pj_champ.call(dossier))
attach_file_to_champ(pj_champ.call(witness))
end
context 'with a single attachment' do
before do
attach_file_to_champ(pj_champ.call(dossier))
attach_file_to_champ(pj_champ.call(witness))
end
it { expect(subject).to match_array(pj_champ.call(dossier).piece_justificative_file.attachments) }
end
context 'with a multiple attachments' do
before do
attach_file_to_champ(pj_champ.call(dossier))
attach_file_to_champ(pj_champ.call(witness))
attach_file_to_champ(pj_champ.call(dossier))
end
it { expect(subject.count).to eq(2) }
it { expect(subject).to match_array(pj_champ.call(dossier).piece_justificative_file.attachments) }
end
context 'with a pj not safe on a champ' do
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:pj_champ) { -> (d) { d.champs_public.find { |c| c.type == 'Champs::PieceJustificativeChamp' } } }
before { attach_file_to_champ(pj_champ.call(dossier), safe = false) }
it { expect(subject).to be_empty }
end
context 'with a identite champ pj' do
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :titre_identite }]) }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:witness) { create(:dossier, procedure: procedure) }
let(:champ_identite) { dossier.champs_public.find { |c| c.type == 'Champs::TitreIdentiteChamp' } }
before { attach_file_to_champ(champ_identite) }
it "doesn't return sensitive documents like titre_identite" do
expect(champ_identite.piece_justificative_file).to be_attached
expect(subject).to be_empty
end
end
context 'with a pj on an commentaire' do
let(:dossier) { create(:dossier) }
let(:witness) { create(:dossier) }
let!(:commentaire) { create(:commentaire, dossier: dossier) }
let!(:witness_commentaire) { create(:commentaire, dossier: witness) }
before do
attach_file(commentaire.piece_jointe)
attach_file(witness_commentaire.piece_jointe)
end
it { expect(subject).to match_array(dossier.commentaires.first.piece_jointe.attachment) }
end
context 'with a pj not safe on a commentaire' do
let(:dossier) { create(:dossier) }
let!(:commentaire) { create(:commentaire, dossier: dossier) }
before { attach_file(commentaire.piece_jointe, safe = false) }
it { expect(subject).to be_empty }
end
context 'with a motivation' do
let(:dossier) { create(:dossier, :with_justificatif) }
let!(:witness) { create(:dossier, :with_justificatif) }
it { expect(subject).to match_array(dossier.justificatif_motivation.attachment) }
end
context 'with a motivation not safe' do
let(:dossier) { create(:dossier) }
before { attach_file(dossier.justificatif_motivation, safe = false) }
it { expect(subject).to be_empty }
end
context 'with an attestation' do
let(:dossier) { create(:dossier, :with_attestation) }
let!(:witness) { create(:dossier, :with_attestation) }
it { expect(subject).to match_array(dossier.attestation.pdf.attachment) }
end
context 'with an etablissement' do
let(:dossier) { create(:dossier, :with_entreprise) }
let(:attestation_sociale) { dossier.etablissement.entreprise_attestation_sociale }
let(:attestation_fiscale) { dossier.etablissement.entreprise_attestation_fiscale }
let!(:witness) { create(:dossier, :with_entreprise) }
let!(:witness_attestation_sociale) { witness.etablissement.entreprise_attestation_sociale }
let!(:witness_attestation_fiscale) { witness.etablissement.entreprise_attestation_fiscale }
before do
attach_file(attestation_sociale)
attach_file(attestation_fiscale)
end
it { expect(subject).to match_array([attestation_sociale.attachment, attestation_fiscale.attachment]) }
end
end
context 'with a pj not safe on a champ' do
context 'acl on private pj champ' do
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:pj_champ) { -> (d) { d.champs_public.find { |c| c.type == 'Champs::PieceJustificativeChamp' } } }
before { attach_file_to_champ(pj_champ.call(dossier), safe = false) }
it { expect(subject).to be_empty }
end
context 'with a private pj champ' do
let(:procedure) { create(:procedure) }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:witness) { create(:dossier, procedure: procedure) }
let!(:private_pj) { create(:type_de_champ_piece_justificative, procedure: procedure, private: true) }
@ -59,138 +134,23 @@ describe PiecesJustificativesService do
attach_file_to_champ(private_pj_champ.call(witness))
end
it { expect(subject).to match_array(private_pj_champ.call(dossier).piece_justificative_file.attachments) }
context 'given an administrateur' do
let(:user_profile) { build(:administrateur) }
it { expect(subject).to match_array(private_pj_champ.call(dossier).piece_justificative_file.attachments) }
end
context 'without private champ' do
let(:with_champs_private) { false }
context 'given an instructeur' do
let(:user_profile) { create(:instructeur) }
it { expect(subject).to match_array(private_pj_champ.call(dossier).piece_justificative_file.attachments) }
end
it { expect(subject).to be_empty }
context 'given an expert' do
let(:user_profile) { create(:expert) }
it { expect(subject).not_to match_array(private_pj_champ.call(dossier).piece_justificative_file.attachments) }
end
end
context 'with avis.piece_justificative being confidentiel' do
let(:procedure) { create(:procedure) }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:avis) { create(:avis, dossier: dossier, confidentiel: true) }
let(:with_avis_piece_justificative) { false }
before do
to_be_attached = {
io: StringIO.new("toto"),
filename: "toto.png",
content_type: "image/png",
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
}
avis.piece_justificative_file.attach(to_be_attached)
end
it "doesn't return confidentiel avis.piece_justificative_file" do
expect(subject).to be_empty
end
end
context 'with avis.piece_justificative being public' do
let(:procedure) { create(:procedure) }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:avis) { create(:avis, dossier: dossier) }
let(:with_avis_piece_justificative) { false }
before do
to_be_attached = {
io: StringIO.new("toto"),
filename: "toto.png",
content_type: "image/png",
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
}
avis.piece_justificative_file.attach(to_be_attached)
end
it "return avis.piece_justificative_file not confidentiel" do
expect(subject).not_to be_empty
end
end
context 'with a identite champ pj' do
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :titre_identite }]) }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:witness) { create(:dossier, procedure: procedure) }
let(:champ_identite) { dossier.champs_public.find { |c| c.type == 'Champs::TitreIdentiteChamp' } }
before { attach_file_to_champ(champ_identite) }
it "doesn't return sensitive documents like titre_identite" do
expect(champ_identite.piece_justificative_file).to be_attached
expect(subject).to be_empty
end
end
context 'with a pj on an commentaire' do
let(:dossier) { create(:dossier) }
let(:witness) { create(:dossier) }
let!(:commentaire) { create(:commentaire, dossier: dossier) }
let!(:witness_commentaire) { create(:commentaire, dossier: witness) }
before do
attach_file(commentaire.piece_jointe)
attach_file(witness_commentaire.piece_jointe)
end
it { expect(subject).to match_array(dossier.commentaires.first.piece_jointe.attachment) }
end
context 'with a pj not safe on a commentaire' do
let(:dossier) { create(:dossier) }
let!(:commentaire) { create(:commentaire, dossier: dossier) }
before { attach_file(commentaire.piece_jointe, safe = false) }
it { expect(subject).to be_empty }
end
context 'with a motivation' do
let(:dossier) { create(:dossier, :with_justificatif) }
let!(:witness) { create(:dossier, :with_justificatif) }
it { expect(subject).to match_array(dossier.justificatif_motivation.attachment) }
end
context 'with a motivation not safe' do
let(:dossier) { create(:dossier) }
before { attach_file(dossier.justificatif_motivation, safe = false) }
it { expect(subject).to be_empty }
end
context 'with an attestation' do
let(:dossier) { create(:dossier, :with_attestation) }
let!(:witness) { create(:dossier, :with_attestation) }
it { expect(subject).to match_array(dossier.attestation.pdf.attachment) }
end
context 'with an etablissement' do
let(:dossier) { create(:dossier, :with_entreprise) }
let(:attestation_sociale) { dossier.etablissement.entreprise_attestation_sociale }
let(:attestation_fiscale) { dossier.etablissement.entreprise_attestation_fiscale }
let!(:witness) { create(:dossier, :with_entreprise) }
let!(:witness_attestation_sociale) { witness.etablissement.entreprise_attestation_sociale }
let!(:witness_attestation_fiscale) { witness.etablissement.entreprise_attestation_fiscale }
before do
attach_file(attestation_sociale)
attach_file(attestation_fiscale)
end
it { expect(subject).to match_array([attestation_sociale.attachment, attestation_fiscale.attachment]) }
end
context 'with a bill' do
context 'acl on bill' do
let(:dossier) { create(:dossier) }
let(:witness) { create(:dossier) }
@ -213,58 +173,140 @@ describe PiecesJustificativesService do
let(:dossier_bs) { dossier.dossier_operation_logs.first.bill_signature }
it "returns serialized bill and signature" do
expect(subject).to match_array([dossier_bs.serialized.attachment, dossier_bs.signature.attachment])
context 'given an Administrateur, includes bills' do
let(:user_profile) { build(:administrateur) }
it "returns serialized bill and signature" do
expect(subject).to match_array([dossier_bs.serialized.attachment, dossier_bs.signature.attachment])
end
context 'with a dol' do
let(:dol) { create(:dossier_operation_log, dossier: dossier) }
let(:witness_dol) { create(:dossier_operation_log, dossier: witness) }
before do
attach_file(dol.serialized)
attach_file(witness_dol.serialized)
end
it { expect(subject).to include(dol.serialized.attachment) }
end
end
context 'without bills' do
let(:with_bills) { false }
context 'given an expert, does not includes bills' do
let(:user_profile) { create(:expert) }
it { expect(subject).to be_empty }
end
context 'given an instructeur, does not includes bills' do
let(:user_profile) { create(:instructeur) }
it { expect(subject).to be_empty }
end
end
context 'with a dol' do
let(:dossier) { create(:dossier) }
let(:witness) { create(:dossier) }
context 'acl on with_avis_piece_justificative' do
let(:user_profile) { create(:expert) }
let(:procedure) { create(:procedure) }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:dol) { create(:dossier_operation_log, dossier: dossier) }
let(:witness_dol) { create(:dossier_operation_log, dossier: witness) }
context 'with avis.piece_justificative being confidentiel' do
let(:procedure) { create(:procedure) }
let(:avis) { create(:avis, dossier: dossier, confidentiel: true) }
before do
attach_file(dol.serialized)
attach_file(witness_dol.serialized)
before do
to_be_attached = {
io: StringIO.new("toto"),
filename: "toto.png",
content_type: "image/png",
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
}
avis.piece_justificative_file.attach(to_be_attached)
end
context 'given an administrateur' do
let(:user_profile) { build(:administrateur) }
it "doesn't return confidentiel avis.piece_justificative_file" do
expect(subject).not_to be_empty
end
end
context 'given an instructeur' do
let(:user_profile) { create(:instructeur) }
it "doesn't return confidentiel avis.piece_justificative_file" do
expect(subject).not_to be_empty
end
end
context 'given an expert' do
let(:user_profile) { create(:expert) }
it "doesn't return confidentiel avis.piece_justificative_file" do
expect(subject).to be_empty
end
end
end
it { expect(subject).to match_array(dol.serialized.attachment) }
context 'with avis.piece_justificative being public' do
let(:procedure) { create(:procedure) }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:avis) { create(:avis, dossier: dossier) }
before do
to_be_attached = {
io: StringIO.new("toto"),
filename: "toto.png",
content_type: "image/png",
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
}
context 'without bills' do
let(:with_bills) { false }
avis.piece_justificative_file.attach(to_be_attached)
end
it { expect(subject).to be_empty }
context 'given an administrateur' do
let(:user_profile) { build(:administrateur) }
it "doesn't return confidentiel avis.piece_justificative_file" do
expect(subject).not_to be_empty
end
end
context 'given an instructeur' do
let(:user_profile) { create(:instructeur) }
it "doesn't return confidentiel avis.piece_justificative_file" do
expect(subject).not_to be_empty
end
end
context 'given an expert' do
let(:user_profile) { create(:expert) }
it "doesn't return confidentiel avis.piece_justificative_file" do
expect(subject).not_to be_empty
end
end
end
end
end
describe '.generate_dossier_export' do
describe '.generate_dossiers_export' do
let(:user_profile) { build(:administrateur) }
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :repetition, children: [{ type: :piece_justificative }] }]) }
let(:dossier) { create(:dossier, :with_populated_champs, procedure: procedure) }
subject { PiecesJustificativesService.generate_dossier_export(Dossier.where(id: dossier.id)) }
let(:dossiers) { Dossier.where(id: dossier.id) }
subject { PiecesJustificativesService.new(user_profile:).generate_dossiers_export(dossiers) }
it "doesn't update dossier" do
expect { subject }.not_to change { dossier.updated_at }
end
context 'when given an expert' do
let!(:expert) { create(:expert) }
let!(:user_profile) { create(:expert) }
let!(:confidentiel_avis) { create(:avis, :confidentiel, dossier: dossier) }
let!(:not_confidentiel_avis) { create(:avis, :not_confidentiel, dossier: dossier) }
let!(:expert_avis) { create(:avis, :confidentiel, dossier: dossier, expert: expert) }
let!(:expert_avis) { create(:avis, :confidentiel, dossier: dossier, expert: user_profile) }
subject { PiecesJustificativesService.generate_dossier_export(Dossier.where(id: dossier.id), include_avis_for_expert: expert) }
subject { PiecesJustificativesService.new(user_profile:).generate_dossiers_export(dossiers) }
it "includes avis not confidentiel as well as expert's avis" do
expect_any_instance_of(Dossier).to receive(:avis_for_expert).with(expert).and_return([])
expect_any_instance_of(Dossier).to receive(:avis_for_expert).with(user_profile).and_return([])
subject
end
end

View file

@ -1,6 +1,7 @@
describe ProcedureArchiveService do
let(:procedure) { create(:procedure, :published) }
let(:procedure) { create(:procedure, :published, administrateurs: [administrateur]) }
let(:instructeur) { create(:instructeur) }
let(:administrateur) { create(:administrateur) }
let(:service) { ProcedureArchiveService.new(procedure) }
let(:year) { 2020 }
let(:month) { 3 }
@ -18,7 +19,7 @@ describe ProcedureArchiveService do
after { Timecop.return }
context 'for a specific month' do
let(:archive) { create(:archive, time_span_type: 'monthly', job_status: 'pending', month: date_month, groupe_instructeurs: groupe_instructeurs) }
let(:archive) { create(:archive, user_profile: administrateur, time_span_type: 'monthly', job_status: 'pending', month: date_month, groupe_instructeurs: groupe_instructeurs) }
let(:year) { 2021 }
it 'collects files with success' do
@ -86,7 +87,7 @@ describe ProcedureArchiveService do
let(:documents) { [pj, bad_pj].map { |p| ActiveStorage::DownloadableFile.pj_and_path(dossier.id, p) } }
before do
allow(PiecesJustificativesService).to receive(:liste_documents).and_return(documents)
allow_any_instance_of(PiecesJustificativesService).to receive(:liste_documents).and_return(documents)
end
it 'collect files without raising exception' do
@ -120,7 +121,7 @@ describe ProcedureArchiveService do
end
context 'for all months' do
let(:archive) { create(:archive, time_span_type: 'everything', job_status: 'pending', groupe_instructeurs: groupe_instructeurs) }
let(:archive) { create(:archive, user_profile: administrateur, time_span_type: 'everything', job_status: 'pending', groupe_instructeurs: groupe_instructeurs) }
it 'collect files' do
allow_any_instance_of(ActiveStorage::Attachment).to receive(:url).and_return("https://opengraph.githubassets.com/5e61989aecb78e369c93674f877d7bf4ecde378850114a9563cdf8b6a2472536/typhoeus/typhoeus/issues/110")

View file

@ -510,16 +510,16 @@ describe ProcedureExportService do
end
end
context 'generate_dossier_export' do
context 'generate_dossiers_export' do
it 'include_infos_administration (so it includes avis, champs privés)' do
expect(ActiveStorage::DownloadableFile).to receive(:create_list_from_dossiers).with(anything, with_champs_private: true, include_infos_administration: true).and_return([])
expect(ActiveStorage::DownloadableFile).to receive(:create_list_from_dossiers).with(dossiers: anything, user_profile: instructeur).and_return([])
subject
end
end
context 'with files (and http calls)' do
let!(:dossier) { create(:dossier, :accepte, :with_populated_champs, :with_individual, procedure: procedure) }
let(:dossier_exports) { PiecesJustificativesService.generate_dossier_export(Dossier.where(id: dossier)) }
let(:dossier_exports) { PiecesJustificativesService.new(user_profile: instructeur).generate_dossiers_export(Dossier.where(id: dossier)) }
before do
allow_any_instance_of(ActiveStorage::Attachment).to receive(:url).and_return("https://opengraph.githubassets.com/d0e7862b24d8026a3c03516d865b28151eb3859029c6c6c2e86605891fbdcd7a/socketry/async-io")
end