- {map ? footer : null}
);
}
From 71e1b6c97380f56834d26fbc7f47cd6ccf851c5c Mon Sep 17 00:00:00 2001
From: Pierre de La Morinerie
Date: Wed, 23 Feb 2022 17:04:24 +0100
Subject: [PATCH 03/12] models: delete AdministrateursProcedure when destroying
Administrateur
By default, `has_and_belongs_to_many` properly deletes the record in
the join table.
However, as the association is declared manually with a
`has_many / through`, it doesn't delete the joined record automatically.
As we also lack a foreign-key contraint on the join table, that means
a dangling record remains in the join table.
To fix this, let's declare it a proper `has_and_belongs_to_many`
association, which will let the join record be deleted automatically
on destroy.
---
app/models/administrateur.rb | 3 +--
spec/models/administrateur_spec.rb | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/app/models/administrateur.rb b/app/models/administrateur.rb
index ebd1e9470..7bdaa90fa 100644
--- a/app/models/administrateur.rb
+++ b/app/models/administrateur.rb
@@ -12,8 +12,7 @@ class Administrateur < ApplicationRecord
include ActiveRecord::SecureToken
has_and_belongs_to_many :instructeurs
- has_many :administrateurs_procedures
- has_many :procedures, through: :administrateurs_procedures
+ has_and_belongs_to_many :procedures
has_many :services
has_one :user, dependent: :nullify
diff --git a/spec/models/administrateur_spec.rb b/spec/models/administrateur_spec.rb
index 55e6c4d32..ce21fb67a 100644
--- a/spec/models/administrateur_spec.rb
+++ b/spec/models/administrateur_spec.rb
@@ -3,7 +3,7 @@ describe Administrateur, type: :model do
describe 'associations' do
it { is_expected.to have_and_belong_to_many(:instructeurs) }
- it { is_expected.to have_many(:procedures) }
+ it { is_expected.to have_and_belong_to_many(:procedures) }
end
describe "#renew_api_token" do
From 3fde7021e71f1d471e85d64b8efdfc2ca5aefd37 Mon Sep 17 00:00:00 2001
From: Pierre de La Morinerie
Date: Tue, 1 Mar 2022 07:47:39 +0000
Subject: [PATCH 04/12] db: add foreign key contraint to
AdministrateursProcedure
---
...ur_foreign_key_to_administrateurs_procedure.rb | 15 +++++++++++++++
1 file changed, 15 insertions(+)
create mode 100644 db/migrate/20220301160753_add_administrateur_foreign_key_to_administrateurs_procedure.rb
diff --git a/db/migrate/20220301160753_add_administrateur_foreign_key_to_administrateurs_procedure.rb b/db/migrate/20220301160753_add_administrateur_foreign_key_to_administrateurs_procedure.rb
new file mode 100644
index 000000000..d8d0bbb0a
--- /dev/null
+++ b/db/migrate/20220301160753_add_administrateur_foreign_key_to_administrateurs_procedure.rb
@@ -0,0 +1,15 @@
+class AddAdministrateurForeignKeyToAdministrateursProcedure < ActiveRecord::Migration[6.1]
+ def up
+ # Sanity check
+ say_with_time 'Removing AdministrateursProcedures where the associated Administrateur no longer exists ' do
+ deleted_administrateur_ids = AdministrateursProcedure.where.missing(:administrateur).pluck(:administrateur_id)
+ AdministrateursProcedure.where(administrateur_id: deleted_administrateur_ids).delete_all
+ end
+
+ add_foreign_key :administrateurs_procedures, :administrateurs
+ end
+
+ def down
+ remove_foreign_key :administrateurs_procedures, :administrateurs
+ end
+end
From 4fd9312fc9cbe7bb50560cfc371f2fa577532f5e Mon Sep 17 00:00:00 2001
From: Matthieu FAURE
Date: Thu, 17 Feb 2022 10:39:45 +0100
Subject: [PATCH 05/12] =?UTF-8?q?DOC=20Ajout=20doc=20d=C3=A9ploiement,=20a?=
=?UTF-8?q?vec=20mont=C3=A9e=20de=20version=20et=20migration=20de=20donn?=
=?UTF-8?q?=C3=A9es=20(afterparty)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
doc/Deploiment.md | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 doc/Deploiment.md
diff --git a/doc/Deploiment.md b/doc/Deploiment.md
new file mode 100644
index 000000000..4fae56c26
--- /dev/null
+++ b/doc/Deploiment.md
@@ -0,0 +1,11 @@
+# Déploiement d'une instance du logiciel Démarches-Simplifiées
+
+## Mises à jour
+
+* Une montée de version N vers N+1 fonctionne.
+* Une montée de version N vers N+X (X>1) n'est pas (encore) gérée
+* Depuis 2022, si des tâches de déploiement figurent dans une version, elles sont mentionnées
+ dans les [releases Github](https://github.com/betagouv/demarches-simplifiees.fr/releases) (mot clé : *AfterParty*)
+* Courant 2021, certaines tâches AfterPArty ont malheureusement été supprimées.
+* Pour les montées de versions de 2021, les tâches AfterParty sont incomplètes et nécessitent une intervention manuelle
+ pour migrer les données.
From bbc45f25ef35412c54cf59534fbb1129a1fac248 Mon Sep 17 00:00:00 2001
From: Pierre de La Morinerie
Date: Tue, 22 Feb 2022 09:16:03 +0100
Subject: [PATCH 06/12] doc: add deployment notes
---
README.md | 9 +------
doc/DEPLOYMENT.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++
doc/Deploiment.md | 11 ---------
3 files changed, 62 insertions(+), 19 deletions(-)
create mode 100644 doc/DEPLOYMENT.md
delete mode 100644 doc/Deploiment.md
diff --git a/README.md b/README.md
index 226ab9857..099f9d371 100644
--- a/README.md
+++ b/README.md
@@ -132,14 +132,7 @@ Le projet utilise plusieurs linters pour vérifier la lisibilité et la qualité
## Déploiement
-Dans le cas d’un déploiement sur plusieurs serveurs, l’application peut être déployée avec la tâche :
-
-```
-DOMAINS="web1 web2" BRANCH="main" bin/rake deploy
-```
-
-En interne, cette tâche utilise [mina](https://github.com/mina-deploy/mina) pour lancer les commandes
-de déploiement sur tous les serveurs spécifiés.
+Voir les notes de déploiement dans [DEPLOYMENT.md](doc/DEPLOYMENT.md)
## Tâches courantes
diff --git a/doc/DEPLOYMENT.md b/doc/DEPLOYMENT.md
new file mode 100644
index 000000000..1b975066d
--- /dev/null
+++ b/doc/DEPLOYMENT.md
@@ -0,0 +1,61 @@
+# Deployment documentation
+
+demarches-simplifiees.fr is a standard Rails app, and can be deployed using standard methods (PaaS, Docker, bare-metal, etc.) Deployments are engineered not to require any downtime.
+
+## 1. Deploying demarches-simplifiees.fr
+
+Usually, a deployment goes like this (in pseudo-code):
+
+```
+# Run database schema migrations (e.g. `bin/rails db:migrate`)
+# For each server:
+ # Stop the server
+ # Get the new code (e.g. `git clone git@github.com:betagouv/demarches-simplifiees.fr.git`)
+ # Install new dependencies (e.g. `bundle install && yarn install`)
+ # Restart the app server
+# Run data migrations (e.g. `rake after_party:run`)
+```
+
+On the main instance, this deployment flow is implemented using [`mina`](https://github.com/mina-deploy/mina), which automatically sshs to the application servers, run the appropriate commands (see `lib/tasks/deploy.rake` and `config/deploy.rb`), and restarts the puma webserver in a way that ensures zero-downtime deployments.
+A deploy on multiple application servers is typically done using:
+```shell
+DOMAINS="web1 web2" BRANCH="main" bin/rake deploy
+```
+
+But of course other methods can be used.
+
+## 2. Upgrading demarches-simplifiees.fr
+
+### 2.1 Standard upgrade path
+
+Theoretically, only deploying each version sequentially is fully supported. This means that to deploy the version N+3, the upgrade plan should be to deploy the version N+1, N+2 and then only N+3, in that order.
+
+Release notes for each version are available on [GitHub's Releases page](https://github.com/betagouv/demarches-simplifiees.fr/releases). Since 2022, when a release includes a database schema or data migration is present, this is mentionned in the release notes.
+
+### 2.2 Upgrading several releases at once
+
+Upgrading from several releases at once (like migrating directly from a version N to a version N+3) is theoretically unsupported. This is because database schema migrations and data migrations have to run in the exact order they were created, along the application code as it was when the migration was written.
+That said, it is possible to batch the upgrade of several releases at once, _provided that the data migrations run in the correct order_.
+
+The rule of thumb is that _an intermediary upgrade should be done before every database schema migration that follows a data migration_.
+
+_NB: There are some plans to improve this, and contributions are welcome. See https://github.com/betagouv/demarches-simplifiees.fr/issues/6970_
+
+# Historical notes
+
+- During 2021, some older data migration tasks were deleted from the repository. This has to be checked manually when upgrading from an older version.
+ ```
+ lib/tasks/deployment/20200326133630_cleanup_deleted_dossiers.rake
+ lib/tasks/deployment/20200401123317_process_expired_dossiers_en_construction.rake
+ lib/tasks/deployment/20200527124112_fix_champ_etablissement.rake
+ lib/tasks/deployment/20200528124044_fix_dossier_etablissement.rake
+ lib/tasks/deployment/20200618121241_drop_down_list_options_to_json.rake
+ lib/tasks/deployment/20200625113026_migrate_revisions.rake
+ lib/tasks/deployment/20200630154829_add_traitements_from_dossiers.rake
+ lib/tasks/deployment/20200708101123_add_default_skip_validation_to_piece_justificative.rake
+ lib/tasks/deployment/20200728150458_fix_cloned_revisions.rake
+ lib/tasks/deployment/20200813111957_fix_geo_areas_geometry.rake
+ lib/tasks/deployment/20201001161931_migrate_filters_to_use_stable_id.rake
+ lib/tasks/deployment/20201006123842_setup_first_stats.rake
+ lib/tasks/deployment/20201218163035_fix_types_de_champ_revisions.rake
+ ```
diff --git a/doc/Deploiment.md b/doc/Deploiment.md
deleted file mode 100644
index 4fae56c26..000000000
--- a/doc/Deploiment.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Déploiement d'une instance du logiciel Démarches-Simplifiées
-
-## Mises à jour
-
-* Une montée de version N vers N+1 fonctionne.
-* Une montée de version N vers N+X (X>1) n'est pas (encore) gérée
-* Depuis 2022, si des tâches de déploiement figurent dans une version, elles sont mentionnées
- dans les [releases Github](https://github.com/betagouv/demarches-simplifiees.fr/releases) (mot clé : *AfterParty*)
-* Courant 2021, certaines tâches AfterPArty ont malheureusement été supprimées.
-* Pour les montées de versions de 2021, les tâches AfterParty sont incomplètes et nécessitent une intervention manuelle
- pour migrer les données.
From 64a28cc8bdf3d79520a2b3204202d7a418c8e0ff Mon Sep 17 00:00:00 2001
From: Pierre de La Morinerie
Date: Tue, 22 Feb 2022 09:16:12 +0100
Subject: [PATCH 07/12] doc: move the ADR to their own directory
---
doc/{ => architecture-decision-records}/adr-csrf-forgery.md | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename doc/{ => architecture-decision-records}/adr-csrf-forgery.md (100%)
diff --git a/doc/adr-csrf-forgery.md b/doc/architecture-decision-records/adr-csrf-forgery.md
similarity index 100%
rename from doc/adr-csrf-forgery.md
rename to doc/architecture-decision-records/adr-csrf-forgery.md
From 19cde3140e2b8a13089942e9ebac8e2f7fd8b03f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 1 Mar 2022 23:35:43 +0000
Subject: [PATCH 08/12] chore(deps): bump image_processing from 1.12.1 to
1.12.2
Bumps [image_processing](https://github.com/janko/image_processing) from 1.12.1 to 1.12.2.
- [Release notes](https://github.com/janko/image_processing/releases)
- [Changelog](https://github.com/janko/image_processing/blob/master/CHANGELOG.md)
- [Commits](https://github.com/janko/image_processing/compare/v1.12.1...v1.12.2)
---
updated-dependencies:
- dependency-name: image_processing
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
---
Gemfile.lock | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Gemfile.lock b/Gemfile.lock
index c249c873c..08472eebd 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -251,7 +251,7 @@ GEM
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
- ffi (1.15.4)
+ ffi (1.15.5)
flipper (0.20.3)
flipper-active_record (0.20.3)
activerecord (>= 5.0, < 7)
@@ -350,7 +350,7 @@ GEM
i18n_data (0.13.0)
iban-tools (1.1.0)
ice_nine (0.11.2)
- image_processing (1.12.1)
+ image_processing (1.12.2)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
invisible_captcha (2.0.0)
@@ -621,8 +621,8 @@ GEM
rexml
ruby-progressbar (1.11.0)
ruby-saml-idp (0.3.5)
- ruby-vips (2.0.17)
- ffi (~> 1.9)
+ ruby-vips (2.1.4)
+ ffi (~> 1.12)
ruby2_keywords (0.0.5)
ruby_parser (3.15.1)
sexp_processor (~> 4.9)
From b8a22ae8b20c2525d8e190c430504100e4d4b9dc Mon Sep 17 00:00:00 2001
From: Paul Chavard
Date: Wed, 2 Mar 2022 09:48:42 +0000
Subject: [PATCH 09/12] fix(multi-select): fix labels on multi select component
---
.../{ComboMultiple.jsx => ComboMultiple.tsx} | 163 ++++++++++--------
package.json | 1 +
yarn.lock | 5 +
3 files changed, 96 insertions(+), 73 deletions(-)
rename app/javascript/components/{ComboMultiple.jsx => ComboMultiple.tsx} (73%)
diff --git a/app/javascript/components/ComboMultiple.jsx b/app/javascript/components/ComboMultiple.tsx
similarity index 73%
rename from app/javascript/components/ComboMultiple.jsx
rename to app/javascript/components/ComboMultiple.tsx
index 7938518a0..a0741ad09 100644
--- a/app/javascript/components/ComboMultiple.jsx
+++ b/app/javascript/components/ComboMultiple.tsx
@@ -5,9 +5,12 @@ import React, {
useContext,
createContext,
useEffect,
- useLayoutEffect
+ useLayoutEffect,
+ MutableRefObject,
+ ReactNode,
+ ChangeEventHandler,
+ KeyboardEventHandler
} from 'react';
-import PropTypes from 'prop-types';
import {
Combobox,
ComboboxInput,
@@ -24,22 +27,51 @@ import invariant from 'tiny-invariant';
import { useDeferredSubmit, useHiddenField } from './shared/hooks';
-const Context = createContext();
+const Context = createContext<{
+ selectionsRef: MutableRefObject;
+ onRemove: (value: string) => void;
+} | null>(null);
-const optionValueByLabel = (values, options, label) => {
- const maybeOption = values.includes(label)
+type Option = [label: string, value: string];
+
+function isOptions(options: string[] | Option[]): options is Option[] {
+ return Array.isArray(options[0]);
+}
+
+const optionValueByLabel = (
+ values: string[],
+ options: Option[],
+ label: string
+): string => {
+ const maybeOption: Option | undefined = values.includes(label)
? [label, label]
: options.find(([optionLabel]) => optionLabel == label);
- return maybeOption ? maybeOption[1] : undefined;
+ return maybeOption ? maybeOption[1] : '';
};
-const optionLabelByValue = (values, options, value) => {
- const maybeOption = values.includes(value)
+const optionLabelByValue = (
+ values: string[],
+ options: Option[],
+ value: string
+): string => {
+ const maybeOption: Option | undefined = values.includes(value)
? [value, value]
: options.find(([, optionValue]) => optionValue == value);
- return maybeOption ? maybeOption[0] : undefined;
+ return maybeOption ? maybeOption[0] : '';
};
-function ComboMultiple({
+export type ComboMultipleProps = {
+ options: string[] | Option[];
+ id: string;
+ labelledby: string;
+ describedby: string;
+ label: string;
+ group: string;
+ name?: string;
+ selected: string[];
+ acceptNewValues?: boolean;
+};
+
+export default function ComboMultiple({
options,
id,
labelledby,
@@ -49,21 +81,21 @@ function ComboMultiple({
name = 'value',
selected,
acceptNewValues = false
-}) {
+}: ComboMultipleProps) {
invariant(id || label, 'ComboMultiple: `id` or a `label` are required');
invariant(group, 'ComboMultiple: `group` is required');
- const inputRef = useRef();
+ const inputRef = useRef(null);
const [term, setTerm] = useState('');
const [selections, setSelections] = useState(selected);
- const [newValues, setNewValues] = useState([]);
+ const [newValues, setNewValues] = useState([]);
const inputId = useId(id);
const removedLabelledby = `${inputId}-remove`;
const selectedLabelledby = `${inputId}-selected`;
- const optionsWithLabels = useMemo(
+ const optionsWithLabels = useMemo