From fb66c064cd06774d0e67ea90d8bb6baec1fcb789 Mon Sep 17 00:00:00 2001
From: Elias Coppens <elias@dgnum.eu>
Date: Thu, 19 Dec 2024 14:07:35 +0100
Subject: [PATCH 1/5] chore: Partial version bump

---
 gestioasso/urls.py                            |   7 +-
 gestioncof/cms/migrations/0001_initial.py     | 120 +++++------
 .../0003_directory_entry_optional_links.py    |  46 ++--
 .../cms/migrations/0004_auto_20200829_2314.py |  64 +++---
 ...er_cofdirectoryentrypage_links_and_more.py | 203 ++++++++++++++++++
 gestioncof/cms/models.py                      |  21 +-
 .../migrations/0020_merge_20241218_2240.py    |  13 ++
 kfet/cms/hooks.py                             |   2 +-
 .../management/commands/kfet_loadwagtail.py   |   2 +-
 kfet/cms/migrations/0001_initial.py           |  24 +--
 .../migrations/0003_alter_kfetpage_content.py |  90 ++++++++
 kfet/cms/models.py                            |  22 +-
 requirements.txt                              |  34 +--
 13 files changed, 470 insertions(+), 178 deletions(-)
 create mode 100644 gestioncof/cms/migrations/0005_alter_cofdirectoryentrypage_links_and_more.py
 create mode 100644 gestioncof/migrations/0020_merge_20241218_2240.py
 create mode 100644 kfet/cms/migrations/0003_alter_kfetpage_content.py

diff --git a/gestioasso/urls.py b/gestioasso/urls.py
index 10173fbb..cd1ccc47 100644
--- a/gestioasso/urls.py
+++ b/gestioasso/urls.py
@@ -1,6 +1,7 @@
 """
 Fichier principal de configuration des urls du projet GestioCOF
 """
+
 from django.conf import settings
 from django.conf.urls.i18n import i18n_patterns
 from django.conf.urls.static import static
@@ -58,10 +59,10 @@ if settings.DEBUG:
     urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
 
 
-# Wagtail URLs (wagtail.core urls must be last, as catch-all)
-if "wagtail.core" in settings.INSTALLED_APPS:
+# Wagtail URLs (wagtail urls must be last, as catch-all)
+if "wagtail" in settings.INSTALLED_APPS:
+    from wagtail import urls as wagtail_urls
     from wagtail.admin import urls as wagtailadmin_urls
-    from wagtail.core import urls as wagtail_urls
     from wagtail.documents import urls as wagtaildocs_urls
 
     urlpatterns += [
diff --git a/gestioncof/cms/migrations/0001_initial.py b/gestioncof/cms/migrations/0001_initial.py
index 36a3ff1f..ef024c74 100644
--- a/gestioncof/cms/migrations/0001_initial.py
+++ b/gestioncof/cms/migrations/0001_initial.py
@@ -3,9 +3,9 @@
 from __future__ import unicode_literals
 
 import django.db.models.deletion
+import wagtail.blocks
 import wagtail.contrib.routable_page.models
-import wagtail.core.blocks
-import wagtail.core.fields
+import wagtail.fields
 import wagtail.images.blocks
 from django.db import migrations, models
 
@@ -72,18 +72,14 @@ class Migration(migrations.Migration):
                         blank=True, null=True, verbose_name="Description rapide"
                     ),
                 ),
-                ("body", wagtail.core.fields.RichTextField(verbose_name="Contenu")),
+                ("body", wagtail.fields.RichTextField(verbose_name="Contenu")),
                 (
                     "body_fr",
-                    wagtail.core.fields.RichTextField(
-                        null=True, verbose_name="Contenu"
-                    ),
+                    wagtail.fields.RichTextField(null=True, verbose_name="Contenu"),
                 ),
                 (
                     "body_en",
-                    wagtail.core.fields.RichTextField(
-                        null=True, verbose_name="Contenu"
-                    ),
+                    wagtail.fields.RichTextField(null=True, verbose_name="Contenu"),
                 ),
                 (
                     "is_event",
@@ -138,46 +134,40 @@ class Migration(migrations.Migration):
                         to="wagtailcore.Page",
                     ),
                 ),
-                ("body", wagtail.core.fields.RichTextField(verbose_name="Description")),
+                ("body", wagtail.fields.RichTextField(verbose_name="Description")),
                 (
                     "body_fr",
-                    wagtail.core.fields.RichTextField(
-                        null=True, verbose_name="Description"
-                    ),
+                    wagtail.fields.RichTextField(null=True, verbose_name="Description"),
                 ),
                 (
                     "body_en",
-                    wagtail.core.fields.RichTextField(
-                        null=True, verbose_name="Description"
-                    ),
+                    wagtail.fields.RichTextField(null=True, verbose_name="Description"),
                 ),
                 (
                     "links",
-                    wagtail.core.fields.StreamField(
+                    wagtail.fields.StreamField(
                         [
                             (
                                 "lien",
-                                wagtail.core.blocks.StructBlock(
+                                wagtail.blocks.StructBlock(
                                     [
                                         (
                                             "url",
-                                            wagtail.core.blocks.URLBlock(required=True),
+                                            wagtail.blocks.URLBlock(required=True),
                                         ),
-                                        ("texte", wagtail.core.blocks.CharBlock()),
+                                        ("texte", wagtail.blocks.CharBlock()),
                                     ]
                                 ),
                             ),
                             (
                                 "contact",
-                                wagtail.core.blocks.StructBlock(
+                                wagtail.blocks.StructBlock(
                                     [
                                         (
                                             "email",
-                                            wagtail.core.blocks.EmailBlock(
-                                                required=True
-                                            ),
+                                            wagtail.blocks.EmailBlock(required=True),
                                         ),
-                                        ("texte", wagtail.core.blocks.CharBlock()),
+                                        ("texte", wagtail.blocks.CharBlock()),
                                     ]
                                 ),
                             ),
@@ -186,31 +176,29 @@ class Migration(migrations.Migration):
                 ),
                 (
                     "links_fr",
-                    wagtail.core.fields.StreamField(
+                    wagtail.fields.StreamField(
                         [
                             (
                                 "lien",
-                                wagtail.core.blocks.StructBlock(
+                                wagtail.blocks.StructBlock(
                                     [
                                         (
                                             "url",
-                                            wagtail.core.blocks.URLBlock(required=True),
+                                            wagtail.blocks.URLBlock(required=True),
                                         ),
-                                        ("texte", wagtail.core.blocks.CharBlock()),
+                                        ("texte", wagtail.blocks.CharBlock()),
                                     ]
                                 ),
                             ),
                             (
                                 "contact",
-                                wagtail.core.blocks.StructBlock(
+                                wagtail.blocks.StructBlock(
                                     [
                                         (
                                             "email",
-                                            wagtail.core.blocks.EmailBlock(
-                                                required=True
-                                            ),
+                                            wagtail.blocks.EmailBlock(required=True),
                                         ),
-                                        ("texte", wagtail.core.blocks.CharBlock()),
+                                        ("texte", wagtail.blocks.CharBlock()),
                                     ]
                                 ),
                             ),
@@ -220,31 +208,29 @@ class Migration(migrations.Migration):
                 ),
                 (
                     "links_en",
-                    wagtail.core.fields.StreamField(
+                    wagtail.fields.StreamField(
                         [
                             (
                                 "lien",
-                                wagtail.core.blocks.StructBlock(
+                                wagtail.blocks.StructBlock(
                                     [
                                         (
                                             "url",
-                                            wagtail.core.blocks.URLBlock(required=True),
+                                            wagtail.blocks.URLBlock(required=True),
                                         ),
-                                        ("texte", wagtail.core.blocks.CharBlock()),
+                                        ("texte", wagtail.blocks.CharBlock()),
                                     ]
                                 ),
                             ),
                             (
                                 "contact",
-                                wagtail.core.blocks.StructBlock(
+                                wagtail.blocks.StructBlock(
                                     [
                                         (
                                             "email",
-                                            wagtail.core.blocks.EmailBlock(
-                                                required=True
-                                            ),
+                                            wagtail.blocks.EmailBlock(required=True),
                                         ),
-                                        ("texte", wagtail.core.blocks.CharBlock()),
+                                        ("texte", wagtail.blocks.CharBlock()),
                                     ]
                                 ),
                             ),
@@ -286,17 +272,17 @@ class Migration(migrations.Migration):
                 ),
                 (
                     "introduction",
-                    wagtail.core.fields.RichTextField(verbose_name="Introduction"),
+                    wagtail.fields.RichTextField(verbose_name="Introduction"),
                 ),
                 (
                     "introduction_fr",
-                    wagtail.core.fields.RichTextField(
+                    wagtail.fields.RichTextField(
                         null=True, verbose_name="Introduction"
                     ),
                 ),
                 (
                     "introduction_en",
-                    wagtail.core.fields.RichTextField(
+                    wagtail.fields.RichTextField(
                         null=True, verbose_name="Introduction"
                     ),
                 ),
@@ -329,27 +315,27 @@ class Migration(migrations.Migration):
                 ),
                 (
                     "body",
-                    wagtail.core.fields.StreamField(
+                    wagtail.fields.StreamField(
                         [
                             (
                                 "heading",
-                                wagtail.core.blocks.CharBlock(classname="full title"),
+                                wagtail.blocks.CharBlock(classname="full title"),
                             ),
-                            ("paragraph", wagtail.core.blocks.RichTextBlock()),
+                            ("paragraph", wagtail.blocks.RichTextBlock()),
                             ("image", wagtail.images.blocks.ImageChooserBlock()),
                             (
                                 "iframe",
-                                wagtail.core.blocks.StructBlock(
+                                wagtail.blocks.StructBlock(
                                     [
                                         (
                                             "url",
-                                            wagtail.core.blocks.URLBlock(
+                                            wagtail.blocks.URLBlock(
                                                 "Adresse de la page"
                                             ),
                                         ),
                                         (
                                             "height",
-                                            wagtail.core.blocks.CharBlock(
+                                            wagtail.blocks.CharBlock(
                                                 "Hauteur (en pixels)"
                                             ),
                                         ),
@@ -361,27 +347,27 @@ class Migration(migrations.Migration):
                 ),
                 (
                     "body_fr",
-                    wagtail.core.fields.StreamField(
+                    wagtail.fields.StreamField(
                         [
                             (
                                 "heading",
-                                wagtail.core.blocks.CharBlock(classname="full title"),
+                                wagtail.blocks.CharBlock(classname="full title"),
                             ),
-                            ("paragraph", wagtail.core.blocks.RichTextBlock()),
+                            ("paragraph", wagtail.blocks.RichTextBlock()),
                             ("image", wagtail.images.blocks.ImageChooserBlock()),
                             (
                                 "iframe",
-                                wagtail.core.blocks.StructBlock(
+                                wagtail.blocks.StructBlock(
                                     [
                                         (
                                             "url",
-                                            wagtail.core.blocks.URLBlock(
+                                            wagtail.blocks.URLBlock(
                                                 "Adresse de la page"
                                             ),
                                         ),
                                         (
                                             "height",
-                                            wagtail.core.blocks.CharBlock(
+                                            wagtail.blocks.CharBlock(
                                                 "Hauteur (en pixels)"
                                             ),
                                         ),
@@ -394,27 +380,27 @@ class Migration(migrations.Migration):
                 ),
                 (
                     "body_en",
-                    wagtail.core.fields.StreamField(
+                    wagtail.fields.StreamField(
                         [
                             (
                                 "heading",
-                                wagtail.core.blocks.CharBlock(classname="full title"),
+                                wagtail.blocks.CharBlock(classname="full title"),
                             ),
-                            ("paragraph", wagtail.core.blocks.RichTextBlock()),
+                            ("paragraph", wagtail.blocks.RichTextBlock()),
                             ("image", wagtail.images.blocks.ImageChooserBlock()),
                             (
                                 "iframe",
-                                wagtail.core.blocks.StructBlock(
+                                wagtail.blocks.StructBlock(
                                     [
                                         (
                                             "url",
-                                            wagtail.core.blocks.URLBlock(
+                                            wagtail.blocks.URLBlock(
                                                 "Adresse de la page"
                                             ),
                                         ),
                                         (
                                             "height",
-                                            wagtail.core.blocks.CharBlock(
+                                            wagtail.blocks.CharBlock(
                                                 "Hauteur (en pixels)"
                                             ),
                                         ),
@@ -448,17 +434,17 @@ class Migration(migrations.Migration):
                 ),
                 (
                     "introduction",
-                    wagtail.core.fields.RichTextField(verbose_name="Introduction"),
+                    wagtail.fields.RichTextField(verbose_name="Introduction"),
                 ),
                 (
                     "introduction_fr",
-                    wagtail.core.fields.RichTextField(
+                    wagtail.fields.RichTextField(
                         null=True, verbose_name="Introduction"
                     ),
                 ),
                 (
                     "introduction_en",
-                    wagtail.core.fields.RichTextField(
+                    wagtail.fields.RichTextField(
                         null=True, verbose_name="Introduction"
                     ),
                 ),
diff --git a/gestioncof/cms/migrations/0003_directory_entry_optional_links.py b/gestioncof/cms/migrations/0003_directory_entry_optional_links.py
index 6555236b..22533193 100644
--- a/gestioncof/cms/migrations/0003_directory_entry_optional_links.py
+++ b/gestioncof/cms/migrations/0003_directory_entry_optional_links.py
@@ -1,7 +1,7 @@
 # Generated by Django 2.2.8 on 2019-12-20 16:22
 
-import wagtail.core.blocks
-import wagtail.core.fields
+import wagtail.blocks
+import wagtail.fields
 from django.db import migrations
 
 
@@ -14,26 +14,26 @@ class Migration(migrations.Migration):
         migrations.AlterField(
             model_name="cofdirectoryentrypage",
             name="links",
-            field=wagtail.core.fields.StreamField(
+            field=wagtail.fields.StreamField(
                 [
                     (
                         "lien",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
-                                ("url", wagtail.core.blocks.URLBlock(required=True)),
-                                ("texte", wagtail.core.blocks.CharBlock()),
+                                ("url", wagtail.blocks.URLBlock(required=True)),
+                                ("texte", wagtail.blocks.CharBlock()),
                             ]
                         ),
                     ),
                     (
                         "contact",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
                                 (
                                     "email",
-                                    wagtail.core.blocks.EmailBlock(required=True),
+                                    wagtail.blocks.EmailBlock(required=True),
                                 ),
-                                ("texte", wagtail.core.blocks.CharBlock()),
+                                ("texte", wagtail.blocks.CharBlock()),
                             ]
                         ),
                     ),
@@ -44,26 +44,26 @@ class Migration(migrations.Migration):
         migrations.AlterField(
             model_name="cofdirectoryentrypage",
             name="links_en",
-            field=wagtail.core.fields.StreamField(
+            field=wagtail.fields.StreamField(
                 [
                     (
                         "lien",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
-                                ("url", wagtail.core.blocks.URLBlock(required=True)),
-                                ("texte", wagtail.core.blocks.CharBlock()),
+                                ("url", wagtail.blocks.URLBlock(required=True)),
+                                ("texte", wagtail.blocks.CharBlock()),
                             ]
                         ),
                     ),
                     (
                         "contact",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
                                 (
                                     "email",
-                                    wagtail.core.blocks.EmailBlock(required=True),
+                                    wagtail.blocks.EmailBlock(required=True),
                                 ),
-                                ("texte", wagtail.core.blocks.CharBlock()),
+                                ("texte", wagtail.blocks.CharBlock()),
                             ]
                         ),
                     ),
@@ -75,26 +75,26 @@ class Migration(migrations.Migration):
         migrations.AlterField(
             model_name="cofdirectoryentrypage",
             name="links_fr",
-            field=wagtail.core.fields.StreamField(
+            field=wagtail.fields.StreamField(
                 [
                     (
                         "lien",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
-                                ("url", wagtail.core.blocks.URLBlock(required=True)),
-                                ("texte", wagtail.core.blocks.CharBlock()),
+                                ("url", wagtail.blocks.URLBlock(required=True)),
+                                ("texte", wagtail.blocks.CharBlock()),
                             ]
                         ),
                     ),
                     (
                         "contact",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
                                 (
                                     "email",
-                                    wagtail.core.blocks.EmailBlock(required=True),
+                                    wagtail.blocks.EmailBlock(required=True),
                                 ),
-                                ("texte", wagtail.core.blocks.CharBlock()),
+                                ("texte", wagtail.blocks.CharBlock()),
                             ]
                         ),
                     ),
diff --git a/gestioncof/cms/migrations/0004_auto_20200829_2314.py b/gestioncof/cms/migrations/0004_auto_20200829_2314.py
index dd525a2c..eb660ad9 100644
--- a/gestioncof/cms/migrations/0004_auto_20200829_2314.py
+++ b/gestioncof/cms/migrations/0004_auto_20200829_2314.py
@@ -1,7 +1,7 @@
 # Generated by Django 2.2.15 on 2020-08-29 21:14
 
-import wagtail.core.blocks
-import wagtail.core.fields
+import wagtail.blocks
+import wagtail.fields
 from django.db import migrations
 
 
@@ -14,35 +14,35 @@ class Migration(migrations.Migration):
         migrations.AlterField(
             model_name="cofdirectoryentrypage",
             name="links",
-            field=wagtail.core.fields.StreamField(
+            field=wagtail.fields.StreamField(
                 [
                     (
                         "lien",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
-                                ("url", wagtail.core.blocks.URLBlock(required=True)),
-                                ("texte", wagtail.core.blocks.CharBlock()),
+                                ("url", wagtail.blocks.URLBlock(required=True)),
+                                ("texte", wagtail.blocks.CharBlock()),
                             ]
                         ),
                     ),
                     (
                         "contact",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
                                 (
                                     "email",
-                                    wagtail.core.blocks.EmailBlock(required=True),
+                                    wagtail.blocks.EmailBlock(required=True),
                                 ),
-                                ("texte", wagtail.core.blocks.CharBlock()),
+                                ("texte", wagtail.blocks.CharBlock()),
                             ]
                         ),
                     ),
                     (
                         "info",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
-                                ("nom", wagtail.core.blocks.CharBlock(required=False)),
-                                ("texte", wagtail.core.blocks.CharBlock(required=True)),
+                                ("nom", wagtail.blocks.CharBlock(required=False)),
+                                ("texte", wagtail.blocks.CharBlock(required=True)),
                             ]
                         ),
                     ),
@@ -53,35 +53,35 @@ class Migration(migrations.Migration):
         migrations.AlterField(
             model_name="cofdirectoryentrypage",
             name="links_en",
-            field=wagtail.core.fields.StreamField(
+            field=wagtail.fields.StreamField(
                 [
                     (
                         "lien",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
-                                ("url", wagtail.core.blocks.URLBlock(required=True)),
-                                ("texte", wagtail.core.blocks.CharBlock()),
+                                ("url", wagtail.blocks.URLBlock(required=True)),
+                                ("texte", wagtail.blocks.CharBlock()),
                             ]
                         ),
                     ),
                     (
                         "contact",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
                                 (
                                     "email",
-                                    wagtail.core.blocks.EmailBlock(required=True),
+                                    wagtail.blocks.EmailBlock(required=True),
                                 ),
-                                ("texte", wagtail.core.blocks.CharBlock()),
+                                ("texte", wagtail.blocks.CharBlock()),
                             ]
                         ),
                     ),
                     (
                         "info",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
-                                ("nom", wagtail.core.blocks.CharBlock(required=False)),
-                                ("texte", wagtail.core.blocks.CharBlock(required=True)),
+                                ("nom", wagtail.blocks.CharBlock(required=False)),
+                                ("texte", wagtail.blocks.CharBlock(required=True)),
                             ]
                         ),
                     ),
@@ -93,35 +93,35 @@ class Migration(migrations.Migration):
         migrations.AlterField(
             model_name="cofdirectoryentrypage",
             name="links_fr",
-            field=wagtail.core.fields.StreamField(
+            field=wagtail.fields.StreamField(
                 [
                     (
                         "lien",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
-                                ("url", wagtail.core.blocks.URLBlock(required=True)),
-                                ("texte", wagtail.core.blocks.CharBlock()),
+                                ("url", wagtail.blocks.URLBlock(required=True)),
+                                ("texte", wagtail.blocks.CharBlock()),
                             ]
                         ),
                     ),
                     (
                         "contact",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
                                 (
                                     "email",
-                                    wagtail.core.blocks.EmailBlock(required=True),
+                                    wagtail.blocks.EmailBlock(required=True),
                                 ),
-                                ("texte", wagtail.core.blocks.CharBlock()),
+                                ("texte", wagtail.blocks.CharBlock()),
                             ]
                         ),
                     ),
                     (
                         "info",
-                        wagtail.core.blocks.StructBlock(
+                        wagtail.blocks.StructBlock(
                             [
-                                ("nom", wagtail.core.blocks.CharBlock(required=False)),
-                                ("texte", wagtail.core.blocks.CharBlock(required=True)),
+                                ("nom", wagtail.blocks.CharBlock(required=False)),
+                                ("texte", wagtail.blocks.CharBlock(required=True)),
                             ]
                         ),
                     ),
diff --git a/gestioncof/cms/migrations/0005_alter_cofdirectoryentrypage_links_and_more.py b/gestioncof/cms/migrations/0005_alter_cofdirectoryentrypage_links_and_more.py
new file mode 100644
index 00000000..5b563942
--- /dev/null
+++ b/gestioncof/cms/migrations/0005_alter_cofdirectoryentrypage_links_and_more.py
@@ -0,0 +1,203 @@
+# Generated by Django 4.2.17 on 2024-12-19 12:27
+
+import wagtail.blocks
+import wagtail.fields
+import wagtail.images.blocks
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("cofcms", "0004_auto_20200829_2314"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="cofdirectoryentrypage",
+            name="links",
+            field=wagtail.fields.StreamField(
+                [
+                    (
+                        "lien",
+                        wagtail.blocks.StructBlock(
+                            [
+                                ("url", wagtail.blocks.URLBlock(required=True)),
+                                ("texte", wagtail.blocks.CharBlock()),
+                            ]
+                        ),
+                    ),
+                    (
+                        "contact",
+                        wagtail.blocks.StructBlock(
+                            [
+                                ("email", wagtail.blocks.EmailBlock(required=True)),
+                                ("texte", wagtail.blocks.CharBlock()),
+                            ]
+                        ),
+                    ),
+                    (
+                        "info",
+                        wagtail.blocks.StructBlock(
+                            [
+                                ("nom", wagtail.blocks.CharBlock(required=False)),
+                                ("texte", wagtail.blocks.CharBlock(required=True)),
+                            ]
+                        ),
+                    ),
+                ],
+                blank=True,
+                use_json_field=True,
+            ),
+        ),
+        migrations.AlterField(
+            model_name="cofdirectoryentrypage",
+            name="links_en",
+            field=wagtail.fields.StreamField(
+                [
+                    (
+                        "lien",
+                        wagtail.blocks.StructBlock(
+                            [
+                                ("url", wagtail.blocks.URLBlock(required=True)),
+                                ("texte", wagtail.blocks.CharBlock()),
+                            ]
+                        ),
+                    ),
+                    (
+                        "contact",
+                        wagtail.blocks.StructBlock(
+                            [
+                                ("email", wagtail.blocks.EmailBlock(required=True)),
+                                ("texte", wagtail.blocks.CharBlock()),
+                            ]
+                        ),
+                    ),
+                    (
+                        "info",
+                        wagtail.blocks.StructBlock(
+                            [
+                                ("nom", wagtail.blocks.CharBlock(required=False)),
+                                ("texte", wagtail.blocks.CharBlock(required=True)),
+                            ]
+                        ),
+                    ),
+                ],
+                blank=True,
+                null=True,
+                use_json_field=True,
+            ),
+        ),
+        migrations.AlterField(
+            model_name="cofdirectoryentrypage",
+            name="links_fr",
+            field=wagtail.fields.StreamField(
+                [
+                    (
+                        "lien",
+                        wagtail.blocks.StructBlock(
+                            [
+                                ("url", wagtail.blocks.URLBlock(required=True)),
+                                ("texte", wagtail.blocks.CharBlock()),
+                            ]
+                        ),
+                    ),
+                    (
+                        "contact",
+                        wagtail.blocks.StructBlock(
+                            [
+                                ("email", wagtail.blocks.EmailBlock(required=True)),
+                                ("texte", wagtail.blocks.CharBlock()),
+                            ]
+                        ),
+                    ),
+                    (
+                        "info",
+                        wagtail.blocks.StructBlock(
+                            [
+                                ("nom", wagtail.blocks.CharBlock(required=False)),
+                                ("texte", wagtail.blocks.CharBlock(required=True)),
+                            ]
+                        ),
+                    ),
+                ],
+                blank=True,
+                null=True,
+                use_json_field=True,
+            ),
+        ),
+        migrations.AlterField(
+            model_name="cofpage",
+            name="body",
+            field=wagtail.fields.StreamField(
+                [
+                    ("heading", wagtail.blocks.CharBlock(form_classname="full title")),
+                    ("paragraph", wagtail.blocks.RichTextBlock()),
+                    ("image", wagtail.images.blocks.ImageChooserBlock()),
+                    (
+                        "iframe",
+                        wagtail.blocks.StructBlock(
+                            [
+                                ("url", wagtail.blocks.URLBlock("Adresse de la page")),
+                                (
+                                    "height",
+                                    wagtail.blocks.CharBlock("Hauteur (en pixels)"),
+                                ),
+                            ]
+                        ),
+                    ),
+                ],
+                use_json_field=True,
+            ),
+        ),
+        migrations.AlterField(
+            model_name="cofpage",
+            name="body_en",
+            field=wagtail.fields.StreamField(
+                [
+                    ("heading", wagtail.blocks.CharBlock(form_classname="full title")),
+                    ("paragraph", wagtail.blocks.RichTextBlock()),
+                    ("image", wagtail.images.blocks.ImageChooserBlock()),
+                    (
+                        "iframe",
+                        wagtail.blocks.StructBlock(
+                            [
+                                ("url", wagtail.blocks.URLBlock("Adresse de la page")),
+                                (
+                                    "height",
+                                    wagtail.blocks.CharBlock("Hauteur (en pixels)"),
+                                ),
+                            ]
+                        ),
+                    ),
+                ],
+                null=True,
+                use_json_field=True,
+            ),
+        ),
+        migrations.AlterField(
+            model_name="cofpage",
+            name="body_fr",
+            field=wagtail.fields.StreamField(
+                [
+                    ("heading", wagtail.blocks.CharBlock(form_classname="full title")),
+                    ("paragraph", wagtail.blocks.RichTextBlock()),
+                    ("image", wagtail.images.blocks.ImageChooserBlock()),
+                    (
+                        "iframe",
+                        wagtail.blocks.StructBlock(
+                            [
+                                ("url", wagtail.blocks.URLBlock("Adresse de la page")),
+                                (
+                                    "height",
+                                    wagtail.blocks.CharBlock("Hauteur (en pixels)"),
+                                ),
+                            ]
+                        ),
+                    ),
+                ],
+                null=True,
+                use_json_field=True,
+            ),
+        ),
+    ]
diff --git a/gestioncof/cms/models.py b/gestioncof/cms/models.py
index 57881084..6e9e8715 100644
--- a/gestioncof/cms/models.py
+++ b/gestioncof/cms/models.py
@@ -1,12 +1,11 @@
 from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
 from django.db import models
-from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
+from wagtail import blocks
+from wagtail.admin.panels import FieldPanel
 from wagtail.contrib.routable_page.models import RoutablePageMixin, route
-from wagtail.core import blocks
-from wagtail.core.fields import RichTextField, StreamField
-from wagtail.core.models import Page
+from wagtail.fields import RichTextField, StreamField
 from wagtail.images.blocks import ImageChooserBlock
-from wagtail.images.edit_handlers import ImageChooserPanel
+from wagtail.models import Page
 
 
 # Page pouvant afficher des actualités
@@ -69,10 +68,11 @@ class COFPage(Page):
             ("paragraph", blocks.RichTextBlock()),
             ("image", ImageChooserBlock()),
             ("iframe", IFrameBlock()),
-        ]
+        ],
+        use_json_field=True,
     )
 
-    content_panels = Page.content_panels + [StreamFieldPanel("body")]
+    content_panels = Page.content_panels + [FieldPanel("body")]
 
     subpage_types = ["COFDirectoryPage", "COFPage"]
     parent_page_types = ["COFPage", "COFRootPage"]
@@ -127,7 +127,7 @@ class COFActuPage(RoutablePageMixin, Page):
     all_day = models.BooleanField("Toute la journée", default=False, blank=True)
 
     content_panels = Page.content_panels + [
-        ImageChooserPanel("image"),
+        FieldPanel("image"),
         FieldPanel("chapo"),
         FieldPanel("body", classname="full"),
         FieldPanel("is_event"),
@@ -204,6 +204,7 @@ class COFDirectoryEntryPage(Page):
             ),
         ],
         blank=True,
+        use_json_field=True,
     )
 
     image = models.ForeignKey(
@@ -216,9 +217,9 @@ class COFDirectoryEntryPage(Page):
     )
 
     content_panels = Page.content_panels + [
-        ImageChooserPanel("image"),
+        FieldPanel("image"),
         FieldPanel("body", classname="full"),
-        StreamFieldPanel("links"),
+        FieldPanel("links"),
     ]
 
     subpage_types = []
diff --git a/gestioncof/migrations/0020_merge_20241218_2240.py b/gestioncof/migrations/0020_merge_20241218_2240.py
new file mode 100644
index 00000000..af017d4c
--- /dev/null
+++ b/gestioncof/migrations/0020_merge_20241218_2240.py
@@ -0,0 +1,13 @@
+# Generated by Django 3.2.25 on 2024-12-18 21:40
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("gestioncof", "0019_auto_20220630_1241"),
+        ("gestioncof", "0019_cofprofile_date_adhesion"),
+    ]
+
+    operations = []
diff --git a/kfet/cms/hooks.py b/kfet/cms/hooks.py
index 67261c74..df400e0f 100644
--- a/kfet/cms/hooks.py
+++ b/kfet/cms/hooks.py
@@ -1,6 +1,6 @@
 from django.templatetags.static import static
 from django.utils.html import format_html
-from wagtail.core import hooks
+from wagtail import hooks
 
 
 @hooks.register("insert_editor_css")
diff --git a/kfet/cms/management/commands/kfet_loadwagtail.py b/kfet/cms/management/commands/kfet_loadwagtail.py
index 17ed842a..fd04e8e3 100644
--- a/kfet/cms/management/commands/kfet_loadwagtail.py
+++ b/kfet/cms/management/commands/kfet_loadwagtail.py
@@ -1,7 +1,7 @@
 from django.contrib.auth.models import Group
 from django.core.management import call_command
 from django.core.management.base import BaseCommand
-from wagtail.core.models import Page, Site
+from wagtail.models import Page, Site
 
 
 class Command(BaseCommand):
diff --git a/kfet/cms/migrations/0001_initial.py b/kfet/cms/migrations/0001_initial.py
index af3a1f09..b19f0db5 100644
--- a/kfet/cms/migrations/0001_initial.py
+++ b/kfet/cms/migrations/0001_initial.py
@@ -2,8 +2,8 @@
 from __future__ import unicode_literals
 
 import django.db.models.deletion
-import wagtail.core.blocks
-import wagtail.core.fields
+import wagtail.blocks
+import wagtail.fields
 import wagtail.snippets.blocks
 from django.db import migrations, models
 
@@ -41,20 +41,20 @@ class Migration(migrations.Migration):
                 ),
                 (
                     "content",
-                    wagtail.core.fields.StreamField(
+                    wagtail.fields.StreamField(
                         (
                             (
                                 "rich",
-                                wagtail.core.blocks.RichTextBlock(label="Éditeur"),
+                                wagtail.blocks.RichTextBlock(label="Éditeur"),
                             ),
                             ("carte", kfet.cms.models.MenuBlock()),
                             (
                                 "group_team",
-                                wagtail.core.blocks.StructBlock(
+                                wagtail.blocks.StructBlock(
                                     (
                                         (
                                             "show_only",
-                                            wagtail.core.blocks.IntegerBlock(
+                                            wagtail.blocks.IntegerBlock(
                                                 help_text="Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.",  # noqa
                                                 required=False,
                                                 label="Montrer seulement",
@@ -62,7 +62,7 @@ class Migration(migrations.Migration):
                                         ),
                                         (
                                             "members",
-                                            wagtail.core.blocks.ListBlock(
+                                            wagtail.blocks.ListBlock(
                                                 wagtail.snippets.blocks.SnippetChooserBlock(  # noqa
                                                     kfet.cms.models.MemberTeam
                                                 ),
@@ -75,22 +75,22 @@ class Migration(migrations.Migration):
                             ),
                             (
                                 "group",
-                                wagtail.core.blocks.StreamBlock(
+                                wagtail.blocks.StreamBlock(
                                     (
                                         (
                                             "rich",
-                                            wagtail.core.blocks.RichTextBlock(
+                                            wagtail.blocks.RichTextBlock(
                                                 label="Éditeur"
                                             ),
                                         ),
                                         ("carte", kfet.cms.models.MenuBlock()),
                                         (
                                             "group_team",
-                                            wagtail.core.blocks.StructBlock(
+                                            wagtail.blocks.StructBlock(
                                                 (
                                                     (
                                                         "show_only",
-                                                        wagtail.core.blocks.IntegerBlock(  # noqa
+                                                        wagtail.blocks.IntegerBlock(  # noqa
                                                             help_text="Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.",  # noqa
                                                             required=False,
                                                             label="Montrer seulement",
@@ -98,7 +98,7 @@ class Migration(migrations.Migration):
                                                     ),
                                                     (
                                                         "members",
-                                                        wagtail.core.blocks.ListBlock(
+                                                        wagtail.blocks.ListBlock(
                                                             wagtail.snippets.blocks.SnippetChooserBlock(  # noqa
                                                                 kfet.cms.models.MemberTeam  # noqa
                                                             ),
diff --git a/kfet/cms/migrations/0003_alter_kfetpage_content.py b/kfet/cms/migrations/0003_alter_kfetpage_content.py
new file mode 100644
index 00000000..7e41eab4
--- /dev/null
+++ b/kfet/cms/migrations/0003_alter_kfetpage_content.py
@@ -0,0 +1,90 @@
+# Generated by Django 4.2.17 on 2024-12-19 12:27
+
+import wagtail.blocks
+import wagtail.fields
+import wagtail.snippets.blocks
+from django.db import migrations
+
+import kfet.cms.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("kfetcms", "0002_alter_kfetpage_colcount"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="kfetpage",
+            name="content",
+            field=wagtail.fields.StreamField(
+                [
+                    ("rich", wagtail.blocks.RichTextBlock(label="Éditeur")),
+                    ("carte", kfet.cms.models.MenuBlock()),
+                    (
+                        "group_team",
+                        wagtail.blocks.StructBlock(
+                            [
+                                (
+                                    "show_only",
+                                    wagtail.blocks.IntegerBlock(
+                                        help_text="Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.",
+                                        label="Montrer seulement",
+                                        required=False,
+                                    ),
+                                ),
+                                (
+                                    "members",
+                                    wagtail.blocks.ListBlock(
+                                        wagtail.snippets.blocks.SnippetChooserBlock(
+                                            kfet.cms.models.MemberTeam
+                                        ),
+                                        form_classname="team-group",
+                                        label="K-Fêt-eux-ses",
+                                    ),
+                                ),
+                            ]
+                        ),
+                    ),
+                    (
+                        "group",
+                        wagtail.blocks.StreamBlock(
+                            [
+                                ("rich", wagtail.blocks.RichTextBlock(label="Éditeur")),
+                                ("carte", kfet.cms.models.MenuBlock()),
+                                (
+                                    "group_team",
+                                    wagtail.blocks.StructBlock(
+                                        [
+                                            (
+                                                "show_only",
+                                                wagtail.blocks.IntegerBlock(
+                                                    help_text="Nombre initial de membres affichés. Laisser vide pour tou-te-s les afficher.",
+                                                    label="Montrer seulement",
+                                                    required=False,
+                                                ),
+                                            ),
+                                            (
+                                                "members",
+                                                wagtail.blocks.ListBlock(
+                                                    wagtail.snippets.blocks.SnippetChooserBlock(
+                                                        kfet.cms.models.MemberTeam
+                                                    ),
+                                                    form_classname="team-group",
+                                                    label="K-Fêt-eux-ses",
+                                                ),
+                                            ),
+                                        ]
+                                    ),
+                                ),
+                            ],
+                            label="Contenu groupé",
+                        ),
+                    ),
+                ],
+                use_json_field=True,
+                verbose_name="Contenu",
+            ),
+        ),
+    ]
diff --git a/kfet/cms/models.py b/kfet/cms/models.py
index 8747c280..6ba36940 100644
--- a/kfet/cms/models.py
+++ b/kfet/cms/models.py
@@ -1,15 +1,9 @@
 from django.db import models
 from django.utils.translation import gettext_lazy as _
-from wagtail.admin.edit_handlers import (
-    FieldPanel,
-    FieldRowPanel,
-    MultiFieldPanel,
-    StreamFieldPanel,
-)
-from wagtail.core import blocks
-from wagtail.core.fields import StreamField
-from wagtail.core.models import Page
-from wagtail.images.edit_handlers import ImageChooserPanel
+from wagtail import blocks
+from wagtail.admin.panels import FieldPanel, FieldRowPanel, MultiFieldPanel
+from wagtail.fields import StreamField
+from wagtail.models import Page
 from wagtail.snippets.blocks import SnippetChooserBlock
 from wagtail.snippets.models import register_snippet
 
@@ -43,7 +37,7 @@ class MemberTeam(models.Model):
         FieldPanel("first_name"),
         FieldPanel("last_name"),
         FieldPanel("nick_name"),
-        ImageChooserPanel("photo"),
+        FieldPanel("photo"),
     ]
 
     def __str__(self):
@@ -97,7 +91,9 @@ class KFetStreamBlock(ChoicesStreamBlock):
 
 
 class KFetPage(Page):
-    content = StreamField(KFetStreamBlock, verbose_name=_("Contenu"))
+    content = StreamField(
+        KFetStreamBlock, verbose_name=_("Contenu"), use_json_field=True
+    )
 
     # Layout fields
 
@@ -135,7 +131,7 @@ class KFetPage(Page):
 
     # Panels
 
-    content_panels = Page.content_panels + [StreamFieldPanel("content")]
+    content_panels = Page.content_panels + [FieldPanel("content")]
 
     layout_panel = [
         FieldPanel("no_header"),
diff --git a/requirements.txt b/requirements.txt
index 2016b576..42ce4704 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,19 +1,21 @@
-Django==3.2.*
-Pillow==7.2.0
+Django==4.2.17
+Pillow==9.5.0
 authens==0.1b4
-channels==3.0.*
-configparser==3.5.0
-django-autocomplete-light==3.9.4
-django-bootstrap-form==3.3
-django-cas-ng==4.3.*
-django-cors-headers==3.13.0
-django-djconfig==0.10.0
+channels==3.0.5
+configparser==5.3.0
+django-autocomplete-light==3.11.0
+django-bootstrap-form==3.4
+django-cas-ng==5.0.1
+django-cors-headers==3.14.0
+django-djconfig==0.11.0
 django-hCaptcha==0.2.0
-django-js-reverse==0.9.1
-django-widget-tweaks==1.4.1
-icalendar==4.0.7
-python-dateutil==2.8.1
+django-js-reverse==0.10.2
+django-widget-tweaks==1.4.12
+icalendar==5.0.13
+python-dateutil==2.9.0.post0
 statistics==1.0.3.5
-wagtail-modeltranslation==0.11.*
-wagtail==2.13.*
-wagtailmenus==3.0.*
+wagtail-modeltranslation==0.14.2
+django-modeltranslation==0.18.9
+wagtail==5.2.7
+wagtailmenus==3.1.9
+django-debug-toolbar==4.3.0
-- 
2.47.0


From aafbab29ff9f249f8b52afd2678d0b369f48c6e6 Mon Sep 17 00:00:00 2001
From: Elias Coppens <elias@dgnum.eu>
Date: Fri, 20 Dec 2024 00:20:31 +0100
Subject: [PATCH 2/5] chore: Finished version bump

---
 gestioasso/settings/cof_prod.py            |  4 ++--
 kfet/migrations/0040_auto_20160829_2035.py |  5 +++--
 requirements-devel.txt                     |  2 +-
 requirements-prod.txt                      | 10 +++++-----
 requirements.txt                           | 22 ++++++++++------------
 5 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/gestioasso/settings/cof_prod.py b/gestioasso/settings/cof_prod.py
index 58496057..91bee648 100644
--- a/gestioasso/settings/cof_prod.py
+++ b/gestioasso/settings/cof_prod.py
@@ -67,8 +67,8 @@ INSTALLED_APPS = (
         "wagtail.images",
         "wagtail.search",
         "wagtail.admin",
-        "wagtail.core",
-        "wagtail.contrib.modeladmin",
+        "wagtail",
+        # "wagtail.contrib.modeladmin",
         "wagtail.contrib.routable_page",
         "wagtailmenus",
         "modelcluster",
diff --git a/kfet/migrations/0040_auto_20160829_2035.py b/kfet/migrations/0040_auto_20160829_2035.py
index dc1aeeab..15f972f4 100644
--- a/kfet/migrations/0040_auto_20160829_2035.py
+++ b/kfet/migrations/0040_auto_20160829_2035.py
@@ -4,7 +4,6 @@ from __future__ import unicode_literals
 import datetime
 
 from django.db import migrations, models
-from django.utils.timezone import utc
 
 
 class Migration(migrations.Migration):
@@ -17,7 +16,9 @@ class Migration(migrations.Migration):
             name="at",
             field=models.DateTimeField(
                 auto_now_add=True,
-                default=datetime.datetime(2016, 8, 29, 18, 35, 3, 419033, tzinfo=utc),
+                default=datetime.datetime(
+                    2016, 8, 29, 18, 35, 3, 419033, tzinfo=datetime.timezone.utc
+                ),
             ),
             preserve_default=False,
         ),
diff --git a/requirements-devel.txt b/requirements-devel.txt
index d6b5c0a4..2de02a5d 100644
--- a/requirements-devel.txt
+++ b/requirements-devel.txt
@@ -1,5 +1,5 @@
 -r requirements.txt
-django-debug-toolbar==3.2.*
+django-debug-toolbar==4.4.6
 ipython
 
 # Tools
diff --git a/requirements-prod.txt b/requirements-prod.txt
index b4a99d6b..45ac4920 100644
--- a/requirements-prod.txt
+++ b/requirements-prod.txt
@@ -1,15 +1,15 @@
 -r requirements.txt
 
 # Postgresql bindings
-psycopg2==2.9.*
+psycopg2==2.9.10
 
 # Redis
-django-redis-cache==3.0.*
-redis==3.5.*
-channels-redis==3.4.*
+django-redis-cache==3.0.1
+redis==3.5.3
+channels-redis==3.4.1
 
 # ASGI protocol and HTTP server
-daphne==3.0.*
+daphne==3.0.2
 
 # ldap bindings
 python-ldap
diff --git a/requirements.txt b/requirements.txt
index 42ce4704..2f69c5c5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,21 +1,19 @@
-Django==4.2.17
-Pillow==9.5.0
-authens==0.1b4
+Django==5.1.4
+Pillow==11.0.0
+authens==0.2.0
 channels==3.0.5
-configparser==5.3.0
+configparser==7.1.0
 django-autocomplete-light==3.11.0
 django-bootstrap-form==3.4
 django-cas-ng==5.0.1
-django-cors-headers==3.14.0
+django-cors-headers==4.6.0
 django-djconfig==0.11.0
 django-hCaptcha==0.2.0
 django-js-reverse==0.10.2
-django-widget-tweaks==1.4.12
-icalendar==5.0.13
+django-widget-tweaks==1.5.0
+icalendar==6.1.0
 python-dateutil==2.9.0.post0
 statistics==1.0.3.5
-wagtail-modeltranslation==0.14.2
-django-modeltranslation==0.18.9
-wagtail==5.2.7
-wagtailmenus==3.1.9
-django-debug-toolbar==4.3.0
+wagtail-modeltranslation==0.15.1
+wagtail==6.3.1
+wagtailmenus==4.0.1
-- 
2.47.0


From 0fdc1a2a46b0641379bf565702d030c94acd0eef Mon Sep 17 00:00:00 2001
From: catvayor <catvayor@katvayor.net>
Date: Mon, 23 Dec 2024 11:27:19 +0100
Subject: [PATCH 3/5] fix(k-fet/accouts/new): reverse path at trigramme
 creation

---
 kfet/models.py | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/kfet/models.py b/kfet/models.py
index 003609a4..f30e093e 100644
--- a/kfet/models.py
+++ b/kfet/models.py
@@ -283,9 +283,13 @@ class Account(models.Model):
                 context={
                     "account": self,
                     "site": Site.objects.get_current(),
-                    "url_read": reverse("kfet.account.read", args=(self.trigramme)),
-                    "url_update": reverse("kfet.account.update", args=(self.trigramme)),
-                    "url_delete": reverse("kfet.account.delete", args=(self.trigramme))
+                    "url_read": reverse("kfet.account.read", args=(self.trigramme,)),
+                    "url_update": reverse(
+                        "kfet.account.update", args=(self.trigramme,)
+                    ),
+                    "url_delete": reverse(
+                        "kfet.account.delete", args=(self.trigramme,)
+                    ),
                 },
             ),
             from_email=mail_data["FROM"],
-- 
2.47.0


From 57ff8fe131b3e0b905613b6a13013ca6b0b28c1a Mon Sep 17 00:00:00 2001
From: catvayor <catvayor@katvayor.net>
Date: Sat, 28 Dec 2024 17:23:04 +0100
Subject: [PATCH 4/5] chore: use Django LTS

---
 requirements.txt | 2 +-
 shell.nix        | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/requirements.txt b/requirements.txt
index 2f69c5c5..65d1d380 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-Django==5.1.4
+Django==4.2.17
 Pillow==11.0.0
 authens==0.2.0
 channels==3.0.5
diff --git a/shell.nix b/shell.nix
index 69411b79..8208e005 100644
--- a/shell.nix
+++ b/shell.nix
@@ -4,7 +4,7 @@
 }:
 
 let
-  python = pkgs.python39;
+  python = pkgs.python313;
 in
 
 pkgs.mkShell {
-- 
2.47.0


From b8c963779ac26b7b2f90ac98480941299ce376d2 Mon Sep 17 00:00:00 2001
From: catvayor <catvayor@katvayor.net>
Date: Tue, 10 Dec 2024 15:41:21 +0100
Subject: [PATCH 5/5] fix: shell.nix

---
 npins/default.nix  | 81 ++++++++++++++++++++++++++++++++++++++++++++++
 npins/sources.json | 33 +++++++++++++++++++
 shell.nix          | 67 ++++++++++++++++++++++++++------------
 3 files changed, 161 insertions(+), 20 deletions(-)
 create mode 100644 npins/default.nix
 create mode 100644 npins/sources.json

diff --git a/npins/default.nix b/npins/default.nix
new file mode 100644
index 00000000..d256a275
--- /dev/null
+++ b/npins/default.nix
@@ -0,0 +1,81 @@
+# Generated by npins. Do not modify; will be overwritten regularly
+let
+  data = builtins.fromJSON (builtins.readFile ./sources.json);
+  version = data.version;
+
+  mkSource =
+    spec:
+    assert spec ? type;
+    let
+      path =
+        if spec.type == "Git" then
+          mkGitSource spec
+        else if spec.type == "GitRelease" then
+          mkGitSource spec
+        else if spec.type == "PyPi" then
+          mkPyPiSource spec
+        else if spec.type == "Channel" then
+          mkChannelSource spec
+        else
+          builtins.throw "Unknown source type ${spec.type}";
+    in
+    spec // { outPath = path; };
+
+  mkGitSource =
+    {
+      repository,
+      revision,
+      url ? null,
+      hash,
+      branch ? null,
+      ...
+    }:
+    assert repository ? type;
+    # At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
+    # In the latter case, there we will always be an url to the tarball
+    if url != null then
+      (builtins.fetchTarball {
+        inherit url;
+        sha256 = hash; # FIXME: check nix version & use SRI hashes
+      })
+    else
+      assert repository.type == "Git";
+      let
+        urlToName =
+          url: rev:
+          let
+            matched = builtins.match "^.*/([^/]*)(\\.git)?$" repository.url;
+
+            short = builtins.substring 0 7 rev;
+
+            appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
+          in
+          "${if matched == null then "source" else builtins.head matched}${appendShort}";
+        name = urlToName repository.url revision;
+      in
+      builtins.fetchGit {
+        url = repository.url;
+        rev = revision;
+        inherit name;
+        allRefs = true;
+        # hash = hash;
+      };
+
+  mkPyPiSource =
+    { url, hash, ... }:
+    builtins.fetchurl {
+      inherit url;
+      sha256 = hash;
+    };
+
+  mkChannelSource =
+    { url, hash, ... }:
+    builtins.fetchTarball {
+      inherit url;
+      sha256 = hash;
+    };
+in
+if version == 3 then
+  builtins.mapAttrs (_: mkSource) data.pins
+else
+  throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"
diff --git a/npins/sources.json b/npins/sources.json
new file mode 100644
index 00000000..9ed77931
--- /dev/null
+++ b/npins/sources.json
@@ -0,0 +1,33 @@
+{
+  "pins": {
+    "kat-pkgs": {
+      "type": "Git",
+      "repository": {
+        "type": "Git",
+        "url": "https://git.dgnum.eu/lbailly/kat-pkgs.git"
+      },
+      "branch": "master",
+      "revision": "6b600b716f409c6012b424de006eac3b02148b81",
+      "url": null,
+      "hash": "0204f91vxa5qglihpfkf3j5w3k7v98wry861xf2skl024faf9idf"
+    },
+    "nix-pkgs": {
+      "type": "Git",
+      "repository": {
+        "type": "Git",
+        "url": "https://git.hubrecht.ovh/hubrecht/nix-pkgs"
+      },
+      "branch": "main",
+      "revision": "ac4ff5a34789ae3398aff9501735b67b6a5a285a",
+      "url": null,
+      "hash": "16n37f74p6h30hhid98vab9w5b08xqj4qcshz2kc1jh67z5n49p6"
+    },
+    "nixpkgs": {
+      "type": "Channel",
+      "name": "nixos-unstable",
+      "url": "https://releases.nixos.org/nixos/unstable/nixos-25.05beta719504.a73246e2eef4/nixexprs.tar.xz",
+      "hash": "1jjmg13jzbqxm5m5ql51n2kq1qggfyb0rhmjwhqhvqxhl350z58a"
+    }
+  },
+  "version": 3
+}
\ No newline at end of file
diff --git a/shell.nix b/shell.nix
index 8208e005..ee150476 100644
--- a/shell.nix
+++ b/shell.nix
@@ -1,30 +1,57 @@
-{
-  pkgs ? import <nixpkgs> { },
-  ...
-}:
-
 let
-  python = pkgs.python313;
+  sources = import ./npins;
+  pkgs = import sources.nixpkgs { };
+  nix-pkgs = import sources.nix-pkgs { inherit pkgs; };
+  kat-pkgs = import sources.kat-pkgs { inherit pkgs; };
+  python3 = pkgs.python3.override {
+    packageOverrides = final: prev: {
+      inherit (nix-pkgs) authens django-bootstrap-form django-cas-ng;
+      inherit (kat-pkgs.python3Packages)
+        django-djconfig
+        django-hCaptcha
+        wagtail-modeltranslation
+        wagtailmenus
+        ;
+    };
+  };
 in
-
 pkgs.mkShell {
   shellHook = ''
     export DJANGO_SETTINGS_MODULE=gestioasso.settings.local
-
-    virtualenv .venv
-    source .venv/bin/activate
-
-    pip install -r requirements-devel.txt | grep -v 'Requirement already satisfied:'
   '';
 
-  packages =
-    [ python ]
-    ++ (with python.pkgs; [
-      django-types
-      pip
-      virtualenv
-      python-ldap
-    ]);
+  packages = [
+    (python3.withPackages (
+      ps: with ps; [
+        django
+        pillow
+        authens
+        channels
+        configparser
+        django-autocomplete-light
+        django-bootstrap-form
+        django-cas-ng
+        django-cors-headers
+        django-djconfig
+        django-hCaptcha
+        django-js-reverse
+        django-widget-tweaks
+        icalendar
+        python-dateutil
+        statistics
+        wagtail-modeltranslation
+        wagtail
+        wagtailmenus
+
+        django-debug-toolbar
+        ipython
+        black
+        flake8
+        isort
+      ]
+    ))
+    pkgs.npins
+  ];
 
   allowSubstitutes = false;
 }
-- 
2.47.0