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/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/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/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/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/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