From 653d7d51bb9aba6886e6d7dcfd9aab5171402f58 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Thu, 27 Aug 2020 16:22:18 +0200 Subject: [PATCH 01/27] ci: add workflow to publish releases to Sentry See https://blog.sentry.io/2020/07/30/automate-release-management-with-the-sentry-release-github-action --- .github/workflows/sentry-release.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/sentry-release.yml diff --git a/.github/workflows/sentry-release.yml b/.github/workflows/sentry-release.yml new file mode 100644 index 000000000..e1d5050d3 --- /dev/null +++ b/.github/workflows/sentry-release.yml @@ -0,0 +1,18 @@ +on: + push: + tags: + - '*' +name: Publish release on Sentry +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Sentry Release + uses: getsentry/action-release@v1.0.0 + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_ORG: ${{ secrets.SENTRY_ORG }} + SENTRY_PROJECT: rails + with: + environment: production From bfb28e5a2b5e4f9a7000e0a2c40833fc49d904ef Mon Sep 17 00:00:00 2001 From: Fabrice Gangler Date: Sat, 1 Aug 2020 06:28:35 +0200 Subject: [PATCH 02/27] Fix(mailers/_signature): use APPLICATION_NAME Refs: #5456 --- app/views/layouts/mailers/_signature.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/layouts/mailers/_signature.html.haml b/app/views/layouts/mailers/_signature.html.haml index 82d83f7b1..985288c7b 100644 --- a/app/views/layouts/mailers/_signature.html.haml +++ b/app/views/layouts/mailers/_signature.html.haml @@ -4,5 +4,5 @@ - if defined?(service) && service && service.nom.present? = service.nom - else - -# The WORD JOINER unicode entity prevents email clients from auto-linking the signature - L’équipe demarches-simplifiees⁠.fr + -# The WORD JOINER unicode entity (⁠) prevents email clients from auto-linking the signature + L’équipe #{APPLICATION_NAME.gsub(".","⁠.").html_safe} From 60d6b1909d913eeb01a6b86daf0b638f642b7e86 Mon Sep 17 00:00:00 2001 From: Fabrice Gangler Date: Thu, 6 Aug 2020 09:55:37 +0200 Subject: [PATCH 03/27] Fix for using APPLICATION_NAME in .env file Refs: #5450 --- config/application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/application.rb b/config/application.rb index 049f5f7ee..cc8508f4f 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,13 +1,13 @@ require File.expand_path('boot', __dir__) require 'rails/all' -require_relative 'application_name' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) Dotenv::Railtie.load +require_relative 'application_name' module TPS class Application < Rails::Application From 7bc5a0a2788c554c80e4d164011472105e2c1551 Mon Sep 17 00:00:00 2001 From: Judith Date: Mon, 31 Aug 2020 12:23:40 +0200 Subject: [PATCH 04/27] internationalization of /contact-admin --- app/views/support/admin.html.haml | 26 ++++++++++------------- config/locales/en.yml | 7 ------ config/locales/fr.yml | 7 ------ config/locales/views/support/index.en.yml | 14 ++++++++++++ config/locales/views/support/index.fr.yml | 15 +++++++++++++ 5 files changed, 40 insertions(+), 29 deletions(-) diff --git a/app/views/support/admin.html.haml b/app/views/support/admin.html.haml index 88177c590..7b07df30d 100644 --- a/app/views/support/admin.html.haml +++ b/app/views/support/admin.html.haml @@ -2,45 +2,41 @@ #contact-form .container - %h1.new-h1 Contactez notre équipe + %h1.new-h1 + = t('contact_team', scope: [:supportadmin]) .description - En tant qu'administration, vous pouvez nous contactez via ce formulaire. Nous vous répondrons dans les plus brefs délais, par email ou par téléphone. + = t('admin_intro_html', scope: [:supportadmin], contact_path: contact_path) %br - %br - %strong - Attention, ce formulaire est réservée uniquement aux organismes publics. - Il ne concerne ni les particuliers, ni les entreprises, ni les associations (sauf celles reconnues d'utilité publique). Si c'est votre cas, rendez-vous sur notre - = link_to contact_path do - formulaire de contact public - \. + %p.mandatory-explanation= t('asterisk_html', scope: [:utils]) = form_tag contact_path, method: :post, class: 'form' do |f| - if !user_signed_in? .contact-champ = label_tag :email do - Adresse email professionnelle + = t('pro_mail', scope: [:supportadmin]) %span.mandatory * = text_field_tag :email, params[:email], required: true .contact-champ = label_tag :type do - Catégorie + = t('your_question', scope: [:support, :question]) %span.mandatory * = select_tag :type, options_for_select(@options, params[:type]) .contact-champ - = label_tag :phone, 'Numéro de téléphone professionnel (ligne directe)' + = label_tag :phone do + = t('professional_phone_number', scope: [:supportadmin]) = text_field_tag :phone .contact-champ = label_tag :subject do - Sujet + = t('subject', scope: [:utils]) = text_field_tag :subject, params[:subject], required: false .contact-champ = label_tag :text do - Message + = t('message', scope: [:utils]) %span.mandatory * = text_area_tag :text, params[:text], rows: 6, required: true @@ -48,4 +44,4 @@ = hidden_field_tag :admin, true .send-wrapper - = button_tag 'Envoyer le message', type: :submit, class: 'button send primary' + = button_tag t('send_mail', scope: [:utils]), type: :submit, class: 'button send primary' diff --git a/config/locales/en.yml b/config/locales/en.yml index 62bdf05ce..796d52b2f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -60,13 +60,6 @@ en: submit: publish: Publish reopen: Reopen - supportadmin: - # admin demande rdv: Demande de RDV pour une présentation à distance de demarches-simplifiees.fr - admin question: I have a question about demarches-simplifiees.fr - admin soucis: I am facing a technical issue on demarches-simplifiees.fr - admin suggestion produit: I have a suggestion for an evolution - admin demande compte: I want to open an admin account with an Orange, Wanadoo, etc. email - admin autre: Other topic number: currency: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 06bc5943e..c41522222 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -60,13 +60,6 @@ fr: submit: publish: Publier reopen: Réactiver - supportadmin: - admin demande rdv: Demande de RDV pour une présentation à distance de demarches-simplifiees.fr - admin question: J’ai une question sur demarches-simplifiees.fr - admin soucis: J’ai un problème technique avec demarches-simplifiees.fr - admin suggestion produit: J’ai une proposition d’évolution - admin demande compte: Je souhaite ouvrir un compte administrateur avec un email Orange, Wanadoo, etc. - admin autre: Autre sujet number: currency: diff --git a/config/locales/views/support/index.en.yml b/config/locales/views/support/index.en.yml index d2692528c..8d92f06f3 100644 --- a/config/locales/views/support/index.en.yml +++ b/config/locales/views/support/index.en.yml @@ -30,3 +30,17 @@ en:

%{link_lost_user}

" notice_pj_product: A screenshot can help us identify the element to improve. notice_pj_other: A screenshot can help us identify the issue. + supportadmin: + admin_intro_html: "

As an administration, you can contact us through this form. We'll answer you as quickly as possibly by e-mail or phone.

+
+

Caution, this form is dedicated to public bodies only. + It does not concern individuals, companies nor associations (except those recognised of public utility). If you belong to one of these categories, contact us here.

" + contact_team: Contact our team + pro_phone_number: Professional phone number (direct line) + pro_mail: Professional email address + admin demande rdv: I request an appointment for an online presentation of demarches-simplifiees.fr + admin question: I have a question about demarches-simplifiees.fr + admin soucis: I am facing a technical issue on demarches-simplifiees.fr + admin suggestion produit: I have a suggestion for an evolution + admin demande compte: I want to open an admin account with an Orange, Wanadoo, etc. email + admin autre: Other topic diff --git a/config/locales/views/support/index.fr.yml b/config/locales/views/support/index.fr.yml index 06b0decbe..8c09f38e1 100644 --- a/config/locales/views/support/index.fr.yml +++ b/config/locales/views/support/index.fr.yml @@ -29,3 +29,18 @@ fr:

%{link_lost_user}

" notice_pj_product: Une capture d’écran peut nous aider à identifier plus facilement l’endroit à améliorer. notice_pj_other: Une capture d’écran peut nous aider à identifier plus facilement le problème. + supportadmin: + admin_intro_html: "

En tant qu'administration, vous pouvez nous contactez via ce formulaire. Nous vous répondrons dans les plus brefs délais, par email ou par téléphone.

+
+

Attention, ce formulaire est réservé uniquement aux organismes publics. + Il ne concerne ni les particuliers, ni les entreprises, ni les associations (sauf celles reconnues d'utilité publique). Si c'est votre cas, rendez-vous sur notre + formulaire de contact public.

" + contact_team: Contactez notre équipe + pro_phone_number: Numéro de téléphone professionnel (ligne directe) + pro_mail: Adresse e-mail professionnelle + admin demande rdv: Demande de RDV pour une présentation à distance de demarches-simplifiees.fr + admin question: J’ai une question sur demarches-simplifiees.fr + admin soucis: J’ai un problème technique avec demarches-simplifiees.fr + admin suggestion produit: J’ai une proposition d’évolution + admin demande compte: Je souhaite ouvrir un compte administrateur avec un email Orange, Wanadoo, etc. + admin autre: Autre sujet From f2c4378596b56c910a5071ccb4385c24d8d31b8d Mon Sep 17 00:00:00 2001 From: Fabrice Gangler Date: Sat, 1 Aug 2020 06:32:09 +0200 Subject: [PATCH 05/27] fix: use APPLICATION_NAME in view/users/sessions/new Refs: #5462 --- app/views/users/sessions/new.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/users/sessions/new.html.haml b/app/views/users/sessions/new.html.haml index fe57eb71f..5305f9e8d 100644 --- a/app/views/users/sessions/new.html.haml +++ b/app/views/users/sessions/new.html.haml @@ -25,7 +25,7 @@ %hr %p.center - %span Vous êtes nouveau sur demarches‑simplifiees.fr ? + %span Vous êtes nouveau sur #{APPLICATION_NAME.gsub("-","‑").html_safe} ? %br %br = link_to "Trouvez votre démarche", COMMENT_TROUVER_MA_DEMARCHE_URL, target: "_blank", class: "button expend secondary" From 1a43f888fbe54f78e45566f1c80085b7f7c303a8 Mon Sep 17 00:00:00 2001 From: Fabrice Gangler Date: Sat, 1 Aug 2020 10:33:38 +0200 Subject: [PATCH 06/27] Feat: allow to disable France-Connect Refs: #5440 --- .../france_connect/particulier_controller.rb | 6 ++++- app/services/france_connect_service.rb | 4 +++ .../shared/_france_connect_login.html.haml | 25 +++++++++++-------- config/env.example.optional | 3 +++ 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/app/controllers/france_connect/particulier_controller.rb b/app/controllers/france_connect/particulier_controller.rb index c841ae8bf..e3ef69241 100644 --- a/app/controllers/france_connect/particulier_controller.rb +++ b/app/controllers/france_connect/particulier_controller.rb @@ -2,7 +2,11 @@ class FranceConnect::ParticulierController < ApplicationController before_action :redirect_to_login_if_fc_aborted, only: [:callback] def login - redirect_to FranceConnectService.authorization_uri + if FranceConnectService.enabled? + redirect_to FranceConnectService.authorization_uri + else + redirect_to new_user_session_path + end end def callback diff --git a/app/services/france_connect_service.rb b/app/services/france_connect_service.rb index 4249c4710..70e8785b8 100644 --- a/app/services/france_connect_service.rb +++ b/app/services/france_connect_service.rb @@ -1,4 +1,8 @@ class FranceConnectService + def self.enabled? + ENV.fetch("FRANCE_CONNECT_ENABLED", "enabled") == "enabled" + end + def self.authorization_uri client = FranceConnectParticulierClient.new diff --git a/app/views/shared/_france_connect_login.html.haml b/app/views/shared/_france_connect_login.html.haml index 9f4a33646..9b1b9794c 100644 --- a/app/views/shared/_france_connect_login.html.haml +++ b/app/views/shared/_france_connect_login.html.haml @@ -1,11 +1,14 @@ -.france-connect-login - %h2 - = t('views.shared.france_connect_login.title') - %p - = t('views.shared.france_connect_login.description') - .france-connect-login-buttons - = link_to t('views.shared.france_connect_login.login_button'), url, class: "france-connect-login-button" - .france-connect-help-link - = link_to t('views.shared.france_connect_login.help_link'), "https://franceconnect.gouv.fr/", target: "_blank", rel: "noopener", class: "link" - .france-connect-login-separator - = t('views.shared.france_connect_login.separator') +- if FranceConnectService.enabled? + .france-connect-login + %h2 + = t('views.shared.france_connect_login.title') + %p + = t('views.shared.france_connect_login.description') + .france-connect-login-buttons + = link_to t('views.shared.france_connect_login.login_button'), url, class: "france-connect-login-button" + .france-connect-help-link + = link_to t('views.shared.france_connect_login.help_link'), "https://franceconnect.gouv.fr/", target: "_blank", rel: "noopener", class: "link" + .france-connect-login-separator + = t('views.shared.france_connect_login.separator') +- else + diff --git a/config/env.example.optional b/config/env.example.optional index 20748e4be..fd59171fa 100644 --- a/config/env.example.optional +++ b/config/env.example.optional @@ -6,6 +6,9 @@ APPLICATION_NAME="demarches-simplifiees.fr" APPLICATION_SHORTNAME="d-s.fr" APPLICATION_BASE_URL="https://www.demarches-simplifiees.fr" +# Utilisation de France Connect +# FRANCE_CONNECT_ENABLED="disabled" # "enabled" par défaut + # Personnalisation d'instance - Adresses Email de l'application et téléphone # CONTACT_EMAIL="" # EQUIPE_EMAIL="" From 25a24ba7c800acbf944facc715b84f8fa5571dab Mon Sep 17 00:00:00 2001 From: Judith Date: Mon, 31 Aug 2020 13:47:27 +0200 Subject: [PATCH 07/27] removal of translation keys already present in the gem rails-i18n --- app/helpers/application_helper.rb | 2 +- config/locales/en.yml | 153 +----------------- config/locales/fr.yml | 151 +---------------- .../champs/decimal_number_champ_spec.rb | 2 +- .../dossiers/_demande.html.haml_spec.rb | 2 +- 5 files changed, 8 insertions(+), 302 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index cc6adef9e..443d7c166 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -140,7 +140,7 @@ module ApplicationHelper end def try_format_date(date) - date.present? ? I18n.l(date) : '' + date.present? ? I18n.l(date, format: :long) : '' end def try_format_datetime(datetime) diff --git a/config/locales/en.yml b/config/locales/en.yml index 796d52b2f..e45800715 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -22,9 +22,6 @@ en: utils: deconnexion: "Log out" - involved: "See concerned people" - no-commentaires: "There is no message yet, feel free to start the first one." - depositaire: "Dépositaire" pj: "Attachments" asterisk_html: Fields marked by an asterisk ( * ) are mandatory. file_number: File number @@ -61,55 +58,6 @@ en: publish: Publish reopen: Reopen - number: - currency: - format: - delimiter: "," - format: "%u%n" - precision: 2 - separator: "." - significant: false - strip_insignificant_zeros: false - unit: "€" - format: - delimiter: "," - precision: 3 - separator: "." - significant: false - strip_insignificant_zeros: false - human: - decimal_units: - format: "%n %u" - units: - billion: Billion - million: Million - quadrillion: Quadrillion - thousand: Thousand - trillion: Trillion - unit: '' - format: - delimiter: '' - precision: 3 - significant: true - strip_insignificant_zeros: true - storage_units: - format: "%n %u" - units: - byte: - one: Byte - other: Bytes - gb: GB - kb: KB - mb: MB - pb: PB - tb: TB - percentage: - format: - delimiter: '' - format: "%n%" - precision: - format: - delimiter: '' activerecord: attributes: user: @@ -119,13 +67,7 @@ en: password: 'password' errors: messages: - blank: "must be filled" - not_a_number: 'must be a number' - not_an_integer: 'must be an integer (without digit after the comma)' - greater_than: "must be greater than %{count}" - greater_than_or_equal_to: "must be greater than or equal to %{count}" - less_than: "must be less than %{count}" - less_than_or_equal_to: "must be less than or equal to %{count}" + not_a_phone: 'Invalid phone number' models: attestation_template: attributes: @@ -190,98 +132,9 @@ en: # parcelles_agricoles_empty: # one: "Aucune parcelle agricole sur la zone sélectionnée" # other: "Aucune parcelle agricole sur les zones sélectionnées" + not_an_integer: "must be an integer (without any digit after the comma)" + blank: "can't be blank" - date: - abbr_day_names: - - Sun - - Mon - - Tue - - Wed - - Thu - - Fri - - Sat - abbr_month_names: - - - - Jan - - Feb - - Mar - - Apr - - May - - Jun - - Jul - - Aug - - Sep - - Oct - - Nov - - Dec - month_names: - - - - January - - February - - March - - April - - May - - June - - July - - August - - September - - October - - November - - December - order: - - :year - - :month - - :day - day_names: - - Sunday - - Monday - - Tuesday - - Wednesday - - Thursday - - Friday - - Saturday - formats: - default: "%Y-%m-%d" - long: "%B %d, %Y" - short: "%b %d" - datetime: - distance_in_words: - about_x_hours: - one: about an hour - other: about %{count} hours - about_x_months: - one: about a month - other: about %{count} months - about_x_years: - one: about a year - other: about %{count} years - almost_x_years: - one: almost a year - other: almost %{count} years - half_a_minute: half a minute - less_than_x_minutes: - zero: less than a minute - one: less than a minute - other: less than %{count} minutes - less_than_x_seconds: - zero: less than a second - one: less than a second - other: less than %{count} seconds - over_x_years: - one: more than a year - other: more than %{count} years - x_days: - one: 1 day - other: "%{count} days" - x_minutes: - one: 1 minute - other: "%{count} minutes" - x_months: - one: 1 month - other: "%{count} months" - x_seconds: - one: 1 second - other: "%{count} seconds" time: formats: default: "%B %d %Y %R" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index c41522222..465afd67b 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -22,9 +22,6 @@ fr: utils: deconnexion: "Déconnexion" - involved: "Voir les personnes impliquées" - no-commentaires: "Il n’y a aucun message dans le fil de discussion, n’hésitez pas à initier le premier." - depositaire: "Dépositaire" pj: "Pièces jointes" asterisk_html: Les champs suivis d’un astérisque ( * ) sont obligatoires. file_number: Numéro de dossier @@ -61,54 +58,6 @@ fr: publish: Publier reopen: Réactiver - number: - currency: - format: - delimiter: " " - format: "%n %u" - precision: 2 - separator: "," - significant: false - strip_insignificant_zeros: false - unit: "€" - format: - delimiter: " " - precision: 3 - separator: "," - significant: false - strip_insignificant_zeros: false - human: - decimal_units: - format: "%n %u" - units: - billion: milliard - million: million - quadrillion: million de milliards - thousand: millier - trillion: billion - unit: '' - format: - delimiter: '' - precision: 3 - significant: true - strip_insignificant_zeros: true - storage_units: - format: "%n %u" - units: - byte: - one: octet - other: octets - gb: Go - kb: ko - mb: Mo - tb: To - percentage: - format: - delimiter: '' - format: "%n%" - precision: - format: - delimiter: '' activerecord: attributes: user: @@ -118,14 +67,7 @@ fr: password: 'Le mot de passe' errors: messages: - blank: "doit être rempli" - not_a_number: 'doit être un nombre' - not_an_integer: 'doit être un nombre entier (sans chiffres après la virgule)' not_a_phone: 'Numéro de téléphone invalide' - greater_than: "doit être supérieur à %{count}" - greater_than_or_equal_to: "doit être supérieur ou égal à %{count}" - less_than: "doit être inférieur à %{count}" - less_than_or_equal_to: "doit être inférieur ou égal à %{count}" models: attestation_template: attributes: @@ -190,98 +132,9 @@ fr: parcelles_agricoles_empty: one: "Aucune parcelle agricole sur la zone sélectionnée" other: "Aucune parcelle agricole sur les zones sélectionnées" + not_an_integer: "doit être un nombre entier (sans chiffres après la virgule)" + blank: "doit être rempli" - date: - abbr_day_names: - - dim - - lun - - mar - - mer - - jeu - - ven - - sam - abbr_month_names: - - - - jan. - - fév. - - mar. - - avr. - - mai - - juin - - juil. - - août - - sept. - - oct. - - nov. - - déc. - month_names: - - - - janvier - - février - - mars - - avril - - mai - - juin - - juillet - - août - - septembre - - octobre - - novembre - - décembre - order: - - :day - - :month - - :year - day_names: - - dimanche - - lundi - - mardi - - mercredi - - jeudi - - vendredi - - samedi - formats: - default: "%d %B %Y" - short: "%e %b" - long: "%e %B %Y" - datetime: - distance_in_words: - about_x_hours: - one: environ une heure - other: environ %{count} heures - about_x_months: - one: environ un mois - other: environ %{count} mois - about_x_years: - one: environ un an - other: environ %{count} ans - almost_x_years: - one: presqu’un an - other: presque %{count} ans - half_a_minute: une demi-minute - less_than_x_minutes: - zero: moins d’une minute - one: moins d’une minute - other: moins de %{count} minutes - less_than_x_seconds: - zero: moins d’une seconde - one: moins d’une seconde - other: moins de %{count} secondes - over_x_years: - one: plus d’un an - other: plus de %{count} ans - x_days: - one: 1 jour - other: "%{count} jours" - x_minutes: - one: 1 minute - other: "%{count} minutes" - x_months: - one: 1 mois - other: "%{count} mois" - x_seconds: - one: 1 seconde - other: "%{count} secondes" time: formats: default: "%d %B %Y %R" diff --git a/spec/models/champs/decimal_number_champ_spec.rb b/spec/models/champs/decimal_number_champ_spec.rb index 3684beeec..0ad8be67e 100644 --- a/spec/models/champs/decimal_number_champ_spec.rb +++ b/spec/models/champs/decimal_number_champ_spec.rb @@ -18,7 +18,7 @@ describe Champs::DecimalNumberChamp do let(:value) { 'toto' } it { is_expected.to_not be_valid } - it { expect(subject.errors[:value]).to eq(["« #{subject.libelle} » doit être un nombre"]) } + it { expect(subject.errors[:value]).to eq(["« #{subject.libelle} » n'est pas un nombre"]) } end context 'when the value is blank' do diff --git a/spec/views/shared/dossiers/_demande.html.haml_spec.rb b/spec/views/shared/dossiers/_demande.html.haml_spec.rb index f435e8e6a..cb48f4de2 100644 --- a/spec/views/shared/dossiers/_demande.html.haml_spec.rb +++ b/spec/views/shared/dossiers/_demande.html.haml_spec.rb @@ -38,7 +38,7 @@ describe 'shared/dossiers/demande.html.haml', type: :view do expect(subject).to include(individual.gender) expect(subject).to include(individual.nom) expect(subject).to include(individual.prenom) - expect(subject).to include(I18n.l(individual.birthdate)) + expect(subject).to include(I18n.l(individual.birthdate, format: :long)) end end From 9553dae7bdf3d768c9e25c73ba259d296481ef2d Mon Sep 17 00:00:00 2001 From: Judith Date: Mon, 31 Aug 2020 11:10:35 +0200 Subject: [PATCH 08/27] gem devise-i18n added to Gemfile to remove the config/locales/devises.*.yml files. --- Gemfile | 1 + Gemfile.lock | 3 ++ config/locales/devise.en.yml | 60 --------------------------------- config/locales/devise.fr.yml | 64 ------------------------------------ 4 files changed, 4 insertions(+), 124 deletions(-) delete mode 100644 config/locales/devise.en.yml delete mode 100755 config/locales/devise.fr.yml diff --git a/Gemfile b/Gemfile index af5ddcae9..c0c5e4e46 100644 --- a/Gemfile +++ b/Gemfile @@ -22,6 +22,7 @@ gem 'delayed_job_active_record' gem 'delayed_job_web' gem 'devise' # Gestion des comptes utilisateurs gem 'devise-async' +gem 'devise-i18n' gem 'discard' gem 'dotenv-rails', require: 'dotenv/rails-now' # dotenv should always be loaded before rails gem 'ffi-geos', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 960e5a887..754c8ec6d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -205,6 +205,8 @@ GEM devise-async (1.0.0) activejob (>= 5.0) devise (>= 4.0) + devise-i18n (1.9.2) + devise (>= 4.7.1) diff-lcs (1.3) discard (1.2.0) activerecord (>= 4.2, < 7) @@ -787,6 +789,7 @@ DEPENDENCIES delayed_job_web devise devise-async + devise-i18n discard dotenv-rails factory_bot diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml deleted file mode 100644 index 9573f3d1b..000000000 --- a/config/locales/devise.en.yml +++ /dev/null @@ -1,60 +0,0 @@ -# Additional translations at https://github.com/plataformatec/devise/wiki/I18n - -en: - devise: - confirmations: - confirmed: "Your email address has been successfully confirmed." - send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes." - send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes." - failure: - already_authenticated: "You are already signed in." - inactive: "Your account is not activated yet." - invalid: "Invalid %{authentication_keys} or password." - locked: "Your account is locked." - last_attempt: "You have one more attempt before your account is locked." - not_found_in_database: "Invalid %{authentication_keys} or password." - timeout: "Your session expired. Please sign in again to continue." - unauthenticated: "You need to sign in or sign up before continuing." - unconfirmed: "You have to confirm your email address before continuing." - mailer: - confirmation_instructions: - subject: "Confirmation instructions" - reset_password_instructions: - subject: "Reset password instructions" - unlock_instructions: - subject: "Unlock instructions" - omniauth_callbacks: - failure: "Could not authenticate you from %{kind} because \"%{reason}\"." - success: "Successfully authenticated from %{kind} account." - passwords: - no_token: "You can’t access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." - send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes." - send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." - updated: "Your password has been changed successfully. You are now signed in." - updated_not_active: "Your password has been changed successfully." - registrations: - destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon." - signed_up: "Welcome! You have signed up successfully." - signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." - signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." - signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." - update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address." - updated: "Your account has been updated successfully." - sessions: - signed_in: "Signed in successfully." - signed_out: "Signed out successfully." - already_signed_out: "Signed out successfully." - unlocks: - send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes." - send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes." - unlocked: "Your account has been unlocked successfully. Please sign in to continue." - errors: - messages: - already_confirmed: "was already confirmed, please try signing in" - confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" - expired: "has expired, please request a new one" - not_found: "not found" - not_locked: "was not locked" - not_saved: - one: "1 error prohibited this %{resource} from being saved:" - other: "%{count} errors prohibited this %{resource} from being saved:" diff --git a/config/locales/devise.fr.yml b/config/locales/devise.fr.yml deleted file mode 100755 index 958274540..000000000 --- a/config/locales/devise.fr.yml +++ /dev/null @@ -1,64 +0,0 @@ -# Additional translations at https://github.com/plataformatec/devise/wiki/I18n - -fr: - devise: - confirmations: - confirmed: "Votre compte a été activé." - send_instructions: "Vous allez recevoir un email avec les instructions nécessaires à l’activation de votre compte dans quelques minutes." - send_paranoid_instructions: "Si votre adresse email existe dans notre base de données, vous allez bientôt recevoir un email contenant les instructions d’activation de votre compte." - failure: - already_authenticated: "Vous êtes déjà connecté" - inactive: "Votre compte n’est pas encore activé." - invalid: "adresse email ou mot de passe incorrect." - last_attempt: "Vous avez droit à une tentative avant que votre compte ne soit verrouillé." - locked: "Votre compte est verrouillé." - not_found_in_database: "adresse email ou mot de passe invalide." - timeout: "Votre session est expirée. Veuillez vous reconnecter pour continuer." - unauthenticated: "Vous devez vous connecter ou vous inscrire pour continuer." - unconfirmed: "Vous devez confirmer votre adresse email pour continuer. Cliquez sur le lien qui vous a été envoyé par email." - mailer: - confirmation_instructions: - subject: "Instructions d’activation de votre compte" - reset_password_instructions: - subject: "Instructions pour changer le mot de passe" - unlock_instructions: - subject: "Instructions pour déverrouiller le compte" - email_changed: - subject: "Changement d’adresse email" - password_change: - subject: "Votre mot de passe a été modifié avec succés." - omniauth_callbacks: - failure: "Nous n’avons pas pu vous authentifier via %{kind} : '%{reason}'." - success: "Authentifié avec succès via %{kind}." - passwords: - no_token: "Vous ne pouvez accéder à cette page sans passer par un email de réinitialisation de mot de passe. Si vous êtes passé par un email de ce type, assurez-vous d’utiliser l’URL complète." - send_instructions: "Vous allez recevoir les instructions de réinitialisation du mot de passe dans quelques instants" - send_paranoid_instructions: "Si votre adresse email existe dans notre base de données, vous allez recevoir un lien de réinitialisation par email" - updated: "Votre mot de passe a été changé avec succès, vous êtes maintenant connecté" - updated_not_active: "Votre mot de passe a été changé avec succès." - registrations: - destroyed: "Votre compte a été supprimé avec succès. Nous espérons vous revoir bientôt." - signed_up: "Bienvenue, vous êtes connecté." - signed_up_but_inactive: "Vous êtes bien enregistré. Vous ne pouvez cependant pas vous connecter car votre compte n’est pas encore activé." - signed_up_but_locked: "Vous êtes bien enregistré. Vous ne pouvez cependant pas vous connecter car votre compte est verrouillé." - signed_up_but_unconfirmed: "Nous vous avons envoyé un email contenant un lien d’activation. Ouvrez ce lien pour activer votre compte." - update_needs_confirmation: "Vous devez confirmer votre nouvelle adresse email. Vérifiez vos emails, et cliquez sur le lien de confirmation pour confirmer votre changement d’adresse." - updated: "Votre compte a été modifié avec succès." - sessions: - signed_in: "Connecté." - signed_out: "Déconnecté." - already_signed_out: "Déconnecté." - unlocks: - send_instructions: "Vous allez recevoir les instructions nécessaires au déverrouillage de votre compte dans quelques instants" - send_paranoid_instructions: "Si votre compte existe, vous allez bientôt recevoir un email contenant les instructions pour le déverrouiller." - unlocked: "Votre compte a été déverrouillé avec succès, vous êtes maintenant connecté." - errors: - messages: - already_confirmed: "a déjà été validé(e), veuillez essayer de vous connecter" - confirmation_period_expired: "à activer dans les %{period}, merci de faire une nouvelle demande" - expired: "a expiré, merci d’en faire une nouvelle demande" - not_found: "n’a pas été trouvé(e)" - not_locked: "n’était pas verrouillé(e)" - not_saved: - one: "1 erreur a empêché ce(tte) %{resource} d’être sauvegardé(e) :" - other: "%{count} erreurs ont empêché ce(tte) %{resource} d’être sauvegardé(e) :" From 7eee9beed7fc77147e83db57dd6365ed66e724d5 Mon Sep 17 00:00:00 2001 From: Judith Date: Tue, 1 Sep 2020 15:28:31 +0200 Subject: [PATCH 09/27] adapting the specs --- config/locales/en.yml | 2 +- spec/controllers/users/profil_controller_spec.rb | 2 +- spec/controllers/users/sessions_controller_spec.rb | 2 +- spec/features/sessions/sign_in_spec.rb | 2 +- spec/features/users/invite_spec.rb | 2 +- spec/features/users/managing_password_spec.rb | 8 ++++---- spec/features/users/sign_up_spec.rb | 6 +++--- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index e45800715..ee24bb44a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -132,7 +132,7 @@ en: # parcelles_agricoles_empty: # one: "Aucune parcelle agricole sur la zone sélectionnée" # other: "Aucune parcelle agricole sur les zones sélectionnées" - not_an_integer: "must be an integer (without any digit after the comma)" + not_an_integer: "must be an integer (without decimal)" blank: "can't be blank" time: diff --git a/spec/controllers/users/profil_controller_spec.rb b/spec/controllers/users/profil_controller_spec.rb index 2d79fca85..cf163ba93 100644 --- a/spec/controllers/users/profil_controller_spec.rb +++ b/spec/controllers/users/profil_controller_spec.rb @@ -56,7 +56,7 @@ describe Users::ProfilController, type: :controller do end it { expect(response).to redirect_to(profil_path) } - it { expect(flash.alert).to eq(['Email invalide']) } + it { expect(flash.alert).to eq(['Courriel invalide']) } end context 'when the user has an instructeur role' do diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index 7734b9538..e9ca9fcee 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -62,7 +62,7 @@ describe Users::SessionsController, type: :controller do subject expect(response).to render_template(:new) - expect(flash.alert).to eq(I18n.t('devise.failure.invalid')) + expect(flash.alert).to eq('Courriel ou mot de passe incorrect.') end end end diff --git a/spec/features/sessions/sign_in_spec.rb b/spec/features/sessions/sign_in_spec.rb index b97980d6a..84361db70 100644 --- a/spec/features/sessions/sign_in_spec.rb +++ b/spec/features/sessions/sign_in_spec.rb @@ -60,7 +60,7 @@ feature 'Signin in:' do click_on 'Connexion' sign_in_with user.email, password - expect(page).to have_content 'Vous devez confirmer votre adresse email pour continuer' + expect(page).to have_content('Vous devez confirmer votre compte par courriel.') end end end diff --git a/spec/features/users/invite_spec.rb b/spec/features/users/invite_spec.rb index 9ca3c6217..e78fef219 100644 --- a/spec/features/users/invite_spec.rb +++ b/spec/features/users/invite_spec.rb @@ -41,7 +41,7 @@ feature 'Invitations' do # Confirm the account # (The user should be redirected to the dossier they was invited on) click_confirmation_link_for invite.email - expect(page).to have_content('Votre compte a été activé') + expect(page).to have_content('Votre compte a bien été confirmé.') expect(page).to have_current_path(brouillon_dossier_path(dossier)) end end diff --git a/spec/features/users/managing_password_spec.rb b/spec/features/users/managing_password_spec.rb index 52aa4c109..96ee9bdd5 100644 --- a/spec/features/users/managing_password_spec.rb +++ b/spec/features/users/managing_password_spec.rb @@ -13,7 +13,7 @@ feature 'Managing password:' do perform_enqueued_jobs do click_on 'Réinitialiser' end - expect(page).to have_content 'vous allez recevoir un lien de réinitialisation par email' + expect(page).to have_content('Si votre courriel existe dans notre base de données, vous recevrez un lien vous permettant de récupérer votre mot de passe.') click_reset_password_link_for user.email expect(page).to have_content 'Changement de mot de passe' @@ -21,7 +21,7 @@ feature 'Managing password:' do fill_in 'user_password', with: new_password fill_in 'user_password_confirmation', with: new_password click_on 'Changer le mot de passe' - expect(page).to have_content('Votre mot de passe a été changé avec succès') + expect(page).to have_content('Votre mot de passe a bien été modifié.') end end @@ -40,7 +40,7 @@ feature 'Managing password:' do perform_enqueued_jobs do click_on 'Réinitialiser' end - expect(page).to have_content 'vous allez recevoir un lien de réinitialisation par email' + expect(page).to have_content('Si votre courriel existe dans notre base de données, vous recevrez un lien vous permettant de récupérer votre mot de passe.') click_reset_password_link_for user.email @@ -49,7 +49,7 @@ feature 'Managing password:' do fill_in 'user_password', with: new_password fill_in 'user_password_confirmation', with: new_password click_on 'Changer le mot de passe' - expect(page).to have_content('Votre mot de passe a été changé avec succès') + expect(page).to have_content('Votre mot de passe a bien été modifié.') end end end diff --git a/spec/features/users/sign_up_spec.rb b/spec/features/users/sign_up_spec.rb index 65182a303..000a7a3b4 100644 --- a/spec/features/users/sign_up_spec.rb +++ b/spec/features/users/sign_up_spec.rb @@ -10,7 +10,7 @@ feature 'Signing up:' do expect(page).to have_content "nous avons besoin de vérifier votre adresse #{user_email}" click_confirmation_link_for user_email - expect(page).to have_content 'Votre compte a été activé' + expect(page).to have_content('Votre compte a bien été confirmé.') expect(page).to have_current_path dossiers_path end @@ -80,7 +80,7 @@ feature 'Signing up:' do # After confirmation, the user is redirected to the procedure they were initially starting # (even when confirming the account in another browser). expect(page).to have_current_path(commencer_path(path: procedure.path)) - expect(page).to have_content 'Votre compte a été activé' + expect(page).to have_content I18n.t('devise.confirmations.confirmed') click_on 'Commencer la démarche' expect(page).to have_current_path identite_dossier_path(procedure.reload.dossiers.last) @@ -112,7 +112,7 @@ feature 'Signing up:' do # After confirmation, the user is redirected to the procedure they were initially starting # (even when confirming the account in another browser). expect(page).to have_current_path(commencer_path(path: procedure.path)) - expect(page).to have_content 'Votre compte a été activé' + expect(page).to have_content I18n.t('devise.confirmations.confirmed') expect(page).to have_content 'Commencer la démarche' end end From 17884716641ec3321a623347151b731d0729f238 Mon Sep 17 00:00:00 2001 From: kara Diaby Date: Tue, 1 Sep 2020 16:41:02 +0200 Subject: [PATCH 10/27] carto hack : traduce edition buttons in french --- app/javascript/components/MapEditor/index.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/javascript/components/MapEditor/index.js b/app/javascript/components/MapEditor/index.js index 3bb828e29..c8bb44555 100644 --- a/app/javascript/components/MapEditor/index.js +++ b/app/javascript/components/MapEditor/index.js @@ -40,6 +40,19 @@ function MapEditor({ featureCollection, url, preview, hasCadastres, ign }) { hasCadastres ]); + const translations = [ + ['.mapbox-gl-draw_line', 'Tracer une ligne'], + ['.mapbox-gl-draw_polygon', 'Dessiner un polygone'], + ['.mapbox-gl-draw_point', 'Ajouter un point'], + ['.mapbox-gl-draw_trash', 'Supprimer'] + ]; + for (const [selector, translation] of translations) { + const element = document.querySelector(selector); + if (element) { + element.setAttribute('title', translation); + } + } + const onFeatureFocus = useCallback( ({ detail }) => { const { id } = detail; From ae1f14a3f96f87c10b3112bc4287eb2324d2170a Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Tue, 1 Sep 2020 17:57:10 +0200 Subject: [PATCH 11/27] views: reduce nested flex containers in admin procedures list We can achieve the same layout with fewer nested flex containers. --- .../new_design/admin-procedures-list.scss | 4 ++++ .../procedures/_procedures_list.html.haml | 17 ++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) create mode 100644 app/assets/stylesheets/new_design/admin-procedures-list.scss diff --git a/app/assets/stylesheets/new_design/admin-procedures-list.scss b/app/assets/stylesheets/new_design/admin-procedures-list.scss new file mode 100644 index 000000000..3ac4dcc5c --- /dev/null +++ b/app/assets/stylesheets/new_design/admin-procedures-list.scss @@ -0,0 +1,4 @@ +// Push the timestamps column to the right of the row +.admin-procedures-list-timestamps { + margin-left: auto; +} diff --git a/app/views/new_administrateur/procedures/_procedures_list.html.haml b/app/views/new_administrateur/procedures/_procedures_list.html.haml index 8923f657e..c59bca47d 100644 --- a/app/views/new_administrateur/procedures/_procedures_list.html.haml +++ b/app/views/new_administrateur/procedures/_procedures_list.html.haml @@ -1,15 +1,14 @@ - procedures.each do |procedure| .card - .flex.justify-between - .flex - - if procedure.logo.present? - = image_tag procedure.logo, alt: procedure.libelle, width: '100' - .flex.column.ml-1 - .card-title - = link_to procedure.libelle, admin_procedure_path(procedure), style: 'color: black;' - = link_to(procedure_lien(procedure), procedure_lien(procedure), class: 'procedure-lien mb-1') + .flex + - if procedure.logo.present? + = image_tag procedure.logo, alt: procedure.libelle, width: '100' + .flex.column.ml-1 + .card-title + = link_to procedure.libelle, admin_procedure_path(procedure), style: 'color: black;' + = link_to(procedure_lien(procedure), procedure_lien(procedure), class: 'procedure-lien mb-1') - %div + .admin-procedures-list-timestamps %p.notice N° #{procedure.id} %p.notice créée le #{procedure.created_at.strftime('%d/%m/%Y')} - if procedure.published_at.present? From d5a2fc0788cd0031d48ac573b74a1ac71960c756 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Tue, 1 Sep 2020 17:57:51 +0200 Subject: [PATCH 12/27] views: fix Safari stretching logos in admin procedures list --- .../stylesheets/new_design/admin-procedures-list.scss | 7 +++++++ .../procedures/_procedures_list.html.haml | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/new_design/admin-procedures-list.scss b/app/assets/stylesheets/new_design/admin-procedures-list.scss index 3ac4dcc5c..ece3f2726 100644 --- a/app/assets/stylesheets/new_design/admin-procedures-list.scss +++ b/app/assets/stylesheets/new_design/admin-procedures-list.scss @@ -2,3 +2,10 @@ .admin-procedures-list-timestamps { margin-left: auto; } + +// Fix a Safari flexbox bug where the inner procedure logo +// would stretch the container vertically. +// See https://stackoverflow.com/questions/57516373/image-stretching-in-flexbox-in-safari +.admin-procedures-list-row.infos { + align-items: flex-start; +} diff --git a/app/views/new_administrateur/procedures/_procedures_list.html.haml b/app/views/new_administrateur/procedures/_procedures_list.html.haml index c59bca47d..2641df629 100644 --- a/app/views/new_administrateur/procedures/_procedures_list.html.haml +++ b/app/views/new_administrateur/procedures/_procedures_list.html.haml @@ -1,6 +1,6 @@ - procedures.each do |procedure| .card - .flex + .admin-procedures-list-row.infos.flex - if procedure.logo.present? = image_tag procedure.logo, alt: procedure.libelle, width: '100' .flex.column.ml-1 @@ -16,7 +16,7 @@ - if procedure.closed_at.present? %p.notice archivée le #{procedure.closed_at.strftime('%d/%m/%Y')} - .flex.justify-between + .admin-procedures-list-row.actions.flex.justify-between %div - if feature_enabled?(:administrateur_routage) %span.icon.person From ec72fdd1641477fdc1ae474b4d4c8d346bff34b9 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 27 Aug 2020 19:55:10 +0200 Subject: [PATCH 13/27] Remove migration service --- .../procedures_controller.rb | 3 +- .../types_de_champ_controller.rb | 21 ++---- app/controllers/stats_controller.rb | 3 +- app/controllers/users/dossiers_controller.rb | 2 - app/dashboards/procedure_dashboard.rb | 8 +- .../components/TypeDeChamp.js | 1 - .../TypesDeChampEditor/operations.js | 2 +- .../TypesDeChampEditor/typeDeChampsReducer.js | 3 +- .../tmp_dossiers_migrate_revisions_job.rb | 21 ------ app/models/champ.rb | 3 + app/models/dossier.rb | 18 +++-- app/models/procedure.rb | 73 ++++++++----------- app/models/procedure_revision.rb | 23 +++--- .../procedure_revision_type_de_champ.rb | 14 ++-- app/models/type_de_champ.rb | 40 +++++++--- app/serializers/dossier_serializer.rb | 2 +- app/serializers/procedure_serializer.rb | 2 +- app/services/pieces_justificatives_service.rb | 4 +- app/services/revisions_migration.rb | 36 --------- .../procedures/show.html.haml | 6 +- 20 files changed, 109 insertions(+), 176 deletions(-) delete mode 100644 app/jobs/tmp_dossiers_migrate_revisions_job.rb delete mode 100644 app/services/revisions_migration.rb diff --git a/app/controllers/new_administrateur/procedures_controller.rb b/app/controllers/new_administrateur/procedures_controller.rb index 70e0bbf9f..61a031c20 100644 --- a/app/controllers/new_administrateur/procedures_controller.rb +++ b/app/controllers/new_administrateur/procedures_controller.rb @@ -66,6 +66,7 @@ module NewAdministrateur def create @procedure = Procedure.new(procedure_params.merge(administrateurs: [current_administrateur])) + @procedure.draft_revision = @procedure.revisions.build if !@procedure.save flash.now.alert = @procedure.errors.full_messages @@ -73,8 +74,6 @@ module NewAdministrateur else flash.notice = 'Démarche enregistrée.' current_administrateur.instructeur.assign_to_procedure(@procedure) - # FIXUP: needed during transition to revisions - RevisionsMigration.add_revisions(@procedure) redirect_to champs_admin_procedure_path(@procedure) end diff --git a/app/controllers/new_administrateur/types_de_champ_controller.rb b/app/controllers/new_administrateur/types_de_champ_controller.rb index c7c663acb..b88cb1642 100644 --- a/app/controllers/new_administrateur/types_de_champ_controller.rb +++ b/app/controllers/new_administrateur/types_de_champ_controller.rb @@ -2,7 +2,6 @@ module NewAdministrateur class TypesDeChampController < AdministrateurController before_action :retrieve_procedure, only: [:create, :update, :move, :destroy] before_action :procedure_locked?, only: [:create, :update, :move, :destroy] - before_action :revisions_migration def create type_de_champ = @procedure.draft_revision.add_type_de_champ(type_de_champ_create_params) @@ -16,7 +15,7 @@ module NewAdministrateur end def update - type_de_champ = @procedure.draft_revision.find_or_clone_type_de_champ(type_de_champ_stable_id) + type_de_champ = @procedure.draft_revision.find_or_clone_type_de_champ(TypeDeChamp.to_stable_id(params[:id])) if type_de_champ.update(type_de_champ_update_params) reset_procedure @@ -27,13 +26,13 @@ module NewAdministrateur end def move - @procedure.draft_revision.move_type_de_champ(type_de_champ_stable_id, (params[:position] || params[:order_place]).to_i) + @procedure.draft_revision.move_type_de_champ(TypeDeChamp.to_stable_id(params[:id]), (params[:position] || params[:order_place]).to_i) head :no_content end def destroy - @procedure.draft_revision.remove_type_de_champ(type_de_champ_stable_id) + @procedure.draft_revision.remove_type_de_champ(TypeDeChamp.to_stable_id(params[:id])) reset_procedure head :no_content @@ -41,19 +40,11 @@ module NewAdministrateur private - def type_de_champ_stable_id - TypeDeChamp.find(params[:id]).stable_id - end - - def revisions_migration - # FIXUP: needed during transition to revisions - RevisionsMigration.add_revisions(@procedure) - end - def serialize_type_de_champ(type_de_champ) { type_de_champ: type_de_champ.as_json( except: [ + :id, :created_at, :options, :order_place, @@ -73,7 +64,7 @@ module NewAdministrateur :piece_justificative_template_url, :quartiers_prioritaires ] - ) + ).merge(id: TypeDeChamp.format_stable_id(type_de_champ.stable_id)) } end @@ -92,7 +83,7 @@ module NewAdministrateur :type_champ) if type_de_champ_params[:parent_id].present? - type_de_champ_params[:parent_id] = TypeDeChamp.find(type_de_champ_params[:parent_id]).stable_id + type_de_champ_params[:parent_id] = TypeDeChamp.to_stable_id(type_de_champ_params[:parent_id]) end type_de_champ_params diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index d676b5b40..5051f4153 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -313,7 +313,8 @@ class StatsController < ApplicationController procedure_id_type_de_champs_count = TypeDeChamp .where(private: false) - .group(:procedure_id) + .joins(:revision) + .group('procedure_revisions.procedure_id') .count groupe_instructeur_id_type_de_champs_count = groupe_instructeurs.reduce({}) do |acc, (gi_id, procedure_id)| diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index 47536f28c..b7ba17dfe 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -259,8 +259,6 @@ module Users return redirect_to url_for dossiers_path end - # FIXUP: needed during transition to revisions - RevisionsMigration.add_revisions(procedure) dossier = Dossier.new( revision: procedure.active_revision, groupe_instructeur: procedure.defaut_groupe_instructeur, diff --git a/app/dashboards/procedure_dashboard.rb b/app/dashboards/procedure_dashboard.rb index 076df9cb3..aaf0717db 100644 --- a/app/dashboards/procedure_dashboard.rb +++ b/app/dashboards/procedure_dashboard.rb @@ -8,8 +8,8 @@ class ProcedureDashboard < Administrate::BaseDashboard # which determines how the attribute is displayed # on pages throughout the dashboard. ATTRIBUTE_TYPES = { - types_de_champ: TypesDeChampCollectionField, - types_de_champ_private: TypesDeChampCollectionField, + published_types_de_champ: TypesDeChampCollectionField, + published_types_de_champ_private: TypesDeChampCollectionField, path: ProcedureLinkField, dossiers: Field::HasMany, administrateurs: Field::HasMany, @@ -70,8 +70,8 @@ class ProcedureDashboard < Administrate::BaseDashboard :whitelisted_at, :hidden_at, :closed_at, - :types_de_champ, - :types_de_champ_private, + :published_types_de_champ, + :published_types_de_champ_private, :for_individual, :auto_archive_on, :initiated_mail_template, diff --git a/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js b/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js index 3787639e5..6d68ffbe1 100644 --- a/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js +++ b/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js @@ -210,7 +210,6 @@ export const FIELDS = [ 'drop_down_list_value', 'libelle', 'mandatory', - 'order_place', 'parcelles_agricoles', 'parent_id', 'piece_justificative_template', diff --git a/app/javascript/components/TypesDeChampEditor/operations.js b/app/javascript/components/TypesDeChampEditor/operations.js index c88215807..a2a04116c 100644 --- a/app/javascript/components/TypesDeChampEditor/operations.js +++ b/app/javascript/components/TypesDeChampEditor/operations.js @@ -22,7 +22,7 @@ export function moveTypeDeChampOperation(typeDeChamp, index, queue) { return queue.enqueue({ path: `/${typeDeChamp.id}/move`, method: 'patch', - payload: { order_place: index } + payload: { position: index } }); } diff --git a/app/javascript/components/TypesDeChampEditor/typeDeChampsReducer.js b/app/javascript/components/TypesDeChampEditor/typeDeChampsReducer.js index f594ecf67..35eb2d83a 100644 --- a/app/javascript/components/TypesDeChampEditor/typeDeChampsReducer.js +++ b/app/javascript/components/TypesDeChampEditor/typeDeChampsReducer.js @@ -37,8 +37,7 @@ export default function typeDeChampsReducer(state, { type, params, done }) { function addTypeDeChamp(state, typeDeChamps, insertAfter, done) { const typeDeChamp = { - ...state.defaultTypeDeChampAttributes, - order_place: typeDeChamps.length + ...state.defaultTypeDeChampAttributes }; createTypeDeChampOperation(typeDeChamp, state.queue) diff --git a/app/jobs/tmp_dossiers_migrate_revisions_job.rb b/app/jobs/tmp_dossiers_migrate_revisions_job.rb deleted file mode 100644 index 1e0669217..000000000 --- a/app/jobs/tmp_dossiers_migrate_revisions_job.rb +++ /dev/null @@ -1,21 +0,0 @@ -class TmpDossiersMigrateRevisionsJob < ApplicationJob - def perform(except) - dossiers = Dossier.with_discarded.where(revision_id: nil) - - dossiers.where - .not(id: except) - .includes(procedure: [:draft_revision, :published_revision]) - .limit(2000) - .find_each do |dossier| - if dossier.procedure.present? - dossier.update_column(:revision_id, dossier.procedure.active_revision.id) - else - except << dossier.id - end - end - - if dossiers.where.not(id: except).exists? - TmpDossiersMigrateRevisionsJob.perform_later(except) - end - end -end diff --git a/app/models/champ.rb b/app/models/champ.rb index f6861b498..b4231596c 100644 --- a/app/models/champ.rb +++ b/app/models/champ.rb @@ -47,6 +47,9 @@ class Champ < ApplicationRecord scope :public_only, -> { where(private: false) } scope :private_only, -> { where(private: true) } scope :ordered, -> { includes(:type_de_champ).order(:row, 'types_de_champ.order_place') } + scope :public_ordered, -> { public_only.joins(dossier: { revision: :revision_types_de_champ }).where('procedure_revision_types_de_champ.type_de_champ_id = champs.type_de_champ_id').order(:position) } + scope :private_ordered, -> { private_only.joins(dossier: { revision: :revision_types_de_champ_private }).where('procedure_revision_types_de_champ.type_de_champ_id = champs.type_de_champ_id').order(:position) } + scope :root, -> { where(parent_id: nil) } before_validation :set_dossier_id, if: :needs_dossier_id? diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 51237c304..1cca19ee4 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -62,8 +62,8 @@ class Dossier < ApplicationRecord has_one_attached :justificatif_motivation - has_many :champs, -> { root.public_only.ordered }, inverse_of: :dossier, dependent: :destroy - has_many :champs_private, -> { root.private_only.ordered }, class_name: 'Champ', inverse_of: :dossier, dependent: :destroy + has_many :champs, -> { root.public_ordered }, inverse_of: :dossier, dependent: :destroy + has_many :champs_private, -> { root.private_ordered }, class_name: 'Champ', inverse_of: :dossier, dependent: :destroy has_many :commentaires, inverse_of: :dossier, dependent: :destroy has_many :invites, dependent: :destroy has_many :follows, -> { active }, inverse_of: :dossier @@ -76,10 +76,13 @@ class Dossier < ApplicationRecord has_many :dossier_operation_logs, -> { order(:created_at) }, dependent: :nullify, inverse_of: :dossier belongs_to :groupe_instructeur, optional: false - has_one :procedure, through: :groupe_instructeur - belongs_to :revision, class_name: 'ProcedureRevision', optional: true + belongs_to :revision, class_name: 'ProcedureRevision', optional: false belongs_to :user, optional: false + has_one :procedure, through: :revision + has_many :types_de_champ, through: :revision + has_many :types_de_champ_private, through: :revision + accepts_nested_attributes_for :champs accepts_nested_attributes_for :champs_private @@ -315,7 +318,6 @@ class Dossier < ApplicationRecord accepts_nested_attributes_for :individual delegate :siret, :siren, to: :etablissement, allow_nil: true - delegate :types_de_champ, to: :procedure delegate :france_connect_information, to: :user before_save :build_default_champs, if: Proc.new { groupe_instructeur_id_was.nil? } @@ -326,7 +328,7 @@ class Dossier < ApplicationRecord after_create :send_draft_notification_email validates :user, presence: true - validates :individual, presence: true, if: -> { procedure.for_individual? } + validates :individual, presence: true, if: -> { revision.procedure.for_individual? } validates :groupe_instructeur, presence: true def motivation @@ -351,10 +353,10 @@ class Dossier < ApplicationRecord end def build_default_champs - procedure.build_champs.each do |champ| + revision.build_champs.each do |champ| champs << champ end - procedure.build_champs_private.each do |champ| + revision.build_champs_private.each do |champ| champs_private << champ end end diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 2433679c5..ab04a58bd 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -56,13 +56,16 @@ class Procedure < ApplicationRecord MAX_DUREE_CONSERVATION = 36 MAX_DUREE_CONSERVATION_EXPORT = 3.hours - has_many :types_de_champ, -> { root.public_only.ordered }, inverse_of: :procedure, dependent: :destroy - has_many :types_de_champ_private, -> { root.private_only.ordered }, class_name: 'TypeDeChamp', inverse_of: :procedure, dependent: :destroy has_many :revisions, -> { order(:id) }, class_name: 'ProcedureRevision', inverse_of: :procedure, dependent: :destroy - belongs_to :draft_revision, class_name: 'ProcedureRevision', optional: true + belongs_to :draft_revision, class_name: 'ProcedureRevision', optional: false belongs_to :published_revision, class_name: 'ProcedureRevision', optional: true has_many :deleted_dossiers, dependent: :destroy + has_many :published_types_de_champ, through: :published_revision, source: :types_de_champ + has_many :published_types_de_champ_private, through: :published_revision, source: :types_de_champ_private + has_many :draft_types_de_champ, through: :draft_revision, source: :types_de_champ + has_many :draft_types_de_champ_private, through: :draft_revision, source: :types_de_champ_private + has_one :module_api_carto, dependent: :destroy has_one :attestation_template, dependent: :destroy @@ -74,6 +77,14 @@ class Procedure < ApplicationRecord brouillon? ? draft_revision : published_revision end + def types_de_champ + brouillon? ? draft_types_de_champ : published_types_de_champ + end + + def types_de_champ_private + brouillon? ? draft_types_de_champ_private : published_types_de_champ_private + end + has_many :administrateurs_procedures has_many :administrateurs, through: :administrateurs_procedures, after_remove: -> (procedure, _admin) { procedure.validate! } has_many :groupe_instructeurs, dependent: :destroy @@ -93,9 +104,6 @@ class Procedure < ApplicationRecord has_one_attached :notice has_one_attached :deliberation - accepts_nested_attributes_for :types_de_champ, reject_if: proc { |attributes| attributes['libelle'].blank? }, allow_destroy: true - accepts_nested_attributes_for :types_de_champ_private, reject_if: proc { |attributes| attributes['libelle'].blank? }, allow_destroy: true - scope :brouillons, -> { where(aasm_state: :brouillon) } scope :publiees, -> { where(aasm_state: :publiee) } scope :closes, -> { where(aasm_state: [:close, :depubliee]) } @@ -114,9 +122,15 @@ class Procedure < ApplicationRecord scope :for_api, -> { includes( :administrateurs, - :types_de_champ_private, - :types_de_champ, - :module_api_carto + :module_api_carto, + published_revision: [ + :types_de_champ_private, + :types_de_champ + ], + draft_revision: [ + :types_de_champ_private, + :types_de_champ + ] ) } @@ -289,22 +303,13 @@ class Procedure < ApplicationRecord # to save a dossier created from this method def new_dossier Dossier.new( - procedure: self, revision: active_revision, - champs: build_champs, - champs_private: build_champs_private, + champs: active_revision.build_champs, + champs_private: active_revision.build_champs_private, groupe_instructeur: defaut_groupe_instructeur ) end - def build_champs - types_de_champ.map(&:build_champ) - end - - def build_champs_private - types_de_champ_private.map(&:build_champ) - end - def path_customized? !path.match?(/[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}/) end @@ -318,9 +323,6 @@ class Procedure < ApplicationRecord end def clone(admin, from_library) - # FIXUP: needed during transition to revisions - RevisionsMigration.add_revisions(self) - is_different_admin = !admin.owns?(self) populate_champ_stable_ids @@ -371,19 +373,11 @@ class Procedure < ApplicationRecord end procedure.save - procedure.draft_revision.types_de_champ.update_all(revision_id: procedure.draft_revision.id) - procedure.draft_revision.types_de_champ_private.update_all(revision_id: procedure.draft_revision.id) - - # FIXUP: needed during transition to revisions - procedure.draft_revision.types_de_champ.each do |type_de_champ| - procedure.types_de_champ << type_de_champ - end - procedure.draft_revision.types_de_champ_private.each do |type_de_champ| - procedure.types_de_champ_private << type_de_champ - end + procedure.draft_types_de_champ.update_all(revision_id: procedure.draft_revision.id) + procedure.draft_types_de_champ_private.update_all(revision_id: procedure.draft_revision.id) if is_different_admin || from_library - procedure.types_de_champ.each { |tdc| tdc.options&.delete(:old_pj) } + procedure.draft_types_de_champ.each { |tdc| tdc.options&.delete(:old_pj) } end procedure @@ -608,23 +602,14 @@ class Procedure < ApplicationRecord end def after_publish(canonical_procedure = nil) - # FIXUP: needed during transition to revisions - if RevisionsMigration.add_revisions(self) - update!(published_at: Time.zone.now, canonical_procedure: canonical_procedure) - else - update!(published_at: Time.zone.now, canonical_procedure: canonical_procedure, draft_revision: create_new_revision, published_revision: draft_revision) - end + update!(published_at: Time.zone.now, canonical_procedure: canonical_procedure, draft_revision: create_new_revision, published_revision: draft_revision) end def after_close - # FIXUP: needed during transition to revisions - RevisionsMigration.add_revisions(self) update!(closed_at: Time.zone.now) end def after_unpublish - # FIXUP: needed during transition to revisions - RevisionsMigration.add_revisions(self) update!(unpublished_at: Time.zone.now) end diff --git a/app/models/procedure_revision.rb b/app/models/procedure_revision.rb index a86d0fdb1..b97564455 100644 --- a/app/models/procedure_revision.rb +++ b/app/models/procedure_revision.rb @@ -9,15 +9,22 @@ # class ProcedureRevision < ApplicationRecord self.implicit_order_column = :created_at - belongs_to :procedure, -> { with_discarded }, inverse_of: :revisions + belongs_to :procedure, -> { with_discarded }, inverse_of: :revisions, optional: false has_many :revision_types_de_champ, -> { public_only.ordered }, class_name: 'ProcedureRevisionTypeDeChamp', foreign_key: :revision_id, dependent: :destroy, inverse_of: :revision has_many :revision_types_de_champ_private, -> { private_only.ordered }, class_name: 'ProcedureRevisionTypeDeChamp', foreign_key: :revision_id, dependent: :destroy, inverse_of: :revision has_many :types_de_champ, through: :revision_types_de_champ, source: :type_de_champ has_many :types_de_champ_private, through: :revision_types_de_champ_private, source: :type_de_champ + def build_champs + types_de_champ.map(&:build_champ) + end + + def build_champs_private + types_de_champ_private.map(&:build_champ) + end + def add_type_de_champ(params) - params[:procedure] = procedure params[:revision] = self if params[:parent_id] @@ -27,15 +34,9 @@ class ProcedureRevision < ApplicationRecord params[:order_place] = types_de_champ.present? ? types_de_champ.last.order_place + 1 : 0 end.create(params) elsif params[:private] - types_de_champ_private.tap do |types_de_champ| - # FIXUP: needed during transition to revisions - params[:order_place] = types_de_champ.present? ? types_de_champ.last.order_place + 1 : 0 - end.create(params) + types_de_champ_private.create(params) else - types_de_champ.tap do |types_de_champ| - # FIXUP: needed during transition to revisions - params[:order_place] = types_de_champ.present? ? types_de_champ.last.order_place + 1 : 0 - end.create(params) + types_de_champ.create(params) end end @@ -112,8 +113,6 @@ class ProcedureRevision < ApplicationRecord if types_de_champ.delete_at(old_index) types_de_champ.insert(new_index, type_de_champ) .map.with_index do |type_de_champ, index| - # FIXUP: needed during transition to revisions - type_de_champ.update!(order_place: index) [type_de_champ.id, index] end else diff --git a/app/models/procedure_revision_type_de_champ.rb b/app/models/procedure_revision_type_de_champ.rb index e4e243ec5..6859d1884 100644 --- a/app/models/procedure_revision_type_de_champ.rb +++ b/app/models/procedure_revision_type_de_champ.rb @@ -26,15 +26,11 @@ class ProcedureRevisionTypeDeChamp < ApplicationRecord private def set_position - self.position ||= if private? - if revision.types_de_champ_private.present? - revision.revision_types_de_champ_private.filter(&:persisted?).last.position + 1 - else - 0 - end - else - if revision.types_de_champ.present? - revision.revision_types_de_champ.filter(&:persisted?).last.position + 1 + self.position ||= begin + types_de_champ = (private? ? revision.revision_types_de_champ_private : revision.revision_types_de_champ).filter(&:persisted?) + + if types_de_champ.present? + types_de_champ.last.position + 1 else 0 end diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index 68a031009..c308f397a 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -49,8 +49,8 @@ class TypeDeChamp < ApplicationRecord repetition: 'repetition' } - belongs_to :procedure, optional: false belongs_to :revision, class_name: 'ProcedureRevision', optional: true + has_one :procedure, through: :revision belongs_to :parent, class_name: 'TypeDeChamp', optional: true has_many :types_de_champ, -> { ordered }, foreign_key: :parent_id, class_name: 'TypeDeChamp', inverse_of: :parent, dependent: :destroy @@ -73,7 +73,6 @@ class TypeDeChamp < ApplicationRecord serialize :options, WithIndifferentAccess after_initialize :set_dynamic_type - before_validation :setup_procedure after_create :populate_stable_id attr_reader :dynamic_type @@ -298,9 +297,34 @@ class TypeDeChamp < ApplicationRecord .merge(include: { types_de_champ: TYPES_DE_CHAMP_BASE }) def self.as_json_for_editor - includes(piece_justificative_template_attachment: :blob, - types_de_champ: [piece_justificative_template_attachment: :blob]) - .as_json(TYPES_DE_CHAMP) + includes(piece_justificative_template_attachment: :blob, types_de_champ: [piece_justificative_template_attachment: :blob]).as_json(TYPES_DE_CHAMP) + end + + def read_attribute_for_serialization(name) + if name == 'id' + self.class.format_stable_id(stable_id) + else + super + end + end + + # FIXME: We are changing how id is exposed to the editor. + # We used to expose type_de_champ.id as primary key to the editor. With revisions + # we need primary key to be type_de_champ.stable_id because any update can create + # a new version but we do not want editor to know about this. + # This is only needed for a clean migration without downtime. We want to ensure + # that if editor send a simple id because it was loaded before deployment + # we would still do the right thing. + def self.format_stable_id(stable_id) + "stable:#{stable_id}" + end + + def self.to_stable_id(id_or_stable_id) + if id_or_stable_id.to_s =~ /^stable:/ + id_or_stable_id.to_s.gsub(/^stable:/, '') + else + find(id_or_stable_id).stable_id + end end private @@ -311,12 +335,6 @@ class TypeDeChamp < ApplicationRecord result.blank? ? [] : [''] + result end - def setup_procedure - types_de_champ.each do |type_de_champ| - type_de_champ.procedure = procedure - end - end - def populate_stable_id if !stable_id update_column(:stable_id, id) diff --git a/app/serializers/dossier_serializer.rb b/app/serializers/dossier_serializer.rb index d4b4a90d6..9fdebb9f0 100644 --- a/app/serializers/dossier_serializer.rb +++ b/app/serializers/dossier_serializer.rb @@ -67,7 +67,7 @@ class DossierSerializer < ActiveModel::Serializer end def types_de_piece_justificative - PiecesJustificativesService.serialize_types_de_champ_as_type_pj(object) + PiecesJustificativesService.serialize_types_de_champ_as_type_pj(object.revision) end def email diff --git a/app/serializers/procedure_serializer.rb b/app/serializers/procedure_serializer.rb index 6dd3a0df0..ef0eb2b35 100644 --- a/app/serializers/procedure_serializer.rb +++ b/app/serializers/procedure_serializer.rb @@ -48,6 +48,6 @@ class ProcedureSerializer < ActiveModel::Serializer end def types_de_piece_justificative - PiecesJustificativesService.serialize_types_de_champ_as_type_pj(object) + PiecesJustificativesService.serialize_types_de_champ_as_type_pj(object.active_revision) end end diff --git a/app/services/pieces_justificatives_service.rb b/app/services/pieces_justificatives_service.rb index 7b4632b09..2c4e6fe80 100644 --- a/app/services/pieces_justificatives_service.rb +++ b/app/services/pieces_justificatives_service.rb @@ -12,8 +12,8 @@ class PiecesJustificativesService .sum(&:byte_size) end - def self.serialize_types_de_champ_as_type_pj(procedure) - tdcs = procedure.types_de_champ.filter { |type_champ| type_champ.old_pj.present? } + def self.serialize_types_de_champ_as_type_pj(revision) + tdcs = revision.types_de_champ.filter { |type_champ| type_champ.old_pj.present? } tdcs.map.with_index do |type_champ, order_place| description = type_champ.description if /^(?.*?)(?:[\r\n]+)Récupérer le formulaire vierge pour mon dossier : (?http.*)$/m =~ description diff --git a/app/services/revisions_migration.rb b/app/services/revisions_migration.rb deleted file mode 100644 index df8f4c5b1..000000000 --- a/app/services/revisions_migration.rb +++ /dev/null @@ -1,36 +0,0 @@ -class RevisionsMigration - def self.add_revisions(procedure) - if procedure.draft_revision.present? - return false - end - - procedure.draft_revision = procedure.revisions.create - procedure.save!(validate: false) - - add_types_de_champs_to_revision(procedure, :types_de_champ) - add_types_de_champs_to_revision(procedure, :types_de_champ_private) - - if !procedure.brouillon? - published_revision = procedure.draft_revision - - procedure.draft_revision = procedure.create_new_revision - procedure.published_revision = published_revision - procedure.save!(validate: false) - end - - true - end - - def self.add_types_de_champs_to_revision(procedure, types_de_champ_scope) - types_de_champ = procedure.send(types_de_champ_scope) - types_de_champ.where(revision_id: nil).update_all(revision_id: procedure.draft_revision.id) - - types_de_champ.each.with_index do |type_de_champ, index| - type_de_champ.types_de_champ.where(revision_id: nil).update_all(revision_id: procedure.draft_revision.id) - procedure.draft_revision.send(:"revision_#{types_de_champ_scope}").create!( - type_de_champ: type_de_champ, - position: index - ) - end - end -end diff --git a/app/views/new_administrateur/procedures/show.html.haml b/app/views/new_administrateur/procedures/show.html.haml index d8e40772b..ae27c63e7 100644 --- a/app/views/new_administrateur/procedures/show.html.haml +++ b/app/views/new_administrateur/procedures/show.html.haml @@ -40,7 +40,7 @@ - if !@procedure.locked? .card-admin - - if @procedure.types_de_champ.count > 0 + - if @procedure.draft_types_de_champ.count > 0 %div %span.icon.accept %p.card-admin-status-accept Validé @@ -50,7 +50,7 @@ %p.card-admin-status-todo À faire %div %p.card-admin-title - %span.badge.baseline= @procedure.types_de_champ.count + %span.badge.baseline= @procedure.draft_types_de_champ.count Champs du formulaire %p.card-admin-subtitle À remplir par les usagers .card-admin-action @@ -148,7 +148,7 @@ - if !@procedure.locked? .card-admin - - if @procedure.types_de_champ_private.present? + - if @procedure.draft_types_de_champ_private.present? %div %span.icon.accept %p.card-admin-status-accept Validé From d1fb6c559e0cd6f5db9e626712b0dcd2fffa6a84 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 27 Aug 2020 19:55:37 +0200 Subject: [PATCH 14/27] Update factories to use revisions --- spec/factories/champ.rb | 15 +-- spec/factories/dossier.rb | 8 +- spec/factories/procedure.rb | 91 ++++++++++--------- spec/factories/procedure_revision.rb | 4 + .../procedure_revision_type_de_champ.rb | 4 + spec/factories/type_de_champ.rb | 59 ++++++++++-- 6 files changed, 116 insertions(+), 65 deletions(-) create mode 100644 spec/factories/procedure_revision.rb create mode 100644 spec/factories/procedure_revision_type_de_champ.rb diff --git a/spec/factories/champ.rb b/spec/factories/champ.rb index 1a20f4e50..7d057c320 100644 --- a/spec/factories/champ.rb +++ b/spec/factories/champ.rb @@ -161,23 +161,20 @@ FactoryBot.define do existing_type_de_champ_text = types_de_champ.find { |tdc| tdc.libelle == 'Nom' } type_de_champ_text = existing_type_de_champ_text || build( :type_de_champ_text, - order_place: 0, - procedure: champ_repetition.dossier.procedure, + position: 0, parent: champ_repetition.type_de_champ, libelle: 'Nom' ) - types_de_champ << type_de_champ_text existing_type_de_champ_number = types_de_champ.find { |tdc| tdc.libelle == 'Age' } type_de_champ_number = existing_type_de_champ_number || build( :type_de_champ_number, - order_place: 1, - procedure: champ_repetition.dossier.procedure, + position: 1, parent: champ_repetition.type_de_champ, libelle: 'Age' ) - types_de_champ << type_de_champ_number + champ_repetition.type_de_champ.types_de_champ << [type_de_champ_text, type_de_champ_number] champ_repetition.champs << [ build(:champ_text, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_text, parent: champ_repetition), build(:champ_number, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_number, parent: champ_repetition), @@ -198,13 +195,11 @@ FactoryBot.define do after(:build) do |champ_repetition, _evaluator| type_de_champ_pj0 = build(:type_de_champ_piece_justificative, - procedure: champ_repetition.dossier.procedure, - order_place: 0, + position: 0, parent: champ_repetition.type_de_champ, libelle: 'Justificatif de domicile') type_de_champ_pj1 = build(:type_de_champ_piece_justificative, - procedure: champ_repetition.dossier.procedure, - order_place: 1, + position: 1, parent: champ_repetition.type_de_champ, libelle: 'Carte d\'identité') diff --git a/spec/factories/dossier.rb b/spec/factories/dossier.rb index c5aa95d98..cb10c08b7 100644 --- a/spec/factories/dossier.rb +++ b/spec/factories/dossier.rb @@ -15,6 +15,8 @@ FactoryBot.define do procedure = create(:procedure, :published, :with_type_de_champ, :with_type_de_champ_private) end + dossier.revision = procedure.active_revision + # Assign the procedure to the dossier through the groupe_instructeur if dossier.groupe_instructeur.nil? dossier.groupe_instructeur = procedure.defaut_groupe_instructeur @@ -71,7 +73,7 @@ FactoryBot.define do linked_dossier = create(:dossier, :en_construction) # find first type de champ dossier_link - type_de_champ = dossier.procedure.types_de_champ.find do |t| + type_de_champ = dossier.types_de_champ.find do |t| t.type_champ == TypeDeChamp.type_champs.fetch(:dossier_link) end @@ -202,7 +204,7 @@ FactoryBot.define do trait :with_all_champs do after(:create) do |dossier, _evaluator| - dossier.champs = dossier.procedure.types_de_champ.map do |type_de_champ| + dossier.champs = dossier.types_de_champ.map do |type_de_champ| build(:"champ_#{type_de_champ.type_champ}", dossier: dossier, type_de_champ: type_de_champ) end dossier.save! @@ -211,7 +213,7 @@ FactoryBot.define do trait :with_all_annotations do after(:create) do |dossier, _evaluator| - dossier.champs = dossier.procedure.types_de_champ.map do |type_de_champ| + dossier.champs = dossier.types_de_champ.map do |type_de_champ| build(:"champ_#{type_de_champ.type_champ}", dossier: dossier, type_de_champ: type_de_champ) end dossier.save! diff --git a/spec/factories/procedure.rb b/spec/factories/procedure.rb index cf379bac5..4466b1bde 100644 --- a/spec/factories/procedure.rb +++ b/spec/factories/procedure.rb @@ -16,6 +16,9 @@ FactoryBot.define do transient do administrateur { } instructeurs { [] } + types_de_champ { [] } + types_de_champ_private { [] } + updated_at { nil } end after(:build) do |procedure, evaluator| @@ -24,10 +27,35 @@ FactoryBot.define do elsif procedure.administrateurs.empty? procedure.administrateurs = [create(:administrateur)] end + procedure.draft_revision = build(:procedure_revision, procedure: procedure) + + evaluator.types_de_champ.each do |type_de_champ| + type_de_champ.revision = procedure.draft_revision + type_de_champ.private = false + type_de_champ.revision.revision_types_de_champ << build(:procedure_revision_type_de_champ, + revision: procedure.draft_revision, + position: type_de_champ.order_place, + type_de_champ: type_de_champ) + end + + evaluator.types_de_champ_private.each do |type_de_champ| + type_de_champ.revision = procedure.draft_revision + type_de_champ.private = true + type_de_champ.revision.revision_types_de_champ_private << build(:procedure_revision_type_de_champ, + revision: procedure.draft_revision, + position: type_de_champ.order_place, + type_de_champ: type_de_champ) + end end after(:create) do |procedure, evaluator| evaluator.instructeurs.each { |i| i.assign_to_procedure(procedure) } + + if evaluator.updated_at + procedure.update_column(:updated_at, evaluator.updated_at) + end + + procedure.reload end factory :procedure_with_dossiers do @@ -38,9 +66,7 @@ FactoryBot.define do after(:create) do |procedure, evaluator| user = create(:user) evaluator.dossiers_count.times do - dossier = procedure.new_dossier - dossier.user = user - dossier.save! + create(:dossier, procedure: procedure, user: user) end end end @@ -48,7 +74,7 @@ FactoryBot.define do factory :simple_procedure do after(:build) do |procedure, _evaluator| procedure.for_individual = true - procedure.types_de_champ << build(:type_de_champ, libelle: 'Texte obligatoire', mandatory: true) + build(:type_de_champ, libelle: 'Texte obligatoire', mandatory: true, procedure: procedure) procedure.path = generate(:published_path) procedure.publish! end @@ -96,10 +122,8 @@ FactoryBot.define do end after(:build) do |procedure, evaluator| - evaluator.types_de_champ_count.times do - type_de_champ = build(:type_de_champ) - - procedure.types_de_champ << type_de_champ + evaluator.types_de_champ_count.times do |position| + build(:type_de_champ, procedure: procedure, position: position) end end end @@ -110,68 +134,51 @@ FactoryBot.define do end after(:build) do |procedure, evaluator| - evaluator.types_de_champ_private_count.times do - type_de_champ = build(:type_de_champ, :private) - - procedure.types_de_champ_private << type_de_champ + evaluator.types_de_champ_private_count.times do |position| + build(:type_de_champ, :private, procedure: procedure, position: position) end end end trait :with_type_de_champ_mandatory do after(:build) do |procedure, _evaluator| - type_de_champ = build(:type_de_champ, mandatory: true) - - procedure.types_de_champ << type_de_champ + build(:type_de_champ, mandatory: true, procedure: procedure) end end trait :with_datetime do after(:build) do |procedure, _evaluator| - type_de_champ = build(:type_de_champ_datetime, mandatory: true) - - procedure.types_de_champ << type_de_champ + build(:type_de_champ_datetime, mandatory: true, procedure: procedure) end end trait :with_dossier_link do after(:build) do |procedure, _evaluator| - type_de_champ = build(:type_de_champ_dossier_link) - - procedure.types_de_champ << type_de_champ + build(:type_de_champ_dossier_link, procedure: procedure) end end trait :with_yes_no do after(:build) do |procedure, _evaluator| - type_de_champ = build(:type_de_champ_yes_no) - - procedure.types_de_champ << type_de_champ + build(:type_de_champ_yes_no, procedure: procedure) end end trait :with_piece_justificative do after(:build) do |procedure, _evaluator| - type_de_champ = build(:type_de_champ_piece_justificative) - - procedure.types_de_champ << type_de_champ + build(:type_de_champ_piece_justificative, procedure: procedure) end end trait :with_repetition do after(:build) do |procedure, _evaluator| - type_de_champ = build(:type_de_champ_repetition) - procedure.types_de_champ << type_de_champ - - type_de_champ.types_de_champ << build(:type_de_champ, libelle: 'sub type de champ') + build(:type_de_champ_repetition, :with_types_de_champ, procedure: procedure) end end trait :with_number do after(:build) do |procedure, _evaluator| - type_de_champ = build(:type_de_champ_number) - - procedure.types_de_champ << type_de_champ + build(:type_de_champ_number, procedure: procedure) end end @@ -228,35 +235,35 @@ FactoryBot.define do trait :with_all_champs_mandatory do after(:build) do |procedure, _evaluator| - procedure.types_de_champ = TypeDeChamp.type_champs.map.with_index do |(libelle, type_champ), index| + TypeDeChamp.type_champs.map.with_index do |(libelle, type_champ), index| if libelle == 'drop_down_list' libelle = 'simple_drop_down_list' end - build(:"type_de_champ_#{type_champ}", procedure: procedure, mandatory: true, libelle: libelle, order_place: index) + build(:"type_de_champ_#{type_champ}", procedure: procedure, mandatory: true, libelle: libelle, position: index) end - procedure.types_de_champ << build(:type_de_champ_drop_down_list, :long, procedure: procedure, mandatory: true, libelle: 'simple_choice_drop_down_list_long') - procedure.types_de_champ << build(:type_de_champ_multiple_drop_down_list, :long, procedure: procedure, mandatory: true, libelle: 'multiple_choice_drop_down_list_long') + build(:type_de_champ_drop_down_list, :long, procedure: procedure, mandatory: true, libelle: 'simple_choice_drop_down_list_long', position: TypeDeChamp.type_champs.size) + build(:type_de_champ_multiple_drop_down_list, :long, procedure: procedure, mandatory: true, libelle: 'multiple_choice_drop_down_list_long', position: TypeDeChamp.type_champs.size + 1) end end trait :with_all_champs do after(:build) do |procedure, _evaluator| - procedure.types_de_champ = TypeDeChamp.type_champs.map.with_index do |(libelle, type_champ), index| + TypeDeChamp.type_champs.map.with_index do |(libelle, type_champ), index| if libelle == 'drop_down_list' libelle = 'simple_drop_down_list' end - build(:"type_de_champ_#{type_champ}", procedure: procedure, libelle: libelle, order_place: index) + build(:"type_de_champ_#{type_champ}", procedure: procedure, libelle: libelle, position: index) end end end trait :with_all_annotations do after(:build) do |procedure, _evaluator| - procedure.types_de_champ_private = TypeDeChamp.type_champs.map.with_index do |(libelle, type_champ), index| + TypeDeChamp.type_champs.map.with_index do |(libelle, type_champ), index| if libelle == 'drop_down_list' libelle = 'simple_drop_down_list' end - build(:"type_de_champ_#{type_champ}", procedure: procedure, private: true, libelle: libelle, order_place: index) + build(:"type_de_champ_#{type_champ}", procedure: procedure, private: true, libelle: libelle, position: index) end end end diff --git a/spec/factories/procedure_revision.rb b/spec/factories/procedure_revision.rb new file mode 100644 index 000000000..050749066 --- /dev/null +++ b/spec/factories/procedure_revision.rb @@ -0,0 +1,4 @@ +FactoryBot.define do + factory :procedure_revision do + end +end diff --git a/spec/factories/procedure_revision_type_de_champ.rb b/spec/factories/procedure_revision_type_de_champ.rb new file mode 100644 index 000000000..62359ab98 --- /dev/null +++ b/spec/factories/procedure_revision_type_de_champ.rb @@ -0,0 +1,4 @@ +FactoryBot.define do + factory :procedure_revision_type_de_champ do + end +end diff --git a/spec/factories/type_de_champ.rb b/spec/factories/type_de_champ.rb index 340f6060d..0c4f2b7cc 100644 --- a/spec/factories/type_de_champ.rb +++ b/spec/factories/type_de_champ.rb @@ -7,7 +7,40 @@ FactoryBot.define do mandatory { false } add_attribute(:private) { false } - association :procedure + transient do + procedure { nil } + position { nil } + parent { nil } + end + + after(:build) do |type_de_champ, evaluator| + if evaluator.procedure + type_de_champ.revision = evaluator.procedure.active_revision + + build(:procedure_revision_type_de_champ, + position: evaluator.position, + revision: evaluator.procedure.active_revision, + type_de_champ: type_de_champ) + + if type_de_champ.private? + type_de_champ.revision.types_de_champ_private << type_de_champ + else + type_de_champ.revision.types_de_champ << type_de_champ + end + elsif evaluator.parent + type_de_champ.revision = evaluator.parent.revision + type_de_champ.order_place = evaluator.position || evaluator.parent.types_de_champ.size + evaluator.parent.types_de_champ << type_de_champ + else + type_de_champ.order_place = evaluator.position + end + end + + trait :private do + add_attribute(:private) { true } + sequence(:libelle) { |n| "Libelle champ privé #{n}" } + sequence(:description) { |n| "description du champ privé #{n}" } + end factory :type_de_champ_text do type_champ { TypeDeChamp.type_champs.fetch(:text) } @@ -96,8 +129,8 @@ FactoryBot.define do factory :type_de_champ_piece_justificative do type_champ { TypeDeChamp.type_champs.fetch(:piece_justificative) } - after(:build) do |tc, _evaluator| - tc.piece_justificative_template.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain") + after(:build) do |type_de_champ, _evaluator| + type_de_champ.piece_justificative_template.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain") end end factory :type_de_champ_siret do @@ -109,17 +142,23 @@ FactoryBot.define do factory :type_de_champ_repetition do type_champ { TypeDeChamp.type_champs.fetch(:repetition) } + transient do + types_de_champ { [] } + end + + after(:build) do |type_de_champ_repetition, evaluator| + evaluator.types_de_champ.each do |type_de_champ| + type_de_champ.revision = type_de_champ_repetition.revision + type_de_champ.order_place = type_de_champ_repetition.types_de_champ.size + type_de_champ_repetition.types_de_champ << type_de_champ + end + end + trait :with_types_de_champ do after(:build) do |type_de_champ, _evaluator| - type_de_champ.types_de_champ << build(:type_de_champ, procedure: type_de_champ.procedure, libelle: 'sub type de champ') + build(:type_de_champ, libelle: 'sub type de champ', parent: type_de_champ) end end end - - trait :private do - add_attribute(:private) { true } - sequence(:libelle) { |n| "Libelle champ privé #{n}" } - sequence(:description) { |n| "description du champ privé #{n}" } - end end end From 1488e0964bb0bdf5700b1755bd9fee4c8b0c465d Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 27 Aug 2020 19:56:19 +0200 Subject: [PATCH 15/27] update models specs to use revisions --- spec/models/champ_spec.rb | 13 +-- .../champs/header_section_champ_spec.rb | 17 ++-- .../concern/tags_substitution_concern_spec.rb | 38 ++++---- spec/models/dossier_spec.rb | 85 ++++++++---------- spec/models/procedure_presentation_spec.rb | 2 +- spec/models/procedure_revision_spec.rb | 18 +--- spec/models/procedure_spec.rb | 86 ++++++++----------- spec/models/type_de_champ_shared_example.rb | 38 -------- 8 files changed, 103 insertions(+), 194 deletions(-) diff --git a/spec/models/champ_spec.rb b/spec/models/champ_spec.rb index 62551648b..870aa3fc1 100644 --- a/spec/models/champ_spec.rb +++ b/spec/models/champ_spec.rb @@ -427,10 +427,9 @@ describe Champ do end describe 'repetition' do - let(:procedure) { build(:procedure, :published, :with_type_de_champ, :with_type_de_champ_private) } - let(:tdc_text) { build(:type_de_champ_text, procedure: procedure) } - let(:tdc_integer) { build(:type_de_champ_integer_number, procedure: procedure) } - let(:tdc_repetition) { build(:type_de_champ_repetition, procedure: procedure, types_de_champ: [tdc_text, tdc_integer]) } + let(:procedure) { create(:procedure, :published, :with_type_de_champ, :with_type_de_champ_private, types_de_champ: [build(:type_de_champ_repetition, types_de_champ: [tdc_text, tdc_integer])]) } + let(:tdc_text) { build(:type_de_champ_text) } + let(:tdc_integer) { build(:type_de_champ_integer_number) } let(:dossier) { create(:dossier, procedure: procedure) } let(:champ) { dossier.champs.find(&:repetition?) } @@ -438,12 +437,6 @@ describe Champ do let(:champ_integer) { champ.champs.find { |c| c.type_champ == 'integer_number' } } let(:champ_text_attrs) { attributes_for(:champ_text, type_de_champ: tdc_text, row: 1) } - before do - procedure.types_de_champ << tdc_repetition - procedure.save! - procedure.reload - end - context 'when creating the model directly' do let(:champ_text_row_1) { create(:champ_text, type_de_champ: tdc_text, row: 2, parent: champ, dossier: nil) } diff --git a/spec/models/champs/header_section_champ_spec.rb b/spec/models/champs/header_section_champ_spec.rb index 2e604bb5c..e09c5fb87 100644 --- a/spec/models/champs/header_section_champ_spec.rb +++ b/spec/models/champs/header_section_champ_spec.rb @@ -2,11 +2,11 @@ describe Champs::HeaderSectionChamp do describe '#section_index' do let(:types_de_champ) do [ - create(:type_de_champ_header_section, order_place: 1), - create(:type_de_champ_civilite, order_place: 2), - create(:type_de_champ_text, order_place: 3), - create(:type_de_champ_header_section, order_place: 4), - create(:type_de_champ_email, order_place: 5) + build(:type_de_champ_header_section, position: 1), + build(:type_de_champ_civilite, position: 2), + build(:type_de_champ_text, position: 3), + build(:type_de_champ_header_section, position: 4), + build(:type_de_champ_email, position: 5) ] end @@ -23,17 +23,12 @@ describe Champs::HeaderSectionChamp do end context 'for repetition champs' do - let(:procedure) { create(:procedure, :with_repetition) } + let(:procedure) { create(:procedure, types_de_champ: [build(:type_de_champ_repetition, types_de_champ: types_de_champ)]) } let(:dossier) { create(:dossier, procedure: procedure) } - let(:repetition_tdc) { procedure.types_de_champ.find(&:repetition?) } let(:first_header) { dossier.champs.first.champs[0] } let(:second_header) { dossier.champs.first.champs[3] } - before do - repetition_tdc.types_de_champ = types_de_champ - end - it 'returns the index of the section in the repetition (starting from 1)' do expect(first_header.section_index).to eq 1 expect(second_header.section_index).to eq 2 diff --git a/spec/models/concern/tags_substitution_concern_spec.rb b/spec/models/concern/tags_substitution_concern_spec.rb index 37acae977..e0aab4b00 100644 --- a/spec/models/concern/tags_substitution_concern_spec.rb +++ b/spec/models/concern/tags_substitution_concern_spec.rb @@ -97,8 +97,8 @@ describe TagsSubstitutionConcern, type: :model do context 'when the procedure has a type de champ named libelleA et libelleB' do let(:types_de_champ) do [ - create(:type_de_champ, libelle: 'libelleA'), - create(:type_de_champ, libelle: 'libelleB') + build(:type_de_champ, libelle: 'libelleA'), + build(:type_de_champ, libelle: 'libelleB') ] end @@ -141,7 +141,7 @@ describe TagsSubstitutionConcern, type: :model do context 'when the procedure has a type de champ with apostrophes' do let(:types_de_champ) do [ - create(:type_de_champ, libelle: "Intitulé de l'‘«\"évènement\"»’") + build(:type_de_champ, libelle: "Intitulé de l'‘«\"évènement\"»’") ] end @@ -165,9 +165,9 @@ describe TagsSubstitutionConcern, type: :model do let(:template) { '--Répétition--' } let(:types_de_champ) do [ - create(:type_de_champ_repetition, libelle: 'Répétition', types_de_champ: [ - create(:type_de_champ_text, libelle: 'Nom', order_place: 1), - create(:type_de_champ_text, libelle: 'Prénom', order_place: 2) + build(:type_de_champ_repetition, libelle: 'Répétition', types_de_champ: [ + build(:type_de_champ_text, libelle: 'Nom', order_place: 1), + build(:type_de_champ_text, libelle: 'Prénom', order_place: 2) ]) ] end @@ -190,7 +190,7 @@ describe TagsSubstitutionConcern, type: :model do context 'when the procedure has a linked drop down menus type de champ' do let(:type_de_champ) do - create(:type_de_champ_linked_drop_down_list, libelle: 'libelle') + build(:type_de_champ_linked_drop_down_list, libelle: 'libelle') end let(:types_de_champ) { [type_de_champ] } let(:template) { 'tout : --libelle--, primaire : --libelle/primaire--, secondaire : --libelle/secondaire--' } @@ -219,7 +219,7 @@ describe TagsSubstitutionConcern, type: :model do let(:types_de_champ) do [ type_de_champ, - create(:type_de_champ_header_section, libelle: 'libelle') + build(:type_de_champ_header_section, libelle: 'libelle') ] end @@ -253,7 +253,7 @@ describe TagsSubstitutionConcern, type: :model do end context 'when the procedure has a type de champ prive named libelleA' do - let(:types_de_champ_private) { [create(:type_de_champ, :private, libelle: 'libelleA')] } + let(:types_de_champ_private) { [build(:type_de_champ, :private, libelle: 'libelleA')] } context 'and it is used in the template' do let(:template) { '--libelleA--' } @@ -274,13 +274,13 @@ describe TagsSubstitutionConcern, type: :model do # The dossier just transitionned from brouillon to en construction, # so champs private are not valid tags yet - let(:types_de_champ_private) { [create(:type_de_champ, :private, libelle: 'libelleA')] } + let(:types_de_champ_private) { [build(:type_de_champ, :private, libelle: 'libelleA')] } it { is_expected.to eq('--libelleA--') } end context 'champs publics are valid tags' do - let(:types_de_champ) { [create(:type_de_champ, libelle: 'libelleA')] } + let(:types_de_champ) { [build(:type_de_champ, libelle: 'libelleA')] } before { dossier.champs.first.update(value: 'libelle1') } @@ -291,8 +291,8 @@ describe TagsSubstitutionConcern, type: :model do context 'when the procedure has 2 types de champ date and datetime' do let(:types_de_champ) do [ - create(:type_de_champ_date, libelle: TypeDeChamp.type_champs.fetch(:date)), - create(:type_de_champ_datetime, libelle: TypeDeChamp.type_champs.fetch(:datetime)) + build(:type_de_champ_date, libelle: TypeDeChamp.type_champs.fetch(:date)), + build(:type_de_champ_datetime, libelle: TypeDeChamp.type_champs.fetch(:datetime)) ] end @@ -358,13 +358,13 @@ describe TagsSubstitutionConcern, type: :model do shared_examples "treat all kinds of space as equivalent" do context 'and the champ has a non breaking space' do - let(:types_de_champ) { [create(:type_de_champ, libelle: 'mon tag')] } + let(:types_de_champ) { [build(:type_de_champ, libelle: 'mon tag')] } it { is_expected.to eq('valeur') } end context 'and the champ has an ordinary space' do - let(:types_de_champ) { [create(:type_de_champ, libelle: 'mon tag')] } + let(:types_de_champ) { [build(:type_de_champ, libelle: 'mon tag')] } it { is_expected.to eq('valeur') } end @@ -401,12 +401,12 @@ describe TagsSubstitutionConcern, type: :model do let(:types_de_champ) do [ - create(:type_de_champ, libelle: 'public'), - create(:type_de_champ_header_section, libelle: 'entête de section'), - create(:type_de_champ_explication, libelle: 'explication') + build(:type_de_champ, libelle: 'public'), + build(:type_de_champ_header_section, libelle: 'entête de section'), + build(:type_de_champ_explication, libelle: 'explication') ] end - let(:types_de_champ_private) { [create(:type_de_champ, :private, libelle: 'privé')] } + let(:types_de_champ_private) { [build(:type_de_champ, :private, libelle: 'privé')] } context 'do not generate tags for champs that cannot have usager content' do it { is_expected.not_to include(include({ libelle: 'entête de section' })) } diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb index e699b4d13..4a61017a0 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -29,14 +29,8 @@ describe Dossier do end describe 'with_champs' do - let(:procedure) { create(:procedure) } - let(:dossier) { Dossier.create(user: create(:user), groupe_instructeur: procedure.defaut_groupe_instructeur) } - - before do - create(:type_de_champ, libelle: 'l1', order_place: 1, procedure: procedure) - create(:type_de_champ, libelle: 'l3', order_place: 3, procedure: procedure) - create(:type_de_champ, libelle: 'l2', order_place: 2, procedure: procedure) - end + let(:procedure) { create(:procedure, types_de_champ: [build(:type_de_champ, libelle: 'l1', position: 1), build(:type_de_champ, libelle: 'l3', position: 3), build(:type_de_champ, libelle: 'l2', position: 2)]) } + let(:dossier) { create(:dossier, procedure: procedure) } it do expect(Dossier.with_champs.find(dossier.id).champs.map(&:libelle)).to match(['l1', 'l2', 'l3']) @@ -255,27 +249,15 @@ describe Dossier do end describe '#champs' do - let(:procedure) { create(:procedure) } - let(:dossier) { Dossier.create(user: create(:user), groupe_instructeur: procedure.defaut_groupe_instructeur) } - - before do - create(:type_de_champ, libelle: 'l1', order_place: 1, procedure: procedure) - create(:type_de_champ, libelle: 'l3', order_place: 3, procedure: procedure) - create(:type_de_champ, libelle: 'l2', order_place: 2, procedure: procedure) - end + let(:procedure) { create(:procedure, types_de_champ: [build(:type_de_champ, :private, libelle: 'l1', position: 1), build(:type_de_champ, :private, libelle: 'l3', position: 3), build(:type_de_champ, :private, libelle: 'l2', position: 2)]) } + let(:dossier) { create(:dossier, procedure: procedure) } it { expect(dossier.champs.pluck(:libelle)).to match(['l1', 'l2', 'l3']) } end describe '#champs_private' do - let(:procedure) { create :procedure } - let(:dossier) { Dossier.create(user: create(:user), groupe_instructeur: procedure.defaut_groupe_instructeur) } - - before do - create :type_de_champ, :private, libelle: 'l1', order_place: 1, procedure: procedure - create :type_de_champ, :private, libelle: 'l3', order_place: 3, procedure: procedure - create :type_de_champ, :private, libelle: 'l2', order_place: 2, procedure: procedure - end + let(:procedure) { create(:procedure, types_de_champ_private: [build(:type_de_champ, :private, libelle: 'l1', position: 1), build(:type_de_champ, :private, libelle: 'l3', position: 3), build(:type_de_champ, :private, libelle: 'l2', position: 2)]) } + let(:dossier) { create(:dossier, procedure: procedure) } it { expect(dossier.champs_private.pluck(:libelle)).to match(['l1', 'l2', 'l3']) } end @@ -525,7 +507,7 @@ describe Dossier do dossier = nil expect do perform_enqueued_jobs do - dossier = Dossier.create(groupe_instructeur: procedure.defaut_groupe_instructeur, state: Dossier.states.fetch(:brouillon), user: user) + dossier = create(:dossier, procedure: procedure, state: Dossier.states.fetch(:brouillon), user: user) end end.to change(ActionMailer::Base.deliveries, :size).from(0).to(1) @@ -535,17 +517,19 @@ describe Dossier do end it "does not send an email when the dossier is created with a non brouillon state" do - expect { Dossier.create(groupe_instructeur: procedure.defaut_groupe_instructeur, state: Dossier.states.fetch(:en_construction), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) - expect { Dossier.create(groupe_instructeur: procedure.defaut_groupe_instructeur, state: Dossier.states.fetch(:en_instruction), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) - expect { Dossier.create(groupe_instructeur: procedure.defaut_groupe_instructeur, state: Dossier.states.fetch(:accepte), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) - expect { Dossier.create(groupe_instructeur: procedure.defaut_groupe_instructeur, state: Dossier.states.fetch(:refuse), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) - expect { Dossier.create(groupe_instructeur: procedure.defaut_groupe_instructeur, state: Dossier.states.fetch(:sans_suite), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) + expect { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) + expect { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) + expect { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:accepte), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) + expect { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:refuse), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) + expect { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:sans_suite), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) end end describe "#unspecified_attestation_champs" do - let(:procedure) { create(:procedure, attestation_template: attestation_template) } + let(:procedure) { create(:procedure, attestation_template: attestation_template, types_de_champ: types_de_champ, types_de_champ_private: types_de_champ_private) } let(:dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) } + let(:types_de_champ) { [] } + let(:types_de_champ_private) { [] } subject { dossier.unspecified_attestation_champs.map(&:libelle) } @@ -574,14 +558,17 @@ describe Dossier do context "wich is enabled" do let(:activated) { true } - let!(:tdc_1) { create(:type_de_champ, libelle: "specified champ-in-title", procedure: procedure) } - let!(:tdc_2) { create(:type_de_champ, libelle: "unspecified champ-in-title", procedure: procedure) } - let!(:tdc_3) { create(:type_de_champ, libelle: "specified champ-in-body", procedure: procedure) } - let!(:tdc_4) { create(:type_de_champ, libelle: "unspecified champ-in-body", procedure: procedure) } - let!(:tdc_5) { create(:type_de_champ, private: true, libelle: "specified annotation privée-in-title", procedure: procedure) } - let!(:tdc_6) { create(:type_de_champ, private: true, libelle: "unspecified annotation privée-in-title", procedure: procedure) } - let!(:tdc_7) { create(:type_de_champ, private: true, libelle: "specified annotation privée-in-body", procedure: procedure) } - let!(:tdc_8) { create(:type_de_champ, private: true, libelle: "unspecified annotation privée-in-body", procedure: procedure) } + let(:types_de_champ) { [tdc_1, tdc_2, tdc_3, tdc_4] } + let(:types_de_champ_private) { [tdc_5, tdc_6, tdc_7, tdc_8] } + + let(:tdc_1) { build(:type_de_champ, libelle: "specified champ-in-title") } + let(:tdc_2) { build(:type_de_champ, libelle: "unspecified champ-in-title") } + let(:tdc_3) { build(:type_de_champ, libelle: "specified champ-in-body") } + let(:tdc_4) { build(:type_de_champ, libelle: "unspecified champ-in-body") } + let(:tdc_5) { build(:type_de_champ, private: true, libelle: "specified annotation privée-in-title") } + let(:tdc_6) { build(:type_de_champ, private: true, libelle: "unspecified annotation privée-in-title") } + let(:tdc_7) { build(:type_de_champ, private: true, libelle: "specified annotation privée-in-body") } + let(:tdc_8) { build(:type_de_champ, private: true, libelle: "unspecified annotation privée-in-body") } before do (dossier.champs + dossier.champs_private) @@ -1014,7 +1001,7 @@ describe Dossier do end context "with mandatory SIRET champ" do - let(:type_de_champ) { create(:type_de_champ_siret, mandatory: true) } + let(:type_de_champ) { create(:type_de_champ_siret, mandatory: true, procedure: procedure) } let(:champ_siret) { create(:champ_siret, type_de_champ: type_de_champ) } before do @@ -1041,12 +1028,11 @@ describe Dossier do end context "with champ repetition" do - let(:procedure) { create(:procedure) } - let(:type_de_champ_repetition) { create(:type_de_champ_repetition, mandatory: true) } + let(:procedure) { create(:procedure, types_de_champ: [type_de_champ_repetition]) } + let(:type_de_champ_repetition) { build(:type_de_champ_repetition, mandatory: true) } before do - procedure.types_de_champ << type_de_champ_repetition - type_de_champ_repetition.types_de_champ << create(:type_de_champ_text, mandatory: true) + create(:type_de_champ_text, mandatory: true, parent: type_de_champ_repetition) end context "when no champs" do @@ -1261,9 +1247,14 @@ describe Dossier do end describe "to_feature_collection" do + let(:dossier) { create(:dossier) } + let(:type_de_champ_carte) { create(:type_de_champ_carte, procedure: dossier.procedure) } let(:geo_area) { create(:geo_area, :selection_utilisateur, :polygon) } - let(:champ) { create(:champ_carte, geo_areas: [geo_area]) } - let(:dossier) { create(:dossier, champs: [champ]) } + let(:champ_carte) { create(:champ_carte, type_de_champ: type_de_champ_carte, geo_areas: [geo_area]) } + + before do + dossier.champs << champ_carte + end it 'should have all champs carto' do expect(dossier.to_feature_collection).to eq({ @@ -1279,7 +1270,7 @@ describe Dossier do }, properties: { area: 219.0, - champ_id: champ.stable_id, + champ_id: champ_carte.stable_id, dossier_id: dossier.id, id: geo_area.id, source: 'selection_utilisateur' diff --git a/spec/models/procedure_presentation_spec.rb b/spec/models/procedure_presentation_spec.rb index 7f7b96655..915ba52c3 100644 --- a/spec/models/procedure_presentation_spec.rb +++ b/spec/models/procedure_presentation_spec.rb @@ -50,7 +50,7 @@ describe ProcedurePresentation do describe "#fields" do context 'when the procedure can have a SIRET number' do - let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private, :types_de_champ_count => 4, :types_de_champ_private_count => 4) } + let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private, types_de_champ_count: 4, types_de_champ_private_count: 4) } let(:tdc_1) { procedure.types_de_champ[0] } let(:tdc_2) { procedure.types_de_champ[1] } let(:tdc_private_1) { procedure.types_de_champ_private[0] } diff --git a/spec/models/procedure_revision_spec.rb b/spec/models/procedure_revision_spec.rb index b2772e000..7c3c39c79 100644 --- a/spec/models/procedure_revision_spec.rb +++ b/spec/models/procedure_revision_spec.rb @@ -9,10 +9,6 @@ describe ProcedureRevision do type_de_champ end - before do - RevisionsMigration.add_revisions(procedure) - end - describe '#add_type_de_champ' do it 'type_de_champ' do expect(revision.types_de_champ.size).to eq(2) @@ -20,11 +16,8 @@ describe ProcedureRevision do type_champ: TypeDeChamp.type_champs.fetch(:text), libelle: "Un champ text" }) - procedure.reload + revision.reload expect(revision.types_de_champ.size).to eq(3) - expect(procedure.types_de_champ.size).to eq(3) - - expect(procedure.types_de_champ.last).to eq(new_type_de_champ) expect(revision.types_de_champ.last).to eq(new_type_de_champ) expect(revision.revision_types_de_champ.last.position).to eq(2) expect(revision.revision_types_de_champ.last.type_de_champ).to eq(new_type_de_champ) @@ -37,9 +30,8 @@ describe ProcedureRevision do libelle: "Un champ text", private: true }) - procedure.reload + revision.reload expect(revision.types_de_champ_private.size).to eq(2) - expect(procedure.types_de_champ_private.size).to eq(2) end it 'type_de_champ_repetition' do @@ -49,7 +41,6 @@ describe ProcedureRevision do libelle: "Un champ text", parent_id: type_de_champ_repetition.stable_id }) - type_de_champ_repetition.reload expect(type_de_champ_repetition.types_de_champ.size).to eq(2) end end @@ -113,26 +104,21 @@ describe ProcedureRevision do revision.remove_type_de_champ(type_de_champ.stable_id) procedure.reload expect(revision.types_de_champ.size).to eq(1) - expect(procedure.types_de_champ.size).to eq(1) end it 'type_de_champ_private' do expect(revision.types_de_champ_private.size).to eq(1) revision.remove_type_de_champ(type_de_champ_private.stable_id) - procedure.reload expect(revision.types_de_champ_private.size).to eq(0) - expect(procedure.types_de_champ_private.size).to eq(0) end it 'type_de_champ_repetition' do expect(type_de_champ_repetition.types_de_champ.size).to eq(1) expect(revision.types_de_champ.size).to eq(2) revision.remove_type_de_champ(type_de_champ_repetition.types_de_champ.first.stable_id) - procedure.reload type_de_champ_repetition.reload expect(type_de_champ_repetition.types_de_champ.size).to eq(0) expect(revision.types_de_champ.size).to eq(2) - expect(procedure.types_de_champ.size).to eq(2) end end diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index 135bd9b62..14952586d 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -279,15 +279,6 @@ describe Procedure do end end - describe '#types_de_champ (ordered)' do - let(:procedure) { create(:procedure) } - let!(:type_de_champ_0) { create(:type_de_champ, procedure: procedure, order_place: 1) } - let!(:type_de_champ_1) { create(:type_de_champ, procedure: procedure, order_place: 0) } - subject { procedure.types_de_champ } - it { expect(subject.first).to eq(type_de_champ_1) } - it { expect(subject.last).to eq(type_de_champ_0) } - end - describe 'active' do let(:procedure) { create(:procedure) } subject { Procedure.active(procedure.id) } @@ -333,22 +324,22 @@ describe Procedure do end describe 'clone' do - let!(:service) { create(:service) } - let(:procedure) { create(:procedure, received_mail: received_mail, service: service) } - let!(:type_de_champ_0) { create(:type_de_champ, procedure: procedure, order_place: 0) } - let!(:type_de_champ_1) { create(:type_de_champ, procedure: procedure, order_place: 1) } - let!(:type_de_champ_2) { create(:type_de_champ_drop_down_list, procedure: procedure, order_place: 2) } - let!(:type_de_champ_pj) { create(:type_de_champ_piece_justificative, procedure: procedure, order_place: 3, old_pj: { stable_id: 2713 }) } - let!(:type_de_champ_private_0) { create(:type_de_champ, :private, procedure: procedure, order_place: 0) } - let!(:type_de_champ_private_1) { create(:type_de_champ, :private, procedure: procedure, order_place: 1) } - let!(:type_de_champ_private_2) { create(:type_de_champ_drop_down_list, :private, procedure: procedure, order_place: 2) } + let(:service) { create(:service) } + let(:procedure) { create(:procedure, received_mail: received_mail, service: service, types_de_champ: [type_de_champ_0, type_de_champ_1, type_de_champ_2, type_de_champ_pj], types_de_champ_private: [type_de_champ_private_0, type_de_champ_private_1, type_de_champ_private_2]) } + let(:type_de_champ_0) { build(:type_de_champ, position: 0) } + let(:type_de_champ_1) { build(:type_de_champ, position: 1) } + let(:type_de_champ_2) { build(:type_de_champ_drop_down_list, position: 2) } + let(:type_de_champ_pj) { build(:type_de_champ_piece_justificative, position: 3, old_pj: { stable_id: 2713 }) } + let(:type_de_champ_private_0) { build(:type_de_champ, :private, position: 0) } + let(:type_de_champ_private_1) { build(:type_de_champ, :private, position: 1) } + let(:type_de_champ_private_2) { build(:type_de_champ_drop_down_list, :private, position: 2) } let(:received_mail) { build(:received_mail) } let(:from_library) { false } let(:administrateur) { procedure.administrateurs.first } - let!(:groupe_instructeur_1) { create(:groupe_instructeur, procedure: procedure, label: "groupe_1") } - let!(:instructeur_1) { create(:instructeur) } - let!(:instructeur_2) { create(:instructeur) } + let(:groupe_instructeur_1) { create(:groupe_instructeur, procedure: procedure, label: "groupe_1") } + let(:instructeur_1) { create(:instructeur) } + let(:instructeur_2) { create(:instructeur) } let!(:assign_to_1) { create(:assign_to, procedure: procedure, groupe_instructeur: groupe_instructeur_1, instructeur: instructeur_1) } let!(:assign_to_2) { create(:assign_to, procedure: procedure, groupe_instructeur: groupe_instructeur_1, instructeur: instructeur_2) } @@ -379,28 +370,18 @@ describe Procedure do it 'should duplicate specific objects with different id' do expect(subject.id).not_to eq(procedure.id) - expect(subject.types_de_champ.size).to eq(procedure.types_de_champ.size) - expect(subject.types_de_champ_private.size).to eq procedure.types_de_champ_private.size - expect(subject.types_de_champ.map(&:drop_down_options).compact.size).to eq procedure.types_de_champ.map(&:drop_down_options).compact.size - expect(subject.types_de_champ_private.map(&:drop_down_options).compact.size).to eq procedure.types_de_champ_private.map(&:drop_down_options).compact.size - expect(subject.draft_revision.types_de_champ.size).to eq(procedure.draft_revision.types_de_champ.size) - expect(subject.draft_revision.types_de_champ_private.size).to eq(procedure.draft_revision.types_de_champ_private.size) + expect(subject.draft_types_de_champ.size).to eq(procedure.draft_types_de_champ.size) + expect(subject.draft_types_de_champ_private.size).to eq(procedure.draft_types_de_champ_private.size) - procedure.types_de_champ.zip(subject.types_de_champ).each do |ptc, stc| + procedure.draft_types_de_champ.zip(subject.draft_types_de_champ).each do |ptc, stc| expect(stc).to have_same_attributes_as(ptc, except: ["revision_id"]) expect(stc.revision).to eq(subject.draft_revision) end - procedure.types_de_champ.zip(procedure.draft_revision.types_de_champ).each do |ptc, rtc| - expect(ptc).to eq(rtc) - end - subject.types_de_champ_private.zip(procedure.types_de_champ_private).each do |stc, ptc| + procedure.draft_types_de_champ_private.zip(subject.draft_types_de_champ_private).each do |ptc, stc| expect(stc).to have_same_attributes_as(ptc, except: ["revision_id"]) expect(stc.revision).to eq(subject.draft_revision) end - procedure.types_de_champ_private.zip(procedure.draft_revision.types_de_champ_private).each do |ptc, rtc| - expect(ptc).to eq(rtc) - end expect(subject.attestation_template.title).to eq(procedure.attestation_template.title) @@ -423,7 +404,7 @@ describe Procedure do end it 'should discard old pj information' do - subject.types_de_champ.each do |stc| + subject.draft_types_de_champ.each do |stc| expect(stc.old_pj).to be_nil end end @@ -459,7 +440,7 @@ describe Procedure do end it 'should discard old pj information' do - subject.types_de_champ.each do |stc| + subject.draft_types_de_champ.each do |stc| expect(stc.old_pj).to be_nil end end @@ -519,12 +500,12 @@ describe Procedure do end it 'should keep types_de_champ ids stable' do - expect(subject.types_de_champ.first.id).not_to eq(procedure.types_de_champ.first.id) - expect(subject.types_de_champ.first.stable_id).to eq(procedure.types_de_champ.first.id) + expect(subject.draft_types_de_champ.first.id).not_to eq(procedure.draft_types_de_champ.first.id) + expect(subject.draft_types_de_champ.first.stable_id).to eq(procedure.draft_types_de_champ.first.id) end it 'should duplicate piece_justificative_template on a type_de_champ' do - expect(subject.types_de_champ.where(type_champ: "piece_justificative").first.piece_justificative_template.attached?).to be true + expect(subject.draft_types_de_champ.where(type_champ: "piece_justificative").first.piece_justificative_template.attached?).to be true end context 'with a notice attached' do @@ -805,7 +786,7 @@ describe Procedure do end describe 'suggested_path' do - let(:procedure) { create :procedure, aasm_state: :publiee, libelle: 'Inscription au Collège' } + let(:procedure) { create(:procedure, aasm_state: :publiee, libelle: 'Inscription au Collège') } subject { procedure.suggested_path(procedure.administrateurs.first) } @@ -821,7 +802,7 @@ describe Procedure do context 'when the suggestion conflicts with one procedure' do before do - create :procedure, aasm_state: :publiee, path: 'inscription-au-college' + create(:procedure, aasm_state: :publiee, path: 'inscription-au-college') end it { is_expected.to eq 'inscription-au-college-2' } @@ -829,8 +810,8 @@ describe Procedure do context 'when the suggestion conflicts with several procedures' do before do - create :procedure, aasm_state: :publiee, path: 'inscription-au-college' - create :procedure, aasm_state: :publiee, path: 'inscription-au-college-2' + create(:procedure, aasm_state: :publiee, path: 'inscription-au-college') + create(:procedure, aasm_state: :publiee, path: 'inscription-au-college-2') end it { is_expected.to eq 'inscription-au-college-3' } @@ -838,7 +819,7 @@ describe Procedure do context 'when the suggestion conflicts with another procedure of the same admin' do before do - create :procedure, aasm_state: :publiee, path: 'inscription-au-college', administrateurs: procedure.administrateurs + create(:procedure, aasm_state: :publiee, path: 'inscription-au-college', administrateurs: procedure.administrateurs) end it { is_expected.to eq 'inscription-au-college' } @@ -903,13 +884,14 @@ describe Procedure do describe '#new_dossier' do let(:procedure) do - procedure = create(:procedure) - - create(:type_de_champ_text, procedure: procedure, order_place: 1) - create(:type_de_champ_number, procedure: procedure, order_place: 2) - create(:type_de_champ_textarea, :private, procedure: procedure) - - procedure + create(:procedure, + types_de_champ: [ + build(:type_de_champ_text, position: 0), + build(:type_de_champ_number, position: 1) + ], + types_de_champ_private: [ + build(:type_de_champ_textarea, :private) + ]) end let(:dossier) { procedure.new_dossier } diff --git a/spec/models/type_de_champ_shared_example.rb b/spec/models/type_de_champ_shared_example.rb index 30c455363..d00712f3e 100644 --- a/spec/models/type_de_champ_shared_example.rb +++ b/spec/models/type_de_champ_shared_example.rb @@ -153,44 +153,6 @@ shared_examples 'type_de_champ_spec' do end end - describe "repetition" do - let(:procedure) { create(:procedure) } - let(:type_de_champ) { create(:type_de_champ_repetition, procedure: procedure) } - let(:type_de_champ_text) { create(:type_de_champ_text, procedure: procedure) } - let(:type_de_champ_integer_number_attrs) { attributes_for(:type_de_champ_integer_number) } - - it "associates nested types_de_champ to the parent procedure" do - expect(type_de_champ.types_de_champ.size).to eq(0) - expect(procedure.types_de_champ.size).to eq(1) - - procedure.update!(types_de_champ_attributes: [ - { - id: type_de_champ.id, - libelle: type_de_champ.libelle, - types_de_champ_attributes: [type_de_champ_integer_number_attrs] - } - ]) - procedure.reload - type_de_champ.reload - - expect(procedure.types_de_champ.size).to eq(1) - expect(type_de_champ.types_de_champ.size).to eq(1) - - expect(type_de_champ.types_de_champ.first.parent).to eq(type_de_champ) - expect(type_de_champ.types_de_champ.first.procedure).to eq(procedure) - expect(type_de_champ.types_de_champ.first.private?).to eq(false) - - type_de_champ.types_de_champ << type_de_champ_text - expect(type_de_champ.types_de_champ.size).to eq(2) - expect(type_de_champ_text.parent).to eq(type_de_champ) - - admin = create(:administrateur) - cloned_procedure = procedure.clone(admin, false) - - expect(cloned_procedure.types_de_champ.first.types_de_champ).not_to be_empty - end - end - describe "linked_drop_down_list" do let(:type_de_champ) { create(:type_de_champ_linked_drop_down_list) } From dee12a2b0b4f301c9e693dab85c9fc43c3d813be Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 27 Aug 2020 19:56:34 +0200 Subject: [PATCH 16/27] update features specs to use revisions --- spec/features/admin/procedure_cloning_spec.rb | 6 +++--- spec/features/instructeurs/instruction_spec.rb | 6 +++--- .../new_administrateur/types_de_champ_spec.rb | 4 ++-- spec/features/users/brouillon_spec.rb | 18 ++++++++---------- spec/features/users/linked_dropdown_spec.rb | 6 ++---- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/spec/features/admin/procedure_cloning_spec.rb b/spec/features/admin/procedure_cloning_spec.rb index 8f67aea46..3d490f9c0 100644 --- a/spec/features/admin/procedure_cloning_spec.rb +++ b/spec/features/admin/procedure_cloning_spec.rb @@ -6,11 +6,11 @@ feature 'As an administrateur I wanna clone a procedure', js: true do let(:administrateur) { create(:administrateur) } before do - create :procedure, :with_service, :with_instructeur, - aasm_state: :publiee, published_at: Time.zone.now, + create(:procedure, :with_service, :with_instructeur, + aasm_state: :publiee, administrateurs: [administrateur], libelle: 'libellé de la procédure', - path: 'libelle-de-la-procedure' + path: 'libelle-de-la-procedure') login_as administrateur.user, scope: :user end diff --git a/spec/features/instructeurs/instruction_spec.rb b/spec/features/instructeurs/instruction_spec.rb index f5a43c5b3..22e083ad4 100644 --- a/spec/features/instructeurs/instruction_spec.rb +++ b/spec/features/instructeurs/instruction_spec.rb @@ -91,7 +91,7 @@ feature 'Instructing a dossier:' do end scenario 'A instructeur can see the personnes impliquées' do - instructeur2 = FactoryBot.create(:instructeur, password: password) + instructeur2 = create(:instructeur, password: password) log_in(instructeur.email, password) @@ -113,8 +113,8 @@ feature 'Instructing a dossier:' do end scenario 'A instructeur can send a dossier to several instructeurs', js: true do - instructeur_2 = FactoryBot.create(:instructeur) - instructeur_3 = FactoryBot.create(:instructeur) + instructeur_2 = create(:instructeur) + instructeur_3 = create(:instructeur) procedure.defaut_groupe_instructeur.instructeurs << [instructeur_2, instructeur_3] send_dossier = double() diff --git a/spec/features/new_administrateur/types_de_champ_spec.rb b/spec/features/new_administrateur/types_de_champ_spec.rb index c3c5fb77a..20d908f3f 100644 --- a/spec/features/new_administrateur/types_de_champ_spec.rb +++ b/spec/features/new_administrateur/types_de_champ_spec.rb @@ -122,7 +122,7 @@ feature 'As an administrateur I can edit types de champ', js: true do fill_in 'champ-0-libelle', with: 'Libellé de champ carte', fill_options: { clear: :backspace } check 'Cadastres' - wait_until { procedure.types_de_champ.first.cadastres == true } + wait_until { procedure.draft_types_de_champ.first.cadastres == true } expect(page).to have_content('Formulaire enregistré') preview_window = window_opened_by { click_on 'Prévisualiser le formulaire' } @@ -139,7 +139,7 @@ feature 'As an administrateur I can edit types de champ', js: true do fill_in 'champ-0-libelle', with: 'Libellé de champ menu déroulant', fill_options: { clear: :backspace } fill_in 'champ-0-drop_down_list_value', with: 'Un menu', fill_options: { clear: :backspace } - wait_until { procedure.types_de_champ.first.drop_down_list_options == ['', 'Un menu'] } + wait_until { procedure.draft_types_de_champ.first.drop_down_list_options == ['', 'Un menu'] } expect(page).to have_content('Formulaire enregistré') page.refresh diff --git a/spec/features/users/brouillon_spec.rb b/spec/features/users/brouillon_spec.rb index 2f17858a3..eed00238c 100644 --- a/spec/features/users/brouillon_spec.rb +++ b/spec/features/users/brouillon_spec.rb @@ -97,9 +97,7 @@ feature 'The user' do end let(:procedure_with_repetition) do - tdc = create(:type_de_champ_repetition, libelle: 'repetition') - tdc.types_de_champ << create(:type_de_champ_text, libelle: 'text') - create(:procedure, :published, :for_individual, types_de_champ: [tdc]) + create(:procedure, :published, :for_individual, :with_repetition) end scenario 'fill a dossier with repetition', js: true do @@ -107,13 +105,13 @@ feature 'The user' do fill_individual - fill_in('text', with: 'super texte') - expect(page).to have_field('text', with: 'super texte') + fill_in('sub type de champ', with: 'super texte') + expect(page).to have_field('sub type de champ', with: 'super texte') click_on 'Ajouter un élément pour' within '.row-1' do - fill_in('text', with: 'un autre texte') + fill_in('sub type de champ', with: 'un autre texte') end expect(page).to have_content('Supprimer', count: 2) @@ -132,7 +130,7 @@ feature 'The user' do end let(:simple_procedure) do - tdcs = [create(:type_de_champ, mandatory: true, libelle: 'texte obligatoire')] + tdcs = [build(:type_de_champ, mandatory: true, libelle: 'texte obligatoire')] create(:procedure, :published, :for_individual, types_de_champ: tdcs) end @@ -161,14 +159,14 @@ feature 'The user' do end let(:procedure_with_pj) do - tdcs = [create(:type_de_champ_piece_justificative, mandatory: true, libelle: 'Pièce justificative')] + tdcs = [build(:type_de_champ_piece_justificative, mandatory: true, libelle: 'Pièce justificative')] create(:procedure, :published, :for_individual, types_de_champ: tdcs) end let(:procedure_with_pjs) do tdcs = [ - create(:type_de_champ_piece_justificative, mandatory: true, libelle: 'Pièce justificative 1', order_place: 1), - create(:type_de_champ_piece_justificative, mandatory: true, libelle: 'Pièce justificative 2', order_place: 2) + build(:type_de_champ_piece_justificative, mandatory: true, libelle: 'Pièce justificative 1', position: 1), + build(:type_de_champ_piece_justificative, mandatory: true, libelle: 'Pièce justificative 2', position: 2) ] create(:procedure, :published, :for_individual, types_de_champ: tdcs) end diff --git a/spec/features/users/linked_dropdown_spec.rb b/spec/features/users/linked_dropdown_spec.rb index cc54de3ff..3ba3c45cd 100644 --- a/spec/features/users/linked_dropdown_spec.rb +++ b/spec/features/users/linked_dropdown_spec.rb @@ -13,12 +13,10 @@ feature 'linked dropdown lists' do Secondary 2.3 END_OF_LIST end - let(:type_de_champ) { create(:type_de_champ_linked_drop_down_list, libelle: 'linked dropdown', drop_down_list_value: list_items) } + let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, libelle: 'linked dropdown', drop_down_list_value: list_items) } let!(:procedure) do - p = create(:procedure, :published, :for_individual) - p.types_de_champ << type_de_champ - p + create(:procedure, :published, :for_individual, types_de_champ: [type_de_champ]) end let(:user_dossier) { user.dossiers.first } From 6a33a8e48bdf8b7f2ccd9ecb525359f96b8111da Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 27 Aug 2020 19:56:48 +0200 Subject: [PATCH 17/27] update controllers specs to use revisions --- .../api/v1/dossiers_controller_spec.rb | 5 +- .../instructeurs/dossiers_controller_spec.rb | 124 +++++++++--------- .../manager/procedures_controller_spec.rb | 2 +- spec/controllers/stats_controller_spec.rb | 110 ++++++++-------- 4 files changed, 122 insertions(+), 119 deletions(-) diff --git a/spec/controllers/api/v1/dossiers_controller_spec.rb b/spec/controllers/api/v1/dossiers_controller_spec.rb index 1bc8b195b..75426fe7b 100644 --- a/spec/controllers/api/v1/dossiers_controller_spec.rb +++ b/spec/controllers/api/v1/dossiers_controller_spec.rb @@ -255,9 +255,8 @@ describe API::V1::DossiersController do end describe 'repetition' do - let(:procedure) { create(:procedure, administrateur: admin) } - let(:champ) { build(:champ_repetition) } - let(:dossier) { create(:dossier, :en_construction, champs: [champ], procedure: procedure) } + let(:procedure) { create(:procedure, :with_repetition, administrateur: admin) } + let(:dossier) { create(:dossier, :en_construction, :with_all_champs, procedure: procedure) } subject { super().first[:rows] } diff --git a/spec/controllers/instructeurs/dossiers_controller_spec.rb b/spec/controllers/instructeurs/dossiers_controller_spec.rb index 31c8a377e..8da06e9b0 100644 --- a/spec/controllers/instructeurs/dossiers_controller_spec.rb +++ b/spec/controllers/instructeurs/dossiers_controller_spec.rb @@ -560,36 +560,34 @@ describe Instructeurs::DossiersController, type: :controller do end describe "#update_annotations" do + let(:procedure) do + create(:procedure, :published, types_de_champ_private: [ + build(:type_de_champ_multiple_drop_down_list, position: 0), + build(:type_de_champ_linked_drop_down_list, position: 1), + build(:type_de_champ_datetime, position: 2), + build(:type_de_champ_repetition, :with_types_de_champ, position: 3) + ], instructeurs: instructeurs) + end + let(:dossier) { create(:dossier, :en_construction, :with_all_annotations, procedure: procedure) } + let(:now) { Time.zone.parse('01/01/2100') } + let(:champ_multiple_drop_down_list) do - tdc = create(:type_de_champ_multiple_drop_down_list, :private, procedure: procedure, libelle: 'libelle') - create(:champ_multiple_drop_down_list, :private, type_de_champ: tdc, dossier: dossier) + dossier.champs_private.first end let(:champ_linked_drop_down_list) do - tdc = create(:type_de_champ_linked_drop_down_list, :private, procedure: procedure, libelle: 'libelle') - create(:champ_linked_drop_down_list, :private, type_de_champ: tdc, dossier: dossier) + dossier.champs_private.second end let(:champ_datetime) do - tdc = create(:type_de_champ_datetime, :private, procedure: procedure, libelle: 'libelle') - create(:champ_datetime, :private, type_de_champ: tdc, dossier: dossier) + dossier.champs_private.third end let(:champ_repetition) do - tdc = create(:type_de_champ_repetition, :private, :with_types_de_champ, procedure: procedure, libelle: 'libelle') - tdc.types_de_champ << create(:type_de_champ_text, procedure: procedure, libelle: 'libelle') - champ = create(:champ_repetition, :private, type_de_champ: tdc, dossier: dossier) - champ.add_row - champ + dossier.champs_private.fourth end - let(:dossier) { create(:dossier, :en_construction, procedure: procedure) } - - let(:now) { Time.zone.parse('01/01/2100') } - before do - dossier.champs_private << [champ_multiple_drop_down_list, champ_linked_drop_down_list, champ_datetime, champ_repetition] - Timecop.freeze(now) patch :update_annotations, params: params @@ -607,64 +605,70 @@ describe Instructeurs::DossiersController, type: :controller do let(:params) do { procedure_id: procedure.id, - dossier_id: dossier.id, - dossier: { - champs_private_attributes: { - '0': { - id: champ_multiple_drop_down_list.id, - value: ['', 'un', 'deux'] - }, - '1': { - id: champ_datetime.id, - 'value(1i)': 2019, - 'value(2i)': 12, - 'value(3i)': 21, - 'value(4i)': 13, - 'value(5i)': 17 - }, - '2': { - id: champ_linked_drop_down_list.id, - primary_value: 'primary', - secondary_value: 'secondary' - }, - '3': { - id: champ_repetition.id, - champs_attributes: { - id: champ_repetition.champs.first.id, - value: 'text' + dossier_id: dossier.id, + dossier: { + champs_private_attributes: { + '0': { + id: champ_multiple_drop_down_list.id, + value: ['', 'un', 'deux'] + }, + '1': { + id: champ_datetime.id, + 'value(1i)': 2019, + 'value(2i)': 12, + 'value(3i)': 21, + 'value(4i)': 13, + 'value(5i)': 17 + }, + '2': { + id: champ_linked_drop_down_list.id, + primary_value: 'primary', + secondary_value: 'secondary' + }, + '3': { + id: champ_repetition.id, + champs_attributes: { + id: champ_repetition.champs.first.id, + value: 'text' + } } } } } - } end - it { expect(champ_multiple_drop_down_list.value).to eq('["un", "deux"]') } - it { expect(champ_linked_drop_down_list.primary_value).to eq('primary') } - it { expect(champ_linked_drop_down_list.secondary_value).to eq('secondary') } - it { expect(champ_datetime.value).to eq('21/12/2019 13:17') } - it { expect(champ_repetition.champs.first.value).to eq('text') } - it { expect(dossier.reload.last_champ_private_updated_at).to eq(now) } - it { expect(response).to redirect_to(annotations_privees_instructeur_dossier_path(dossier.procedure, dossier)) } + + it { + expect(champ_multiple_drop_down_list.value).to eq('["un", "deux"]') + expect(champ_linked_drop_down_list.primary_value).to eq('primary') + expect(champ_linked_drop_down_list.secondary_value).to eq('secondary') + expect(champ_datetime.value).to eq('21/12/2019 13:17') + expect(champ_repetition.champs.first.value).to eq('text') + expect(dossier.reload.last_champ_private_updated_at).to eq(now) + expect(response).to redirect_to(annotations_privees_instructeur_dossier_path(dossier.procedure, dossier)) + } end context "without new values for champs_private" do let(:params) do { procedure_id: procedure.id, - dossier_id: dossier.id, - dossier: { - champs_private_attributes: {}, - champs_attributes: { - '0': { - id: champ_multiple_drop_down_list.id, - value: ['', 'un', 'deux'] + dossier_id: dossier.id, + dossier: { + champs_private_attributes: {}, + champs_attributes: { + '0': { + id: champ_multiple_drop_down_list.id, + value: ['', 'un', 'deux'] + } } } } - } end - it { expect(dossier.reload.last_champ_private_updated_at).to eq(nil) } - it { expect(response).to redirect_to(annotations_privees_instructeur_dossier_path(dossier.procedure, dossier)) } + + it { + expect(dossier.reload.last_champ_private_updated_at).to eq(nil) + expect(response).to redirect_to(annotations_privees_instructeur_dossier_path(dossier.procedure, dossier)) + } end end diff --git a/spec/controllers/manager/procedures_controller_spec.rb b/spec/controllers/manager/procedures_controller_spec.rb index b8bebd461..04c4dc829 100644 --- a/spec/controllers/manager/procedures_controller_spec.rb +++ b/spec/controllers/manager/procedures_controller_spec.rb @@ -17,7 +17,7 @@ describe Manager::ProceduresController, type: :controller do describe '#show' do render_views - let(:procedure) { create(:procedure, :with_repetition) } + let(:procedure) { create(:procedure, :published, :with_repetition) } before do get :show, params: { id: procedure.id } diff --git a/spec/controllers/stats_controller_spec.rb b/spec/controllers/stats_controller_spec.rb index a16a9281d..796778a62 100644 --- a/spec/controllers/stats_controller_spec.rb +++ b/spec/controllers/stats_controller_spec.rb @@ -2,17 +2,17 @@ describe StatsController, type: :controller do describe "#last_four_months_hash" do context "while a regular user is logged in" do before do - FactoryBot.create(:procedure, :created_at => 6.months.ago, :updated_at => 6.months.ago) - FactoryBot.create(:procedure, :created_at => 2.months.ago, :updated_at => 62.days.ago) - FactoryBot.create(:procedure, :created_at => 2.months.ago, :updated_at => 62.days.ago) - FactoryBot.create(:procedure, :created_at => 2.months.ago, :updated_at => 31.days.ago) - FactoryBot.create(:procedure, :created_at => 2.months.ago, :updated_at => Time.zone.now) + create(:procedure, created_at: 6.months.ago, updated_at: 6.months.ago) + create(:procedure, created_at: 2.months.ago, updated_at: 62.days.ago) + create(:procedure, created_at: 2.months.ago, updated_at: 62.days.ago) + create(:procedure, created_at: 2.months.ago, updated_at: 31.days.ago) + create(:procedure, created_at: 2.months.ago, updated_at: Time.zone.now) @controller = StatsController.new allow(@controller).to receive(:administration_signed_in?).and_return(false) end - let (:association) { Procedure.all } + let(:association) { Procedure.all } subject { @controller.send(:last_four_months_hash, association, :updated_at) } @@ -26,10 +26,10 @@ describe StatsController, type: :controller do context "while a super admin is logged in" do before do - FactoryBot.create(:procedure, :updated_at => 6.months.ago) - FactoryBot.create(:procedure, :updated_at => 45.days.ago) - FactoryBot.create(:procedure, :updated_at => 1.day.ago) - FactoryBot.create(:procedure, :updated_at => 1.day.ago) + create(:procedure, updated_at: 6.months.ago) + create(:procedure, updated_at: 45.days.ago) + create(:procedure, updated_at: 1.day.ago) + create(:procedure, updated_at: 1.day.ago) @controller = StatsController.new @@ -52,11 +52,11 @@ describe StatsController, type: :controller do describe '#cumulative_hash' do before do Timecop.freeze(Time.zone.local(2016, 10, 2)) - FactoryBot.create(:procedure, :created_at => 55.days.ago, :updated_at => 43.days.ago) - FactoryBot.create(:procedure, :created_at => 45.days.ago, :updated_at => 40.days.ago) - FactoryBot.create(:procedure, :created_at => 45.days.ago, :updated_at => 20.days.ago) - FactoryBot.create(:procedure, :created_at => 15.days.ago, :updated_at => 20.days.ago) - FactoryBot.create(:procedure, :created_at => 15.days.ago, :updated_at => 1.hour.ago) + create(:procedure, created_at: 55.days.ago, updated_at: 43.days.ago) + create(:procedure, created_at: 45.days.ago, updated_at: 40.days.ago) + create(:procedure, created_at: 45.days.ago, updated_at: 20.days.ago) + create(:procedure, created_at: 15.days.ago, updated_at: 20.days.ago) + create(:procedure, created_at: 15.days.ago, updated_at: 1.hour.ago) end after { Timecop.return } @@ -104,24 +104,24 @@ describe StatsController, type: :controller do # dossier_p1_c: 5 days before do - procedure_1 = FactoryBot.create(:procedure) - procedure_2 = FactoryBot.create(:procedure) - dossier_p1_a = FactoryBot.create(:dossier, :accepte, - :procedure => procedure_1, - :en_construction_at => 2.months.ago.beginning_of_month, - :processed_at => 2.months.ago.beginning_of_month + 3.days) - dossier_p1_b = FactoryBot.create(:dossier, :accepte, - :procedure => procedure_1, - :en_construction_at => 2.months.ago.beginning_of_month, - :processed_at => 2.months.ago.beginning_of_month + 1.day) - dossier_p1_c = FactoryBot.create(:dossier, :accepte, - :procedure => procedure_1, - :en_construction_at => 1.month.ago.beginning_of_month, - :processed_at => 1.month.ago.beginning_of_month + 5.days) - dossier_p2_a = FactoryBot.create(:dossier, :accepte, - :procedure => procedure_2, - :en_construction_at => 2.months.ago.beginning_of_month, - :processed_at => 2.months.ago.beginning_of_month + 4.days) + procedure_1 = create(:procedure) + procedure_2 = create(:procedure) + dossier_p1_a = create(:dossier, :accepte, + procedure: procedure_1, + en_construction_at: 2.months.ago.beginning_of_month, + processed_at: 2.months.ago.beginning_of_month + 3.days) + dossier_p1_b = create(:dossier, :accepte, + procedure: procedure_1, + en_construction_at: 2.months.ago.beginning_of_month, + processed_at: 2.months.ago.beginning_of_month + 1.day) + dossier_p1_c = create(:dossier, :accepte, + procedure: procedure_1, + en_construction_at: 1.month.ago.beginning_of_month, + processed_at: 1.month.ago.beginning_of_month + 5.days) + dossier_p2_a = create(:dossier, :accepte, + procedure: procedure_2, + en_construction_at: 2.months.ago.beginning_of_month, + processed_at: 2.months.ago.beginning_of_month + 4.days) @expected_hash = { (2.months.ago.beginning_of_month).to_s => 3.0, @@ -149,28 +149,28 @@ describe StatsController, type: :controller do # dossier_p1_c: 50 minutes before do - procedure_1 = FactoryBot.create(:procedure, :with_type_de_champ, :types_de_champ_count => 24) - procedure_2 = FactoryBot.create(:procedure, :with_type_de_champ, :types_de_champ_count => 48) - dossier_p1_a = FactoryBot.create(:dossier, :accepte, - :procedure => procedure_1, - :created_at => 2.months.ago.beginning_of_month, - :en_construction_at => 2.months.ago.beginning_of_month + 30.minutes, - :processed_at => 2.months.ago.beginning_of_month + 1.day) - dossier_p1_b = FactoryBot.create(:dossier, :accepte, - :procedure => procedure_1, - :created_at => 2.months.ago.beginning_of_month, - :en_construction_at => 2.months.ago.beginning_of_month + 10.minutes, - :processed_at => 2.months.ago.beginning_of_month + 1.day) - dossier_p1_c = FactoryBot.create(:dossier, :accepte, - :procedure => procedure_1, - :created_at => 1.month.ago.beginning_of_month, - :en_construction_at => 1.month.ago.beginning_of_month + 50.minutes, - :processed_at => 1.month.ago.beginning_of_month + 1.day) - dossier_p2_a = FactoryBot.create(:dossier, :accepte, - :procedure => procedure_2, - :created_at => 2.months.ago.beginning_of_month, - :en_construction_at => 2.months.ago.beginning_of_month + 80.minutes, - :processed_at => 2.months.ago.beginning_of_month + 1.day) + procedure_1 = create(:procedure, :with_type_de_champ, types_de_champ_count: 24) + procedure_2 = create(:procedure, :with_type_de_champ, types_de_champ_count: 48) + dossier_p1_a = create(:dossier, :accepte, + procedure: procedure_1, + created_at: 2.months.ago.beginning_of_month, + en_construction_at: 2.months.ago.beginning_of_month + 30.minutes, + processed_at: 2.months.ago.beginning_of_month + 1.day) + dossier_p1_b = create(:dossier, :accepte, + procedure: procedure_1, + created_at: 2.months.ago.beginning_of_month, + en_construction_at: 2.months.ago.beginning_of_month + 10.minutes, + processed_at: 2.months.ago.beginning_of_month + 1.day) + dossier_p1_c = create(:dossier, :accepte, + procedure: procedure_1, + created_at: 1.month.ago.beginning_of_month, + en_construction_at: 1.month.ago.beginning_of_month + 50.minutes, + processed_at: 1.month.ago.beginning_of_month + 1.day) + dossier_p2_a = create(:dossier, :accepte, + procedure: procedure_2, + created_at: 2.months.ago.beginning_of_month, + en_construction_at: 2.months.ago.beginning_of_month + 80.minutes, + processed_at: 2.months.ago.beginning_of_month + 1.day) @expected_hash = { (2.months.ago.beginning_of_month).to_s => 30.0, From d1e0b65658f89f0d2c60a7f09abac402b1c1f039 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 27 Aug 2020 19:57:01 +0200 Subject: [PATCH 18/27] update jobs specs to use revisions --- spec/jobs/find_dubious_procedures_job_spec.rb | 11 +++++---- ...tmp_dossiers_migrate_revisions_job_spec.rb | 24 ------------------- 2 files changed, 6 insertions(+), 29 deletions(-) delete mode 100644 spec/jobs/tmp_dossiers_migrate_revisions_job_spec.rb diff --git a/spec/jobs/find_dubious_procedures_job_spec.rb b/spec/jobs/find_dubious_procedures_job_spec.rb index 3bd6fd50f..acbc8df52 100644 --- a/spec/jobs/find_dubious_procedures_job_spec.rb +++ b/spec/jobs/find_dubious_procedures_job_spec.rb @@ -1,23 +1,24 @@ RSpec.describe FindDubiousProceduresJob, type: :job do describe 'perform' do let(:mailer_double) { double('mailer', deliver_later: true) } - let(:procedure) { create(:procedure) } - let(:allowed_tdc) { create(:type_de_champ, libelle: 'fournir') } + let(:procedure) { create(:procedure, types_de_champ: tdcs) } + let(:allowed_tdc) { build(:type_de_champ, libelle: 'fournir') } before do + procedure + allow(AdministrationMailer).to receive(:dubious_procedures) do |arg| @dubious_procedures_args = arg end.and_return(mailer_double) - procedure.types_de_champ << tdcs FindDubiousProceduresJob.new.perform end context 'with suspicious champs' do let(:forbidden_tdcs) do [ - create(:type_de_champ, libelle: 'num de securite sociale, stp'), - create(:type_de_champ, libelle: "t'aurais une carte bancaire ?") + build(:type_de_champ, libelle: 'num de securite sociale, stp'), + build(:type_de_champ, libelle: "t'aurais une carte bancaire ?") ] end diff --git a/spec/jobs/tmp_dossiers_migrate_revisions_job_spec.rb b/spec/jobs/tmp_dossiers_migrate_revisions_job_spec.rb deleted file mode 100644 index ce2984175..000000000 --- a/spec/jobs/tmp_dossiers_migrate_revisions_job_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -RSpec.describe TmpDossiersMigrateRevisionsJob, type: :job do - let(:procedure) { create(:procedure, :published) } - let!(:dossier1) { create(:dossier, procedure: procedure, updated_at: 1.day.ago) } - let!(:dossier2) { create(:dossier, procedure: procedure, updated_at: 2.days.ago) } - - context "add revision to dossiers" do - before do - RevisionsMigration.add_revisions(procedure) - end - - it { - expect(dossier1.revision).to be_nil - expect(dossier2.revision).to be_nil - - TmpDossiersMigrateRevisionsJob.new.perform([]) - [dossier1, dossier2].each(&:reload) - - expect(dossier1.revision).to eq procedure.active_revision - expect(dossier2.revision).to eq procedure.active_revision - expect(dossier1.updated_at < 1.day.ago).to be_truthy - expect(dossier2.updated_at < 1.day.ago).to be_truthy - } - end -end From 4c0f9a4d6194dfb10d945d089162d53898a790d6 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 27 Aug 2020 19:57:13 +0200 Subject: [PATCH 19/27] update serializers specs to use revisions --- spec/serializers/dossier_serializer_spec.rb | 7 +++---- spec/serializers/procedure_serializer_spec.rb | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/spec/serializers/dossier_serializer_spec.rb b/spec/serializers/dossier_serializer_spec.rb index 69c8f624c..33a883d72 100644 --- a/spec/serializers/dossier_serializer_spec.rb +++ b/spec/serializers/dossier_serializer_spec.rb @@ -49,12 +49,11 @@ describe DossierSerializer do context 'when a type de champ PJ was cloned from a legacy PJ' do let(:original_pj_id) { 3 } let(:cloned_type_de_champ) do - tdc = create(:type_de_champ_piece_justificative, + build(:type_de_champ_piece_justificative, libelle: "Vidéo de votre demande de subvention", description: "Pour optimiser vos chances, soignez la chorégraphie et privilégiez le chant polyphonique.\r\nRécupérer le formulaire vierge pour mon dossier : https://www.dance-academy.gouv.fr", - order_place: 0) - tdc.old_pj = { stable_id: original_pj_id } - tdc + old_pj: { stable_id: original_pj_id }, + position: 0) end let(:procedure) { create(:procedure, :published, types_de_champ: [cloned_type_de_champ]) } let(:dossier) { create(:dossier, procedure: procedure) } diff --git a/spec/serializers/procedure_serializer_spec.rb b/spec/serializers/procedure_serializer_spec.rb index 4271cd93e..e7f64b4bd 100644 --- a/spec/serializers/procedure_serializer_spec.rb +++ b/spec/serializers/procedure_serializer_spec.rb @@ -12,12 +12,11 @@ describe ProcedureSerializer do context 'when a type PJ was cloned to a type champ PJ' do let(:original_pj_id) { 3 } let(:cloned_type_de_champ) do - tdc = create(:type_de_champ_piece_justificative, + build(:type_de_champ_piece_justificative, libelle: "Vidéo de votre demande de subvention", description: "Pour optimiser vos chances, soignez la chorégraphie et privilégiez le chant polyphonique.\r\nRécupérer le formulaire vierge pour mon dossier : https://www.dance-academy.gouv.fr", - order_place: 0) - tdc.old_pj = { stable_id: original_pj_id } - tdc + old_pj: { stable_id: original_pj_id }, + position: 0) end let(:procedure) { create(:procedure, :published, types_de_champ: [cloned_type_de_champ]) } From 0a70291b90b87504d556d64834ff2cfe4d07d2c5 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 27 Aug 2020 19:57:21 +0200 Subject: [PATCH 20/27] update services specs to use revisions --- .../administrateur_usage_statistics_service_spec.rb | 8 ++++---- spec/services/procedure_export_service_spec.rb | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/services/administrateur_usage_statistics_service_spec.rb b/spec/services/administrateur_usage_statistics_service_spec.rb index c40e33267..835206df7 100644 --- a/spec/services/administrateur_usage_statistics_service_spec.rb +++ b/spec/services/administrateur_usage_statistics_service_spec.rb @@ -61,7 +61,7 @@ describe AdministrateurUsageStatisticsService do end context 'with a freshly active procedure' do - let(:procedure) { create(:procedure, aasm_state: 'publiee') } + let(:procedure) { create(:procedure, :published) } it do is_expected.to include( @@ -82,7 +82,7 @@ describe AdministrateurUsageStatisticsService do end context 'with a procedure close' do - let(:procedure) { create(:procedure, aasm_state: 'close') } + let(:procedure) { create(:procedure, :closed) } let!(:dossiers) do (1..7).flat_map do [ @@ -163,7 +163,7 @@ describe AdministrateurUsageStatisticsService do end context 'with a procedure en prod' do - let(:procedure) { create(:procedure, aasm_state: 'publiee') } + let(:procedure) { create(:procedure, :published) } let!(:dossiers) do [ create(:dossier, :en_construction, procedure: procedure), @@ -191,7 +191,7 @@ describe AdministrateurUsageStatisticsService do end context 'with a procedure en prod and more than 20 dossiers' do - let(:procedure) { create(:procedure, aasm_state: 'publiee') } + let(:procedure) { create(:procedure, :published) } let!(:dossiers) do (1..7).flat_map do [ diff --git a/spec/services/procedure_export_service_spec.rb b/spec/services/procedure_export_service_spec.rb index 38eb94b19..7f2945981 100644 --- a/spec/services/procedure_export_service_spec.rb +++ b/spec/services/procedure_export_service_spec.rb @@ -18,10 +18,10 @@ describe ProcedureExportService do before do # change one tdc place to check if the header is ordered - tdc_first = procedure.types_de_champ.first - tdc_last = procedure.types_de_champ.last + tdc_first = procedure.active_revision.revision_types_de_champ.first + tdc_last = procedure.active_revision.revision_types_de_champ.last - tdc_first.update(order_place: tdc_last.order_place + 1) + tdc_first.update(position: tdc_last.position + 1) procedure.reload end From 36668403b6441070b4aa2a0e525954ad52c0472c Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 27 Aug 2020 19:57:36 +0200 Subject: [PATCH 21/27] cleanup feature helper --- spec/support/feature_helpers.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spec/support/feature_helpers.rb b/spec/support/feature_helpers.rb index 5f28090b9..e4f26d2f1 100644 --- a/spec/support/feature_helpers.rb +++ b/spec/support/feature_helpers.rb @@ -12,11 +12,6 @@ module FeatureHelpers login_as instructeur, scope: :instructeur end - def create_dossier - dossier = FactoryBot.create(:dossier) - dossier - end - def sign_in_with(email, password, sign_in_by_link = false) fill_in :user_email, with: email fill_in :user_password, with: password From 5ceae8235bbad0c37e1c362c8e7788ea5538dafd Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 27 Aug 2020 20:14:23 +0200 Subject: [PATCH 22/27] Ignore type_de_champ procedure_id --- app/jobs/find_dubious_procedures_job.rb | 2 +- app/models/type_de_champ.rb | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/jobs/find_dubious_procedures_job.rb b/app/jobs/find_dubious_procedures_job.rb index 8f399f672..13c9a91ab 100644 --- a/app/jobs/find_dubious_procedures_job.rb +++ b/app/jobs/find_dubious_procedures_job.rb @@ -24,7 +24,7 @@ class FindDubiousProceduresJob < CronJob .where(procedures: { closed_at: nil, whitelisted_at: nil }) dubious_procedures_and_tdcs = forbidden_tdcs - .group_by(&:procedure_id) + .group_by { |type_de_champ| type_de_champ.procedure.id } .map { |_procedure_id, tdcs| [tdcs[0].procedure, tdcs] } AdministrationMailer.dubious_procedures(dubious_procedures_and_tdcs).deliver_later diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index c308f397a..e0ff6990d 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -18,6 +18,8 @@ # stable_id :bigint # class TypeDeChamp < ApplicationRecord + self.ignored_columns = ['procedure_id'] + enum type_champs: { text: 'text', textarea: 'textarea', From 49aa426d1ba645ae17600007767ece7b1d61ca33 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 2 Sep 2020 16:59:54 +0200 Subject: [PATCH 23/27] application job swallow BadRequest error and retry --- app/jobs/application_job.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index 2dfbc497c..856d1d570 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -1,6 +1,8 @@ class ApplicationJob < ActiveJob::Base DEFAULT_MAX_ATTEMPTS_JOBS = 25 + retry_on Excon::Error::BadRequest + before_perform do |job| Rails.logger.info("#{job.class.name} started at #{Time.zone.now}") end From bd6705b90ae25a31c518997770bf5233e437dc77 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 2 Sep 2020 17:00:26 +0200 Subject: [PATCH 24/27] Remove image and video analyzer which are not used --- config/initializers/active_storage.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/initializers/active_storage.rb b/config/initializers/active_storage.rb index 6be3549bc..2784f955f 100644 --- a/config/initializers/active_storage.rb +++ b/config/initializers/active_storage.rb @@ -1,5 +1,8 @@ Rails.application.config.active_storage.service_urls_expire_in = 1.hour +Rails.application.config.active_storage.analyzers.delete ActiveStorage::Analyzer::ImageAnalyzer +Rails.application.config.active_storage.analyzers.delete ActiveStorage::Analyzer::VideoAnalyzer + ActiveSupport.on_load(:active_storage_blob) do include BlobSignedIdConcern include BlobVirusScannerConcern From 292dc84eb4523c906da8f13ec65cc5323138ca03 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Thu, 3 Sep 2020 11:00:59 +0200 Subject: [PATCH 25/27] jobs: ignore deleted file in Virus Scan We have errors in production where the job starts correctly (i.e. the blob exists), but `blob.open` fails with a `ActiveStorage::FileNotFound` error. When checking later in production, the blob has been deleted. This points to the blob (and the file) being deleted during the virus scan job. In that case, ignore the error (rather than retrying the job). --- app/jobs/virus_scanner_job.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/jobs/virus_scanner_job.rb b/app/jobs/virus_scanner_job.rb index 9cf005e00..29e6f1db6 100644 --- a/app/jobs/virus_scanner_job.rb +++ b/app/jobs/virus_scanner_job.rb @@ -1,7 +1,10 @@ class VirusScannerJob < ApplicationJob queue_as :active_storage_analysis + # If by the time the job runs the blob has been deleted, ignore the error discard_on ActiveRecord::RecordNotFound + # If the file is deleted during the scan, ignore the error + discard_on ActiveStorage::FileNotFoundError def perform(blob) metadata = extract_metadata_via_virus_scanner(blob) From ae61c279afe6f76e4e2dad87712b9e5e89edbb3d Mon Sep 17 00:00:00 2001 From: kara Diaby Date: Tue, 25 Aug 2020 11:40:24 +0200 Subject: [PATCH 26/27] migrate emails text editor to new interface --- .../stylesheets/new_design/actiontext.scss | 35 +++----------- .../admin/mail_templates_controller.rb | 42 ----------------- .../mail_templates_controller.rb | 29 +++++++++++- app/javascript/packs/application.js | 1 + app/models/concerns/mail_template_concern.rb | 5 +- app/models/procedure.rb | 2 +- app/views/admin/mail_templates/edit.html.haml | 40 ---------------- .../admin/mail_templates/index.html.haml | 14 ------ .../mail_templates/_apercu.html.haml | 1 + .../mail_templates/_form.html.haml | 47 +++++++++++++++++++ .../mail_templates/edit.html.haml | 33 +++++++++++++ .../mail_templates/index.html.haml | 6 ++- config/routes.rb | 4 +- .../admin/mail_templates_controller_spec.rb | 31 ------------ .../mail_templates_controller_spec.rb | 23 +++++++++ spec/models/procedure_spec.rb | 2 +- .../mail_templates/edit.html.haml.spec.rb} | 5 +- 17 files changed, 154 insertions(+), 166 deletions(-) delete mode 100644 app/controllers/admin/mail_templates_controller.rb delete mode 100644 app/views/admin/mail_templates/edit.html.haml delete mode 100644 app/views/admin/mail_templates/index.html.haml create mode 100644 app/views/new_administrateur/mail_templates/_apercu.html.haml create mode 100644 app/views/new_administrateur/mail_templates/_form.html.haml create mode 100644 app/views/new_administrateur/mail_templates/edit.html.haml delete mode 100644 spec/controllers/admin/mail_templates_controller_spec.rb rename spec/views/{admin/mail_templates/edit.html.haml_spec.rb => new_administrateur/mail_templates/edit.html.haml.spec.rb} (69%) diff --git a/app/assets/stylesheets/new_design/actiontext.scss b/app/assets/stylesheets/new_design/actiontext.scss index b4560ecae..114c6aa76 100644 --- a/app/assets/stylesheets/new_design/actiontext.scss +++ b/app/assets/stylesheets/new_design/actiontext.scss @@ -5,32 +5,11 @@ // // = require trix -// We need to override trix.css’s image gallery styles to accommodate the -// element we wrap around attachments. Otherwise, -// images in galleries will be squished by the max-width: 33%; rule. -.trix-content { - .attachment-gallery { - > action-text-attachment, - > .attachment { - flex: 1 0 33%; - padding: 0 0.5em; - max-width: 33%; - } - - &.attachment-gallery--2, - &.attachment-gallery--4 { - > action-text-attachment, - > .attachment { - flex-basis: 50%; - max-width: 50%; - } - } - } - - action-text-attachment { - .attachment { - padding: 0 !important; - max-width: 100% !important; - } - } +.trix-button-group.trix-button-group--file-tools { + display: none; +} + +trix-editor { + min-height: 10em; + background-color: #FFFFFF; } diff --git a/app/controllers/admin/mail_templates_controller.rb b/app/controllers/admin/mail_templates_controller.rb deleted file mode 100644 index 3ed7f277d..000000000 --- a/app/controllers/admin/mail_templates_controller.rb +++ /dev/null @@ -1,42 +0,0 @@ -class Admin::MailTemplatesController < AdminController - before_action :retrieve_procedure - - def index - @mail_templates = mail_templates - end - - def edit - @mail_template = find_mail_template_by_slug(params[:id]) - end - - def update - mail_template = find_mail_template_by_slug(params[:id]) - mail_template.update(update_params) - flash.notice = "Email mis à jour" - redirect_to edit_admin_procedure_mail_template_path(mail_template.procedure_id, params[:id]) - end - - private - - def mail_templates - [ - @procedure.initiated_mail_template, - @procedure.received_mail_template, - @procedure.closed_mail_template, - @procedure.refused_mail_template, - @procedure.without_continuation_mail_template - ] - end - - def find_mail_template_by_slug(slug) - mail_templates.find { |template| template.class.const_get(:SLUG) == slug } - end - - def update_params - { - procedure_id: params[:procedure_id], - subject: params[:mail_template][:subject], - body: params[:mail_template][:body] - } - end -end diff --git a/app/controllers/new_administrateur/mail_templates_controller.rb b/app/controllers/new_administrateur/mail_templates_controller.rb index 05089d6f2..872f76ae5 100644 --- a/app/controllers/new_administrateur/mail_templates_controller.rb +++ b/app/controllers/new_administrateur/mail_templates_controller.rb @@ -6,6 +6,24 @@ module NewAdministrateur @mail_templates = mail_templates end + def edit + @procedure = procedure + @mail_template = find_mail_template_by_slug(params[:id]) + end + + def update + @procedure = procedure + mail_template = find_mail_template_by_slug(params[:id]) + + if mail_template.update(update_params) + flash.notice = "Email mis à jour" + else + flash.alert = mail_template.errors.full_messages + end + + redirect_to edit_admin_procedure_mail_template_path(mail_template.procedure_id, params[:id]) + end + def preview mail_template = find_mail_template_by_slug(params[:id]) dossier = Dossier.new(id: '1', procedure: procedure) @@ -13,7 +31,7 @@ module NewAdministrateur @dossier = dossier @logo_url = procedure.logo_url @service = procedure.service - @rendered_template = sanitize(mail_template.body) + @rendered_template = sanitize(mail_template.rich_body.body.to_html) @actions = mail_template.actions_for_dossier(dossier) render(template: 'notification_mailer/send_notification', layout: 'mailers/notifications_layout') @@ -38,5 +56,14 @@ module NewAdministrateur def find_mail_template_by_slug(slug) mail_templates.find { |template| template.class.const_get(:SLUG) == slug } end + + def update_params + mail_template_id = params[:id] + { + procedure_id: params[:procedure_id], + subject: params["mails_#{mail_template_id}"] ? params["mails_#{mail_template_id}"][:subject] : params["mails_#{mail_template_id}_mail"][:subject], + body: params["mails_#{mail_template_id}"] ? params["mails_#{mail_template_id}"][:rich_body] : params["mails_#{mail_template_id}_mail"][:rich_body] + } + end end end diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 70897efcc..3183dcf79 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -1,6 +1,7 @@ import '../shared/polyfills'; import Rails from '@rails/ujs'; import * as ActiveStorage from '@rails/activestorage'; +import 'trix'; import '@rails/actiontext'; import 'whatwg-fetch'; // window.fetch polyfill import ReactRailsUJS from 'react_ujs'; diff --git a/app/models/concerns/mail_template_concern.rb b/app/models/concerns/mail_template_concern.rb index f720c8297..d4368957e 100644 --- a/app/models/concerns/mail_template_concern.rb +++ b/app/models/concerns/mail_template_concern.rb @@ -33,8 +33,9 @@ module MailTemplateConcern module ClassMethods def default_for_procedure(procedure) template_name = default_template_name_for_procedure(procedure) - body = ActionController::Base.new.render_to_string(template: template_name) - new(subject: const_get(:DEFAULT_SUBJECT), body: body, procedure: procedure) + rich_body = ActionController::Base.new.render_to_string(template: template_name) + trix_rich_body = rich_body.gsub(/(?)\n/, '') + new(subject: const_get(:DEFAULT_SUBJECT), rich_body: trix_rich_body, procedure: procedure) end def default_template_name_for_procedure(procedure) diff --git a/app/models/procedure.rb b/app/models/procedure.rb index ab04a58bd..83a3d54e1 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -474,7 +474,7 @@ class Procedure < ApplicationRecord def closed_mail_template_attestation_inconsistency_state # As an optimization, don’t check the predefined templates (they are presumed correct) if closed_mail.present? - tag_present = closed_mail.body.include?("--lien attestation--") + tag_present = closed_mail.body.to_s.include?("--lien attestation--") if attestation_template&.activated? && !tag_present :missing_tag elsif !attestation_template&.activated? && tag_present diff --git a/app/views/admin/mail_templates/edit.html.haml b/app/views/admin/mail_templates/edit.html.haml deleted file mode 100644 index a69a6a0f9..000000000 --- a/app/views/admin/mail_templates/edit.html.haml +++ /dev/null @@ -1,40 +0,0 @@ -- if params[:id] == 'closed_mail' - = render partial: 'admin/closed_mail_template_attestation_inconsistency_alert' -.white-back - %h3 - = @mail_template.class.const_get(:DISPLAYED_NAME) - - = form_for @mail_template, - as: 'mail_template', - url: admin_procedure_mail_template_path(@procedure, @mail_template.class.const_get(:SLUG)), - method: :put do |f| - .row - .col-md-6 - .form-group.string.optional.mail_template_subject - = f.label :subject, "Objet de l'email", class: 'control-label string optional' - = f.text_field :subject, class: 'form-control string optional' - - .form-group.text.optional.mail_template_body - = f.label :body, "Corps de l'email", class: 'control-label string optional' - = f.text_area :body, class: 'wysihtml5 form-control text optional' - - .text-right - = link_to "Annuler", admin_procedure_mail_templates_path(@procedure), class: "btn btn-default" - = f.submit 'Mettre à jour', class: "btn btn-default btn-success" - = link_to "Prévisualiser", preview_admin_procedure_mail_template_path(@procedure, @mail_template.class.const_get(:SLUG)), class: "btn btn-primary", target: "_blank" - - .row - .col-md-12 - %table.table - %tr - %th.col-md-3 - Balise - %th - Description - - @mail_template.tags.each do |tag| - %tr - %td - %code{ style: "white-space: pre-wrap;" } - = "--#{tag[:libelle]}--" - %td - = tag[:description] diff --git a/app/views/admin/mail_templates/index.html.haml b/app/views/admin/mail_templates/index.html.haml deleted file mode 100644 index 4deb55b4b..000000000 --- a/app/views/admin/mail_templates/index.html.haml +++ /dev/null @@ -1,14 +0,0 @@ -= render partial: 'admin/closed_mail_template_attestation_inconsistency_alert' -#custom-mails - .wrapper - %h1 E-mails personnalisables - %table.table - %tr - %th{ colspan: 2 } - Type d'email - - @mail_templates.each do |mail_template| - %tr - %td - = mail_template.class.const_get(:DISPLAYED_NAME) - %td.text-right - = link_to "Personnaliser l'e-mail", edit_admin_procedure_mail_template_path(@procedure, mail_template.class.const_get(:SLUG)) diff --git a/app/views/new_administrateur/mail_templates/_apercu.html.haml b/app/views/new_administrateur/mail_templates/_apercu.html.haml new file mode 100644 index 000000000..c890c7399 --- /dev/null +++ b/app/views/new_administrateur/mail_templates/_apercu.html.haml @@ -0,0 +1 @@ +%iframe{ src: preview_admin_procedure_mail_template_path, width: '100%', height: '650px' } diff --git a/app/views/new_administrateur/mail_templates/_form.html.haml b/app/views/new_administrateur/mail_templates/_form.html.haml new file mode 100644 index 000000000..ee7d66864 --- /dev/null +++ b/app/views/new_administrateur/mail_templates/_form.html.haml @@ -0,0 +1,47 @@ + += f.label :subject do + Objet de l'email + %span.mandatory * += f.text_field :subject, required: true + += f.label :body do + Corps de l'email + %span.mandatory * += f.rich_text_area :rich_body, required: true, class: "mb-4" + +#tags-table + %h2.add-tag-title + Insérer une balise + %p.notice + Copiez-collez les balises ci-dessous pour afficher automatiquement l’information souhaitée. + .head + .tag Balise + .description Description + .items + - @mail_template.tags.each do |tag| + .item + %code.tag + = "--#{tag[:libelle]}--" + .description + = tag[:description] + + +-# Disable accepting dropped images and traduce toolbar tooltips +:javascript + addEventListener('trix-file-accept', function(e) { e.preventDefault(); }); + addEventListener("trix-initialize", function(e) { + document.querySelector('button[data-trix-attribute="bold"]').setAttribute('title', 'Gras'); + document.querySelector('button[data-trix-attribute="italic"]').setAttribute('title', 'Italique'); + document.querySelector('button[data-trix-attribute="strike"]').setAttribute('title', 'Barrer'); + document.querySelector('button[data-trix-attribute="href"]').setAttribute('title', 'Créer lien'); + document.querySelector('button[data-trix-attribute="heading1"]').setAttribute('title', 'Titre'); + document.querySelector('button[data-trix-attribute="quote"]').setAttribute('title', 'Citation'); + document.querySelector('button[data-trix-attribute="bullet"]').setAttribute('title', 'Liste à puce'); + document.querySelector('button[data-trix-attribute="number"]').setAttribute('title', 'Liste numérotée'); + document.querySelector('button[data-trix-action="increaseNestingLevel"]').setAttribute('title', 'Indenter'); + document.querySelector('button[data-trix-action="decreaseNestingLevel"]').setAttribute('title', 'Désindenter'); + document.querySelector('button[data-trix-action="undo"]').setAttribute('title', 'Annuler la modification'); + document.querySelector('button[data-trix-action="redo"]').setAttribute('title', 'Appliquer à nouveau la modification'); + document.querySelector('.trix-button.trix-button--dialog[data-trix-method="setAttribute"]').value = "Créer lien"; + document.querySelector('.trix-button.trix-button--dialog[data-trix-method="removeAttribute"]').value = "Effacer lien"; + }) diff --git a/app/views/new_administrateur/mail_templates/edit.html.haml b/app/views/new_administrateur/mail_templates/edit.html.haml new file mode 100644 index 000000000..7f56949fb --- /dev/null +++ b/app/views/new_administrateur/mail_templates/edit.html.haml @@ -0,0 +1,33 @@ +- if params[:id] == 'closed_mail' + = render partial: 'admin/closed_mail_template_attestation_inconsistency_alert' + += render partial: 'new_administrateur/breadcrumbs', + locals: { steps: [link_to('Démarches', admin_procedures_path), + link_to(@procedure.libelle, admin_procedure_path(@procedure)), + link_to("Emails", admin_procedure_mail_templates_path(@procedure)), + @mail_template.class.const_get(:DISPLAYED_NAME)] } + +.procedure-form + .procedure-form__columns.container + + = form_for @mail_template, + url: admin_procedure_mail_template_path(@procedure, @mail_template.class.const_get(:SLUG)), + method: :put, + html: { class: 'form procedure-form__column--form' } do |f| + + %h1.page-title= @mail_template.class.const_get(:DISPLAYED_NAME) + = render partial: 'form', locals: { f: f } + .procedure-form__actions.sticky--bottom + .actions-right + = f.submit 'Enregistrer', class: 'button primary send' + + .procedure-form__column--preview + .procedure-form__preview.sticky--top + %h3 + .procedure-form__preview-title + Aperçu + .notice + Cet aperçu est mis à jour après chaque sauvegarde. + .procedure-preview + = render partial: 'apercu', locals: { procedure: @procedure } + diff --git a/app/views/new_administrateur/mail_templates/index.html.haml b/app/views/new_administrateur/mail_templates/index.html.haml index 00ee10d58..8d4963992 100644 --- a/app/views/new_administrateur/mail_templates/index.html.haml +++ b/app/views/new_administrateur/mail_templates/index.html.haml @@ -8,6 +8,10 @@ .flex.justify-between %div .card-title= mail_template.class.const_get(:DISPLAYED_NAME) - %p.notice= mail_template.class.const_get(:DISPLAYED_NAME) === 'Accusé de réception' ? 'Personnalisé' : 'Modèle standard' + - if mail_template.updated_at.blank? + %p.notice= mail_template.class.const_get(:DISPLAYED_NAME) === 'Accusé de réception' ? 'Personnalisé' : 'Modèle standard' + - else + %span.badge.baseline modifié le #{mail_template.updated_at.strftime('%d-%m-%Y')} + %div = link_to 'Modifier', edit_admin_procedure_mail_template_path(@procedure, mail_template.class.const_get(:SLUG)), class: 'button' diff --git a/config/routes.rb b/config/routes.rb index beefd87d3..043fc16d8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -189,8 +189,6 @@ Rails.application.routes.draw do delete :delete_notice end - resources :mail_templates, only: [:edit, :update] - put 'archive' => 'procedures#archive', as: :archive get 'publish_validate' => 'procedures#publish_validate', as: :publish_validate put 'publish' => 'procedures#publish', as: :publish @@ -373,6 +371,8 @@ Rails.application.routes.draw do patch 'update_jeton' end + resources :mail_templates, only: [:edit, :update] + resources :groupe_instructeurs, only: [:index, :show, :create, :update, :destroy] do member do post 'add_instructeur' diff --git a/spec/controllers/admin/mail_templates_controller_spec.rb b/spec/controllers/admin/mail_templates_controller_spec.rb deleted file mode 100644 index 29d2804ac..000000000 --- a/spec/controllers/admin/mail_templates_controller_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -describe Admin::MailTemplatesController, type: :controller do - let(:procedure) { create :procedure } - let(:initiated_mail) { Mails::InitiatedMail.default_for_procedure(procedure) } - - before do - sign_in(procedure.administrateurs.first.user) - end - - describe 'PATCH update' do - let(:mail_subject) { 'plop modif' } - let(:mail_body) { 'plip modif' } - - before :each do - patch :update, - params: { - procedure_id: procedure.id, - id: initiated_mail.class.const_get(:SLUG), - mail_template: { subject: mail_subject, body: mail_body } - } - end - - it { expect(response).to redirect_to edit_admin_procedure_mail_template_path(procedure, initiated_mail.class.const_get(:SLUG)) } - - context 'the mail template' do - subject { procedure.reload; procedure.initiated_mail_template } - - it { expect(subject.subject).to eq(mail_subject) } - it { expect(subject.body).to eq(mail_body) } - end - end -end diff --git a/spec/controllers/new_administrateur/mail_templates_controller_spec.rb b/spec/controllers/new_administrateur/mail_templates_controller_spec.rb index 8f66ad3fd..36a2a17a5 100644 --- a/spec/controllers/new_administrateur/mail_templates_controller_spec.rb +++ b/spec/controllers/new_administrateur/mail_templates_controller_spec.rb @@ -42,4 +42,27 @@ describe NewAdministrateur::MailTemplatesController, type: :controller do expect(response.body).to include(procedure.service.telephone) end end + + describe 'PATCH update' do + let(:mail_subject) { 'Mise à jour de votre démarche' } + let(:mail_body) { '
Une mise à jour a été effectuée sur votre démarche n° --demarche-id--.
' } + + before :each do + patch :update, + params: { + procedure_id: procedure.id, + id: initiated_mail.class.const_get(:SLUG), + mails_initiated_mail: { subject: mail_subject, rich_body: mail_body } + } + end + + it { expect(response).to redirect_to edit_admin_procedure_mail_template_path(procedure, initiated_mail.class.const_get(:SLUG)) } + + context 'the mail template' do + subject { procedure.reload; procedure.initiated_mail_template } + + it { expect(subject.subject).to eq(mail_subject) } + it { expect(subject.body).to eq(mail_body) } + end + end end diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index 14952586d..eda353e8c 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -42,7 +42,7 @@ describe Procedure do describe 'closed mail template body' do let(:procedure) { create(:procedure) } - subject { procedure.closed_mail_template.body } + subject { procedure.closed_mail_template.rich_body.body.to_html } context 'for procedures without an attestation' do it { is_expected.not_to include('lien attestation') } diff --git a/spec/views/admin/mail_templates/edit.html.haml_spec.rb b/spec/views/new_administrateur/mail_templates/edit.html.haml.spec.rb similarity index 69% rename from spec/views/admin/mail_templates/edit.html.haml_spec.rb rename to spec/views/new_administrateur/mail_templates/edit.html.haml.spec.rb index e67d29681..b0317931d 100644 --- a/spec/views/admin/mail_templates/edit.html.haml_spec.rb +++ b/spec/views/new_administrateur/mail_templates/edit.html.haml.spec.rb @@ -1,10 +1,10 @@ -describe 'admin/mail_templates/edit.html.haml', type: :view do +describe 'new_administrateur/mail_templates/edit.html.haml', type: :view do let(:procedure) { create(:procedure) } let(:mail_template) { create(:received_mail, procedure: procedure) } let(:all_tags) { mail_template.tags } before do - allow(view).to receive(:admin_procedure_mail_template_path).and_return("/toto") + allow(view).to receive(:admin_procedure_mail_templates_path).and_return("/toto") allow(view).to receive(:admin_procedure_mail_templates_path).and_return("/toto") assign(:mail_template, mail_template) @@ -13,6 +13,5 @@ describe 'admin/mail_templates/edit.html.haml', type: :view do context "Champs are listed in the page" do it { expect(all_tags).to include(include({ libelle: 'numéro du dossier' })) } - it { expect(render).to include("numéro du dossier") } end end From e033ec3404b53992522034df8cce7ae99e2bf67a Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Thu, 3 Sep 2020 12:52:42 +0000 Subject: [PATCH 27/27] js: ignore missing DOM element on ProgressBar Currently ProgressBar is used to monitor upload progress of attachments. But there's two cases where the associated DOM element may be removed: - In the champs editor, when the list scrolls, DOM elements are removed and added dynamically by React; - In the user form, the user might start an upload on a repetition, and then remove the associated row during the download. In both those cases, we don't want the missing DOM element to trigger an error. --- .../shared/activestorage/progress-bar.js | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/app/javascript/shared/activestorage/progress-bar.js b/app/javascript/shared/activestorage/progress-bar.js index 14efed061..fbc3797a9 100644 --- a/app/javascript/shared/activestorage/progress-bar.js +++ b/app/javascript/shared/activestorage/progress-bar.js @@ -7,6 +7,12 @@ const COMPLETE_CLASS = 'direct-upload--complete'; rendering upload progress bar. It is used to handle direct-upload form ujs events but also in the Uploader delegate used with uploads on json api. + + As the associated DOM element may disappear for some + reason (a dynamic React list, an element being removed + and recreated again later, etc.), this class doesn't + raise any error if the associated DOM element cannot + be found. */ export default class ProgressBar { static init(input, id, file) { @@ -17,27 +23,31 @@ export default class ProgressBar { static start(id) { const element = getDirectUploadElement(id); - - element.classList.remove(PENDING_CLASS); + if (element) { + element.classList.remove(PENDING_CLASS); + } } static progress(id, progress) { const element = getDirectUploadProgressElement(id); - - element.style.width = `${progress}%`; + if (element) { + element.style.width = `${progress}%`; + } } static error(id, error) { const element = getDirectUploadElement(id); - - element.classList.add(ERROR_CLASS); - element.setAttribute('title', error); + if (element) { + element.classList.add(ERROR_CLASS); + element.setAttribute('title', error); + } } static end(id) { const element = getDirectUploadElement(id); - - element.classList.add(COMPLETE_CLASS); + if (element) { + element.classList.add(COMPLETE_CLASS); + } } static render(id, filename) {