diff --git a/Gemfile.lock b/Gemfile.lock index 89a353b39..6e2f5baaa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -102,7 +102,7 @@ GEM rake (>= 10.4, < 14.0) ast (2.4.1) attr_required (1.0.1) - autoprefixer-rails (10.0.0.1) + autoprefixer-rails (10.0.0.2) execjs axe-matchers (2.6.1) dumb_delegator (~> 0.8) @@ -138,7 +138,7 @@ GEM rack-test (>= 0.6.3) regexp_parser (~> 1.5) xpath (~> 3.2) - capybara-email (3.0.1) + capybara-email (3.0.2) capybara (>= 2.4, < 4.0) mail capybara-screenshot (1.0.24) @@ -159,7 +159,7 @@ GEM choice (0.2.0) chunky_png (1.3.11) clamav-client (3.2.0) - coderay (1.1.2) + coderay (1.1.3) coercible (1.0.0) descendants_tracker (~> 0.0.1) coffee-rails (5.0.0) @@ -171,8 +171,7 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.1.7) connection_pool (2.2.3) - crack (0.4.3) - safe_yaml (~> 1.0.0) + crack (0.4.4) crass (1.0.6) css_parser (1.7.1) addressable @@ -289,7 +288,7 @@ GEM thor (>= 0.19, < 2.0) graphql_playground-rails (2.1.0) rails (>= 5.1.0) - groupdate (5.0.0) + groupdate (5.2.1) activesupport (>= 5) guard (2.16.2) formatador (>= 0.2.4) @@ -467,7 +466,7 @@ GEM prawn (>= 0.11.1, < 3) prawn-table (0.2.2) prawn (>= 1.3.0, < 3.0.0) - premailer (1.11.1) + premailer (1.13.1) addressable css_parser (>= 1.6.0) htmlentities (>= 4.0.0) @@ -488,9 +487,9 @@ GEM activesupport (>= 3.0.0) raabro (1.1.6) rack (2.2.3) - rack-attack (6.2.2) + rack-attack (6.3.1) rack (>= 1.0, < 3) - rack-mini-profiler (2.0.1) + rack-mini-profiler (2.1.0) rack (>= 1.2.0) rack-oauth2 (1.15.0) activesupport @@ -624,10 +623,9 @@ GEM rexml ruby-progressbar (1.10.1) ruby2_keywords (0.0.2) - ruby_parser (3.14.2) + ruby_parser (3.15.0) sexp_processor (~> 4.9) rubyzip (2.3.0) - safe_yaml (1.0.5) sanitize-url (0.1.4) sass (3.7.4) sass-listen (~> 4.0.0) @@ -649,11 +647,11 @@ GEM childprocess (>= 0.5, < 4.0) rubyzip (>= 1.2.2) semantic_range (2.3.0) - sentry-raven (3.0.0) + sentry-raven (3.1.0) faraday (>= 1.0) - sexp_processor (4.14.1) + sexp_processor (4.15.1) shellany (0.0.1) - shoulda-matchers (4.3.0) + shoulda-matchers (4.4.1) activesupport (>= 4.2.0) simple_xlsx_reader (1.0.4) nokogiri @@ -676,7 +674,7 @@ GEM axlsx_styler (>= 1.0.0, < 2) caxlsx (>= 2.0.2, < 4) rodf (>= 1.0.0, < 2) - spring (2.1.0) + spring (2.1.1) spring-commands-rspec (1.0.4) spring (>= 0.9.1) sprockets (3.7.2) @@ -697,7 +695,7 @@ GEM tilt (2.0.10) timecop (0.9.1) ttfunk (1.6.2.1) - typhoeus (1.3.1) + typhoeus (1.4.0) ethon (>= 0.9.0) tzinfo (1.2.7) thread_safe (~> 0.1) @@ -708,10 +706,10 @@ GEM validate_email (0.1.6) activemodel (>= 3.0) mail (>= 2.2.5) - validate_url (1.0.8) + validate_url (1.0.11) activemodel (>= 3.0.0) public_suffix - vcr (5.1.0) + vcr (6.0.0) virtus (1.0.5) axiom-types (~> 0.1) coercible (~> 1.0) @@ -719,19 +717,19 @@ GEM equalizer (~> 0.0, >= 0.0.9) warden (1.2.9) rack (>= 2.0.9) - web-console (4.0.1) + web-console (4.0.4) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - webdrivers (4.2.0) + webdrivers (4.4.1) nokogiri (~> 1.6) rubyzip (>= 1.3.0) selenium-webdriver (>= 3.0, < 4.0) webfinger (1.1.0) activesupport httpclient (>= 2.4) - webmock (3.8.3) + webmock (3.9.1) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) @@ -752,7 +750,7 @@ GEM zipline (1.1.1) rails (>= 3.2.1, < 6.1) zip_tricks (>= 4.2.1, <= 5.0.0) - zxcvbn-ruby (1.0.0) + zxcvbn-ruby (1.1.0) PLATFORMS ruby diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index 4a719effe..a81e39392 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -1291,6 +1291,11 @@ enum TypeDeChamp { """ textarea + """ + Titre identité + """ + titre_identite + """ Oui/Non """ diff --git a/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js b/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js index 57131402b..98ad6af76 100644 --- a/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js +++ b/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js @@ -26,6 +26,7 @@ const TypeDeChamp = sortableElement( const isCarte = typeDeChamp.type_champ === 'carte'; const isExplication = typeDeChamp.type_champ === 'explication'; const isHeaderSection = typeDeChamp.type_champ === 'header_section'; + const isTitreIdentite = typeDeChamp.type_champ === 'titre_identite'; const isRepetition = typeDeChamp.type_champ === 'repetition'; const canBeMandatory = !isHeaderSection && !isExplication && !state.isAnnotation; @@ -118,7 +119,7 @@ const TypeDeChamp = sortableElement(
diff --git a/app/mailers/administration_mailer.rb b/app/mailers/administration_mailer.rb index efd2c573a..4718af99e 100644 --- a/app/mailers/administration_mailer.rb +++ b/app/mailers/administration_mailer.rb @@ -2,13 +2,13 @@ class AdministrationMailer < ApplicationMailer layout 'mailers/layout' - def invite_admin(admin, reset_password_token, administration_id) + def invite_admin(user, reset_password_token, administration_id) @reset_password_token = reset_password_token - @admin = admin + @user = user @author_name = BizDev.full_name(administration_id) subject = "Activez votre compte administrateur" - mail(to: admin.email, + mail(to: user.email, subject: subject, reply_to: CONTACT_EMAIL) end diff --git a/app/models/administrateur.rb b/app/models/administrateur.rb index d32135baa..b78428aef 100644 --- a/app/models/administrateur.rb +++ b/app/models/administrateur.rb @@ -31,14 +31,6 @@ class Administrateur < ApplicationRecord user&.email end - # validate :password_complexity, if: Proc.new { |a| Devise.password_length.include?(a.password.try(:size)) } - - def password_complexity - if password.present? && ZxcvbnService.new(password).score < PASSWORD_COMPLEXITY_FOR_ADMIN - errors.add(:password, :not_strong) - end - end - def self.find_inactive_by_token(reset_password_token) self.inactive.with_reset_password_token(reset_password_token) end diff --git a/app/models/champs/titre_identite_champ.rb b/app/models/champs/titre_identite_champ.rb new file mode 100644 index 000000000..460960ed5 --- /dev/null +++ b/app/models/champs/titre_identite_champ.rb @@ -0,0 +1,57 @@ +# == Schema Information +# +# Table name: champs +# +# id :integer not null, primary key +# private :boolean default(FALSE), not null +# row :integer +# type :string +# value :string +# created_at :datetime +# updated_at :datetime +# dossier_id :integer +# etablissement_id :integer +# parent_id :bigint +# type_de_champ_id :integer +# +class Champs::TitreIdentiteChamp < Champ + MAX_SIZE = 20.megabytes + + ACCEPTED_FORMATS = [ + "image/png", + "image/jpeg" + ] + + # TODO: once we're running on Rails 6, re-enable this validation. + # See https://github.com/betagouv/demarches-simplifiees.fr/issues/4926 + # + validates :piece_justificative_file, + content_type: ACCEPTED_FORMATS, + size: { less_than: MAX_SIZE } + + def main_value_name + :piece_justificative_file + end + + def search_terms + # We don’t know how to search inside documents yet + end + + def mandatory_and_blank? + mandatory? && !piece_justificative_file.attached? + end + + def for_export + piece_justificative_file.filename.to_s if piece_justificative_file.attached? + end + + def for_api + if piece_justificative_file.attached? && (piece_justificative_file.virus_scanner.safe? || piece_justificative_file.virus_scanner.pending?) + piece_justificative_file.service_url + end + end + + def update_skip_pj_validation + type_de_champ.update(skip_pj_validation: true) + end +end diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index 02c3425f0..9974ef1f2 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -47,7 +47,8 @@ class TypeDeChamp < ApplicationRecord piece_justificative: 'piece_justificative', siret: 'siret', carte: 'carte', - repetition: 'repetition' + repetition: 'repetition', + titre_identite: 'titre_identite' } belongs_to :revision, class_name: 'ProcedureRevision', optional: true @@ -189,7 +190,7 @@ class TypeDeChamp < ApplicationRecord end def piece_justificative? - type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative) + type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative) || type_champ == TypeDeChamp.type_champs.fetch(:titre_identite) end def legacy_number? diff --git a/app/models/types_de_champ/titre_identite_type_de_champ.rb b/app/models/types_de_champ/titre_identite_type_de_champ.rb new file mode 100644 index 000000000..7118fed08 --- /dev/null +++ b/app/models/types_de_champ/titre_identite_type_de_champ.rb @@ -0,0 +1,2 @@ +class TypesDeChamp::TitreIdentiteTypeDeChamp < TypesDeChamp::TypeDeChampBase +end diff --git a/app/models/user.rb b/app/models/user.rb index e713006f0..1582b6a6c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -54,6 +54,14 @@ class User < ApplicationRecord before_validation -> { sanitize_email(:email) } + validate :password_complexity, if: -> (u) { u.administrateur.present? && Devise.password_length.include?(u.password.try(:size)) } + + def password_complexity + if password.present? && ZxcvbnService.new(password).score < PASSWORD_COMPLEXITY_FOR_ADMIN + errors.add(:password, :not_strong) + end + end + # Override of Devise::Models::Confirmable#send_confirmation_instructions def send_confirmation_instructions unless @raw_confirmation_token @@ -90,13 +98,7 @@ class User < ApplicationRecord end def invite_administrateur!(administration_id) - reset_password_token = nil - - if !active? - reset_password_token = set_reset_password_token - end - - AdministrationMailer.invite_admin(self, reset_password_token, administration_id).deliver_later + AdministrationMailer.invite_admin(self, set_reset_password_token, administration_id).deliver_later end def remind_invitation! diff --git a/app/views/administration_mailer/invite_admin.html.haml b/app/views/administration_mailer/invite_admin.html.haml index ee56b73a0..456c76654 100644 --- a/app/views/administration_mailer/invite_admin.html.haml +++ b/app/views/administration_mailer/invite_admin.html.haml @@ -7,17 +7,18 @@ Je vous remercie de l’intérêt que vous portez à notre outil de dématérialisation de démarches. %p - Votre compte administrateur a été créé pour l'adresse email #{@admin.email}. + Votre compte administrateur a été créé pour l'adresse email #{@user.email}. -- if @reset_password_token.present? +- if !@user.active? %p %b Pour l’activer, cliquez sur le lien suivant : = link_to(admin_activate_url(token: @reset_password_token), admin_activate_url(token: @reset_password_token)) - else %p - Pour vous connecter, cliquez sur le lien suivant : - = link_to(new_user_session_url, new_user_session_url) + %b + Pour vous connecter, cliquez sur le lien suivant : + = link_to edit_user_password_url(@user, reset_password_token: @reset_password_token), edit_user_password_url(@user, reset_password_token: @reset_password_token) %p = render partial: "layouts/mailers/bizdev_signature", locals: { author_name: @author_name } diff --git a/app/views/shared/dossiers/_champ_row.html.haml b/app/views/shared/dossiers/_champ_row.html.haml index 18d69d390..6d6461468 100644 --- a/app/views/shared/dossiers/_champ_row.html.haml +++ b/app/views/shared/dossiers/_champ_row.html.haml @@ -26,6 +26,8 @@ = render partial: "shared/champs/multiple_drop_down_list/show", locals: { champ: c } - when TypeDeChamp.type_champs.fetch(:piece_justificative) = render partial: "shared/champs/piece_justificative/show", locals: { champ: c } + - when TypeDeChamp.type_champs.fetch(:titre_identite) + = render partial: "shared/champs/piece_justificative/show", locals: { champ: c } - when TypeDeChamp.type_champs.fetch(:siret) = render partial: "shared/champs/siret/show", locals: { champ: c, profile: profile } - when TypeDeChamp.type_champs.fetch(:textarea) diff --git a/app/views/shared/dossiers/editable_champs/_editable_champ.html.haml b/app/views/shared/dossiers/editable_champs/_editable_champ.html.haml index a446bf5f7..0331de761 100644 --- a/app/views/shared/dossiers/editable_champs/_editable_champ.html.haml +++ b/app/views/shared/dossiers/editable_champs/_editable_champ.html.haml @@ -6,6 +6,8 @@ - elsif has_label?(champ) = render partial: 'shared/dossiers/editable_champs/champ_label', locals: { form: form, champ: champ, seen_at: defined?(seen_at) ? seen_at : nil } + - if champ.type_champ == "titre_identite" + %p.notice Carte d'identité (uniquement le recto), passeport ou titre de séjour. Formats acceptés : jpg / png. = render partial: "shared/dossiers/editable_champs/#{champ.type_champ}", locals: { champ: champ, form: form } diff --git a/app/views/shared/dossiers/editable_champs/_titre_identite.html.haml b/app/views/shared/dossiers/editable_champs/_titre_identite.html.haml new file mode 100644 index 000000000..0fc1f99c8 --- /dev/null +++ b/app/views/shared/dossiers/editable_champs/_titre_identite.html.haml @@ -0,0 +1,4 @@ += render 'shared/attachment/edit', + { form: form, + attached_file: champ.piece_justificative_file, + template: champ.type_de_champ.piece_justificative_template, user_can_destroy: true } diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 465afd67b..42641fdd3 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -82,6 +82,7 @@ fr: taken: déjà utilisé password: too_short: 'est trop court' + not_strong: 'n’est pas assez complexe' password_confirmation: confirmation: ': Les deux mots de passe ne correspondent pas' invite: diff --git a/config/locales/models/type_de_champ/fr.yml b/config/locales/models/type_de_champ/fr.yml index 924c14e54..bdc1513ac 100644 --- a/config/locales/models/type_de_champ/fr.yml +++ b/config/locales/models/type_de_champ/fr.yml @@ -33,3 +33,4 @@ fr: siret: 'SIRET' carte: 'Carte' repetition: 'Bloc répétable' + titre_identite: 'Titre identité' diff --git a/spec/controllers/webhook_controller_spec.rb b/spec/controllers/webhook_controller_spec.rb index 534983c84..b5548e224 100644 --- a/spec/controllers/webhook_controller_spec.rb +++ b/spec/controllers/webhook_controller_spec.rb @@ -25,7 +25,7 @@ describe WebhookController, type: :controller do end context 'when there is a matching user' do - let(:user) { create(:user) } + let(:user) { create(:user, :with_strong_password) } let(:customer_email) { user.email } it 'returns a 200 response' do diff --git a/spec/factories/administrateur.rb b/spec/factories/administrateur.rb index c82404e2c..b665f9249 100644 --- a/spec/factories/administrateur.rb +++ b/spec/factories/administrateur.rb @@ -3,7 +3,7 @@ FactoryBot.define do factory :administrateur do transient do email { generate(:administrateur_email) } - password { 'mon chien aime les bananes' } + password { 'Mon [hien 4im3 {es banane$' } end initialize_with do diff --git a/spec/factories/champ.rb b/spec/factories/champ.rb index 7d057c320..000924b78 100644 --- a/spec/factories/champ.rb +++ b/spec/factories/champ.rb @@ -143,6 +143,14 @@ FactoryBot.define do end end + factory :champ_titre_identite, class: 'Champs::TitreIdentiteChamp' do + type_de_champ { association :type_de_champ_titre_identite, procedure: dossier.procedure } + + after(:build) do |champ, _evaluator| + champ.piece_justificative_file.attach(io: StringIO.new("toto"), filename: "toto.png", content_type: "image/png") + end + end + factory :champ_carte, class: 'Champs::CarteChamp' do type_de_champ { association :type_de_champ_carte, procedure: dossier.procedure } end diff --git a/spec/factories/type_de_champ.rb b/spec/factories/type_de_champ.rb index 0c4f2b7cc..eb43d56ff 100644 --- a/spec/factories/type_de_champ.rb +++ b/spec/factories/type_de_champ.rb @@ -133,6 +133,9 @@ FactoryBot.define do type_de_champ.piece_justificative_template.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain") end end + factory :type_de_champ_titre_identite do + type_champ { TypeDeChamp.type_champs.fetch(:titre_identite) } + end factory :type_de_champ_siret do type_champ { TypeDeChamp.type_champs.fetch(:siret) } end diff --git a/spec/factories/user.rb b/spec/factories/user.rb index 55c6d258e..a5bcfa1a4 100644 --- a/spec/factories/user.rb +++ b/spec/factories/user.rb @@ -8,5 +8,9 @@ FactoryBot.define do trait :unconfirmed do confirmed_at { nil } end + + trait :with_strong_password do + password { '{my-%s3cure[]-p4$$w0rd' } + end end end diff --git a/spec/mailers/administration_mailer_spec.rb b/spec/mailers/administration_mailer_spec.rb index 0646b7a12..e2e8e875a 100644 --- a/spec/mailers/administration_mailer_spec.rb +++ b/spec/mailers/administration_mailer_spec.rb @@ -1,12 +1,24 @@ RSpec.describe AdministrationMailer, type: :mailer do describe '#invite_admin' do - let(:admin) { create(:administrateur) } - let(:token) { "Toc toc toc" } + let(:admin_user) { create(:user, last_sign_in_at: last_sign_in_at) } + let(:token) { "some_token" } let(:administration_id) { BizDev::PIPEDRIVE_ID } + let(:last_sign_in_at) { nil } - subject { described_class.invite_admin(admin, token, administration_id) } + subject { described_class.invite_admin(admin_user, token, administration_id) } it { expect(subject.subject).not_to be_empty } + + describe "when the user has not been activated" do + it { expect(subject.body).to include(admin_activate_path(token: token)) } + it { expect(subject.body).not_to include(edit_user_password_url(admin_user, reset_password_token: token)) } + end + + describe "when the user is already active" do + let(:last_sign_in_at) { Time.zone.now } + it { expect(subject.body).not_to include(admin_activate_path(token: token)) } + it { expect(subject.body).to include(edit_user_password_url(admin_user, reset_password_token: token)) } + end end describe '#refuse_admin' do diff --git a/spec/models/administrateur_spec.rb b/spec/models/administrateur_spec.rb index 6b449d900..f8c3e9a85 100644 --- a/spec/models/administrateur_spec.rb +++ b/spec/models/administrateur_spec.rb @@ -75,34 +75,4 @@ describe Administrateur, type: :model do expect(Administrateur.find_by(id: administrateur.id)).to be_nil end end - - # describe '#password_complexity' do - # let(:email) { 'mail@beta.gouv.fr' } - # let(:passwords) { ['pass', '12pass23', 'démarches ', 'démarches-simple', 'my-s3cure-p4ssword'] } - # let(:administrateur) { build(:administrateur, email: email, password: password) } - # let(:min_complexity) { PASSWORD_COMPLEXITY_FOR_ADMIN } - - # subject do - # administrateur.save - # administrateur.errors.full_messages - # end - - # context 'when password is too short' do - # let(:password) { 's' * (PASSWORD_MIN_LENGTH - 1) } - - # it { expect(subject).to eq(["Le mot de passe est trop court"]) } - # end - - # context 'when password is too simple' do - # let(:password) { passwords[min_complexity - 1] } - - # it { expect(subject).to eq(["Le mot de passe n'est pas assez complexe"]) } - # end - - # context 'when password is acceptable' do - # let(:password) { passwords[min_complexity] } - - # it { expect(subject).to eq([]) } - # end - # end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 54b6a856e..8dd086276 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -186,7 +186,9 @@ describe User, type: :model do subject end - it { expect(AdministrationMailer).to have_received(:invite_admin).with(user, nil, administration.id) } + it 'receives an invitation to update its password' do + expect(AdministrationMailer).to have_received(:invite_admin).with(user, kind_of(String), administration.id) + end end end @@ -293,4 +295,55 @@ describe User, type: :model do end end end + + describe '#password_complexity' do + # This password list is sorted by password complexity, according to zxcvbn (used for complexity evaluation) + # 0 - too guessable: risky password. (guesses < 10^3) + # 1 - very guessable: protection from throttled online attacks. (guesses < 10^6) + # 2 - somewhat guessable: protection from unthrottled online attacks. (guesses < 10^8) + # 3 - safely unguessable: moderate protection from offline slow-hash scenario. (guesses < 10^10) + # 4 - very unguessable: strong protection from offline slow-hash scenario. (guesses >= 10^10) + passwords = ['pass', '12pass23', 'démarches ', 'démarches-simple', '{My-$3cure-p4ssWord}'] + min_complexity = PASSWORD_COMPLEXITY_FOR_ADMIN + + context 'administrateurs' do + let(:email) { 'mail@beta.gouv.fr' } + let(:administrateur) { build(:user, email: email, password: password, administrateur: build(:administrateur)) } + + subject do + administrateur.save + administrateur.errors.full_messages + end + + context 'when password is too short' do + let(:password) { 's' * (PASSWORD_MIN_LENGTH - 1) } + + it { expect(subject).to eq(["Le mot de passe est trop court"]) } + end + + context 'when password is too simple' do + passwords[0..(min_complexity - 1)].each do |password| + let(:password) { password } + + it { expect(subject).to eq(["Le mot de passe n’est pas assez complexe"]) } + end + end + + context 'when password is acceptable' do + let(:password) { passwords[min_complexity] } + + it { expect(subject).to eq([]) } + end + end + + context 'simple users' do + passwords.each do |password| + let(:user) { build(:user, email: 'some@email.fr', password: password) } + it 'has no complexity validation' do + user.save + expect(user.errors.full_messages).to eq([]) + end + end + end + end end diff --git a/spec/services/administrateur_usage_statistics_service_spec.rb b/spec/services/administrateur_usage_statistics_service_spec.rb index 835206df7..17749a21c 100644 --- a/spec/services/administrateur_usage_statistics_service_spec.rb +++ b/spec/services/administrateur_usage_statistics_service_spec.rb @@ -36,7 +36,7 @@ describe AdministrateurUsageStatisticsService do context 'for an administrateur that has plenty of things' do let(:administrateur) do create(:administrateur, - user: create(:user, sign_in_count: 17, current_sign_in_at: Time.zone.local(2019, 3, 7), last_sign_in_at: Time.zone.local(2019, 2, 27)), + user: create(:user, :with_strong_password, sign_in_count: 17, current_sign_in_at: Time.zone.local(2019, 3, 7), last_sign_in_at: Time.zone.local(2019, 2, 27)), services: [create(:service)], instructeurs: [create(:instructeur)]) end diff --git a/spec/services/procedure_export_service_spec.rb b/spec/services/procedure_export_service_spec.rb index 7f2945981..0f8cafdfe 100644 --- a/spec/services/procedure_export_service_spec.rb +++ b/spec/services/procedure_export_service_spec.rb @@ -73,6 +73,7 @@ describe ProcedureExportService do "piece_justificative", "siret", "carte", + "titre_identite", "text" ] end @@ -156,6 +157,7 @@ describe ProcedureExportService do "piece_justificative", "siret", "carte", + "titre_identite", "text" ] end @@ -235,6 +237,7 @@ describe ProcedureExportService do "piece_justificative", "siret", "carte", + "titre_identite", "text" ] end