Merge pull request #6698 from betagouv/main

2021-11-30-02
This commit is contained in:
LeSim 2021-11-30 12:49:17 +01:00 committed by GitHub
commit 3eb7be0803
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 85 additions and 44 deletions

View file

@ -1 +1 @@
2.7.3 3.0.3

View file

@ -67,6 +67,7 @@ gem 'rails'
gem 'rails-i18n' # Locales par défaut gem 'rails-i18n' # Locales par défaut
gem 'rake-progressbar', require: false gem 'rake-progressbar', require: false
gem 'react-rails' gem 'react-rails'
gem 'rexml' # add missing gem due to ruby3 (https://github.com/Shopify/bootsnap/issues/325)
gem 'rgeo-geojson' gem 'rgeo-geojson'
gem 'rqrcode' gem 'rqrcode'
gem 'ruby-saml-idp' gem 'ruby-saml-idp'

View file

@ -145,7 +145,7 @@ GEM
bcrypt (3.1.16) bcrypt (3.1.16)
bindata (2.4.10) bindata (2.4.10)
bindex (0.8.1) bindex (0.8.1)
bootsnap (1.7.2) bootsnap (1.9.3)
msgpack (~> 1.0) msgpack (~> 1.0)
brakeman (5.1.1) brakeman (5.1.1)
browser (5.3.1) browser (5.3.1)
@ -858,6 +858,7 @@ DEPENDENCIES
rails-i18n rails-i18n
rake-progressbar rake-progressbar
react-rails react-rails
rexml
rgeo-geojson rgeo-geojson
rqrcode rqrcode
rspec-rails rspec-rails
@ -892,4 +893,4 @@ DEPENDENCIES
zxcvbn-ruby zxcvbn-ruby
BUNDLED WITH BUNDLED WITH
2.1.4 2.2.32

View file

@ -215,7 +215,7 @@ module Administrateurs
else else
file = group_csv_file.read file = group_csv_file.read
base_encoding = CharlockHolmes::EncodingDetector.detect(file) base_encoding = CharlockHolmes::EncodingDetector.detect(file)
groupes_emails = ACSV::CSV.new(file.encode("UTF-8", base_encoding[:encoding], invalid: :replace, replace: ""), headers: true, header_converters: :downcase) groupes_emails = ACSV::CSV.new_for_ruby3(file.encode("UTF-8", base_encoding[:encoding], invalid: :replace, replace: ""), headers: true, header_converters: :downcase)
.map { |r| r.to_h.slice('groupe', 'email') } .map { |r| r.to_h.slice('groupe', 'email') }
groupes_emails_has_keys = groupes_emails.first.has_key?("groupe") && groupes_emails.first.has_key?("email") groupes_emails_has_keys = groupes_emails.first.has_key?("groupe") && groupes_emails.first.has_key?("email")

View file

@ -112,7 +112,7 @@ module Instructeurs
def passer_en_instruction def passer_en_instruction
begin begin
dossier.passer_en_instruction!(current_instructeur) dossier.passer_en_instruction!(instructeur: current_instructeur)
flash.notice = 'Dossier passé en instruction.' flash.notice = 'Dossier passé en instruction.'
rescue AASM::InvalidTransition => e rescue AASM::InvalidTransition => e
flash.alert = aasm_error_message(e, target_state: :en_instruction) flash.alert = aasm_error_message(e, target_state: :en_instruction)
@ -138,7 +138,7 @@ module Instructeurs
dossier.update!(hidden_by_user_at: nil) dossier.update!(hidden_by_user_at: nil)
end end
flash.notice = "Le dossier #{dossier.id} a été repassé en instruction." flash.notice = "Le dossier #{dossier.id} a été repassé en instruction."
dossier.repasser_en_instruction!(current_instructeur) dossier.repasser_en_instruction!(instructeur: current_instructeur)
rescue AASM::InvalidTransition => e rescue AASM::InvalidTransition => e
flash.alert = aasm_error_message(e, target_state: :en_instruction) flash.alert = aasm_error_message(e, target_state: :en_instruction)
end end
@ -150,19 +150,21 @@ module Instructeurs
motivation = params[:dossier] && params[:dossier][:motivation] motivation = params[:dossier] && params[:dossier][:motivation]
justificatif = params[:dossier] && params[:dossier][:justificatif_motivation] justificatif = params[:dossier] && params[:dossier][:justificatif_motivation]
h = { instructeur: current_instructeur, motivation: motivation, justificatif: justificatif }
begin begin
case params[:process_action] case params[:process_action]
when "refuser" when "refuser"
target_state = :refuse target_state = :refuse
dossier.refuser!(current_instructeur, motivation, justificatif: justificatif) dossier.refuser!(h)
flash.notice = "Dossier considéré comme refusé." flash.notice = "Dossier considéré comme refusé."
when "classer_sans_suite" when "classer_sans_suite"
target_state = :sans_suite target_state = :sans_suite
dossier.classer_sans_suite!(current_instructeur, motivation, justificatif: justificatif) dossier.classer_sans_suite!(h)
flash.notice = "Dossier considéré comme sans suite." flash.notice = "Dossier considéré comme sans suite."
when "accepter" when "accepter"
target_state = :accepte target_state = :accepte
dossier.accepter!(current_instructeur, motivation, justificatif: justificatif) dossier.accepter!(h)
flash.notice = "Dossier traité avec succès." flash.notice = "Dossier traité avec succès."
end end
rescue AASM::InvalidTransition => e rescue AASM::InvalidTransition => e

View file

@ -41,7 +41,7 @@ module Manager
def repasser_en_instruction def repasser_en_instruction
dossier = Dossier.find(params[:id]) dossier = Dossier.find(params[:id])
dossier.repasser_en_instruction(current_super_admin) dossier.repasser_en_instruction(instructeur: current_super_admin)
logger.info("Le dossier #{dossier.id} est repassé en instruction par #{current_super_admin.email}") logger.info("Le dossier #{dossier.id} est repassé en instruction par #{current_super_admin.email}")
flash[:notice] = "Le dossier #{dossier.id} est repassé en instruction." flash[:notice] = "Le dossier #{dossier.id} est repassé en instruction."

View file

@ -14,7 +14,7 @@ module Mutations
field :errors, [Types::ValidationErrorType], null: true field :errors, [Types::ValidationErrorType], null: true
def resolve(dossier:, instructeur:, motivation: nil, justificatif: nil, disable_notification:) def resolve(dossier:, instructeur:, motivation: nil, justificatif: nil, disable_notification:)
dossier.accepter!(instructeur, motivation, justificatif: justificatif, disable_notification: disable_notification) dossier.accepter!(instructeur: instructeur, motivation: motivation, justificatif: justificatif, disable_notification: disable_notification)
{ dossier: dossier } { dossier: dossier }
end end

View file

@ -14,7 +14,7 @@ module Mutations
field :errors, [Types::ValidationErrorType], null: true field :errors, [Types::ValidationErrorType], null: true
def resolve(dossier:, instructeur:, motivation:, justificatif: nil, disable_notification:) def resolve(dossier:, instructeur:, motivation:, justificatif: nil, disable_notification:)
dossier.classer_sans_suite!(instructeur, motivation, justificatif: justificatif, disable_notification: disable_notification) dossier.classer_sans_suite!(instructeur: instructeur, motivation: motivation, justificatif: justificatif, disable_notification: disable_notification)
{ dossier: dossier } { dossier: dossier }
end end

View file

@ -12,7 +12,7 @@ module Mutations
field :errors, [Types::ValidationErrorType], null: true field :errors, [Types::ValidationErrorType], null: true
def resolve(dossier:, instructeur:, disable_notification:) def resolve(dossier:, instructeur:, disable_notification:)
dossier.passer_en_instruction!(instructeur, disable_notification: disable_notification) dossier.passer_en_instruction!(instructeur: instructeur, disable_notification: disable_notification)
{ dossier: dossier } { dossier: dossier }
end end

View file

@ -14,7 +14,7 @@ module Mutations
field :errors, [Types::ValidationErrorType], null: true field :errors, [Types::ValidationErrorType], null: true
def resolve(dossier:, instructeur:, motivation:, justificatif: nil, disable_notification:) def resolve(dossier:, instructeur:, motivation:, justificatif: nil, disable_notification:)
dossier.refuser!(instructeur, motivation, justificatif: justificatif, disable_notification: disable_notification) dossier.refuser!(instructeur: instructeur, motivation: motivation, justificatif: justificatif, disable_notification: disable_notification)
{ dossier: dossier } { dossier: dossier }
end end

View file

@ -787,7 +787,10 @@ class Dossier < ApplicationRecord
save! save!
end end
def after_passer_en_instruction(instructeur, disable_notification: false) def after_passer_en_instruction(h)
instructeur = h[:instructeur]
disable_notification = h.fetch(:disable_notification, false)
instructeur.follow(self) instructeur.follow(self)
self.en_construction_close_to_expiration_notice_sent_at = nil self.en_construction_close_to_expiration_notice_sent_at = nil
@ -825,7 +828,10 @@ class Dossier < ApplicationRecord
log_dossier_operation(instructeur, :repasser_en_construction) log_dossier_operation(instructeur, :repasser_en_construction)
end end
def after_repasser_en_instruction(instructeur, disable_notification: false) def after_repasser_en_instruction(h)
instructeur = h[:instructeur]
disable_notification = h.fetch(:disable_notification, false)
create_missing_traitemets create_missing_traitemets
self.archived = false self.archived = false
@ -843,7 +849,12 @@ class Dossier < ApplicationRecord
log_dossier_operation(instructeur, :repasser_en_instruction) log_dossier_operation(instructeur, :repasser_en_instruction)
end end
def after_accepter(instructeur, motivation, justificatif: nil, disable_notification: false) def after_accepter(h)
instructeur = h[:instructeur]
motivation = h[:motivation]
justificatif = h[:justificatif]
disable_notification = h.fetch(:disable_notification, false)
self.processed_at = self.traitements self.processed_at = self.traitements
.accepter(motivation: motivation, instructeur: instructeur) .accepter(motivation: motivation, instructeur: instructeur)
.processed_at .processed_at
@ -882,7 +893,12 @@ class Dossier < ApplicationRecord
log_automatic_dossier_operation(:accepter, self) log_automatic_dossier_operation(:accepter, self)
end end
def after_refuser(instructeur, motivation, justificatif: nil, disable_notification: false) def after_refuser(h)
instructeur = h[:instructeur]
motivation = h[:motivation]
justificatif = h[:justificatif]
disable_notification = h.fetch(:disable_notification, false)
self.processed_at = self.traitements self.processed_at = self.traitements
.refuser(motivation: motivation, instructeur: instructeur) .refuser(motivation: motivation, instructeur: instructeur)
.processed_at .processed_at
@ -901,7 +917,12 @@ class Dossier < ApplicationRecord
log_dossier_operation(instructeur, :refuser, self) log_dossier_operation(instructeur, :refuser, self)
end end
def after_classer_sans_suite(instructeur, motivation, justificatif: nil, disable_notification: false) def after_classer_sans_suite(h)
instructeur = h[:instructeur]
motivation = h[:motivation]
justificatif = h[:justificatif]
disable_notification = h.fetch(:disable_notification, false)
self.processed_at = self.traitements self.processed_at = self.traitements
.classer_sans_suite(motivation: motivation, instructeur: instructeur) .classer_sans_suite(motivation: motivation, instructeur: instructeur)
.processed_at .processed_at

View file

@ -0,0 +1,16 @@
require 'csv'
# PR : https://github.com/wvengen/ruby-acsv/pull/3
module ACSV
class CSV < ::CSV
def self.new_for_ruby3(data, options = {})
options[:col_sep] ||= ACSV::Detect.separator(data)
# because of the Separation of positional and keyword arguments in Ruby 3.0
# (https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/)
# instead of
# super(data, options)
# we do
::CSV.new(data, **options)
end
end
end

View file

@ -219,7 +219,7 @@ describe Instructeurs::DossiersController, type: :controller do
describe '#terminer' do describe '#terminer' do
context "with refuser" do context "with refuser" do
before do before do
dossier.passer_en_instruction!(instructeur) dossier.passer_en_instruction!(instructeur: instructeur)
sign_in(instructeur.user) sign_in(instructeur.user)
end end
@ -260,7 +260,7 @@ describe Instructeurs::DossiersController, type: :controller do
context "with classer_sans_suite" do context "with classer_sans_suite" do
before do before do
dossier.passer_en_instruction!(instructeur) dossier.passer_en_instruction!(instructeur: instructeur)
sign_in(instructeur.user) sign_in(instructeur.user)
end end
context 'without attachment' do context 'without attachment' do
@ -302,7 +302,7 @@ describe Instructeurs::DossiersController, type: :controller do
context "with accepter" do context "with accepter" do
before do before do
dossier.passer_en_instruction!(instructeur) dossier.passer_en_instruction!(instructeur: instructeur)
sign_in(instructeur.user) sign_in(instructeur.user)
expect(NotificationMailer).to receive(:send_accepte_notification) expect(NotificationMailer).to receive(:send_accepte_notification)
@ -749,12 +749,12 @@ describe Instructeurs::DossiersController, type: :controller do
end end
before do before do
dossier.passer_en_instruction(instructeur) dossier.passer_en_instruction(instructeur: instructeur)
end end
context 'just before delete the dossier, the operation must be equal to 2' do context 'just before delete the dossier, the operation must be equal to 2' do
before do before do
dossier.accepter!(instructeur, 'le dossier est correct') dossier.accepter!(instructeur: instructeur, motivation: 'le dossier est correct')
end end
it 'has 2 operations logs before deletion' do it 'has 2 operations logs before deletion' do
@ -764,7 +764,7 @@ describe Instructeurs::DossiersController, type: :controller do
context 'when the instructeur want to delete a dossier with a decision' do context 'when the instructeur want to delete a dossier with a decision' do
before do before do
dossier.accepter!(instructeur, "le dossier est correct") dossier.accepter!(instructeur: instructeur, motivation: "le dossier est correct")
allow(DossierMailer).to receive(:notify_instructeur_deletion_to_user).and_return(double(deliver_later: nil)) allow(DossierMailer).to receive(:notify_instructeur_deletion_to_user).and_return(double(deliver_later: nil))
subject subject
end end

View file

@ -318,9 +318,9 @@ describe TagsSubstitutionConcern, type: :model do
Timecop.freeze(Time.zone.local(2001, 2, 3)) Timecop.freeze(Time.zone.local(2001, 2, 3))
dossier.passer_en_construction! dossier.passer_en_construction!
Timecop.freeze(Time.zone.local(2004, 5, 6)) Timecop.freeze(Time.zone.local(2004, 5, 6))
dossier.passer_en_instruction!(instructeur) dossier.passer_en_instruction!(instructeur: instructeur)
Timecop.freeze(Time.zone.local(2007, 8, 9)) Timecop.freeze(Time.zone.local(2007, 8, 9))
dossier.accepter!(instructeur, nil) dossier.accepter!(instructeur: instructeur)
Timecop.return Timecop.return
end end

View file

@ -306,9 +306,9 @@ describe Dossier do
Timecop.freeze(date1) Timecop.freeze(date1)
d.passer_en_construction! d.passer_en_construction!
Timecop.freeze(date2) Timecop.freeze(date2)
d.passer_en_instruction!(instructeur) d.passer_en_instruction!(instructeur: instructeur)
Timecop.freeze(date3) Timecop.freeze(date3)
d.accepter!(instructeur, "Motivation") d.accepter!(instructeur: instructeur, motivation: "Motivation")
Timecop.return Timecop.return
d d
end end
@ -462,7 +462,7 @@ describe Dossier do
it 'should keep first en_construction_at date' do it 'should keep first en_construction_at date' do
Timecop.return Timecop.return
dossier.passer_en_instruction!(instructeur) dossier.passer_en_instruction!(instructeur: instructeur)
dossier.repasser_en_construction!(instructeur) dossier.repasser_en_construction!(instructeur)
expect(dossier.traitements.size).to eq(3) expect(dossier.traitements.size).to eq(3)
@ -478,7 +478,7 @@ describe Dossier do
let(:instructeur) { create(:instructeur) } let(:instructeur) { create(:instructeur) }
before do before do
dossier.passer_en_instruction!(instructeur) dossier.passer_en_instruction!(instructeur: instructeur)
dossier.reload dossier.reload
end end
@ -490,7 +490,7 @@ describe Dossier do
it 'should keep first en_instruction_at date if dossier is set to en_construction again' do it 'should keep first en_instruction_at date if dossier is set to en_construction again' do
Timecop.return Timecop.return
dossier.repasser_en_construction!(instructeur) dossier.repasser_en_construction!(instructeur)
dossier.passer_en_instruction!(instructeur) dossier.passer_en_instruction!(instructeur: instructeur)
expect(dossier.traitements.size).to eq(4) expect(dossier.traitements.size).to eq(4)
expect(dossier.traitements.en_construction.first.processed_at).to eq(dossier.depose_at) expect(dossier.traitements.en_construction.first.processed_at).to eq(dossier.depose_at)
@ -504,7 +504,7 @@ describe Dossier do
let(:dossier) { create(:dossier, :en_instruction, :with_individual) } let(:dossier) { create(:dossier, :en_instruction, :with_individual) }
before do before do
dossier.accepter!(instructeur, nil) dossier.accepter!(instructeur: instructeur)
dossier.reload dossier.reload
end end
@ -518,7 +518,7 @@ describe Dossier do
let(:dossier) { create(:dossier, :en_instruction, :with_individual) } let(:dossier) { create(:dossier, :en_instruction, :with_individual) }
before do before do
dossier.refuser!(instructeur, nil) dossier.refuser!(instructeur: instructeur)
dossier.reload dossier.reload
end end
@ -532,7 +532,7 @@ describe Dossier do
let(:dossier) { create(:dossier, :en_instruction, :with_individual) } let(:dossier) { create(:dossier, :en_instruction, :with_individual) }
before do before do
dossier.classer_sans_suite!(instructeur, nil) dossier.classer_sans_suite!(instructeur: instructeur)
dossier.reload dossier.reload
end end
@ -611,7 +611,7 @@ describe Dossier do
end end
it "sends an email when the dossier becomes en_instruction" do it "sends an email when the dossier becomes en_instruction" do
dossier.passer_en_instruction!(instructeur) dossier.passer_en_instruction!(instructeur: instructeur)
expect(NotificationMailer).to have_received(:send_en_instruction_notification).with(dossier) expect(NotificationMailer).to have_received(:send_en_instruction_notification).with(dossier)
end end
@ -949,7 +949,7 @@ describe Dossier do
}.to_not have_enqueued_job(WebHookJob) }.to_not have_enqueued_job(WebHookJob)
expect { expect {
dossier.passer_en_instruction!(instructeur) dossier.passer_en_instruction!(instructeur: instructeur)
}.to have_enqueued_job(WebHookJob) }.to have_enqueued_job(WebHookJob)
end end
end end
@ -1034,7 +1034,7 @@ describe Dossier do
allow(dossier).to receive(:build_attestation).and_return(attestation) allow(dossier).to receive(:build_attestation).and_return(attestation)
Timecop.freeze(now) Timecop.freeze(now)
dossier.accepter!(instructeur, 'motivation') dossier.accepter!(instructeur: instructeur, motivation: 'motivation')
dossier.reload dossier.reload
end end
@ -1089,7 +1089,7 @@ describe Dossier do
let(:operation_serialized) { JSON.parse(last_operation.serialized.download) } let(:operation_serialized) { JSON.parse(last_operation.serialized.download) }
let(:instructeur) { create(:instructeur) } let(:instructeur) { create(:instructeur) }
before { dossier.passer_en_instruction!(instructeur) } before { dossier.passer_en_instruction!(instructeur: instructeur) }
it { expect(dossier.state).to eq('en_instruction') } it { expect(dossier.state).to eq('en_instruction') }
it { expect(dossier.followers_instructeurs).to include(instructeur) } it { expect(dossier.followers_instructeurs).to include(instructeur) }
@ -1216,7 +1216,7 @@ describe Dossier do
Timecop.freeze Timecop.freeze
allow(DossierMailer).to receive(:notify_revert_to_instruction) allow(DossierMailer).to receive(:notify_revert_to_instruction)
.and_return(double(deliver_later: true)) .and_return(double(deliver_later: true))
dossier.repasser_en_instruction!(instructeur) dossier.repasser_en_instruction!(instructeur: instructeur)
dossier.reload dossier.reload
end end
@ -1495,21 +1495,21 @@ describe Dossier do
it "clean up titres identite on accepter" do it "clean up titres identite on accepter" do
expect(champ_titre_identite.piece_justificative_file.attached?).to be_truthy expect(champ_titre_identite.piece_justificative_file.attached?).to be_truthy
expect(champ_titre_identite_vide.piece_justificative_file.attached?).to be_falsey expect(champ_titre_identite_vide.piece_justificative_file.attached?).to be_falsey
dossier.accepter!(dossier.followers_instructeurs.first, "yolo!") dossier.accepter!(instructeur: dossier.followers_instructeurs.first, motivation: "yolo!")
expect(champ_titre_identite.piece_justificative_file.attached?).to be_falsey expect(champ_titre_identite.piece_justificative_file.attached?).to be_falsey
end end
it "clean up titres identite on refuser" do it "clean up titres identite on refuser" do
expect(champ_titre_identite.piece_justificative_file.attached?).to be_truthy expect(champ_titre_identite.piece_justificative_file.attached?).to be_truthy
expect(champ_titre_identite_vide.piece_justificative_file.attached?).to be_falsey expect(champ_titre_identite_vide.piece_justificative_file.attached?).to be_falsey
dossier.refuser!(dossier.followers_instructeurs.first, "yolo!") dossier.refuser!(instructeur: dossier.followers_instructeurs.first, motivation: "yolo!")
expect(champ_titre_identite.piece_justificative_file.attached?).to be_falsey expect(champ_titre_identite.piece_justificative_file.attached?).to be_falsey
end end
it "clean up titres identite on classer_sans_suite" do it "clean up titres identite on classer_sans_suite" do
expect(champ_titre_identite.piece_justificative_file.attached?).to be_truthy expect(champ_titre_identite.piece_justificative_file.attached?).to be_truthy
expect(champ_titre_identite_vide.piece_justificative_file.attached?).to be_falsey expect(champ_titre_identite_vide.piece_justificative_file.attached?).to be_falsey
dossier.classer_sans_suite!(dossier.followers_instructeurs.first, "yolo!") dossier.classer_sans_suite!(instructeur: dossier.followers_instructeurs.first, motivation: "yolo!")
expect(champ_titre_identite.piece_justificative_file.attached?).to be_falsey expect(champ_titre_identite.piece_justificative_file.attached?).to be_falsey
end end

View file

@ -181,7 +181,7 @@ describe 'Instructing a dossier:', js: true do
let(:commentaire) { create(:commentaire, instructeur: instructeur, dossier: dossier) } let(:commentaire) { create(:commentaire, instructeur: instructeur, dossier: dossier) }
before do before do
dossier.passer_en_instruction!(instructeur) dossier.passer_en_instruction!(instructeur: instructeur)
champ.piece_justificative_file.attach(io: File.open(path), filename: "piece_justificative_0.pdf", content_type: "application/pdf") champ.piece_justificative_file.attach(io: File.open(path), filename: "piece_justificative_0.pdf", content_type: "application/pdf")
log_in(instructeur.email, password) log_in(instructeur.email, password)