Skip to content

Commit

Permalink
fix: an invite cannot submit a fork (server side)
Browse files Browse the repository at this point in the history
  • Loading branch information
LeSim committed Dec 18, 2024
1 parent cd0cf03 commit 51e3002
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 90 deletions.
2 changes: 1 addition & 1 deletion app/controllers/users/dossiers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class DossiersController < UserController
layout 'procedure_context', only: [:identite, :update_identite, :siret, :update_siret]

ACTIONS_ALLOWED_TO_ANY_USER = [:index, :new, :transferer_all, :deleted_dossiers]
ACTIONS_ALLOWED_TO_OWNER_OR_INVITE = [:show, :destroy, :demande, :messagerie, :brouillon, :submit_en_construction, :modifier, :update, :create_commentaire, :papertrail, :restore, :champ]
ACTIONS_ALLOWED_TO_OWNER_OR_INVITE = [:show, :destroy, :demande, :messagerie, :brouillon, :modifier, :update, :create_commentaire, :papertrail, :restore, :champ]

before_action :ensure_ownership!, except: ACTIONS_ALLOWED_TO_ANY_USER + ACTIONS_ALLOWED_TO_OWNER_OR_INVITE
before_action :ensure_ownership_or_invitation!, only: ACTIONS_ALLOWED_TO_OWNER_OR_INVITE
Expand Down
195 changes: 106 additions & 89 deletions spec/controllers/users/dossiers_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -501,10 +501,10 @@
end

describe '#submit_en_construction' do
before { sign_in(user) }
let(:owner) { create(:user) }
let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :text, mandatory: false }] }
let(:dossier) { create(:dossier, :en_construction, procedure:, user:) }
let(:dossier) { create(:dossier, :en_construction, procedure:, user: owner) }
let(:first_champ) { dossier.owner_editing_fork.project_champs_public.first }
let(:anchor_to_first_champ) { controller.helpers.link_to I18n.t('views.users.dossiers.fix_champ'), modifier_dossier_path(anchor: first_champ.labelledby_id), class: 'error-anchor' }
let(:value) { 'beautiful value' }
Expand All @@ -519,132 +519,149 @@
end
end

context 'when the dossier cannot be updated by the user' do
let!(:dossier) { create(:dossier, :en_instruction, user: user) }

it 'redirects to the dossiers list' do
subject
context 'when the owner signs in' do
before { sign_in(owner) }

expect(response).to redirect_to(dossier_path(dossier))
expect(flash.alert).to eq('Votre dossier ne peut plus être modifié')
end
end
context 'when the dossier cannot be updated by the owner' do
let!(:dossier) { create(:dossier, :en_instruction, user: owner) }

context 'when the update fails' do
render_views

before do
allow_any_instance_of(Dossier).to receive(:validate).and_return(false)
allow_any_instance_of(Dossier).to receive(:errors).and_return(
[double(inner_error: double(base: first_champ), message: 'nop')]
)
it 'redirects to the dossiers list' do
subject

subject
expect(response).to redirect_to(dossier_path(dossier))
expect(flash.alert).to eq('Votre dossier ne peut plus être modifié')
end
end

it { expect(response).to render_template(:modifier) }
end
context 'when the update fails' do
render_views

context 'when a mandatory champ is missing' do
let(:value) { nil }
render_views
let(:types_de_champ_public) { [{ type: :text, mandatory: true, libelle: 'l' }] }
before { subject }
before do
allow_any_instance_of(Dossier).to receive(:validate).and_return(false)
allow_any_instance_of(Dossier).to receive(:errors).and_return(
[double(inner_error: double(base: first_champ), message: 'nop')]
)

it { expect(response).to render_template(:modifier) }
it { expect(response.body).to have_content("doit être rempli") }
it { expect(response.body).to have_link(first_champ.libelle, href: "##{first_champ.labelledby_id}") }
end
subject
end

context 'when dossier has no champ' do
let(:submit_payload) { { id: dossier.id } }
it { expect(response).to render_template(:modifier) }
end

it 'does not raise any errors' do
subject
context 'when a mandatory champ is missing' do
let(:value) { nil }
render_views
let(:types_de_champ_public) { [{ type: :text, mandatory: true, libelle: 'l' }] }
before { subject }

expect(response).to redirect_to(dossier_path(dossier))
it { expect(response).to render_template(:modifier) }
it { expect(response.body).to have_content("doit être rempli") }
it { expect(response.body).to have_link(first_champ.libelle, href: "##{first_champ.labelledby_id}") }
end
end

context 'when dossier repetition had been removed in newer version' do
let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:, user:) }
let(:types_de_champ_public) { [{ type: :repetition, libelle: 'repetition', children: [{ type: :text, libelle: 'child' }] }] }
let(:editing_fork) { dossier.owner_editing_fork }
let(:champ_repetition) { editing_fork.project_champs_public.find(&:repetition?) }
before do
editing_fork
context 'when dossier has no champ' do
let(:submit_payload) { { id: dossier.id } }

procedure.draft_revision.remove_type_de_champ(champ_repetition.stable_id)
procedure.publish_revision!
it 'does not raise any errors' do
subject

editing_fork.reload
editing_fork.rebase!
expect(response).to redirect_to(dossier_path(dossier))
end
end
let(:submit_payload) { { id: dossier.id } }

it { expect { subject }.not_to raise_error }
end
context 'when dossier repetition had been removed in newer version' do
let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:, user:) }
let(:types_de_champ_public) { [{ type: :repetition, libelle: 'repetition', children: [{ type: :text, libelle: 'child' }] }] }
let(:editing_fork) { dossier.owner_editing_fork }
let(:champ_repetition) { editing_fork.project_champs_public.find(&:repetition?) }
before do
editing_fork

context 'when dossier was already submitted' do
before do
expect_any_instance_of(Dossier).to receive(:remove_not_visible_or_empty_champs!)
post :submit_en_construction, params: payload
end
procedure.draft_revision.remove_type_de_champ(champ_repetition.stable_id)
procedure.publish_revision!

it 'redirects to the dossier' do
subject
editing_fork.reload
editing_fork.rebase!
end
let(:submit_payload) { { id: dossier.id } }

expect(response).to redirect_to(dossier_path(dossier))
expect(flash.alert).to eq("Les modifications ont déjà été déposées")
it { expect { subject }.not_to raise_error }
end
end

context "when there are pending correction" do
let!(:correction) { create(:dossier_correction, dossier: dossier) }
context 'when dossier was already submitted' do
before do
expect_any_instance_of(Dossier).to receive(:remove_not_visible_or_empty_champs!)
post :submit_en_construction, params: payload
end

subject { post :submit_en_construction, params: { id: dossier.id } }
it 'redirects to the dossier' do
subject

it "resolves correction automatically" do
expect { subject }.to change { correction.reload.resolved_at }.to be_truthy
expect(response).to redirect_to(dossier_path(dossier))
expect(flash.alert).to eq("Les modifications ont déjà été déposées")
end
end

context 'when procedure has sva enabled' do
let(:procedure) { create(:procedure, :sva) }
let(:dossier) { create(:dossier, :en_construction, procedure:, user:) }
context "when there are pending correction" do
let!(:correction) { create(:dossier_correction, dossier: dossier) }

subject { post :submit_en_construction, params: { id: dossier.id, dossier: { pending_correction: pending_correction_value } } }
subject { post :submit_en_construction, params: { id: dossier.id } }

context 'when resolving correction' do
let(:pending_correction_value) { "1" }
it 'passe automatiquement en instruction' do
expect(dossier.pending_correction?).to be_truthy
it "resolves correction automatically" do
expect { subject }.to change { correction.reload.resolved_at }.to be_truthy
end

subject
dossier.reload
context 'when procedure has sva enabled' do
let(:procedure) { create(:procedure, :sva) }
let(:dossier) { create(:dossier, :en_construction, procedure:, user: owner) }
let!(:correction) { create(:dossier_correction, dossier: dossier) }

expect(dossier).to be_en_instruction
expect(dossier.pending_correction?).to be_falsey
expect(dossier.en_instruction_at).to within(5.seconds).of(Time.current)
subject { post :submit_en_construction, params: { id: dossier.id, dossier: { pending_correction: pending_correction_value } } }

context 'when resolving correction' do
let(:pending_correction_value) { "1" }
it 'passe automatiquement en instruction' do
expect(dossier.pending_correction?).to be_truthy

subject
dossier.reload

expect(dossier).to be_en_instruction
expect(dossier.pending_correction?).to be_falsey
expect(dossier.en_instruction_at).to within(5.seconds).of(Time.current)
end
end
end

context 'when not resolving correction' do
render_views
context 'when not resolving correction' do
render_views

let(:pending_correction_value) { "" }
it 'does not passe automatiquement en instruction' do
subject
dossier.reload
let(:pending_correction_value) { "" }
it 'does not passe automatiquement en instruction' do
subject
dossier.reload

expect(dossier).to be_en_construction
expect(dossier.pending_correction?).to be_truthy
expect(dossier).to be_en_construction
expect(dossier.pending_correction?).to be_truthy

expect(response.body).to include("Cochez la case")
expect(response.body).to include("Cochez la case")
end
end
end
end
end

context 'when a invite signs in' do
let(:invite_user) { create(:user) }
let!(:invite) { create(:invite, dossier:, user: invite_user) }

before { sign_in(invite_user) }
context 'and the invite tries to submit the dossier' do
before { subject }

it { expect(response).to redirect_to(root_path) }
it { expect(flash.alert).to include("Vous n’avez pas accès à ce dossier") }
end
end
end

describe '#update brouillon' do
Expand Down

0 comments on commit 51e3002

Please sign in to comment.