2024-04-29 00:17:15 +02:00
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
2019-08-06 11:02:54 +02:00
|
|
|
|
describe Instructeurs::ProceduresController, type: :controller do
|
2017-07-04 10:26:50 +02:00
|
|
|
|
describe "before_action: ensure_ownership!" do
|
|
|
|
|
it "is present" do
|
2019-08-06 11:02:54 +02:00
|
|
|
|
before_actions = Instructeurs::ProceduresController
|
2017-06-29 15:30:42 +02:00
|
|
|
|
._process_action_callbacks
|
2019-09-12 11:26:22 +02:00
|
|
|
|
.filter { |process_action_callbacks| process_action_callbacks.kind == :before }
|
2017-06-29 15:30:42 +02:00
|
|
|
|
.map(&:filter)
|
|
|
|
|
|
|
|
|
|
expect(before_actions).to include(:ensure_ownership!)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2017-07-04 10:26:50 +02:00
|
|
|
|
describe "ensure_ownership!" do
|
2019-08-06 11:02:54 +02:00
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
2017-06-29 15:30:42 +02:00
|
|
|
|
|
|
|
|
|
before do
|
2018-01-23 18:28:09 +01:00
|
|
|
|
@controller.params = @controller.params.merge(procedure_id: asked_procedure.id)
|
2019-08-06 11:02:54 +02:00
|
|
|
|
expect(@controller).to receive(:current_instructeur).and_return(instructeur)
|
2017-06-29 15:30:42 +02:00
|
|
|
|
allow(@controller).to receive(:redirect_to)
|
|
|
|
|
|
|
|
|
|
@controller.send(:ensure_ownership!)
|
|
|
|
|
end
|
|
|
|
|
|
2019-08-06 11:02:54 +02:00
|
|
|
|
context "when a instructeur asks for its procedure" do
|
|
|
|
|
let(:asked_procedure) { create(:procedure, instructeurs: [instructeur]) }
|
2017-06-29 15:30:42 +02:00
|
|
|
|
|
2017-07-04 10:26:50 +02:00
|
|
|
|
it "does not redirects nor flash" do
|
2017-06-29 15:30:42 +02:00
|
|
|
|
expect(@controller).not_to have_received(:redirect_to)
|
|
|
|
|
expect(flash.alert).to eq(nil)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-08-06 11:02:54 +02:00
|
|
|
|
context "when a instructeur asks for another procedure" do
|
2017-06-29 15:30:42 +02:00
|
|
|
|
let(:asked_procedure) { create(:procedure) }
|
|
|
|
|
|
2017-07-04 10:26:50 +02:00
|
|
|
|
it "redirects and flash" do
|
2017-06-29 15:30:42 +02:00
|
|
|
|
expect(@controller).to have_received(:redirect_to).with(root_path)
|
2020-01-29 12:16:38 +01:00
|
|
|
|
expect(flash.alert).to eq("Vous n’avez pas accès à cette démarche")
|
2017-06-29 15:30:42 +02:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2017-07-04 13:52:08 +02:00
|
|
|
|
|
|
|
|
|
describe "#index" do
|
2019-08-06 11:02:54 +02:00
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
2017-07-04 13:52:08 +02:00
|
|
|
|
subject { get :index }
|
|
|
|
|
|
|
|
|
|
context "when not logged" do
|
|
|
|
|
before { subject }
|
2018-01-15 21:54:40 +01:00
|
|
|
|
it { expect(response).to redirect_to(new_user_session_path) }
|
2017-07-04 13:52:08 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "when logged in" do
|
2019-08-07 11:15:16 +02:00
|
|
|
|
before { sign_in(instructeur.user) }
|
2017-07-04 13:52:08 +02:00
|
|
|
|
|
|
|
|
|
it { expect(response).to have_http_status(:ok) }
|
|
|
|
|
|
|
|
|
|
context "with procedures assigned" do
|
2020-04-22 15:12:34 +02:00
|
|
|
|
let(:procedure_draft) { create(:procedure) }
|
|
|
|
|
let(:procedure_published) { create(:procedure, :published) }
|
|
|
|
|
let(:procedure_closed) { create(:procedure, :closed) }
|
2020-04-22 15:16:21 +02:00
|
|
|
|
let(:procedure_draft_discarded) { create(:procedure, :discarded) }
|
|
|
|
|
let(:procedure_closed_discarded) { create(:procedure, :discarded) }
|
2020-04-22 15:12:34 +02:00
|
|
|
|
let(:procedure_not_assigned) { create(:procedure) }
|
2017-07-04 13:52:08 +02:00
|
|
|
|
|
|
|
|
|
before do
|
2020-04-22 15:16:21 +02:00
|
|
|
|
[procedure_draft, procedure_published, procedure_closed, procedure_draft_discarded, procedure_closed_discarded].each do |p|
|
2020-04-22 15:12:34 +02:00
|
|
|
|
instructeur.groupe_instructeurs << p.defaut_groupe_instructeur
|
|
|
|
|
end
|
2017-07-04 13:52:08 +02:00
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
2020-04-22 15:12:34 +02:00
|
|
|
|
it 'assigns procedures visible to the instructeur' do
|
|
|
|
|
expect(assigns(:procedures)).to include(procedure_draft, procedure_published, procedure_closed)
|
2020-04-22 15:16:21 +02:00
|
|
|
|
expect(assigns(:procedures)).not_to include(procedure_draft_discarded, procedure_closed_discarded, procedure_not_assigned)
|
2020-04-22 15:12:34 +02:00
|
|
|
|
end
|
2017-07-04 13:52:08 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with dossiers" do
|
2022-03-09 10:29:16 +01:00
|
|
|
|
let(:procedure) { create(:procedure, :published, :expirable) }
|
2017-07-04 13:52:08 +02:00
|
|
|
|
let(:dossier) { create(:dossier, state: state, procedure: procedure) }
|
|
|
|
|
|
|
|
|
|
before do
|
2019-08-20 18:03:33 +02:00
|
|
|
|
instructeur.groupe_instructeurs << procedure.defaut_groupe_instructeur
|
2017-07-04 13:52:08 +02:00
|
|
|
|
dossier
|
|
|
|
|
end
|
|
|
|
|
|
2017-12-04 16:17:15 +01:00
|
|
|
|
context "with brouillon state" do
|
2018-08-28 14:10:55 +02:00
|
|
|
|
let(:state) { Dossier.states.fetch(:brouillon) }
|
2017-07-04 13:52:08 +02:00
|
|
|
|
before { subject }
|
|
|
|
|
|
2019-09-12 17:26:59 +02:00
|
|
|
|
it { expect(assigns(:dossiers_count_per_procedure)[procedure.id]).to eq(nil) }
|
|
|
|
|
it { expect(assigns(:dossiers_a_suivre_count_per_procedure)[procedure.id]).to eq(nil) }
|
|
|
|
|
it { expect(assigns(:dossiers_archived_count_per_procedure)[procedure.id]).to eq(nil) }
|
|
|
|
|
it { expect(assigns(:followed_dossiers_count_per_procedure)[procedure.id]).to eq(nil) }
|
|
|
|
|
it { expect(assigns(:dossiers_termines_count_per_procedure)[procedure.id]).to eq(nil) }
|
2022-03-09 10:29:16 +01:00
|
|
|
|
it { expect(assigns(:dossiers_expirant_count_per_procedure)[procedure.id]).to eq(nil) }
|
2020-06-25 15:19:54 +02:00
|
|
|
|
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['à suivre']).to eq(0) }
|
2020-06-26 15:22:40 +02:00
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['suivis']).to eq(0) }
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['traités']).to eq(0) }
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['dossiers']).to eq(0) }
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['archivés']).to eq(0) }
|
2022-03-09 10:29:16 +01:00
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['expirant']).to eq(0) }
|
2017-07-04 13:52:08 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with not draft state on multiple procedures" do
|
2022-03-09 10:29:16 +01:00
|
|
|
|
let(:procedure2) { create(:procedure, :published, :expirable) }
|
2023-09-25 15:34:37 +02:00
|
|
|
|
let(:procedure3) { create(:procedure, :closed, :expirable) }
|
|
|
|
|
let(:procedure4) { create(:procedure, :closed, :expirable) }
|
2018-08-28 14:10:55 +02:00
|
|
|
|
let(:state) { Dossier.states.fetch(:en_construction) }
|
2017-07-04 13:52:08 +02:00
|
|
|
|
|
|
|
|
|
before do
|
2018-08-28 14:10:55 +02:00
|
|
|
|
create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction))
|
2022-01-24 15:32:47 +01:00
|
|
|
|
create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction), hidden_by_user_at: 1.hour.ago)
|
2018-08-28 14:10:55 +02:00
|
|
|
|
create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction))
|
2022-03-09 10:29:16 +01:00
|
|
|
|
|
2018-08-28 14:10:55 +02:00
|
|
|
|
create(:dossier, procedure: procedure, state: Dossier.states.fetch(:sans_suite), archived: true)
|
2022-03-09 10:29:16 +01:00
|
|
|
|
create(:dossier, procedure: procedure, state: Dossier.states.fetch(:sans_suite), archived: true,
|
|
|
|
|
hidden_by_administration_at: 1.day.ago)
|
2017-07-17 11:22:12 +02:00
|
|
|
|
|
2019-08-20 18:03:33 +02:00
|
|
|
|
instructeur.groupe_instructeurs << procedure2.defaut_groupe_instructeur
|
2018-08-28 14:10:55 +02:00
|
|
|
|
create(:dossier, :followed, procedure: procedure2, state: Dossier.states.fetch(:en_construction))
|
|
|
|
|
create(:dossier, procedure: procedure2, state: Dossier.states.fetch(:accepte))
|
2019-08-06 11:02:54 +02:00
|
|
|
|
instructeur.followed_dossiers << create(:dossier, procedure: procedure2, state: Dossier.states.fetch(:en_instruction))
|
2017-07-17 11:22:12 +02:00
|
|
|
|
|
2022-03-09 10:29:16 +01:00
|
|
|
|
create(:dossier, procedure: procedure,
|
|
|
|
|
state: Dossier.states.fetch(:sans_suite),
|
|
|
|
|
processed_at: 8.months.ago) # counted as expirable
|
|
|
|
|
create(:dossier, procedure: procedure,
|
|
|
|
|
state: Dossier.states.fetch(:sans_suite),
|
|
|
|
|
processed_at: 8.months.ago,
|
|
|
|
|
hidden_by_administration_at: 1.day.ago) # not counted as expirable since its removed by instructeur
|
|
|
|
|
create(:dossier, procedure: procedure,
|
|
|
|
|
state: Dossier.states.fetch(:sans_suite),
|
|
|
|
|
processed_at: 8.months.ago,
|
|
|
|
|
hidden_by_user_at: 1.day.ago) # counted as expirable because even if user remove it, instructeur see it
|
2023-09-25 15:34:37 +02:00
|
|
|
|
|
|
|
|
|
instructeur.groupe_instructeurs << procedure3.defaut_groupe_instructeur
|
|
|
|
|
create(:dossier, :followed, procedure: procedure3, state: Dossier.states.fetch(:en_construction))
|
|
|
|
|
create(:dossier, procedure: procedure3, state: Dossier.states.fetch(:sans_suite))
|
|
|
|
|
|
|
|
|
|
instructeur.groupe_instructeurs << procedure4.defaut_groupe_instructeur
|
|
|
|
|
create(:dossier, procedure: procedure4, state: Dossier.states.fetch(:sans_suite))
|
2017-07-04 13:52:08 +02:00
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
2022-03-09 10:29:16 +01:00
|
|
|
|
it { expect(assigns(:dossiers_count_per_procedure)[procedure.id]).to eq(5) }
|
2019-09-12 17:26:59 +02:00
|
|
|
|
it { expect(assigns(:dossiers_a_suivre_count_per_procedure)[procedure.id]).to eq(3) }
|
|
|
|
|
it { expect(assigns(:followed_dossiers_count_per_procedure)[procedure.id]).to eq(nil) }
|
|
|
|
|
it { expect(assigns(:dossiers_archived_count_per_procedure)[procedure.id]).to eq(1) }
|
2022-03-09 10:29:16 +01:00
|
|
|
|
it { expect(assigns(:dossiers_termines_count_per_procedure)[procedure.id]).to eq(2) }
|
|
|
|
|
it { expect(assigns(:dossiers_expirant_count_per_procedure)[procedure.id]).to eq(2) }
|
2019-09-12 17:26:59 +02:00
|
|
|
|
|
|
|
|
|
it { expect(assigns(:dossiers_count_per_procedure)[procedure2.id]).to eq(3) }
|
|
|
|
|
it { expect(assigns(:dossiers_a_suivre_count_per_procedure)[procedure2.id]).to eq(nil) }
|
|
|
|
|
it { expect(assigns(:followed_dossiers_count_per_procedure)[procedure2.id]).to eq(1) }
|
|
|
|
|
it { expect(assigns(:dossiers_archived_count_per_procedure)[procedure2.id]).to eq(nil) }
|
|
|
|
|
it { expect(assigns(:dossiers_termines_count_per_procedure)[procedure2.id]).to eq(1) }
|
2020-06-25 15:19:54 +02:00
|
|
|
|
|
2023-09-25 15:34:37 +02:00
|
|
|
|
it { expect(assigns(:dossiers_count_per_procedure)[procedure3.id]).to eq(2) }
|
|
|
|
|
|
2020-06-25 15:19:54 +02:00
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['à suivre']).to eq(3 + 0) }
|
2020-06-26 15:22:40 +02:00
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['suivis']).to eq(0 + 1) }
|
2023-09-25 15:34:37 +02:00
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['traités']).to eq(2 + 1 + 1 + 1) }
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['dossiers']).to eq(5 + 3 + 2 + 1) }
|
2020-06-26 15:22:40 +02:00
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['archivés']).to eq(1 + 0) }
|
2022-03-09 10:29:16 +01:00
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['expirant']).to eq(2 + 0) }
|
2023-09-25 15:34:37 +02:00
|
|
|
|
|
2023-09-28 11:19:06 +02:00
|
|
|
|
it { expect(assigns(:procedures_en_cours)).to match_array([procedure2, procedure, procedure3]) }
|
2023-09-25 15:34:37 +02:00
|
|
|
|
it { expect(assigns(:procedures_en_cours_count)).to eq(3) }
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:procedures_closes)).to eq([procedure4]) }
|
|
|
|
|
it { expect(assigns(:procedures_closes_count)).to eq(1) }
|
2019-09-12 17:26:59 +02:00
|
|
|
|
end
|
2022-04-04 15:29:38 +02:00
|
|
|
|
|
|
|
|
|
context 'with not draft state on discarded procedure' do
|
|
|
|
|
let(:discarded_procedure) { create(:procedure, :discarded, :expirable) }
|
|
|
|
|
let(:state) { Dossier.states.fetch(:en_construction) }
|
|
|
|
|
before do
|
|
|
|
|
create(:dossier, procedure: discarded_procedure, state: Dossier.states.fetch(:en_construction))
|
|
|
|
|
instructeur.groupe_instructeurs << discarded_procedure.defaut_groupe_instructeur
|
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:dossiers_count_per_procedure)[procedure.id]).to eq(1) }
|
|
|
|
|
it { expect(assigns(:dossiers_a_suivre_count_per_procedure)[procedure.id]).to eq(1) }
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:dossiers_count_per_procedure)[discarded_procedure.id]).to be_nil }
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['à suivre']).to eq(1) }
|
|
|
|
|
end
|
2019-09-12 17:26:59 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with a routed procedure" do
|
|
|
|
|
let!(:procedure) { create(:procedure, :published) }
|
|
|
|
|
let!(:gi_p1_1) { procedure.defaut_groupe_instructeur }
|
|
|
|
|
let!(:gi_p1_2) { GroupeInstructeur.create(label: '2', procedure: procedure) }
|
|
|
|
|
|
|
|
|
|
context 'with multiple dossiers en construction on each group' do
|
|
|
|
|
before do
|
|
|
|
|
alternate_gis = 0.upto(20).map { |i| i.even? ? gi_p1_1 : gi_p1_2 }
|
|
|
|
|
|
|
|
|
|
alternate_gis.take(4).each { |gi| create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction), groupe_instructeur: gi) }
|
|
|
|
|
|
|
|
|
|
alternate_gis.take(6).each do |gi|
|
|
|
|
|
instructeur.followed_dossiers << create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction), groupe_instructeur: gi)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
alternate_gis.take(10).each { |gi| create(:dossier, procedure: procedure, state: Dossier.states.fetch(:sans_suite), groupe_instructeur: gi) }
|
|
|
|
|
alternate_gis.take(14).each { |gi| create(:dossier, procedure: procedure, state: Dossier.states.fetch(:sans_suite), archived: true, groupe_instructeur: gi) }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when an instructeur belongs to the 2 gi' do
|
|
|
|
|
before do
|
|
|
|
|
instructeur.groupe_instructeurs << gi_p1_1 << gi_p1_2
|
|
|
|
|
|
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:dossiers_a_suivre_count_per_procedure)[procedure.id]).to eq(4) }
|
|
|
|
|
it { expect(assigns(:followed_dossiers_count_per_procedure)[procedure.id]).to eq(6) }
|
|
|
|
|
it { expect(assigns(:dossiers_termines_count_per_procedure)[procedure.id]).to eq(10) }
|
|
|
|
|
it { expect(assigns(:dossiers_count_per_procedure)[procedure.id]).to eq(4 + 6 + 10) }
|
|
|
|
|
it { expect(assigns(:dossiers_archived_count_per_procedure)[procedure.id]).to eq(14) }
|
2020-06-25 15:19:54 +02:00
|
|
|
|
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['à suivre']).to eq(4) }
|
2020-06-26 15:22:40 +02:00
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['suivis']).to eq(6) }
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['traités']).to eq(10) }
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['dossiers']).to eq(4 + 6 + 10) }
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['archivés']).to eq(14) }
|
2019-09-12 17:26:59 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when an instructeur only belongs to one of them gi' do
|
|
|
|
|
before do
|
|
|
|
|
instructeur.groupe_instructeurs << gi_p1_1
|
|
|
|
|
|
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:dossiers_a_suivre_count_per_procedure)[procedure.id]).to eq(2) }
|
|
|
|
|
# An instructeur cannot follow a dossier which belongs to another groupe
|
|
|
|
|
it { expect(assigns(:followed_dossiers_count_per_procedure)[procedure.id]).to eq(3) }
|
|
|
|
|
it { expect(assigns(:dossiers_termines_count_per_procedure)[procedure.id]).to eq(5) }
|
|
|
|
|
it { expect(assigns(:dossiers_count_per_procedure)[procedure.id]).to eq(2 + 3 + 5) }
|
|
|
|
|
it { expect(assigns(:dossiers_archived_count_per_procedure)[procedure.id]).to eq(7) }
|
2020-06-25 15:19:54 +02:00
|
|
|
|
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['à suivre']).to eq(2) }
|
2020-06-26 15:22:40 +02:00
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['suivis']).to eq(3) }
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['traités']).to eq(5) }
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['dossiers']).to eq(2 + 3 + 5) }
|
|
|
|
|
it { expect(assigns(:all_dossiers_counts)['archivés']).to eq(7) }
|
2019-09-12 17:26:59 +02:00
|
|
|
|
end
|
2017-07-04 13:52:08 +02:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2017-07-11 16:09:03 +02:00
|
|
|
|
|
|
|
|
|
describe "#show" do
|
2019-08-06 11:02:54 +02:00
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
2024-02-15 09:30:38 +01:00
|
|
|
|
let(:procedure) { create(:procedure, :expirable, instructeurs: [instructeur]) }
|
2023-06-29 11:45:20 +02:00
|
|
|
|
let!(:gi_2) { create(:groupe_instructeur, label: '2', procedure: procedure) }
|
|
|
|
|
let!(:gi_3) { create(:groupe_instructeur, label: '3', procedure: procedure) }
|
|
|
|
|
|
2020-04-22 15:52:28 +02:00
|
|
|
|
let(:statut) { nil }
|
|
|
|
|
|
|
|
|
|
subject do
|
|
|
|
|
get :show, params: { procedure_id: procedure.id, statut: statut }
|
|
|
|
|
end
|
2017-07-11 16:09:03 +02:00
|
|
|
|
|
2024-02-15 09:30:38 +01:00
|
|
|
|
describe 'access to groupes_instructeur' do
|
|
|
|
|
render_views
|
|
|
|
|
let(:procedure) { create(:procedure, instructeurs_self_management_enabled:, instructeurs: [instructeur]) }
|
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
sign_in(instructeur.user)
|
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when instructeurs_self_management? is false' do
|
|
|
|
|
let(:instructeurs_self_management_enabled) { false }
|
|
|
|
|
it { expect(response.body).not_to have_link(href: admin_procedure_groupe_instructeurs_path(procedure)) }
|
|
|
|
|
it { expect(response.body).not_to have_link(href: instructeur_groupes_path(procedure)) }
|
|
|
|
|
it { expect(response.body).not_to have_link(href: instructeur_groupe_path(procedure, procedure.defaut_groupe_instructeur)) }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when instructeurs_self_management? is true' do
|
|
|
|
|
let(:instructeurs_self_management_enabled) { true }
|
|
|
|
|
it { expect(response.body).not_to have_link(href: admin_procedure_groupe_instructeurs_path(procedure)) }
|
|
|
|
|
it { expect(response.body).to have_link(href: instructeur_groupes_path(procedure)) }
|
|
|
|
|
it { expect(response.body).not_to have_link(href: instructeur_groupe_path(procedure, procedure.defaut_groupe_instructeur)) }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when instructeurs_self_management? is false but as owner of the procedure' do
|
|
|
|
|
let(:instructeurs_self_management_enabled) { false }
|
|
|
|
|
let(:administrateur) { create(:administrateur, user: instructeur.user) }
|
|
|
|
|
let(:procedure) { create(:procedure, :expirable, instructeurs_self_management_enabled:, administrateurs: [administrateur], instructeurs: [instructeur]) }
|
|
|
|
|
it { expect(response.body).to have_link(href: admin_procedure_groupe_instructeurs_path(procedure)) }
|
|
|
|
|
it { expect(response.body).not_to have_link(href: instructeur_groupes_path(procedure)) }
|
|
|
|
|
it { expect(response.body).not_to have_link(href: instructeur_groupe_path(procedure, procedure.defaut_groupe_instructeur)) }
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-09-18 13:44:00 +02:00
|
|
|
|
context "when logged in, and belonging to gi_1, gi_2" do
|
2017-07-11 16:09:03 +02:00
|
|
|
|
before do
|
2019-08-07 11:15:16 +02:00
|
|
|
|
sign_in(instructeur.user)
|
2019-09-18 13:44:00 +02:00
|
|
|
|
instructeur.groupe_instructeurs << gi_2
|
2017-07-11 16:09:03 +02:00
|
|
|
|
end
|
|
|
|
|
|
2020-04-22 15:53:54 +02:00
|
|
|
|
context 'when the procedure is discarded' do
|
|
|
|
|
before do
|
|
|
|
|
procedure.discard!
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
|
|
|
|
|
end
|
|
|
|
|
|
2020-04-22 15:52:28 +02:00
|
|
|
|
context "without any dossier" do
|
|
|
|
|
before { subject }
|
2017-09-28 19:07:18 +02:00
|
|
|
|
|
|
|
|
|
it { expect(response).to have_http_status(:ok) }
|
|
|
|
|
it { expect(assigns(:procedure)).to eq(procedure) }
|
|
|
|
|
end
|
2017-07-11 16:09:03 +02:00
|
|
|
|
|
|
|
|
|
context 'with a new dossier without follower' do
|
2021-03-09 11:21:30 +01:00
|
|
|
|
let!(:new_unfollow_dossier) { create(:dossier, :en_instruction, procedure: procedure) }
|
2017-07-11 16:09:03 +02:00
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
context do
|
|
|
|
|
before { subject }
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_unfollow_dossier].map(&:id)) }
|
|
|
|
|
end
|
2019-09-18 13:44:00 +02:00
|
|
|
|
|
2024-06-21 16:11:34 +02:00
|
|
|
|
context 'with pagination' do
|
2024-06-21 16:16:14 +02:00
|
|
|
|
let(:dossiers) { Array.new(26) { create(:dossier, :en_instruction, procedure: procedure) } }
|
|
|
|
|
before do # warmup cache
|
|
|
|
|
get :show, params: { procedure_id: procedure.id, statut: statut }
|
|
|
|
|
dossiers
|
|
|
|
|
end
|
|
|
|
|
|
2024-06-21 16:11:34 +02:00
|
|
|
|
it 'keeps request count stable' do
|
2024-06-21 16:16:14 +02:00
|
|
|
|
count_with_25, count_with_100 = 0, 0
|
|
|
|
|
|
|
|
|
|
stub_const('Instructeurs::ProceduresController::ITEMS_PER_PAGE', 25)
|
|
|
|
|
ActiveSupport::Notifications.subscribed(lambda { |*_args| count_with_25 += 1 }, "sql.active_record") do
|
|
|
|
|
get :show, params: { procedure_id: procedure.id, statut: statut }
|
2024-06-21 16:11:34 +02:00
|
|
|
|
expect(assigns(:projected_dossiers).size).to eq(25)
|
|
|
|
|
end
|
2024-06-21 16:16:14 +02:00
|
|
|
|
|
|
|
|
|
stub_const('Instructeurs::ProceduresController::ITEMS_PER_PAGE', 100)
|
|
|
|
|
ActiveSupport::Notifications.subscribed(lambda { |*_args| count_with_100 += 1 }, "sql.active_record") do
|
|
|
|
|
get :show, params: { procedure_id: procedure.id, statut: statut }
|
|
|
|
|
expect(assigns(:projected_dossiers).size).to eq(dossiers.size + 1) # +1 due to let!(:new_unfollow_dossier)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
expect(count_with_100).to eq(count_with_25)
|
2024-06-21 16:11:34 +02:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2022-01-24 15:32:47 +01:00
|
|
|
|
context 'with a dossier en contruction hidden by user' do
|
2022-03-31 16:33:14 +02:00
|
|
|
|
let!(:hidden_dossier) { create(:dossier, :en_construction, groupe_instructeur: gi_2, hidden_by_user_at: 1.hour.ago) }
|
2022-01-24 15:32:47 +01:00
|
|
|
|
before { subject }
|
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_unfollow_dossier].map(&:id)) }
|
2022-01-24 15:32:47 +01:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with a dossier en contruction not hidden by user' do
|
2022-03-31 16:33:14 +02:00
|
|
|
|
let!(:en_construction_dossier) { create(:dossier, :en_construction, groupe_instructeur: gi_2) }
|
2022-01-24 15:32:47 +01:00
|
|
|
|
before { subject }
|
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_unfollow_dossier, en_construction_dossier].map(&:id)) }
|
2022-01-24 15:32:47 +01:00
|
|
|
|
end
|
|
|
|
|
|
2019-09-18 13:44:00 +02:00
|
|
|
|
context 'and dossiers without follower on each of the others groups' do
|
2022-03-31 16:33:14 +02:00
|
|
|
|
let!(:new_unfollow_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2) }
|
|
|
|
|
let!(:new_unfollow_dossier_on_gi_3) { create(:dossier, :en_instruction, groupe_instructeur: gi_3) }
|
2019-09-18 13:44:00 +02:00
|
|
|
|
|
2020-04-22 15:52:28 +02:00
|
|
|
|
before { subject }
|
2019-09-18 13:44:00 +02:00
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_unfollow_dossier, new_unfollow_dossier_on_gi_2].map(&:id)) }
|
2019-09-18 13:44:00 +02:00
|
|
|
|
end
|
2017-07-11 16:09:03 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with a new dossier with a follower' do
|
2022-03-31 16:33:14 +02:00
|
|
|
|
let(:statut) { 'suivis' }
|
2022-03-31 18:28:12 +02:00
|
|
|
|
let!(:new_followed_dossier) { create(:dossier, :en_instruction, procedure: procedure, followers_instructeurs: [instructeur]) }
|
2017-07-11 16:09:03 +02:00
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
context do
|
|
|
|
|
before { subject }
|
2017-07-11 16:09:03 +02:00
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_followed_dossier].map(&:id)) }
|
|
|
|
|
end
|
2019-09-18 13:44:00 +02:00
|
|
|
|
|
|
|
|
|
context 'and dossier with a follower on each of the others groups' do
|
2022-03-31 18:28:12 +02:00
|
|
|
|
let!(:new_follow_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2, followers_instructeurs: [instructeur]) }
|
|
|
|
|
let!(:new_follow_dossier_on_gi_3) { create(:dossier, :en_instruction, groupe_instructeur: gi_3, followers_instructeurs: [instructeur]) }
|
2019-09-18 13:44:00 +02:00
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
before { subject }
|
2019-09-18 13:44:00 +02:00
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_followed_dossier, new_follow_dossier_on_gi_2].map(&:id)) }
|
2019-09-18 13:44:00 +02:00
|
|
|
|
end
|
2017-07-11 16:09:03 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with a termine dossier with a follower' do
|
2022-03-31 16:33:14 +02:00
|
|
|
|
let(:statut) { 'traites' }
|
2021-03-09 11:21:30 +01:00
|
|
|
|
let!(:termine_dossier) { create(:dossier, :accepte, procedure: procedure) }
|
2017-07-11 16:09:03 +02:00
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
context do
|
|
|
|
|
before { subject }
|
2017-09-28 19:07:18 +02:00
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([termine_dossier].map(&:id)) }
|
|
|
|
|
end
|
2019-09-18 13:44:00 +02:00
|
|
|
|
|
|
|
|
|
context 'and terminer dossiers on each of the others groups' do
|
2022-03-31 16:33:14 +02:00
|
|
|
|
let!(:termine_dossier_on_gi_2) { create(:dossier, :accepte, groupe_instructeur: gi_2) }
|
|
|
|
|
let!(:termine_dossier_on_gi_3) { create(:dossier, :accepte, groupe_instructeur: gi_3) }
|
2019-09-18 13:44:00 +02:00
|
|
|
|
|
2020-04-22 15:52:28 +02:00
|
|
|
|
before { subject }
|
2019-09-18 13:44:00 +02:00
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([termine_dossier, termine_dossier_on_gi_2].map(&:id)) }
|
2019-09-18 13:44:00 +02:00
|
|
|
|
end
|
2022-12-01 11:22:20 +01:00
|
|
|
|
|
2022-12-01 11:22:20 +01:00
|
|
|
|
context 'with batch operations' do
|
2023-01-03 11:17:18 +01:00
|
|
|
|
let!(:batch_operation) { create(:batch_operation, operation: :archiver, dossiers: [termine_dossier], instructeur: instructeur) }
|
2022-12-01 11:22:20 +01:00
|
|
|
|
let!(:termine_dossier_2) { create(:dossier, :accepte, procedure: procedure) }
|
2023-01-03 11:17:18 +01:00
|
|
|
|
let!(:batch_operation_2) { create(:batch_operation, operation: :archiver, dossiers: [termine_dossier_2], instructeur: instructeur) }
|
2022-12-02 09:58:35 +01:00
|
|
|
|
|
|
|
|
|
before { subject }
|
2022-12-01 11:22:20 +01:00
|
|
|
|
|
2022-12-02 09:58:35 +01:00
|
|
|
|
it { expect(assigns(:batch_operations)).to match_array([batch_operation, batch_operation_2]) }
|
|
|
|
|
end
|
|
|
|
|
|
2023-01-03 11:17:18 +01:00
|
|
|
|
context 'with a dossier in a groupe instructeur where current instructeur is not ' do
|
2022-12-01 11:22:20 +01:00
|
|
|
|
let(:instructeur_2) { create(:instructeur) }
|
2023-01-03 11:17:18 +01:00
|
|
|
|
let!(:termine_dossier) { create(:dossier, :accepte, procedure: procedure, groupe_instructeur: gi_3) }
|
2022-12-01 11:22:20 +01:00
|
|
|
|
let!(:batch_operation) { create(:batch_operation, operation: :archiver, dossiers: [termine_dossier], instructeur: instructeur_2) }
|
2023-01-03 11:17:18 +01:00
|
|
|
|
|
2022-12-01 11:22:20 +01:00
|
|
|
|
before { subject }
|
|
|
|
|
|
2022-12-02 17:16:29 +01:00
|
|
|
|
it { expect(assigns(:batch_operations)).to eq([]) }
|
2022-12-01 11:22:20 +01:00
|
|
|
|
end
|
2017-07-11 16:09:03 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with an archived dossier' do
|
2022-03-31 16:33:14 +02:00
|
|
|
|
let(:statut) { 'archives' }
|
2021-03-09 11:21:30 +01:00
|
|
|
|
let!(:archived_dossier) { create(:dossier, :en_instruction, procedure: procedure, archived: true) }
|
2022-03-09 10:29:16 +01:00
|
|
|
|
let!(:archived_dossier_deleted) { create(:dossier, :en_instruction, procedure: procedure, archived: true, hidden_by_administration_at: 2.days.ago) }
|
2017-07-11 16:09:03 +02:00
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
context do
|
|
|
|
|
before { subject }
|
2017-09-28 19:07:18 +02:00
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([archived_dossier].map(&:id)) }
|
|
|
|
|
end
|
2019-09-18 13:44:00 +02:00
|
|
|
|
|
|
|
|
|
context 'and terminer dossiers on each of the others groups' do
|
2021-03-09 11:21:30 +01:00
|
|
|
|
let!(:archived_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2, archived: true) }
|
|
|
|
|
let!(:archived_dossier_on_gi_3) { create(:dossier, :en_instruction, groupe_instructeur: gi_3, archived: true) }
|
2019-09-18 13:44:00 +02:00
|
|
|
|
|
2020-04-22 15:52:28 +02:00
|
|
|
|
before { subject }
|
2019-09-18 13:44:00 +02:00
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([archived_dossier, archived_dossier_on_gi_2].map(&:id)) }
|
2019-09-18 13:44:00 +02:00
|
|
|
|
end
|
2017-07-11 16:09:03 +02:00
|
|
|
|
end
|
2017-07-11 15:40:09 +02:00
|
|
|
|
|
2022-03-09 10:29:16 +01:00
|
|
|
|
context 'with an expirants dossier' do
|
2022-03-31 16:33:14 +02:00
|
|
|
|
let(:statut) { 'expirant' }
|
2022-03-09 10:29:16 +01:00
|
|
|
|
let!(:expiring_dossier_termine_deleted) { create(:dossier, :accepte, procedure: procedure, processed_at: 175.days.ago, hidden_by_administration_at: 2.days.ago) }
|
|
|
|
|
let!(:expiring_dossier_termine) { create(:dossier, :accepte, procedure: procedure, processed_at: 175.days.ago) }
|
|
|
|
|
let!(:expiring_dossier_en_construction) { create(:dossier, :en_construction, procedure: procedure, en_construction_at: 175.days.ago) }
|
|
|
|
|
|
|
|
|
|
before { subject }
|
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([expiring_dossier_termine, expiring_dossier_en_construction].map(&:id)) }
|
2022-03-09 10:29:16 +01:00
|
|
|
|
end
|
|
|
|
|
|
2017-07-11 15:40:09 +02:00
|
|
|
|
describe 'statut' do
|
2022-03-31 16:33:14 +02:00
|
|
|
|
let!(:a_suivre_dossier) { Timecop.freeze(1.day.ago) { create(:dossier, :en_instruction, procedure: procedure) } }
|
2021-03-09 11:21:30 +01:00
|
|
|
|
let!(:new_followed_dossier) { Timecop.freeze(2.days.ago) { create(:dossier, :en_instruction, procedure: procedure) } }
|
|
|
|
|
let!(:termine_dossier) { Timecop.freeze(3.days.ago) { create(:dossier, :accepte, procedure: procedure) } }
|
|
|
|
|
let!(:archived_dossier) { Timecop.freeze(4.days.ago) { create(:dossier, :en_instruction, procedure: procedure, archived: true) } }
|
2017-09-28 19:07:18 +02:00
|
|
|
|
|
2017-07-11 15:40:09 +02:00
|
|
|
|
before do
|
2019-08-06 11:02:54 +02:00
|
|
|
|
instructeur.followed_dossiers << new_followed_dossier
|
2020-04-22 15:52:28 +02:00
|
|
|
|
subject
|
2017-07-11 15:40:09 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when statut is empty' do
|
|
|
|
|
let(:statut) { nil }
|
|
|
|
|
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([a_suivre_dossier].map(&:id)) }
|
2017-07-11 15:40:09 +02:00
|
|
|
|
it { expect(assigns(:statut)).to eq('a-suivre') }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when statut is a-suivre' do
|
|
|
|
|
let(:statut) { 'a-suivre' }
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:statut)).to eq('a-suivre') }
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([a_suivre_dossier].map(&:id)) }
|
2017-07-11 15:40:09 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when statut is suivis' do
|
|
|
|
|
let(:statut) { 'suivis' }
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:statut)).to eq('suivis') }
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_followed_dossier].map(&:id)) }
|
2017-07-11 15:40:09 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when statut is traites' do
|
|
|
|
|
let(:statut) { 'traites' }
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:statut)).to eq('traites') }
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([termine_dossier].map(&:id)) }
|
2017-07-11 15:40:09 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when statut is tous' do
|
|
|
|
|
let(:statut) { 'tous' }
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:statut)).to eq('tous') }
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([a_suivre_dossier, new_followed_dossier, termine_dossier].map(&:id)) }
|
2017-07-11 15:40:09 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when statut is archives' do
|
|
|
|
|
let(:statut) { 'archives' }
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:statut)).to eq('archives') }
|
2022-03-31 18:28:12 +02:00
|
|
|
|
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([archived_dossier].map(&:id)) }
|
2017-07-11 15:40:09 +02:00
|
|
|
|
end
|
|
|
|
|
end
|
2023-09-18 12:43:14 +02:00
|
|
|
|
|
|
|
|
|
context 'exports notification' do
|
|
|
|
|
context 'without generated export' do
|
|
|
|
|
before do
|
|
|
|
|
create(:export, :pending, groupe_instructeurs: [gi_2])
|
|
|
|
|
|
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:has_export_notification)).to be(false) }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with generated export' do
|
|
|
|
|
render_views
|
|
|
|
|
before do
|
|
|
|
|
create(:export, :generated, groupe_instructeurs: [gi_2], updated_at: 1.minute.ago)
|
|
|
|
|
|
|
|
|
|
if exports_seen_at
|
|
|
|
|
cookies.encrypted["exports_#{procedure.id}_seen_at"] = exports_seen_at.to_datetime.to_s
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'without cookie' do
|
|
|
|
|
let(:exports_seen_at) { nil }
|
|
|
|
|
it { expect(assigns(:has_export_notification)).to be(true) }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with cookie in past' do
|
|
|
|
|
let(:exports_seen_at) { 1.hour.ago }
|
|
|
|
|
it { expect(assigns(:has_export_notification)).to be(true) }
|
|
|
|
|
|
|
|
|
|
it { expect(response.body).to match(/Un nouvel export est prêt/) }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with cookie set after last generated export' do
|
|
|
|
|
let(:exports_seen_at) { 10.seconds.ago }
|
|
|
|
|
it { expect(assigns(:has_export_notification)).to be(false) }
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2023-12-18 11:25:52 +01:00
|
|
|
|
|
|
|
|
|
context 'exports alert' do
|
|
|
|
|
context 'without generated export' do
|
|
|
|
|
let(:statut) { 'tous' }
|
|
|
|
|
let!(:export) { create(:export, :pending, groupe_instructeurs: [gi_2]) }
|
|
|
|
|
render_views
|
|
|
|
|
before do
|
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-19 14:32:34 +01:00
|
|
|
|
it { expect(assigns(:last_export)).to eq(export) }
|
2023-12-18 11:25:52 +01:00
|
|
|
|
it { expect(response.body).to include("Votre dernier export est en cours de création") }
|
2024-01-24 13:15:59 +01:00
|
|
|
|
|
|
|
|
|
context 'when export is generated but file not yet attached' do
|
|
|
|
|
let!(:export) { create(:export, :generated, groupe_instructeurs: [gi_2]) }
|
|
|
|
|
it { expect(response.body).to include("Votre dernier export est en cours de création") }
|
|
|
|
|
end
|
2023-12-18 11:25:52 +01:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with recent generated export' do
|
|
|
|
|
let(:statut) { 'tous' }
|
|
|
|
|
let!(:export) { create(:export, :generated, groupe_instructeurs: [gi_2], updated_at: 1.minute.ago) }
|
|
|
|
|
render_views
|
|
|
|
|
before do
|
2024-01-24 13:15:59 +01:00
|
|
|
|
export.file.attach(io: StringIO.new, filename: 'file')
|
2023-12-18 11:25:52 +01:00
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-19 14:32:34 +01:00
|
|
|
|
it { expect(assigns(:last_export)).to eq(export) }
|
2023-12-18 11:25:52 +01:00
|
|
|
|
it { expect(response.body).to include("Votre dernier export au format csv est prêt") }
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-18 14:09:47 +01:00
|
|
|
|
context 'with failed export ' do
|
|
|
|
|
let(:statut) { 'tous' }
|
|
|
|
|
let!(:export) { create(:export, :failed, groupe_instructeurs: [gi_2], updated_at: 1.minute.ago) }
|
|
|
|
|
render_views
|
|
|
|
|
before do
|
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-19 14:32:34 +01:00
|
|
|
|
it { expect(assigns(:last_export)).to eq(export) }
|
2023-12-18 14:09:47 +01:00
|
|
|
|
it { expect(response.body).to include("Votre dernier export au format csv n'a pas fonctionné") }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with export more than hour ago' do
|
2023-12-18 11:25:52 +01:00
|
|
|
|
let(:statut) { 'tous' }
|
|
|
|
|
let!(:export) { create(:export, :generated, groupe_instructeurs: [gi_2], updated_at: 2.hours.ago) }
|
|
|
|
|
before do
|
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-19 14:32:34 +01:00
|
|
|
|
it { expect(assigns(:last_export)).to eq(nil) }
|
2023-12-18 11:25:52 +01:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'logged in with another instructeur' do
|
|
|
|
|
let(:instructeur_2) { create(:instructeur) }
|
|
|
|
|
let(:statut) { 'tous' }
|
|
|
|
|
let!(:export) { create(:export, :generated, groupe_instructeurs: [gi_2], updated_at: 1.minute.ago) }
|
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
sign_in(instructeur_2.user)
|
|
|
|
|
instructeur_2.groupe_instructeurs << gi_2
|
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-19 14:32:34 +01:00
|
|
|
|
it { expect(assigns(:last_export)).to eq(nil) }
|
2023-12-18 11:25:52 +01:00
|
|
|
|
end
|
|
|
|
|
end
|
2024-10-14 18:07:01 +02:00
|
|
|
|
|
|
|
|
|
context 'dossier labels' do
|
|
|
|
|
let!(:dossier) { create(:dossier, :en_construction, groupe_instructeur: gi_2) }
|
|
|
|
|
let!(:dossier_2) { create(:dossier, :en_construction, groupe_instructeur: gi_2) }
|
|
|
|
|
let(:statut) { 'tous' }
|
|
|
|
|
let(:procedure_label_id) { procedure.find_column(label: 'Labels') }
|
|
|
|
|
let!(:procedure_presentation) do
|
|
|
|
|
ProcedurePresentation.create!(assign_to: AssignTo.first)
|
|
|
|
|
end
|
|
|
|
|
render_views
|
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
DossierLabel.create(dossier_id: dossier.id, procedure_label_id: dossier.procedure.procedure_labels.first.id)
|
|
|
|
|
DossierLabel.create(dossier_id: dossier.id, procedure_label_id: dossier.procedure.procedure_labels.second.id)
|
|
|
|
|
DossierLabel.create(dossier_id: dossier_2.id, procedure_label_id: dossier.procedure.procedure_labels.last.id)
|
|
|
|
|
|
|
|
|
|
procedure_presentation.update(displayed_columns: [
|
|
|
|
|
procedure_label_id.id
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
subject
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'displays correctly labels in instructeur table' do
|
|
|
|
|
expect(response.body).to include("Labels")
|
|
|
|
|
expect(response.body).to have_selector('ul.fr-tags-group li span.fr-tag', text: 'à relancer')
|
|
|
|
|
expect(response.body).to have_selector('ul.fr-tags-group li span.fr-tag', text: 'complet')
|
|
|
|
|
expect(response.body).not_to have_selector('ul li span.fr-tag', text: 'prêt pour validation')
|
|
|
|
|
expect(response.body).to have_selector('span.fr-tag', text: 'prêt pour validation')
|
|
|
|
|
end
|
|
|
|
|
end
|
2017-07-11 16:09:03 +02:00
|
|
|
|
end
|
|
|
|
|
end
|
2018-11-22 00:14:16 +01:00
|
|
|
|
|
2020-03-20 17:59:16 +01:00
|
|
|
|
describe '#deleted_dossiers' do
|
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
|
let(:procedure) { create(:procedure, instructeurs: [instructeur]) }
|
|
|
|
|
let(:deleted_dossier) { create(:deleted_dossier, procedure: procedure, state: :en_construction) }
|
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
sign_in(instructeur.user)
|
|
|
|
|
get :deleted_dossiers, params: { procedure_id: procedure.id }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it { expect(assigns(:deleted_dossiers)).to match_array([deleted_dossier]) }
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 17:37:07 +01:00
|
|
|
|
describe '#update_email_notifications' do
|
2019-08-06 11:02:54 +02:00
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
|
let!(:procedure) { create(:procedure, instructeurs: [instructeur]) }
|
2019-03-13 17:37:07 +01:00
|
|
|
|
|
|
|
|
|
context "when logged in" do
|
2019-08-07 11:15:16 +02:00
|
|
|
|
before { sign_in(instructeur.user) }
|
2019-03-13 17:37:07 +01:00
|
|
|
|
|
2019-08-22 17:58:31 +02:00
|
|
|
|
it { expect(instructeur.groupe_instructeur_with_email_notifications).to be_empty }
|
2019-03-13 17:37:07 +01:00
|
|
|
|
|
2019-08-06 11:02:54 +02:00
|
|
|
|
context 'when the instructeur update its preferences' do
|
2019-08-26 16:17:25 +02:00
|
|
|
|
let(:assign_to) { instructeur.assign_to.joins(:groupe_instructeur).find_by(groupe_instructeurs: { procedure: procedure }) }
|
2019-03-13 17:37:07 +01:00
|
|
|
|
|
|
|
|
|
before do
|
2020-02-27 11:09:19 +01:00
|
|
|
|
patch :update_email_notifications, params: { procedure_id: procedure.id, assign_to: { id: assign_to.id, daily_email_notifications_enabled: true } }
|
2019-03-13 17:37:07 +01:00
|
|
|
|
end
|
|
|
|
|
|
2019-08-22 17:58:31 +02:00
|
|
|
|
it { expect(instructeur.groupe_instructeur_with_email_notifications).to eq([procedure.defaut_groupe_instructeur]) }
|
2019-03-13 17:37:07 +01:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-12-11 17:43:24 +01:00
|
|
|
|
|
2023-07-13 17:58:11 +02:00
|
|
|
|
describe '#email_usagers' do
|
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
|
let(:procedure) { create(:procedure) }
|
|
|
|
|
let!(:gi_1) { create(:groupe_instructeur, label: 'gi_1', procedure: procedure, instructeurs: [instructeur]) }
|
|
|
|
|
let!(:dossier_without_groupe) { create(:dossier, :brouillon, procedure: procedure, groupe_instructeur: nil) }
|
|
|
|
|
|
|
|
|
|
subject do
|
|
|
|
|
get :email_usagers, params: { procedure_id: procedure.id }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it { is_expected.to redirect_to(new_user_session_path) }
|
|
|
|
|
|
|
|
|
|
context 'when authenticated' do
|
|
|
|
|
before { sign_in(instructeur.user) }
|
|
|
|
|
it 'lists dossier brouillon in groupe_instructeur as well as dossiers_brouillon outside groupe_instructeur' do
|
|
|
|
|
is_expected.to have_http_status(200)
|
|
|
|
|
expect(assigns(:dossiers_without_groupe_count)).to eq(1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe '#create_multiple_commentaire' do
|
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
|
let!(:gi_p1_1) { create(:groupe_instructeur, label: '1', procedure: procedure, instructeurs: [instructeur]) }
|
|
|
|
|
let!(:gi_p1_2) { create(:groupe_instructeur, label: '2', procedure: procedure) }
|
|
|
|
|
let(:body) { "avant\napres" }
|
|
|
|
|
let(:bulk_message) { BulkMessage.first }
|
|
|
|
|
let!(:dossier) { create(:dossier, state: "brouillon", procedure: procedure, groupe_instructeur: gi_p1_1) }
|
|
|
|
|
let!(:dossier_2) { create(:dossier, state: "brouillon", procedure: procedure, groupe_instructeur: gi_p1_1) }
|
|
|
|
|
let!(:dossier_3) { create(:dossier, state: "brouillon", procedure: procedure, groupe_instructeur: gi_p1_2) }
|
|
|
|
|
let!(:procedure) { create(:procedure, :published, instructeurs: [instructeur]) }
|
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
sign_in(instructeur.user)
|
|
|
|
|
procedure
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let!(:dossier_4) { create(:dossier, state: "brouillon", procedure: procedure, groupe_instructeur: nil) }
|
|
|
|
|
before do
|
|
|
|
|
post :create_multiple_commentaire,
|
|
|
|
|
params: {
|
|
|
|
|
procedure_id: procedure.id,
|
|
|
|
|
bulk_message: { body: body }
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "creates a commentaire for 1 dossiers" do
|
|
|
|
|
expect(Commentaire.count).to eq(1)
|
|
|
|
|
expect(dossier.commentaires).to eq([])
|
|
|
|
|
expect(dossier_2.commentaires).to eq([])
|
|
|
|
|
expect(dossier_3.commentaires).to eq([])
|
|
|
|
|
expect(dossier_4.commentaires.first.body).to eq("avant\napres")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "creates a Bulk Message for 2 groupes instructeurs" do
|
|
|
|
|
expect(BulkMessage.count).to eq(1)
|
|
|
|
|
expect(bulk_message.body).to eq("avant\napres")
|
2024-02-27 18:02:26 +01:00
|
|
|
|
expect(bulk_message.procedure_id).to eq(procedure.id)
|
2023-07-13 17:58:11 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "creates a flash notice" do
|
|
|
|
|
expect(flash.notice).to be_present
|
|
|
|
|
expect(flash.notice).to eq("Tous les messages ont été envoyés avec succès")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "redirect to instructeur_procedure_path" do
|
|
|
|
|
expect(response).to redirect_to instructeur_procedure_path(procedure)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-12-11 17:43:24 +01:00
|
|
|
|
describe '#download_export' do
|
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
|
let!(:procedure) { create(:procedure) }
|
2022-07-21 16:52:31 +02:00
|
|
|
|
let!(:assign_to) { create(:assign_to, instructeur: instructeur, groupe_instructeur: build(:groupe_instructeur, procedure: procedure), manager: manager) }
|
|
|
|
|
let!(:gi_0) { assign_to.groupe_instructeur }
|
2022-03-31 16:31:05 +02:00
|
|
|
|
let!(:gi_1) { create(:groupe_instructeur, label: 'gi_1', procedure: procedure, instructeurs: [instructeur]) }
|
2022-07-21 16:52:31 +02:00
|
|
|
|
let(:manager) { false }
|
2019-12-11 17:43:24 +01:00
|
|
|
|
before { sign_in(instructeur.user) }
|
|
|
|
|
|
|
|
|
|
subject do
|
|
|
|
|
get :download_export, params: { export_format: :csv, procedure_id: procedure.id }
|
|
|
|
|
end
|
|
|
|
|
|
2023-09-12 11:29:27 +02:00
|
|
|
|
context 'when the export does not exist' do
|
2019-12-11 17:43:24 +01:00
|
|
|
|
it 'displays an notice' do
|
2023-09-13 13:06:07 +02:00
|
|
|
|
is_expected.to redirect_to(exports_instructeur_procedure_url(procedure))
|
2019-12-11 17:43:24 +01:00
|
|
|
|
expect(flash.notice).to be_present
|
|
|
|
|
end
|
|
|
|
|
|
2024-02-07 17:19:50 +01:00
|
|
|
|
it { expect { subject }.to change { Export.where(user_profile: instructeur).count }.by(1) }
|
2024-03-08 17:14:21 +01:00
|
|
|
|
|
|
|
|
|
context 'with an export template' do
|
|
|
|
|
let(:export_template) { create(:export_template) }
|
|
|
|
|
subject do
|
|
|
|
|
get :download_export, params: { export_template_id: export_template.id, procedure_id: procedure.id }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'displays an notice' do
|
|
|
|
|
is_expected.to redirect_to(exports_instructeur_procedure_url(procedure))
|
|
|
|
|
expect(flash.notice).to be_present
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-12-11 17:43:24 +01:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the export is not ready' do
|
|
|
|
|
before do
|
2021-03-31 18:19:28 +02:00
|
|
|
|
create(:export, groupe_instructeurs: [gi_1])
|
2019-12-11 17:43:24 +01:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'displays an notice' do
|
2023-09-13 13:06:07 +02:00
|
|
|
|
is_expected.to redirect_to(exports_instructeur_procedure_url(procedure))
|
2019-12-11 17:43:24 +01:00
|
|
|
|
expect(flash.notice).to be_present
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the export is ready' do
|
2022-07-21 20:05:05 +02:00
|
|
|
|
let(:export) { create(:export, groupe_instructeurs: [gi_1, gi_0], job_status: 'generated') }
|
2019-12-11 17:43:24 +01:00
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
export.file.attach(io: StringIO.new('export'), filename: 'file.csv')
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'displays the download link' do
|
|
|
|
|
subject
|
|
|
|
|
expect(response.headers['Location']).to start_with("http://test.host/rails/active_storage/disk")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when another export is ready' do
|
2022-07-21 20:05:05 +02:00
|
|
|
|
let(:export) { create(:export, groupe_instructeurs: [gi_0]) }
|
2019-12-11 17:43:24 +01:00
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
export.file.attach(io: StringIO.new('export'), filename: 'file.csv')
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'displays an notice' do
|
2023-09-13 13:06:07 +02:00
|
|
|
|
is_expected.to redirect_to(exports_instructeur_procedure_url(procedure))
|
2019-12-11 17:43:24 +01:00
|
|
|
|
expect(flash.notice).to be_present
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2022-05-11 16:11:34 +02:00
|
|
|
|
context 'when the turbo_stream format is used' do
|
2024-03-14 13:11:53 +01:00
|
|
|
|
render_views
|
|
|
|
|
|
2019-12-11 17:43:24 +01:00
|
|
|
|
before do
|
|
|
|
|
post :download_export,
|
2024-03-14 13:11:53 +01:00
|
|
|
|
params: { export_format: :csv, procedure_id: procedure.id, statut: 'traites' },
|
2022-05-11 16:11:34 +02:00
|
|
|
|
format: :turbo_stream
|
2019-12-11 17:43:24 +01:00
|
|
|
|
end
|
|
|
|
|
|
2020-07-13 17:36:28 +02:00
|
|
|
|
it 'responds in the correct format' do
|
2022-05-11 16:11:34 +02:00
|
|
|
|
expect(response.media_type).to eq('text/vnd.turbo-stream.html')
|
2019-12-11 17:43:24 +01:00
|
|
|
|
expect(response).to have_http_status(:ok)
|
2024-03-14 13:11:53 +01:00
|
|
|
|
expect(response.body).to include(polling_last_export_instructeur_procedure_path(procedure))
|
2019-12-11 17:43:24 +01:00
|
|
|
|
end
|
|
|
|
|
end
|
2022-07-21 16:52:31 +02:00
|
|
|
|
|
|
|
|
|
context 'when logged in through super admin' do
|
|
|
|
|
let(:manager) { true }
|
|
|
|
|
it { is_expected.to have_http_status(:forbidden) }
|
|
|
|
|
end
|
2019-12-11 17:43:24 +01:00
|
|
|
|
end
|
2023-09-12 11:29:27 +02:00
|
|
|
|
|
|
|
|
|
describe '#exports' do
|
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
|
let!(:procedure) { create(:procedure) }
|
|
|
|
|
let!(:assign_to) { create(:assign_to, instructeur: instructeur, groupe_instructeur: build(:groupe_instructeur, procedure: procedure), manager: manager) }
|
|
|
|
|
let!(:gi_0) { assign_to.groupe_instructeur }
|
|
|
|
|
let!(:gi_1) { create(:groupe_instructeur, label: 'gi_1', procedure: procedure, instructeurs: [instructeur]) }
|
|
|
|
|
let(:manager) { false }
|
|
|
|
|
before { sign_in(instructeur.user) }
|
|
|
|
|
|
|
|
|
|
subject do
|
|
|
|
|
get :exports, params: { procedure_id: procedure.id }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when there is one export in the instructeurs group' do
|
2023-09-13 12:59:38 +02:00
|
|
|
|
let!(:export) { create(:export, groupe_instructeurs: [gi_1]) }
|
2023-09-12 11:29:27 +02:00
|
|
|
|
it 'retrieves the export' do
|
|
|
|
|
subject
|
|
|
|
|
expect(assigns(:exports)).to eq([export])
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when there is one export in another instructeurs group' do
|
|
|
|
|
let!(:instructeur_2) { create(:instructeur) }
|
|
|
|
|
let!(:gi_2) { create(:groupe_instructeur, label: 'gi_2', procedure: procedure, instructeurs: [instructeur_2]) }
|
2023-09-13 12:59:38 +02:00
|
|
|
|
let!(:export) { create(:export, groupe_instructeurs: [gi_2]) }
|
2023-09-12 11:29:27 +02:00
|
|
|
|
it 'does not retrieved the export' do
|
|
|
|
|
subject
|
|
|
|
|
expect(assigns(:exports)).to eq([])
|
|
|
|
|
end
|
|
|
|
|
end
|
2023-09-21 11:42:28 +02:00
|
|
|
|
|
|
|
|
|
context 'when logged in through super admin' do
|
|
|
|
|
let(:manager) { true }
|
|
|
|
|
it { is_expected.to have_http_status(:forbidden) }
|
|
|
|
|
end
|
2023-09-12 11:29:27 +02:00
|
|
|
|
end
|
2024-02-21 12:13:47 +01:00
|
|
|
|
|
2024-07-22 11:32:07 +02:00
|
|
|
|
describe '#update_filter' do
|
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
|
let(:procedure) { create(:procedure, :for_individual) }
|
|
|
|
|
def procedure_presentation = instructeur.assign_to.first.procedure_presentation_or_default_and_errors.first
|
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
create(:assign_to, instructeur:, groupe_instructeur: build(:groupe_instructeur, procedure:))
|
|
|
|
|
|
|
|
|
|
sign_in(instructeur.user)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'can change order' do
|
2024-09-25 17:43:43 +02:00
|
|
|
|
column = procedure.find_column(label: "Nom")
|
|
|
|
|
expect { get :update_sort, params: { procedure_id: procedure.id, sorted_column: { id: column.id, order: 'asc' } } }
|
|
|
|
|
.to change { procedure_presentation.sorted_column }
|
|
|
|
|
.from(procedure.default_sorted_column)
|
|
|
|
|
.to(SortedColumn.new(column:, order: 'asc'))
|
2024-07-22 11:32:07 +02:00
|
|
|
|
end
|
|
|
|
|
end
|
2024-10-07 21:46:59 +02:00
|
|
|
|
|
2024-02-21 12:13:47 +01:00
|
|
|
|
describe '#add_filter' do
|
|
|
|
|
let(:instructeur) { create(:instructeur) }
|
|
|
|
|
let(:procedure) { create(:procedure, :for_individual) }
|
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
create(:assign_to, instructeur:, groupe_instructeur: build(:groupe_instructeur, procedure:))
|
|
|
|
|
|
|
|
|
|
sign_in(instructeur.user)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
subject do
|
2024-09-27 15:58:34 +02:00
|
|
|
|
column = procedure.find_column(label: "Nom")
|
2024-10-07 09:54:17 +02:00
|
|
|
|
post :add_filter, params: { procedure_id: procedure.id, a_suivre_filters: [{ id: column.id, filter: "n" * 4049 }] }
|
2024-02-21 12:13:47 +01:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'should render the error' do
|
|
|
|
|
subject
|
2024-10-24 11:16:12 +02:00
|
|
|
|
expect(flash.alert[0]).to include("Le filtre « Nom » est trop long (maximum: 4048 caractères)")
|
2024-02-21 12:13:47 +01:00
|
|
|
|
end
|
|
|
|
|
end
|
2017-06-29 15:30:42 +02:00
|
|
|
|
end
|