From 5229f1006486548d465c1751ef5e48d6c4a78825 Mon Sep 17 00:00:00 2001 From: "maxim.joseau" Date: Fri, 29 Nov 2024 12:37:34 +0100 Subject: [PATCH] wip: lexpol integration wip: lexpol 01 review edit and lexpol component chore: few fixes feat: variable support feat: allow administrator to select model for lexpol type field feat: use Typhoeus instead of uri feat: add mapping to variable to send to lexpol & fix dropdown to select lexpol modele chore: rubocop Graphql: add champ descriptor for lexpol chore: dossier controller spec 1 chore: dossier controller spec 1 feat: add feature flag for lexpol chore: graphql schema load fix: some changes according to comments chore: rubocop feat: add feature flag rake chore: upgrade vite --- Gemfile.lock | 658 +++++++++--------- .../editable_champ/lexpol_component.rb | 2 + .../lexpol_component.html.haml | 15 + .../types_de_champ_editor/champ_component.rb | 12 + .../champ_component/champ_component.html.haml | 22 +- .../administrateurs/procedures_controller.rb | 11 + .../types_de_champ_controller.rb | 2 + .../instructeurs/dossiers_controller.rb | 50 ++ .../instructeurs/lexpol_controller.rb | 29 + app/graphql/api/v2/schema.rb | 2 + app/graphql/schema.graphql | 72 ++ app/graphql/schema.json | 501 +++++++++++++ app/graphql/types/champ_descriptor_type.rb | 2 + app/graphql/types/champ_type.rb | 2 + .../lexpol_champ_descriptor_type.rb | 5 + app/graphql/types/champs/lexpol_champ_type.rb | 11 + app/models/champ.rb | 2 + app/models/champs/lexpol_champ.rb | 11 + app/models/concerns/lexpol_concern.rb | 44 ++ app/models/type_de_champ.rb | 26 +- .../types_de_champ/lexpol_type_de_champ.rb | 22 + app/services/api_lexpol.rb | 99 +++ .../lexpol/create_dossier.turbo_stream.erb | 3 + .../lexpol/update_dossier.turbo_stream.erb | 3 + .../shared/champs/lexpol/_show.html.haml | 14 + .../dossiers/_edit_annotations.html.haml | 26 +- config/initializers/flipper.rb | 3 +- config/locales/models/type_de_champ/fr.yml | 1 + config/routes.rb | 4 + package.json | 6 +- spec/factories/champ.rb | 4 + spec/factories/type_de_champ.rb | 3 + ...ature_flag_lexpol_champs_spec.rake_spec.rb | 39 ++ 33 files changed, 1381 insertions(+), 325 deletions(-) create mode 100644 app/components/editable_champ/lexpol_component.rb create mode 100644 app/components/editable_champ/lexpol_component/lexpol_component.html.haml create mode 100644 app/controllers/instructeurs/lexpol_controller.rb create mode 100644 app/graphql/types/champs/descriptor/lexpol_champ_descriptor_type.rb create mode 100644 app/graphql/types/champs/lexpol_champ_type.rb create mode 100644 app/models/champs/lexpol_champ.rb create mode 100644 app/models/concerns/lexpol_concern.rb create mode 100644 app/models/types_de_champ/lexpol_type_de_champ.rb create mode 100644 app/services/api_lexpol.rb create mode 100644 app/views/instructeurs/lexpol/create_dossier.turbo_stream.erb create mode 100644 app/views/instructeurs/lexpol/update_dossier.turbo_stream.erb create mode 100644 app/views/shared/champs/lexpol/_show.html.haml create mode 100644 spec/lib/tasks/deployment/20241215115134_feature_flag_lexpol_champs_spec.rake_spec.rb diff --git a/Gemfile.lock b/Gemfile.lock index 0ef3acac320..cd758ef4c7d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -12,87 +12,88 @@ GEM aasm (5.5.0) concurrent-ruby (~> 1.0) acsv (0.0.1) - actioncable (7.0.8.4) - actionpack (= 7.0.8.4) - activesupport (= 7.0.8.4) + actioncable (7.0.8.7) + actionpack (= 7.0.8.7) + activesupport (= 7.0.8.7) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.8.4) - actionpack (= 7.0.8.4) - activejob (= 7.0.8.4) - activerecord (= 7.0.8.4) - activestorage (= 7.0.8.4) - activesupport (= 7.0.8.4) + actionmailbox (7.0.8.7) + actionpack (= 7.0.8.7) + activejob (= 7.0.8.7) + activerecord (= 7.0.8.7) + activestorage (= 7.0.8.7) + activesupport (= 7.0.8.7) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.8.4) - actionpack (= 7.0.8.4) - actionview (= 7.0.8.4) - activejob (= 7.0.8.4) - activesupport (= 7.0.8.4) + actionmailer (7.0.8.7) + actionpack (= 7.0.8.7) + actionview (= 7.0.8.7) + activejob (= 7.0.8.7) + activesupport (= 7.0.8.7) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.0) - actionpack (7.0.8.4) - actionview (= 7.0.8.4) - activesupport (= 7.0.8.4) + actionpack (7.0.8.7) + actionview (= 7.0.8.7) + activesupport (= 7.0.8.7) rack (~> 2.0, >= 2.2.4) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.8.4) - actionpack (= 7.0.8.4) - activerecord (= 7.0.8.4) - activestorage (= 7.0.8.4) - activesupport (= 7.0.8.4) + actiontext (7.0.8.7) + actionpack (= 7.0.8.7) + activerecord (= 7.0.8.7) + activestorage (= 7.0.8.7) + activesupport (= 7.0.8.7) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.8.4) - activesupport (= 7.0.8.4) + actionview (7.0.8.7) + activesupport (= 7.0.8.7) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - active_model_serializers (0.10.14) + active_model_serializers (0.10.15) actionpack (>= 4.1) activemodel (>= 4.1) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) - active_storage_validations (1.1.4) - activejob (>= 5.2.0) - activemodel (>= 5.2.0) - activestorage (>= 5.2.0) - activesupport (>= 5.2.0) - activejob (7.0.8.4) - activesupport (= 7.0.8.4) + active_storage_validations (1.3.4) + activejob (>= 6.1.4) + activemodel (>= 6.1.4) + activestorage (>= 6.1.4) + activesupport (>= 6.1.4) + marcel (>= 1.0.3) + activejob (7.0.8.7) + activesupport (= 7.0.8.7) globalid (>= 0.3.6) - activemodel (7.0.8.4) - activesupport (= 7.0.8.4) - activerecord (7.0.8.4) - activemodel (= 7.0.8.4) - activesupport (= 7.0.8.4) - activestorage (7.0.8.4) - actionpack (= 7.0.8.4) - activejob (= 7.0.8.4) - activerecord (= 7.0.8.4) - activesupport (= 7.0.8.4) + activemodel (7.0.8.7) + activesupport (= 7.0.8.7) + activerecord (7.0.8.7) + activemodel (= 7.0.8.7) + activesupport (= 7.0.8.7) + activestorage (7.0.8.7) + actionpack (= 7.0.8.7) + activejob (= 7.0.8.7) + activerecord (= 7.0.8.7) + activesupport (= 7.0.8.7) marcel (~> 1.0) mini_mime (>= 1.1.0) activestorage-openstack (1.6.0) fog-openstack (>= 1.0.9) marcel rails (>= 5.2.2) - activesupport (7.0.8.4) + activesupport (7.0.8.7) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) administrate (0.20.1) actionpack (>= 6.0, < 8.0) actionview (>= 6.0, < 8.0) @@ -104,39 +105,41 @@ GEM administrate-field-enum (0.0.9) administrate (~> 0.12) aes_key_wrap (1.1.0) - after_commit_everywhere (1.4.0) + after_commit_everywhere (1.5.0) activerecord (>= 4.2) activesupport - after_party (1.11.2) + after_party (2.0.0) ancestry (4.3.3) activerecord (>= 5.2.6) anchored (1.1.0) - anyway_config (2.6.3) + anyway_config (2.6.4) ruby-next-core (~> 1.0) ast (2.4.2) - attr_required (1.0.1) + attr_required (1.0.2) aws-eventstream (1.3.0) - aws-partitions (1.916.0) - aws-sdk-core (3.192.1) + aws-partitions (1.1020.0) + aws-sdk-core (3.214.0) aws-eventstream (~> 1, >= 1.3.0) - aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.8) + aws-partitions (~> 1, >= 1.992.0) + aws-sigv4 (~> 1.9) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.79.0) - aws-sdk-core (~> 3, >= 3.191.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.147.0) - aws-sdk-core (~> 3, >= 3.192.0) + aws-sdk-kms (1.96.0) + aws-sdk-core (~> 3, >= 3.210.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.176.0) + aws-sdk-core (~> 3, >= 3.210.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.8) - aws-sigv4 (1.8.0) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.10.1) aws-eventstream (~> 1, >= 1.0.2) - axe-core-api (4.8.1) + axe-core-api (4.10.2) dumb_delegator + ostruct virtus - axe-core-rspec (4.8.2) - axe-core-api + axe-core-rspec (4.10.2) + axe-core-api (= 4.10.2) dumb_delegator + ostruct virtus axiom-types (0.1.1) descendants_tracker (~> 0.0.4) @@ -144,23 +147,16 @@ GEM thread_safe (~> 0.3, >= 0.3.1) base64 (0.2.0) bcrypt (3.1.20) - benchmark-ips (2.13.0) - better_html (2.0.2) - actionview (>= 6.0) - activesupport (>= 6.0) - ast (~> 2.0) - erubi (~> 1.4) - parser (>= 2.4) - smart_properties + benchmark-ips (2.14.0) bigdecimal (3.1.8) bindata (2.5.0) bindex (0.8.1) - bootsnap (1.18.3) + bootsnap (1.18.4) msgpack (~> 1.2) - brakeman (6.1.2) + brakeman (6.2.2) racc - browser (5.3.1) - builder (3.2.4) + browser (6.2.0) + builder (3.3.0) capybara (3.40.0) addressable matrix @@ -183,33 +179,39 @@ GEM marcel (~> 1.0) nokogiri (~> 1.10, >= 1.10.4) rubyzip (>= 1.3.0, < 3) - charlock_holmes (0.7.7) - chartkick (5.0.6) + charlock_holmes (0.7.9) + chartkick (5.1.2) + childprocess (5.1.0) + logger (~> 1.5) choice (0.2.0) chunky_png (1.4.0) clamav-client (3.2.0) cmdparse (3.0.7) coercible (1.0.0) descendants_tracker (~> 0.0.1) - concurrent-ruby (1.3.1) + concurrent-ruby (1.3.4) connection_pool (2.4.1) content_disposition (1.0.0) crack (1.0.0) bigdecimal rexml crass (1.0.6) - css_parser (1.16.0) + cronex (0.15.0) + tzinfo + unicode (>= 0.4.4.5) + css_parser (1.19.1) addressable + csv (3.3.0) daemons (1.4.1) - date (3.3.4) - deep_cloneable (3.2.0) - activerecord (>= 3.1.0, < 8) + date (3.4.1) + deep_cloneable (3.2.1) + activerecord (>= 3.1.0, < 9) delayed_cron_job (0.9.0) fugit (>= 1.5) - delayed_job (4.1.11) - activesupport (>= 3.0, < 8.0) - delayed_job_active_record (4.1.8) - activerecord (>= 3.0, < 8.0) + delayed_job (4.1.13) + activesupport (>= 3.0, < 9.0) + delayed_job_active_record (4.1.11) + activerecord (>= 3.0, < 9.0) delayed_job (>= 3.0, < 5) delayed_job_web (1.4.4) activerecord (> 3.0.0) @@ -224,24 +226,25 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) - devise-i18n (1.12.0) + devise-i18n (1.12.1) devise (>= 4.9.0) - devise-two-factor (5.0.0) - activesupport (~> 7.0) + devise-two-factor (6.1.0) + activesupport (>= 7.0, < 8.1) devise (~> 4.0) - railties (~> 7.0) + railties (>= 7.0, < 8.1) rotp (~> 6.0) diff-lcs (1.5.1) - discard (1.3.0) - activerecord (>= 4.2, < 8) - docile (1.4.0) - dotenv (2.8.1) - dotenv-rails (2.8.1) - dotenv (= 2.8.1) - railties (>= 3.2) - dry-cli (1.0.0) - dry-core (1.0.1) + discard (1.4.0) + activerecord (>= 4.2, < 9.0) + docile (1.4.1) + dotenv (3.1.4) + dotenv-rails (3.1.4) + dotenv (= 3.1.4) + railties (>= 6.1) + dry-cli (1.2.0) + dry-core (1.0.2) concurrent-ruby (~> 1.0) + logger zeitwerk (~> 2.6) dry-initializer (3.1.1) dry-monads (1.6.0) @@ -251,56 +254,70 @@ GEM dumb_delegator (1.0.0) email_validator (2.2.4) activemodel - erubi (1.12.0) + erubi (1.13.0) et-orbi (1.2.11) tzinfo ethon (0.16.0) ffi (>= 1.15.0) - excon (0.109.0) - factory_bot (6.4.6) + excon (1.2.2) + factory_bot (6.5.0) activesupport (>= 5.0.0) - faraday (2.9.0) - faraday-net_http (>= 2.0, < 3.2) + faraday (2.12.2) + faraday-net_http (>= 2.0, < 3.5) + json + logger faraday-follow_redirects (0.3.0) faraday (>= 1, < 3) faraday-jwt (0.1.0) faraday (~> 2.0) json-jwt (~> 1.16) - faraday-net_http (3.1.0) - net-http - ffi (1.16.3) - flipper (1.2.2) + faraday-net_http (3.4.0) + net-http (>= 0.5.0) + ffi (1.17.0-aarch64-linux-gnu) + ffi (1.17.0-aarch64-linux-musl) + ffi (1.17.0-arm-linux-gnu) + ffi (1.17.0-arm-linux-musl) + ffi (1.17.0-arm64-darwin) + ffi (1.17.0-x86-linux-gnu) + ffi (1.17.0-x86-linux-musl) + ffi (1.17.0-x86_64-darwin) + ffi (1.17.0-x86_64-linux-gnu) + ffi (1.17.0-x86_64-linux-musl) + flipper (1.3.2) concurrent-ruby (< 2) - flipper-active_record (1.2.2) - activerecord (>= 4.2, < 8) - flipper (~> 1.2.2) - flipper-active_support_cache_store (1.2.2) - activesupport (>= 4.2, < 8) - flipper (~> 1.2.2) - flipper-ui (1.2.2) + flipper-active_record (1.3.2) + activerecord (>= 4.2, < 9) + flipper (~> 1.3.2) + flipper-active_support_cache_store (1.3.2) + activesupport (>= 4.2, < 9) + flipper (~> 1.3.2) + flipper-ui (1.3.2) erubi (>= 1.0.0, < 2.0.0) - flipper (~> 1.2.2) + flipper (~> 1.3.2) rack (>= 1.4, < 4) - rack-protection (>= 1.5.3, <= 4.0.0) + rack-protection (>= 1.5.3, < 5.0.0) + rack-session (>= 1.0.2, < 3.0.0) sanitize (< 7) - fog-core (2.4.0) + fog-core (2.6.0) builder - excon (~> 0.71) + excon (~> 1.0) formatador (>= 0.2, < 2.0) mime-types fog-json (1.2.0) fog-core multi_json (~> 1.10) - fog-openstack (1.1.0) + fog-openstack (1.1.3) fog-core (~> 2.1) fog-json (>= 1.0) formatador (1.1.0) front_matter_parser (1.0.1) - fugit (1.10.1) - et-orbi (~> 1, >= 1.2.7) + fugit (1.11.1) + et-orbi (~> 1, >= 1.2.11) raabro (~> 1.4) geo_coord (0.2.0) - geocoder (1.8.2) + geocoder (1.8.4) + base64 (>= 0.1.0) + csv (>= 3.0.0) geom2d (0.4.1) globalid (1.2.1) activesupport (>= 6.1) @@ -313,17 +330,17 @@ GEM graphql-batch (0.5.1) graphql (>= 1.10, < 3) promise.rb (~> 0.7.2) - graphql-rails_logger (1.2.4) + graphql-rails_logger (1.2.5) actionpack (> 5.0) activesupport (> 5.0) railties (> 5.0) - rouge (~> 3.0) + rouge (>= 3.0) graphql-schema_comparator (1.2.1) bundler (>= 1.14) graphql (>= 1.10, < 3.0) thor (>= 0.19, < 2.0) - groupdate (6.4.0) - activesupport (>= 6.1) + groupdate (6.5.1) + activesupport (>= 7) haml (6.3.0) temple (>= 0.8.2) thor @@ -335,28 +352,28 @@ GEM activesupport (>= 5.1) haml (>= 4.0.6) railties (>= 5.1) - haml_lint (0.56.0) + haml_lint (0.59.0) haml (>= 5.0) parallel (~> 1.10) rainbow rubocop (>= 1.0) sysexits (~> 1.1) hana (1.3.7) - hashdiff (1.1.0) + hashdiff (1.1.2) hashie (5.0.0) - hexapdf (0.40.0) + hexapdf (1.0.3) cmdparse (~> 3.0, >= 3.0.3) geom2d (~> 0.4, >= 0.4.1) openssl (>= 2.2.1) - highline (3.0.1) + highline (3.1.1) + reline htmlentities (4.3.4) http_accept_language (2.1.1) - i18n (1.14.5) + i18n (1.14.6) concurrent-ruby (~> 1.0) - i18n-tasks (1.0.13) + i18n-tasks (1.0.14) activesupport (>= 4.0.2) ast (>= 2.1.0) - better_html (>= 1.0, < 3.0) erubi highline (>= 2.0.0) i18n @@ -364,41 +381,39 @@ GEM rails-i18n rainbow (>= 2.2.2, < 4.0) terminal-table (>= 1.5.1) - i18n_data (0.13.0) + i18n_data (1.1.0) + simple_po_parser (~> 1.1) iban-tools (1.2.1) ice_nine (0.11.2) - image_processing (1.12.2) - mini_magick (>= 4.9.5, < 5) - ruby-vips (>= 2.0.17, < 3) - invisible_captcha (2.2.0) + image_processing (0.11.2) + invisible_captcha (2.3.0) rails (>= 5.2) - io-console (0.7.2) - irb (1.12.0) - rdoc + io-console (0.8.0) + irb (1.14.1) + rdoc (>= 4.0.0) reline (>= 0.4.2) jmespath (1.6.2) - job-iteration (1.4.1) + job-iteration (1.8.0) activejob (>= 5.2) jquery-rails (4.6.0) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (2.7.2) - json-jwt (1.16.6) + json (2.9.0) + json-jwt (1.16.7) activesupport (>= 4.2) aes_key_wrap base64 bindata faraday (~> 2.0) faraday-follow_redirects - json_schemer (2.2.1) - base64 + json_schemer (2.3.0) bigdecimal hana (~> 1.3) regexp_parser (~> 2.0) simpleidn (~> 0.2) jsonapi-renderer (0.2.2) - jwt (2.8.1) + jwt (2.9.3) base64 kaminari (1.2.2) activesupport (>= 4.1.0) @@ -417,25 +432,27 @@ GEM activesupport (>= 6.0.0) redis (>= 4.2, < 6) language_server-protocol (3.17.0.3) - launchy (2.5.2) + launchy (3.0.1) addressable (~> 2.8) - letter_opener (1.9.0) - launchy (>= 2.2, < 3) - letter_opener_web (2.0.0) - actionmailer (>= 5.2) - letter_opener (~> 1.7) - railties (>= 5.2) + childprocess (~> 5.0) + letter_opener (1.10.0) + launchy (>= 2.2, < 4) + letter_opener_web (3.0.0) + actionmailer (>= 6.1) + letter_opener (~> 1.9) + railties (>= 6.1) rexml listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) + logger (1.6.2) lograge (0.14.0) actionpack (>= 4) activesupport (>= 4) railties (>= 4) request_store (~> 1.0) logstash-event (1.2.02) - loofah (2.22.0) + loofah (2.23.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.8.1) @@ -443,32 +460,35 @@ GEM net-imap net-pop net-smtp - maintenance_tasks (2.7.0) - actionpack (>= 6.0) - activejob (>= 6.0) - activerecord (>= 6.0) + maintenance_tasks (2.10.0) + actionpack (>= 6.1) + activejob (>= 6.1) + activerecord (>= 6.1) + csv job-iteration (>= 1.3.6) - railties (>= 6.0) + railties (>= 6.1) zeitwerk (>= 2.6.2) marcel (1.0.4) matrix (0.4.2) - memory_profiler (1.0.1) + memory_profiler (1.1.0) method_source (1.1.0) - mime-types (3.5.2) + mime-types (3.6.0) + logger mime-types-data (~> 3.2015) - mime-types-data (3.2024.0206) + mime-types-data (3.2024.1203) mina (1.2.5) rake - mini_magick (4.12.0) + mini_magick (5.0.1) mini_mime (1.1.5) - minitest (5.23.1) - msgpack (1.7.2) + minitest (5.25.4) + msgpack (1.7.5) multi_json (1.15.0) - mustermann (3.0.0) + mustermann (3.0.3) ruby2_keywords (~> 0.0.1) - net-http (0.4.1) + mutex_m (0.3.0) + net-http (0.6.0) uri - net-imap (0.4.12) + net-imap (0.5.1) date net-protocol net-pop (0.1.2) @@ -477,10 +497,20 @@ GEM timeout net-smtp (0.5.0) net-protocol - nio4r (2.7.3) - nokogiri (1.16.5-x86_64-linux) + nio4r (2.7.4) + nokogiri (1.17.1-aarch64-linux) + racc (~> 1.4) + nokogiri (1.17.1-arm-linux) + racc (~> 1.4) + nokogiri (1.17.1-arm64-darwin) + racc (~> 1.4) + nokogiri (1.17.1-x86-linux) racc (~> 1.4) - openid_connect (2.3.0) + nokogiri (1.17.1-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.17.1-x86_64-linux) + racc (~> 1.4) + openid_connect (2.3.1) activemodel attr_required (>= 1.0.0) email_validator @@ -495,46 +525,50 @@ GEM webfinger (~> 2.0) openssl (3.2.0) orm_adapter (0.5.0) - parallel (1.24.0) + ostruct (0.6.1) + parallel (1.26.3) parsby (1.1.1) - parser (3.3.0.5) + parser (3.3.6.0) ast (~> 2.4.1) racc pdf-core (0.9.0) - pg (1.5.6) - phonelib (0.8.8) + pg (1.5.9) + phonelib (0.10.1) prawn (2.4.0) pdf-core (~> 0.9.0) ttfunk (~> 1.7) prawn-qrcode (0.5.2) prawn (>= 1) rqrcode (>= 1.0.0) - prawn-rails (1.4.2) + prawn-rails (1.5.0) actionview (>= 3.1.0) + activesupport (>= 3.1.0) prawn prawn-table prawn-table (0.2.2) prawn (>= 1.3.0, < 3.0.0) - premailer (1.22.0) + premailer (1.27.0) addressable - css_parser (>= 1.12.0) + css_parser (>= 1.19.0) htmlentities (>= 4.0.0) premailer-rails (1.12.0) actionmailer (>= 3) net-smtp premailer (~> 1.7, >= 1.7.9) - prometheus-client (4.2.2) + prometheus-client (4.2.3) + base64 promise.rb (0.7.4) - psych (5.1.2) + psych (5.2.1) + date stringio - public_suffix (5.0.5) - puma (6.4.2) + public_suffix (6.0.1) + puma (6.5.0) nio4r (~> 2.0) - pundit (2.3.1) + pundit (2.4.0) activesupport (>= 3.0.0) raabro (1.4.0) - racc (1.8.0) - rack (2.2.9) + racc (1.8.1) + rack (2.2.10) rack-attack (6.7.0) rack (>= 1.0, < 4) rack-mini-profiler (3.3.1) @@ -551,25 +585,27 @@ GEM rack (~> 2.2, >= 2.2.4) rack-proxy (0.7.7) rack + rack-session (1.0.2) + rack (< 3) rack-test (2.1.0) rack (>= 1.3) rack_session_access (0.2.0) builder (>= 2.0.0) rack (>= 1.0.0) - rails (7.0.8.4) - actioncable (= 7.0.8.4) - actionmailbox (= 7.0.8.4) - actionmailer (= 7.0.8.4) - actionpack (= 7.0.8.4) - actiontext (= 7.0.8.4) - actionview (= 7.0.8.4) - activejob (= 7.0.8.4) - activemodel (= 7.0.8.4) - activerecord (= 7.0.8.4) - activestorage (= 7.0.8.4) - activesupport (= 7.0.8.4) + rails (7.0.8.7) + actioncable (= 7.0.8.7) + actionmailbox (= 7.0.8.7) + actionmailer (= 7.0.8.7) + actionpack (= 7.0.8.7) + actiontext (= 7.0.8.7) + actionview (= 7.0.8.7) + activejob (= 7.0.8.7) + activemodel (= 7.0.8.7) + activerecord (= 7.0.8.7) + activestorage (= 7.0.8.7) + activesupport (= 7.0.8.7) bundler (>= 1.15.0) - railties (= 7.0.8.4) + railties (= 7.0.8.7) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -583,18 +619,18 @@ GEM activesupport (>= 4.2) choice (~> 0.2.0) ruby-graphviz (~> 1.2) - rails-html-sanitizer (1.6.0) + rails-html-sanitizer (1.6.1) loofah (~> 2.21) - nokogiri (~> 1.14) - rails-i18n (7.0.9) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + rails-i18n (7.0.10) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - rails-pg-extras (5.3.1) + rails-pg-extras (5.4.5) rails - ruby-pg-extras (= 5.3.1) - railties (7.0.8.4) - actionpack (= 7.0.8.4) - activesupport (= 7.0.8.4) + ruby-pg-extras (= 5.4.5) + railties (7.0.8.7) + actionpack (= 7.0.8.7) + activesupport (= 7.0.8.7) method_source rake (>= 12.2) thor (~> 1.0) @@ -603,96 +639,83 @@ GEM rake (13.2.1) rake-progressbar (0.0.5) rb-fsevent (0.11.2) - rb-inotify (0.10.1) + rb-inotify (0.11.1) ffi (~> 1.0) - rdoc (6.6.3.1) + rdoc (6.8.1) psych (>= 4.0.0) redcarpet (3.6.0) - redis (5.2.0) + redis (5.3.0) redis-client (>= 0.22.0) - redis-client (0.22.1) + redis-client (0.23.0) connection_pool - regexp_parser (2.9.0) - reline (0.5.3) + regexp_parser (2.9.3) + reline (0.5.12) io-console (~> 0.5) - request_store (1.5.1) + request_store (1.7.0) rack (>= 1.4) responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) - rexml (3.2.7) - strscan (>= 3.0.9) + rexml (3.3.9) rodf (1.2.0) builder (>= 3.0) rubyzip (>= 1.0) rotp (6.3.0) - rouge (3.30.0) + rouge (4.5.1) rqrcode (2.2.0) chunky_png (~> 1.0) rqrcode_core (~> 1.0) rqrcode_core (1.2.0) - rspec-core (3.13.0) + rspec-core (3.13.2) rspec-support (~> 3.13.0) - rspec-expectations (3.13.0) + rspec-expectations (3.13.3) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-mocks (3.13.0) + rspec-mocks (3.13.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (6.1.2) - actionpack (>= 6.1) - activesupport (>= 6.1) - railties (>= 6.1) + rspec-rails (7.1.0) + actionpack (>= 7.0) + activesupport (>= 7.0) + railties (>= 7.0) rspec-core (~> 3.13) rspec-expectations (~> 3.13) rspec-mocks (~> 3.13) rspec-support (~> 3.13) rspec-retry (0.6.2) rspec-core (> 3.3) - rspec-support (3.13.1) + rspec-support (3.13.2) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.63.3) + rubocop (1.69.1) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.31.1, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.36.2, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.31.2) - parser (>= 3.3.0.4) - rubocop-capybara (2.20.0) - rubocop (~> 1.41) - rubocop-factory_bot (2.25.1) - rubocop (~> 1.41) - rubocop-performance (1.21.0) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.36.2) + parser (>= 3.3.1.0) + rubocop-performance (1.23.0) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rails (2.24.1) + rubocop-rails (2.27.0) activesupport (>= 4.2.0) rack (>= 1.1) - rubocop (>= 1.33.0, < 2.0) + rubocop (>= 1.52.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (2.29.1) - rubocop (~> 1.40) - rubocop-capybara (~> 2.17) - rubocop-factory_bot (~> 2.22) - rubocop-rspec_rails (~> 2.28) - rubocop-rspec_rails (2.28.3) - rubocop (~> 1.40) + rubocop-rspec (3.2.0) + rubocop (~> 1.61) ruby-graphviz (1.2.5) rexml - ruby-next-core (1.0.2) - ruby-pg-extras (5.3.1) + ruby-next-core (1.0.3) + ruby-pg-extras (5.4.5) pg terminal-table ruby-progressbar (1.13.0) - ruby-vips (2.2.0) - ffi (~> 1.12) ruby2_keywords (0.0.5) rubyzip (2.3.2) saml_idp (0.16.0) @@ -701,7 +724,7 @@ GEM nokogiri (>= 1.6.2) rexml xmlenc (>= 0.7.1) - sanitize (6.1.0) + sanitize (6.1.3) crass (~> 1.0.2) nokogiri (>= 1.12.0) sass (3.7.4) @@ -720,41 +743,44 @@ GEM scss_lint (0.60.0) sass (~> 3.5, >= 3.5.5) selectize-rails (0.12.6) - selenium-devtools (0.123.0) + selenium-devtools (0.131.0) selenium-webdriver (~> 4.2) - selenium-webdriver (4.19.0) + selenium-webdriver (4.27.0) base64 (~> 0.2) + logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - sentry-delayed_job (5.17.3) + sentry-delayed_job (5.22.0) delayed_job (>= 4.0) - sentry-ruby (~> 5.17.3) - sentry-rails (5.17.3) + sentry-ruby (~> 5.22.0) + sentry-rails (5.22.0) railties (>= 5.0) - sentry-ruby (~> 5.17.3) - sentry-ruby (5.17.3) + sentry-ruby (~> 5.22.0) + sentry-ruby (5.22.0) bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) - sentry-sidekiq (5.17.3) - sentry-ruby (~> 5.17.3) + sentry-sidekiq (5.22.0) + sentry-ruby (~> 5.22.0) sidekiq (>= 3.0) - shoulda-matchers (6.2.0) + shoulda-matchers (6.4.0) activesupport (>= 5.2.0) sib-api-v3-sdk (9.1.0) addressable (~> 2.3, >= 2.3.0) json (~> 2.1, >= 2.1.0) typhoeus (~> 1.0, >= 1.0.1) - sidekiq (7.2.4) - concurrent-ruby (< 2) + sidekiq (7.3.6) connection_pool (>= 2.3.0) + logger rack (>= 2.2.4) - redis-client (>= 0.19.0) - sidekiq-cron (1.12.0) - fugit (~> 1.8) + redis-client (>= 0.22.2) + sidekiq-cron (2.0.1) + cronex (>= 0.13.0) + fugit (~> 1.8, >= 1.11.1) globalid (>= 1.0.1) - sidekiq (>= 6) - simple_xlsx_reader (1.0.4) + sidekiq (>= 6.5.0) + simple_po_parser (1.1.6) + simple_xlsx_reader (5.0.0) nokogiri rubyzip simplecov (0.22.0) @@ -764,10 +790,9 @@ GEM simplecov-cobertura (2.1.0) rexml simplecov (~> 0.19) - simplecov-html (0.12.3) + simplecov-html (0.13.1) simplecov_json_formatter (0.1.4) - simpleidn (0.2.1) - unf (~> 0.1.4) + simpleidn (0.2.3) sinatra (3.2.0) mustermann (~> 3.0) rack (~> 2.2, >= 2.2.4) @@ -775,8 +800,7 @@ GEM tilt (~> 2.0) skylight (6.0.4) activesupport (>= 5.2.0) - smart_properties (1.17.0) - spreadsheet_architect (5.0.0) + spreadsheet_architect (5.0.1) caxlsx (>= 3.3.0, < 4) rodf (>= 1.0.0, < 2) spring (4.2.1) @@ -785,15 +809,14 @@ GEM sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) + sprockets-rails (3.5.2) + actionpack (>= 6.1) + activesupport (>= 6.1) sprockets (>= 3.0.0) stackprof (0.2.26) - stringio (3.1.0) - strong_migrations (1.8.0) - activerecord (>= 5.2) - strscan (3.1.0) + stringio (3.1.2) + strong_migrations (2.1.0) + activerecord (>= 6.1) swd (2.0.3) activesupport (>= 3) attr_required (>= 0.0.5) @@ -802,46 +825,48 @@ GEM sys-proctable (1.3.0) ffi (~> 1.1) sysexits (1.2.0) - temple (0.8.2) - terminal-table (3.0.2) - unicode-display_width (>= 1.1.1, < 3) - thor (1.3.1) + temple (0.10.3) + terminal-table (1.6.0) + thor (1.3.2) thread_safe (0.3.6) - tilt (2.3.0) - timecop (0.9.8) - timeout (0.4.1) - ttfunk (1.7.0) - turbo-rails (2.0.5) + tilt (2.4.0) + timecop (0.9.10) + timeout (0.4.2) + ttfunk (1.8.0) + bigdecimal (~> 3.1) + turbo-rails (2.0.11) actionpack (>= 6.0.0) - activejob (>= 6.0.0) railties (>= 6.0.0) typhoeus (1.4.1) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) ulid-ruby (1.0.2) - unf (0.1.4) - unf_ext - unf_ext (0.0.9.1) - unicode-display_width (2.5.0) - uri (0.13.0) + unicode (0.4.4.5) + unicode-display_width (3.1.2) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) + uri (1.0.2) validate_url (1.0.15) activemodel (>= 3.0.0) public_suffix - vcr (6.2.0) - view_component (3.12.1) - activesupport (>= 5.2.0, < 8.0) + vcr (6.3.1) + base64 + view_component (3.20.0) + activesupport (>= 5.2.0, < 8.1) concurrent-ruby (~> 1.0) method_source (~> 1.0) virtus (2.0.0) axiom-types (~> 0.1) coercible (~> 1.0) descendants_tracker (~> 0.0, >= 0.0.3) - vite_rails (3.0.17) - railties (>= 5.1, < 8) + vite_rails (3.0.19) + railties (>= 5.1, < 9) vite_ruby (~> 3.0, >= 3.2.2) - vite_ruby (3.5.0) + vite_ruby (3.9.1) dry-cli (>= 0.7, < 2) + logger (~> 1.6) + mutex_m rack-proxy (~> 0.6, >= 0.6.1) zeitwerk (~> 2.2) warden (1.2.9) @@ -855,12 +880,12 @@ GEM activesupport faraday (~> 2.0) faraday-follow_redirects - webmock (3.23.0) + webmock (3.24.0) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - webrick (1.8.1) - websocket (1.2.10) + webrick (1.9.1) + websocket (1.2.11) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) @@ -873,7 +898,7 @@ GEM nokogiri (~> 1.11) xpath (3.2.0) nokogiri (~> 1.8) - yabeda (0.12.0) + yabeda (0.13.1) anyway_config (>= 1.0, < 3) concurrent-ruby dry-initializer @@ -897,16 +922,29 @@ GEM anyway_config (>= 1.3, < 3) sidekiq yabeda (~> 0.6) - zeitwerk (2.6.15) - zip_tricks (5.6.0) - zipline (1.5.0) + zeitwerk (2.7.1) + zip_kit (6.3.1) + zipline (2.0.0) actionpack (>= 6.0, < 8.0) content_disposition (~> 1.0) - zip_tricks (>= 4.2.1, < 6.0) + zip_kit (~> 6, >= 6.2.0, < 7) zxcvbn-ruby (1.2.0) PLATFORMS + aarch64-linux + aarch64-linux-gnu + aarch64-linux-musl + arm-linux + arm-linux-gnu + arm-linux-musl + arm64-darwin + x86-linux + x86-linux-gnu + x86-linux-musl + x86_64-darwin x86_64-linux + x86_64-linux-gnu + x86_64-linux-musl DEPENDENCIES aasm diff --git a/app/components/editable_champ/lexpol_component.rb b/app/components/editable_champ/lexpol_component.rb new file mode 100644 index 00000000000..a1bc213ebf2 --- /dev/null +++ b/app/components/editable_champ/lexpol_component.rb @@ -0,0 +1,2 @@ +class EditableChamp::LexpolComponent < EditableChamp::EditableChampBaseComponent +end diff --git a/app/components/editable_champ/lexpol_component/lexpol_component.html.haml b/app/components/editable_champ/lexpol_component/lexpol_component.html.haml new file mode 100644 index 00000000000..1d67e1e3db8 --- /dev/null +++ b/app/components/editable_champ/lexpol_component/lexpol_component.html.haml @@ -0,0 +1,15 @@ +-# %div.lexpol-champ +-# - if @champ.value.blank? +-# = form_with url: lexpol_create_dossier_instructeur_dossier_path(@champ.dossier.revision.procedure.id, @champ.dossier.id, champ_id: @champ.id), method: :post do |form| +-# = form.submit 'Créer le dossier dans LexPol', class: 'fr-btn' +-# - else +-# %p +-# %strong Numéro NOR : +-# = @champ.value +-# %p +-# %strong Statut du dossier : +-# = @champ.lexpol_status +-# - if @champ.lexpol_dossier_url.present? +-# = link_to 'Aller sur LexPol', @champ.lexpol_dossier_url, target: '_blank', class: 'fr-btn fr-btn--secondary' +-# = form_with url: lexpol_update_dossier_instructeur_dossier_path(@champ.dossier.revision.procedure.id, @champ.dossier.id, champ_id: @champ.id), method: :post do |form| +-# = form.submit 'Mettre à jour le dossier', class: 'fr-btn fr-btn--secondary' diff --git a/app/components/types_de_champ_editor/champ_component.rb b/app/components/types_de_champ_editor/champ_component.rb index c8967cd9bac..3a0820d6c4d 100644 --- a/app/components/types_de_champ_editor/champ_component.rb +++ b/app/components/types_de_champ_editor/champ_component.rb @@ -8,6 +8,18 @@ def initialize(coordinate:, upper_coordinates:, focused: false, errors: '') @errors = errors end + def lexpol_models + @lexpol_models ||= begin + api = APILexpol.new + models_response = api.get_models + models = models_response['modeles'] + models.map { |model| [model['libelle'], model['modele']] } + rescue => e + Rails.logger.error("Erreur lors de la récupération des modèles LexPol : #{e.message}") + [] + end + end + private delegate :type_de_champ, :revision, :procedure, to: :coordinate diff --git a/app/components/types_de_champ_editor/champ_component/champ_component.html.haml b/app/components/types_de_champ_editor/champ_component/champ_component.html.haml index 9229d77d30d..98e5d2ac1f2 100644 --- a/app/components/types_de_champ_editor/champ_component/champ_component.html.haml +++ b/app/components/types_de_champ_editor/champ_component/champ_component.html.haml @@ -45,6 +45,7 @@ = form.label :expression_reguliere_error_message, for: dom_id(type_de_champ, :expression_reguliere_error_message) do = t('.expression_reguliere.labels.error_message') = form.text_field :expression_reguliere_error_message, class: "fr-input small-margin small", id: dom_id(type_de_champ, :expression_reguliere_error_message) + - if !type_de_champ.header_section? && !type_de_champ.titre_identite? .cell.fr-mt-1w = form.label :description, "Description du champ (optionnel)", for: dom_id(type_de_champ, :description) @@ -64,8 +65,25 @@ .cell.fr-mt-1w = form.label :notice_explicative, "Notice explicative", for: dom_id(type_de_champ, :notice_explicative) = render Attachment::EditComponent.new(**notice_explicative_options) - - + - if type_de_champ.lexpol? + .cell.fr-mt-1w + = form.label :lexpol_modele, "Sélectionner un modèle Lexpol", class: 'flex-grow', for: dom_id(type_de_champ, :lexpol_modele) + - if lexpol_models.any? + = form.select :lexpol_modele, + lexpol_models.map { |model| [model.first, model.last] }, + { prompt: 'Sélectionnez un modèle' }, + { class: 'fr-select small-margin small width-100', id: dom_id(type_de_champ, :lexpol_modele) } + - else + .fr-message.fr-message--error + %p Aucune modèle disponible ou erreur lors de la récupération des modèles. + .cell.fr-mt-1w + = form.label :lexpol_mapping, "Variables Lexpol", class: 'flex-grow', for: dom_id(type_de_champ, :lexpol_mapping) + = form.text_area :lexpol_mapping, + value: type_de_champ.lexpol_mapping, + class: 'fr-input small-margin small width-100 resize-y', + rows: 3, + placeholder: "variables_mes_demarches=variable_lexpol\n...", + id: dom_id(type_de_champ, :lexpol_mapping) .flex.justify-start.fr-mt-1w -# ----- Polynesia options diff --git a/app/controllers/administrateurs/procedures_controller.rb b/app/controllers/administrateurs/procedures_controller.rb index 713a33958ff..7e9c4aa57fe 100644 --- a/app/controllers/administrateurs/procedures_controller.rb +++ b/app/controllers/administrateurs/procedures_controller.rb @@ -589,5 +589,16 @@ def allow_decision_access_params def cloned_from_library? params[:from_new_from_existing].present? end + + def update_lexpol(champ) + return unless champ.lexpol? + + if champ.value.blank? + champ.value = LexpolAPI.new.create_dossier(champ) + else + LexpolAPI.new.update_dossier(champ) + end + champ.save + end end end diff --git a/app/controllers/administrateurs/types_de_champ_controller.rb b/app/controllers/administrateurs/types_de_champ_controller.rb index b5b9680d1af..ab914c7f56b 100644 --- a/app/controllers/administrateurs/types_de_champ_controller.rb +++ b/app/controllers/administrateurs/types_de_champ_controller.rb @@ -166,6 +166,8 @@ def type_de_champ_update_params :expression_reguliere, :expression_reguliere_exemple_text, :expression_reguliere_error_message, + :lexpol_modele, + :lexpol_mapping, editable_options: [ *INSTANCE_EDITABLE_OPTIONS, *TypesDeChamp::CarteTypeDeChamp::LAYERS diff --git a/app/controllers/instructeurs/dossiers_controller.rb b/app/controllers/instructeurs/dossiers_controller.rb index c72d6462660..216845e0413 100644 --- a/app/controllers/instructeurs/dossiers_controller.rb +++ b/app/controllers/instructeurs/dossiers_controller.rb @@ -371,6 +371,51 @@ def pieces_jointes .filter { _1.class.in?([Champs::PieceJustificativeChamp, Champs::TitreIdentiteChamp]) } end + def create_lexpol_dossier + begin + api_lexpol = APILexpol.new + + nor = api_lexpol.create_dossier(598706) + + if nor.nil? + raise "Le numéro NOR n'a pas été trouvé dans la réponse de l'API." + end + + champ = Champ.find(params[:champ_id]) + champ.update!(value: nor) + flash[:notice] = "Dossier créé avec succès dans LexPol. Numéro NOR : #{nor}" + rescue => e + Rails.logger.error("Erreur lors de la création du dossier dans LexPol : #{e.message}") + flash[:alert] = "Erreur lors de la création du dossier dans LexPol : #{e.message}" + redirect_to request.referer || root_path + end + end + + def update_lexpol_dossier + dossier = Dossier.find(params[:dossier_id]) + champ = dossier.champs.find_by(id: params[:champ_id]) + + mapping = (champ.type_de_champ.lexpol_mapping || "") + .split(',') + .map { |pair| pair.split('=').map(&:strip) } + .to_h + + variables = dossier.champs.each_with_object({}) do |champ, hash| + next unless champ.value.present? && champ.type_de_champ&.libelle.present? + + mapped_key = mapping[champ.type_de_champ.libelle] || champ.type_de_champ.libelle + hash[mapped_key] = champ.value + end + + if champ&.lexpol_update_dossier(variables) + flash[:notice] = "Dossier LexPol mis à jour avec succès." + else + flash[:alert] = champ&.errors&.full_messages&.join(', ') || "Erreur lors de la mise à jour." + end + + redirect_to annotations_privees_instructeur_dossier_path(dossier.procedure, dossier.id) + end + private def checked_visa?(c) @@ -393,6 +438,10 @@ def dossier end end + def procedure + @procedure ||= dossier.procedure + end + def dossier_with_champs @dossier ||= DossierPreloader.load_one(dossier_scope.find(params[:dossier_id])) end @@ -419,6 +468,7 @@ def champs_private_params :code_departement, :accreditation_number, :accreditation_birthdate, + :lexpol, :feature, value: [] ] + TypeDeChamp::INSTANCE_CHAMPS_PARAMS diff --git a/app/controllers/instructeurs/lexpol_controller.rb b/app/controllers/instructeurs/lexpol_controller.rb new file mode 100644 index 00000000000..c4a850ed202 --- /dev/null +++ b/app/controllers/instructeurs/lexpol_controller.rb @@ -0,0 +1,29 @@ +module Instructeurs + class LexpolController < ApplicationController + before_action :authenticate_instructeur! + before_action :set_dossier_and_champ + + def create_dossier + if @champ.lexpol_create_dossier + redirect_to annotations_instructeur_dossier_path(@dossier.procedure, @dossier), notice: 'Dossier LexPol créé avec succès.' + else + redirect_to annotations_instructeur_dossier_path(@dossier.procedure, @dossier), alert: @champ.errors.full_messages.join(', ') + end + end + + def update_dossier + if @champ.lexpol_update_dossier + redirect_to annotations_instructeur_dossier_path(@dossier.procedure, @dossier), notice: 'Dossier LexPol mis à jour avec succès.' + else + redirect_to annotations_instructeur_dossier_path(@dossier.procedure, @dossier), alert: @champ.errors.full_messages.join(', ') + end + end + + private + + def set_dossier_and_champ + @dossier = Dossier.find(params[:dossier_id]) + @champ = @dossier.champs.find(params[:champ_id]) + end + end +end diff --git a/app/graphql/api/v2/schema.rb b/app/graphql/api/v2/schema.rb index 7ea4970f132..1e21aa07fdc 100644 --- a/app/graphql/api/v2/schema.rb +++ b/app/graphql/api/v2/schema.rb @@ -79,6 +79,7 @@ def self.resolve_type(type_definition, object, ctx) Types::Champs::TextChampType, Types::Champs::TitreIdentiteChampType, Types::Champs::VisaChampType, + Types::Champs::LexpolChampType, Types::Champs::EngagementJuridiqueChampType, Types::GeoAreas::ParcelleCadastraleType, Types::GeoAreas::SelectionUtilisateurType, @@ -128,6 +129,7 @@ def self.resolve_type(type_definition, object, ctx) Types::Champs::Descriptor::TextChampDescriptorType, Types::Champs::Descriptor::TitreIdentiteChampDescriptorType, Types::Champs::Descriptor::VisaChampDescriptorType, + Types::Champs::Descriptor::LexpolChampDescriptorType, Types::Champs::Descriptor::YesNoChampDescriptorType, Types::Champs::Descriptor::ExpressionReguliereChampDescriptorType, Types::Champs::Descriptor::EngagementJuridiqueChampDescriptorType diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index 131c8effca3..dd0d4484a26 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -3197,6 +3197,73 @@ type IntegerNumberChampDescriptor implements ChampDescriptor { type: TypeDeChamp! @deprecated(reason: "Utilisez le champ `__typename` à la place.") } +type LexpolChamp implements Champ { + """ + L'identifiant du champDescriptor de ce champ + """ + champDescriptorId: String! + + """ + Lien vers le dossier Lexpol + """ + dossierURL: String + id: ID! + + """ + Libellé du champ. + """ + label: String! + + """ + Numéro NOR du dossier Lexpol + """ + nor: String + prefilled: Boolean! + + """ + Statut du dossier Lexpol + """ + status: String + + """ + La valeur du champ sous forme texte. + """ + stringValue: String + + """ + Date de dernière modification du champ. + """ + updatedAt: ISO8601DateTime! +} + +type LexpolChampDescriptor implements ChampDescriptor { + """ + Description des champs d’un bloc répétable. + """ + champDescriptors: [ChampDescriptor!] @deprecated(reason: "Utilisez le champ `RepetitionChampDescriptor.champ_descriptors` à la place.") + + """ + Description du champ. + """ + description: String + id: ID! + + """ + Libellé du champ. + """ + label: String! + + """ + Est-ce que le champ est obligatoire ? + """ + required: Boolean! + + """ + Type de la valeur du champ. + """ + type: TypeDeChamp! @deprecated(reason: "Utilisez le champ `__typename` à la place.") +} + type LinkedDropDownListChamp implements Champ { """ L'identifiant du champDescriptor de ce champ @@ -4743,6 +4810,11 @@ enum TypeDeChamp { """ integer_number + """ + Lexpol + """ + lexpol + """ Deux menus déroulants liés """ diff --git a/app/graphql/schema.json b/app/graphql/schema.json index 32ad720855c..2c06ea32763 100644 --- a/app/graphql/schema.json +++ b/app/graphql/schema.json @@ -1594,6 +1594,11 @@ "name": "IntegerNumberChamp", "ofType": null }, + { + "kind": "OBJECT", + "name": "LexpolChamp", + "ofType": null + }, { "kind": "OBJECT", "name": "LinkedDropDownListChamp", @@ -1906,6 +1911,11 @@ "name": "IntegerNumberChampDescriptor", "ofType": null }, + { + "kind": "OBJECT", + "name": "LexpolChampDescriptor", + "ofType": null + }, { "kind": "OBJECT", "name": "LinkedDropDownListChampDescriptor", @@ -7044,6 +7054,42 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "dateDerniereModificationAnnotations", + "description": "Date de la dernière modification des annotations.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ISO8601DateTime", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "dateDerniereModificationChamps", + "description": "Date de la dernière modification des champs.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ISO8601DateTime", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "dateExpiration", "description": "Date d’expiration.", @@ -10375,6 +10421,124 @@ ], "possibleTypes": null }, + { + "kind": "INPUT_OBJECT", + "name": "DossierSupprimerMessageInput", + "description": "Autogenerated input type of DossierSupprimerMessage", + "fields": null, + "inputFields": [ + { + "name": "clientMutationId", + "description": "A unique identifier for the client performing the mutation.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "messageId", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "instructeurId", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "DossierSupprimerMessagePayload", + "description": "Autogenerated return type of DossierSupprimerMessage.", + "fields": [ + { + "name": "clientMutationId", + "description": "A unique identifier for the client performing the mutation.", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "errors", + "description": null, + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "ValidationError", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "message", + "description": null, + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "Message", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "DropDownListChampDescriptor", @@ -13992,6 +14156,294 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "LexpolChamp", + "description": null, + "fields": [ + { + "name": "champDescriptorId", + "description": "L'identifiant du champDescriptor de ce champ", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "dossierURL", + "description": "Lien vers le dossier Lexpol", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "label", + "description": "Libellé du champ.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "nor", + "description": "Numéro NOR du dossier Lexpol", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "prefilled", + "description": null, + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "status", + "description": "Statut du dossier Lexpol", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "stringValue", + "description": "La valeur du champ sous forme texte.", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "updatedAt", + "description": "Date de dernière modification du champ.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ISO8601DateTime", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + { + "kind": "INTERFACE", + "name": "Champ", + "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "LexpolChampDescriptor", + "description": null, + "fields": [ + { + "name": "champDescriptors", + "description": "Description des champs d’un bloc répétable.", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INTERFACE", + "name": "ChampDescriptor", + "ofType": null + } + } + }, + "isDeprecated": true, + "deprecationReason": "Utilisez le champ `RepetitionChampDescriptor.champ_descriptors` à la place." + }, + { + "name": "description", + "description": "Description du champ.", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "label", + "description": "Libellé du champ.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "required", + "description": "Est-ce que le champ est obligatoire ?", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": "Type de la valeur du champ.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "TypeDeChamp", + "ofType": null + } + }, + "isDeprecated": true, + "deprecationReason": "Utilisez le champ `__typename` à la place." + } + ], + "inputFields": null, + "interfaces": [ + { + "kind": "INTERFACE", + "name": "ChampDescriptor", + "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "LinkedDropDownListChamp", @@ -14508,6 +14960,20 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "discardedAt", + "description": null, + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "ISO8601DateTime", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "email", "description": null, @@ -15402,6 +15868,35 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "dossierSupprimerMessage", + "description": "Supprimer un message.", + "args": [ + { + "name": "input", + "description": "Parameters for DossierSupprimerMessage", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "DossierSupprimerMessageInput", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "OBJECT", + "name": "DossierSupprimerMessagePayload", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "groupeInstructeurAjouterInstructeurs", "description": "Ajouter des instructeurs à un groupe instructeur.", @@ -21208,6 +21703,12 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "lexpol", + "description": "Lexpol", + "isDeprecated": false, + "deprecationReason": null + }, { "name": "nationalites", "description": "Nationalités", diff --git a/app/graphql/types/champ_descriptor_type.rb b/app/graphql/types/champ_descriptor_type.rb index 803ca17d8ac..bf8223b56cc 100644 --- a/app/graphql/types/champ_descriptor_type.rb +++ b/app/graphql/types/champ_descriptor_type.rb @@ -116,6 +116,8 @@ def resolve_type(object, context) Types::Champs::Descriptor::EpciChampDescriptorType when TypeDeChamp.type_champs.fetch(:cojo) Types::Champs::Descriptor::COJOChampDescriptorType + when TypeDeChamp.type_champs.fetch(:lexpol) + Types::Champs::Descriptor::LexpolChampDescriptorType when TypeDeChamp.type_champs.fetch(:expression_reguliere) Types::Champs::Descriptor::ExpressionReguliereChampDescriptorType end diff --git a/app/graphql/types/champ_type.rb b/app/graphql/types/champ_type.rb index 642f73c418b..eaa984fa05b 100644 --- a/app/graphql/types/champ_type.rb +++ b/app/graphql/types/champ_type.rb @@ -90,6 +90,8 @@ def resolve_type(object, context) Types::Champs::TitreIdentiteChampType when ::Champs::VisaChamp Types::Champs::VisaChampType + when ::Champs::LexpolChamp + Types::Champs::LexpolChampType when ::Champs::EpciChamp Types::Champs::EpciChampType when ::Champs::RNAChamp diff --git a/app/graphql/types/champs/descriptor/lexpol_champ_descriptor_type.rb b/app/graphql/types/champs/descriptor/lexpol_champ_descriptor_type.rb new file mode 100644 index 00000000000..4ec3104776a --- /dev/null +++ b/app/graphql/types/champs/descriptor/lexpol_champ_descriptor_type.rb @@ -0,0 +1,5 @@ +module Types::Champs::Descriptor + class LexpolChampDescriptorType < Types::BaseObject + implements Types::ChampDescriptorType + end +end diff --git a/app/graphql/types/champs/lexpol_champ_type.rb b/app/graphql/types/champs/lexpol_champ_type.rb new file mode 100644 index 00000000000..f6c80abb4e1 --- /dev/null +++ b/app/graphql/types/champs/lexpol_champ_type.rb @@ -0,0 +1,11 @@ +module Types + module Champs + class LexpolChampType < Types::BaseObject + implements Types::ChampType + + field :nor, String, null: true, description: "Numéro NOR du dossier Lexpol", method: :value + field :status, String, null: true, description: "Statut du dossier Lexpol", method: :lexpol_status + field :dossier_url, String, null: true, description: "Lien vers le dossier Lexpol", method: :lexpol_dossier_url + end + end +end diff --git a/app/models/champ.rb b/app/models/champ.rb index daf2d9f10e3..46bfb2a7c54 100644 --- a/app/models/champ.rb +++ b/app/models/champ.rb @@ -1,6 +1,7 @@ class Champ < ApplicationRecord include ChampConditionalConcern include ChampsValidateConcern + include LexpolConcern belongs_to :dossier, inverse_of: false, touch: true, optional: false belongs_to :type_de_champ, inverse_of: :champ, optional: false @@ -51,6 +52,7 @@ class Champ < ApplicationRecord :mesri?, :rna?, :siret?, + :lexpol?, :carte?, :te_fenua?, :datetime?, diff --git a/app/models/champs/lexpol_champ.rb b/app/models/champs/lexpol_champ.rb new file mode 100644 index 00000000000..695ffa47979 --- /dev/null +++ b/app/models/champs/lexpol_champ.rb @@ -0,0 +1,11 @@ +class Champs::LexpolChamp < Champ + def generate_or_update_lexpol_dossier + if value.blank? + nor_number = APILexpol.new.create_dossier(model_id: '598706') + self.value = nor_number + else + APILexpol.new.update_dossier(nor_number: value) + end + save! + end +end diff --git a/app/models/concerns/lexpol_concern.rb b/app/models/concerns/lexpol_concern.rb new file mode 100644 index 00000000000..04df8cb5722 --- /dev/null +++ b/app/models/concerns/lexpol_concern.rb @@ -0,0 +1,44 @@ +module LexpolConcern + extend ActiveSupport::Concern + + def lexpol_create_dossier + lexpol_service = APILexpol.new + nor = lexpol_service.create_dossier(598706) + update(value: nor) + refresh_lexpol_data! + true + rescue => e + flash[:error] = "Erreur lors de la création du dossier : #{e.message}" + redirect_to request.referer || root_path + false + end + + def lexpol_update_dossier(variables) + return false if value.blank? + + lexpol_service = APILexpol.new + begin + lexpol_service.update_dossier(value, variables) + refresh_lexpol_data! + true + rescue => e + errors.add(:base, e.message) + false + end + end + + def refresh_lexpol_data! + return if value.blank? + + lexpol_service = APILexpol.new + status_info = lexpol_service.get_dossier_status(value) + dossier_info = lexpol_service.get_dossier_infos(value) + + self.data ||= {} + self.data['lexpol_status'] = status_info['libelle'] + self.data['lexpol_dossier_url'] = dossier_info['lienDossier'] + save! + rescue => e + errors.add(:base, "Impossible de rafraîchir les données Lexpol : #{e.message}") + end +end diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index 94b7bbec8f1..be37f3821e4 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -8,7 +8,8 @@ class TypeDeChamp < ApplicationRecord engagement_juridique: :engagement_juridique_type_de_champ, cojo: :cojo_type_de_champ, - expression_reguliere: :expression_reguliere_type_de_champ + expression_reguliere: :expression_reguliere_type_de_champ, + lexpol: :lexpol } MINIMUM_TEXTAREA_CHARACTER_LIMIT_LENGTH = 400 @@ -19,7 +20,8 @@ class TypeDeChamp < ApplicationRecord code_postal_de_polynesie: 'code_postal_de_polynesie', numero_dn: 'numero_dn', te_fenua: 'te_fenua', - visa: 'visa' + visa: 'visa', + lexpol: 'lexpol' } STRUCTURE = :structure @@ -39,7 +41,8 @@ class TypeDeChamp < ApplicationRecord code_postal_de_polynesie: LOCALISATION, numero_dn: REFERENTIEL_EXTERNE, te_fenua: REFERENTIEL_EXTERNE, - visa: STRUCTURE + visa: STRUCTURE, + lexpol: REFERENTIEL_EXTERNE } TYPE_DE_CHAMP_TO_CATEGORIE = { @@ -83,7 +86,8 @@ class TypeDeChamp < ApplicationRecord pole_emploi: REFERENTIEL_EXTERNE, mesri: REFERENTIEL_EXTERNE, cojo: REFERENTIEL_EXTERNE, - expression_reguliere: STANDARD + expression_reguliere: STANDARD, + lexpol: REFERENTIEL_EXTERNE }.merge(INSTANCE_TYPE_DE_CHAMP_TO_CATEGORIE) enum type_champs: { @@ -127,7 +131,8 @@ class TypeDeChamp < ApplicationRecord mesri: 'mesri', epci: 'epci', cojo: 'cojo', - expression_reguliere: 'expression_reguliere' + expression_reguliere: 'expression_reguliere', + lexpol: 'lexpol' }.merge(INSTANCE_TYPE_CHAMPS) INSTANCE_OPTIONS = [:parcelles, :batiments, :zones_manuelles, :min, :max, :level, :accredited_users] @@ -163,7 +168,9 @@ class TypeDeChamp < ApplicationRecord :expression_reguliere_error_message, :collapsible_explanation_enabled, :collapsible_explanation_text, - :header_section_level + :header_section_level, + :lexpol_modele, + :lexpol_mapping has_many :revision_types_de_champ, -> { revision_ordered }, class_name: 'ProcedureRevisionTypeDeChamp', dependent: :destroy, inverse_of: :type_de_champ has_one :revision_type_de_champ, -> { revision_ordered }, class_name: 'ProcedureRevisionTypeDeChamp', inverse_of: false @@ -461,6 +468,10 @@ def visa? type_champ == TypeDeChamp.type_champs.fetch(:visa) end + def lexpol? + type_champ == TypeDeChamp.type_champs.fetch(:lexpol) + end + def te_fenua? type_champ == TypeDeChamp.type_champs.fetch(:te_fenua) end @@ -721,7 +732,8 @@ def self.refresh_after_update?(type_champ) type_champs.fetch(:rna), type_champs.fetch(:siret), type_champs.fetch(:numero_dn), - type_champs.fetch(:te_fenua) + type_champs.fetch(:te_fenua), + type_champs.fetch(:lexpol) false else true diff --git a/app/models/types_de_champ/lexpol_type_de_champ.rb b/app/models/types_de_champ/lexpol_type_de_champ.rb new file mode 100644 index 00000000000..85df141d684 --- /dev/null +++ b/app/models/types_de_champ/lexpol_type_de_champ.rb @@ -0,0 +1,22 @@ +class TypesDeChamp::LexpolTypeDeChamp < TypesDeChamp::TypeDeChampBase + MODEL_ID = 598706 + + class << self + def champ_value_for_api(champ, version = 2) + champ.value + end + + def champ_value_for_export(champ, path = :value) + champ.value + end + end + + def lexpol_mapping + data && data['lexpol_mapping'] || "" + end + + def lexpol_mapping=(value) + self.data ||= {} + self.data['lexpol_mapping'] = value + end +end diff --git a/app/services/api_lexpol.rb b/app/services/api_lexpol.rb new file mode 100644 index 00000000000..21c8ad5c466 --- /dev/null +++ b/app/services/api_lexpol.rb @@ -0,0 +1,99 @@ +require 'typhoeus' +require 'json' + +class APILexpol + BASE_URL = ENV.fetch('API_LEXPOL_BASE_URL', 'https://devapilexpol.cloud.pf/api/v1/geda') + + def initialize + @credentials = { + email: ENV.fetch('API_LEXPOL_EMAIL'), + motdepasse: ENV.fetch('API_LEXPOL_PASSWORD'), + email_agent: ENV.fetch('API_LEXPOL_AGENT_EMAIL') + } + @token = nil + @token_expiration = nil + end + + def authenticate + return @token if @token && @token_expiration && @token_expiration > Time.zone.now + + if defined?(Rails) && Rails.cache + @token, @token_expiration = Rails.cache.fetch("lexpol_token", expires_in: 300) do + perform_authentication + end + else + @token, @token_expiration = perform_authentication + end + + @token + end + + def get_models + authenticate + response = Typhoeus.get("#{BASE_URL}/modeles", params: { jeton: @token }) + handle_response(response, 'Erreur lors de la récupération des modèles') do |body| + body + end + end + + def create_dossier(modele_id, variables = {}) + authenticate + params = { jeton: @token, modele: modele_id } + params[:variables] = variables if variables.present? + + response = Typhoeus.post("#{BASE_URL}/dossier", body: params.to_json, headers: { 'Content-Type' => 'application/json' }) + handle_response(response, 'Erreur lors de la création du dossier') do |body| + body['nor'] + end + end + + def update_dossier(nor, variables) + authenticate + response = Typhoeus.put("#{BASE_URL}/dossier/#{nor}/modifier", + body: { jeton: @token, variables: variables }.to_json, + headers: { 'Content-Type' => 'application/json' }) + handle_response(response, 'Erreur lors de la mise à jour du dossier') do |body| + body['nor'] + end + end + + def get_dossier_status(nor) + authenticate + response = Typhoeus.get("#{BASE_URL}/dossier/#{nor}/statut", params: { jeton: @token }) + handle_response(response, 'Erreur lors de la récupération du statut du dossier') do |body| + { statut: body['statut'], libelle: body['libelle'] } + end + end + + def get_dossier_infos(nor) + authenticate + response = Typhoeus.get("#{BASE_URL}/dossier/#{nor}/infos", params: { jeton: @token }) + handle_response(response, 'Erreur lors de la récupération des informations du dossier') do |body| + body + end + end + + private + + def perform_authentication + response = Typhoeus.post("#{BASE_URL}/authentification", + body: @credentials.to_json, + headers: { 'Content-Type' => 'application/json' }) + + if response.success? + body = JSON.parse(response.body) + [body['jeton'], Time.zone.now + 300] # 300 secondes = 5 minutes + else + raise "Erreur d'authentification LexPol : #{response.body}" + end + end + + def handle_response(response, error_message) + if response.success? + body = JSON.parse(response.body.force_encoding('UTF-8')) + yield(body) + else + raise "#{error_message} : #{response.body}" + end + end +end diff --git a/app/views/instructeurs/lexpol/create_dossier.turbo_stream.erb b/app/views/instructeurs/lexpol/create_dossier.turbo_stream.erb new file mode 100644 index 00000000000..082eb83fe16 --- /dev/null +++ b/app/views/instructeurs/lexpol/create_dossier.turbo_stream.erb @@ -0,0 +1,3 @@ +<%= turbo_stream.replace dom_id(@champ) do %> + <%= render EditableChamp::LexpolComponent.new(form: nil, champ: @champ) %> +<% end %> diff --git a/app/views/instructeurs/lexpol/update_dossier.turbo_stream.erb b/app/views/instructeurs/lexpol/update_dossier.turbo_stream.erb new file mode 100644 index 00000000000..082eb83fe16 --- /dev/null +++ b/app/views/instructeurs/lexpol/update_dossier.turbo_stream.erb @@ -0,0 +1,3 @@ +<%= turbo_stream.replace dom_id(@champ) do %> + <%= render EditableChamp::LexpolComponent.new(form: nil, champ: @champ) %> +<% end %> diff --git a/app/views/shared/champs/lexpol/_show.html.haml b/app/views/shared/champs/lexpol/_show.html.haml new file mode 100644 index 00000000000..df221cf403c --- /dev/null +++ b/app/views/shared/champs/lexpol/_show.html.haml @@ -0,0 +1,14 @@ +-# - if champ.value.blank? +-# = form_with url: create_lexpol_dossier_instructeur_dossier_path(dossier_id: champ.dossier.id, champ_id: champ.id), method: :post do |form| +-# = form.submit 'Créer le dossier dans LexPol', class: 'fr-btn' +-# - else +-# %p +-# %strong Numéro NOR : +-# = champ.value +-# %p +-# %strong Statut du dossier : +-# = champ.lexpol_status +-# - if champ.lexpol_dossier_url.present? +-# = link_to 'Aller sur LexPol', champ.lexpol_dossier_url, target: '_blank', class: 'fr-btn fr-btn--secondary' +-# = form_with url: update_lexpol_dossier_instructeur_dossier_path(champ.dossier, champ_id: champ.id), method: :post do |form| +-# = form.submit 'Mettre à jour le dossier', class: 'fr-btn fr-btn--secondary' diff --git a/app/views/shared/dossiers/_edit_annotations.html.haml b/app/views/shared/dossiers/_edit_annotations.html.haml index 653b75cd2e7..1c7e56205ff 100644 --- a/app/views/shared/dossiers/_edit_annotations.html.haml +++ b/app/views/shared/dossiers/_edit_annotations.html.haml @@ -6,5 +6,27 @@ %fieldset.fr-fieldset= render EditableChamp::SectionComponent.new(dossier:, types_de_champ: dossier.revision.types_de_champ_private) = render Dossiers::EditFooterComponent.new(dossier: dossier, annotation: true) - - else - %h2.empty-text Aucune annotation privée + + - champ_lexpol = dossier.champs.find { |c| c.lexpol? } + + - if champ_lexpol.present? + %section.fr-section + %h2 LexPol + - if champ_lexpol.value.blank? + = form_with url: create_lexpol_dossier_instructeur_dossier_path(dossier_id: dossier.id, champ_id: champ_lexpol.id), method: :post do |form| + = form.submit 'Créer le dossier dans LexPol', class: 'fr-btn' + - else + %p + %strong Numéro NOR : + = champ_lexpol.value + %p + %strong Statut du dossier : + = champ_lexpol.data&.[]('lexpol_status') || 'Inconnu' + + - if champ_lexpol.data&.[]('lexpol_dossier_url').present? + = link_to 'Aller sur LexPol', champ_lexpol.data['lexpol_dossier_url'], target: '_blank', class: 'fr-btn fr-btn--secondary' + + = form_with url: update_lexpol_dossier_instructeur_dossier_path(dossier, champ_id: champ_lexpol.id), method: :post do |form| + = form.submit 'Rafraîchir les données LexPol', class: 'fr-btn fr-btn--secondary' + - else + %h2.empty-text Aucune annotation privée diff --git a/config/initializers/flipper.rb b/config/initializers/flipper.rb index 053de3b119b..88ce9f7ee8d 100644 --- a/config/initializers/flipper.rb +++ b/config/initializers/flipper.rb @@ -29,7 +29,8 @@ def setup_features(features) :qrcoded_pdf, :sva, :switch_domain, - :visa + :visa, + :lexpol ] def database_exists? diff --git a/config/locales/models/type_de_champ/fr.yml b/config/locales/models/type_de_champ/fr.yml index dc51bdc89b6..3d60c6c63cb 100644 --- a/config/locales/models/type_de_champ/fr.yml +++ b/config/locales/models/type_de_champ/fr.yml @@ -62,6 +62,7 @@ fr: mesri: "Données du Ministère de l’Enseignement Supérieur, de la Recherche et de l’Innovation" epci: "EPCI" cojo: "Accréditation Paris 2024" + lexpol: "Lexpol" expression_reguliere: 'Expression régulière' errors: type_de_champ: diff --git a/config/routes.rb b/config/routes.rb index bac4822354c..df397aae939 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -528,6 +528,10 @@ get 'reaffectation' get 'pieces_jointes' post 'reaffecter' + post 'lexpol/create_dossier/:champ_id', to: 'lexpol#create_dossier', as: :lexpol_create_dossier + post 'lexpol/update_dossier/:champ_id', to: 'lexpol#update_dossier', as: :lexpol_update_dossier + post :create_lexpol_dossier + post :update_lexpol_dossier end end diff --git a/package.json b/package.json index 1b058b36891..0f11607e61c 100644 --- a/package.json +++ b/package.json @@ -75,8 +75,8 @@ "@esbuild/darwin-arm64": "=0.19.9", "@esbuild/linux-x64": "=0.19.9", "@esbuild/win32-x64": "=0.19.9", - "@rollup/rollup-linux-x64-gnu": "=4.9.1", "@rollup/rollup-darwin-arm64": "=4.9.1", + "@rollup/rollup-linux-x64-gnu": "=4.9.1", "@rollup/rollup-win32-x64-msvc": "=4.9.1", "@types/debounce": "^1.2.4", "@types/geojson": "^7946.0.14", @@ -102,9 +102,9 @@ "postcss": "^8.4.38", "prettier": "^3.3.0", "typescript": "^5.4.5", - "vite": "^5.2.12", + "vite": "^5.0.0", "vite-plugin-full-reload": "^1.1.0", - "vite-plugin-ruby": "^5.0.0", + "vite-plugin-ruby": "^5.1.0", "vitest": "^1.6.0" }, "scripts": { diff --git a/spec/factories/champ.rb b/spec/factories/champ.rb index 042ff0df6e6..4cb72ed5fe5 100644 --- a/spec/factories/champ.rb +++ b/spec/factories/champ.rb @@ -249,6 +249,10 @@ type_de_champ { association :type_de_champ_visa, procedure: dossier.procedure } end + factory :champ_lexpol, class: 'Champs::LexpolChamp' do + type_de_champ { association :type_de_champ_lexpol, procedure: dossier.procedure } + end + factory :champ_cnaf, class: 'Champs::CnafChamp' do type_de_champ { association :type_de_champ_cnaf, procedure: dossier.procedure } end diff --git a/spec/factories/type_de_champ.rb b/spec/factories/type_de_champ.rb index 1e2bd8509ea..3d1933b6391 100644 --- a/spec/factories/type_de_champ.rb +++ b/spec/factories/type_de_champ.rb @@ -199,6 +199,9 @@ factory :type_de_champ_visa do type_champ { TypeDeChamp.type_champs.fetch(:visa) } end + factory :type_de_champ_lexpol do + type_champ { TypeDeChamp.type_champs.fetch(:lexpol) } + end factory :type_de_champ_epci do type_champ { TypeDeChamp.type_champs.fetch(:epci) } end diff --git a/spec/lib/tasks/deployment/20241215115134_feature_flag_lexpol_champs_spec.rake_spec.rb b/spec/lib/tasks/deployment/20241215115134_feature_flag_lexpol_champs_spec.rake_spec.rb new file mode 100644 index 00000000000..2641d352052 --- /dev/null +++ b/spec/lib/tasks/deployment/20241215115134_feature_flag_lexpol_champs_spec.rake_spec.rb @@ -0,0 +1,39 @@ +describe '20241215115134_feature_flag_lexpol_champs' do + let(:rake_task) { Rake::Task['after_party:feature_flag_lexpol_champs'] } + let!(:procedure_with_admin_featured) { create(:procedure) } + let!(:types_de_champ_private) { [{ type: :lexpol }] } + let!(:procedure_with_lexpol_with_admin_featured) { create(:procedure, types_de_champ_private:, administrateurs: [procedure_with_admin_featured.administrateurs.first]) } + let!(:procedure_without_admin_featured) { create(:procedure) } + let!(:procedure_with_lexpol_without_admin_featured) { create(:procedure, types_de_champ_private:, administrateurs: [procedure_without_admin_featured.administrateurs.first]) } + + subject(:run_task) do + rake_task.invoke + end + + before { Flipper.enable(:lexpol, procedure_with_admin_featured.administrateurs.first.user) } + + after { rake_task.reenable } + + describe 'feature_flag_lexpol_champs' do + it "with bad champs" do + expect(Flipper.enabled?(:lexpol, procedure_with_admin_featured.administrateurs.first.user)).to eq(true) + expect(Flipper.enabled?(:lexpol, procedure_with_admin_featured)).to eq(false) + expect(Flipper.enabled?(:lexpol, procedure_with_lexpol_with_admin_featured)).to eq(false) + expect(Flipper.enabled?(:lexpol, procedure_without_admin_featured)).to eq(false) + expect(Flipper.enabled?(:lexpol, procedure_with_lexpol_without_admin_featured)).to eq(false) + + run_task + + procedure_with_admin_featured.reload + procedure_with_lexpol_with_admin_featured.reload + procedure_without_admin_featured.reload + procedure_with_lexpol_without_admin_featured.reload + + expect(Flipper.enabled?(:lexpol, procedure_with_admin_featured.administrateurs.first.user)).to eq(false) + expect(Flipper.enabled?(:lexpol, procedure_with_admin_featured)).to eq(false) + expect(Flipper.enabled?(:lexpol, procedure_with_lexpol_with_admin_featured)).to eq(true) + expect(Flipper.enabled?(:lexpol, procedure_without_admin_featured)).to eq(false) + expect(Flipper.enabled?(:lexpol, procedure_with_lexpol_without_admin_featured)).to eq(false) + end + end +end \ No newline at end of file