From 3235e5441b481e621e8b0cb48508d68de43521fd Mon Sep 17 00:00:00 2001 From: Alejandro MG Date: Tue, 7 Jan 2025 17:30:05 +0100 Subject: [PATCH] Adds new content field for blog articles --- api/serializers/blogpost.py | 1 + config/settings.py | 1 + config/urls.py | 1 + data/admin/blogpost.py | 22 +++++++---- data/factories/blogpost.py | 3 ++ ...12_blogpost_content_alter_blogpost_body.py | 25 +++++++++++++ data/models/blogpost.py | 4 +- frontend/src/views/BlogPostPage.vue | 2 +- poetry.lock | 37 +++++++++++++++++-- pyproject.toml | 1 + requirements.txt | 2 + 11 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 data/migrations/0112_blogpost_content_alter_blogpost_body.py diff --git a/api/serializers/blogpost.py b/api/serializers/blogpost.py index 8212fce48..978ede70a 100644 --- a/api/serializers/blogpost.py +++ b/api/serializers/blogpost.py @@ -18,6 +18,7 @@ class Meta: "title", "tagline", "body", + "content", "published", "display_date", "author", diff --git a/config/settings.py b/config/settings.py index 817e20897..c15a9fd57 100644 --- a/config/settings.py +++ b/config/settings.py @@ -63,6 +63,7 @@ "rest_framework", "webpack_loader", "django_ckeditor_5", + "prose", "anymail", "simple_history", "django_extensions", diff --git a/config/urls.py b/config/urls.py index 9a55173f5..be7d98408 100644 --- a/config/urls.py +++ b/config/urls.py @@ -9,6 +9,7 @@ urlpatterns = [ path("admin/", admin.site.urls), path("ckeditor5/", include("django_ckeditor_5.urls"), name="ck_editor_5_upload_file"), + path("prose/", include("prose.urls")), path("hijack/", include("hijack.urls")), ] urlpatterns.append(re_path(r"", include(("web.urls", "web"), namespace="web"))) diff --git a/data/admin/blogpost.py b/data/admin/blogpost.py index b1f41d5d1..e154177c6 100644 --- a/data/admin/blogpost.py +++ b/data/admin/blogpost.py @@ -15,13 +15,21 @@ class Meta: @admin.register(BlogPost) class BlogPostAdmin(admin.ModelAdmin): form = BlogPostForm - fields = ( - "title", - "tagline", - "display_date", - "published", - "author", - "body", + fieldsets = ( + ( + "", + { + "fields": ( + "title", + "tagline", + "display_date", + "published", + "author", + "content", + ) + }, + ), + ("Contenu legacy (ne plus utiliser)", {"fields": ("body",)}), ) list_display = ( "title", diff --git a/data/factories/blogpost.py b/data/factories/blogpost.py index 410b6cfa3..3ad9b980e 100644 --- a/data/factories/blogpost.py +++ b/data/factories/blogpost.py @@ -1,5 +1,7 @@ import factory + from data.models import BlogPost + from .user import UserFactory @@ -10,5 +12,6 @@ class Meta: title = factory.Faker("catch_phrase") tagline = factory.Faker("catch_phrase") body = factory.Faker("paragraph") + content = factory.Faker("paragraph") published = factory.Faker("boolean") author = factory.SubFactory(UserFactory) diff --git a/data/migrations/0112_blogpost_content_alter_blogpost_body.py b/data/migrations/0112_blogpost_content_alter_blogpost_body.py new file mode 100644 index 000000000..d50fac564 --- /dev/null +++ b/data/migrations/0112_blogpost_content_alter_blogpost_body.py @@ -0,0 +1,25 @@ +# Generated by Django 5.1.4 on 2025-01-07 15:28 + +import django_ckeditor_5.fields +import prose.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('data', '0111_alter_declaredingredient_request_status_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='blogpost', + name='content', + field=prose.fields.RichTextField(blank=True, null=True, verbose_name='contenu'), + ), + migrations.AlterField( + model_name='blogpost', + name='body', + field=django_ckeditor_5.fields.CKEditor5Field(blank=True, null=True, verbose_name='contenu (legacy)'), + ), + ] diff --git a/data/models/blogpost.py b/data/models/blogpost.py index 655fb9af4..8c83925d9 100644 --- a/data/models/blogpost.py +++ b/data/models/blogpost.py @@ -3,6 +3,7 @@ from django.utils import timezone from django_ckeditor_5.fields import CKEditor5Field +from prose.fields import RichTextField class BlogPost(models.Model): @@ -17,7 +18,8 @@ class Meta: title = models.TextField(verbose_name="titre") tagline = models.TextField(null=True, blank=True, verbose_name="description courte") display_date = models.DateField(default=timezone.now, verbose_name="date affichée") - body = CKEditor5Field(null=True, blank=True, verbose_name="contenu") + body = CKEditor5Field(null=True, blank=True, verbose_name="contenu (legacy)") + content = RichTextField(null=True, blank=True, verbose_name="contenu") published = models.BooleanField(default=False, verbose_name="publié") author = models.ForeignKey( settings.AUTH_USER_MODEL, diff --git a/frontend/src/views/BlogPostPage.vue b/frontend/src/views/BlogPostPage.vue index 5951f86ca..368ce9889 100644 --- a/frontend/src/views/BlogPostPage.vue +++ b/frontend/src/views/BlogPostPage.vue @@ -13,7 +13,7 @@

{{ blogPost.title }}

{{ author }}

{{ date }}

-
+
diff --git a/poetry.lock b/poetry.lock index 83222ba10..b348d542a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "amqp" @@ -136,6 +136,23 @@ files = [ {file = "billiard-4.2.1.tar.gz", hash = "sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f"}, ] +[[package]] +name = "bleach" +version = "6.2.0" +description = "An easy safelist-based HTML-sanitizing tool." +optional = false +python-versions = ">=3.9" +files = [ + {file = "bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e"}, + {file = "bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f"}, +] + +[package.dependencies] +webencodings = "*" + +[package.extras] +css = ["tinycss2 (>=1.1.0,<1.5)"] + [[package]] name = "boto3" version = "1.35.92" @@ -967,6 +984,21 @@ phonenumbers = {version = ">=7.0.2", optional = true, markers = "extra == \"phon phonenumbers = ["phonenumbers (>=7.0.2)"] phonenumberslite = ["phonenumberslite (>=7.0.2)"] +[[package]] +name = "django-prose" +version = "2.1.0" +description = "Wonderful rich text-editing for Django" +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "django_prose-2.1.0-py3-none-any.whl", hash = "sha256:548c117fb511447ea59c51cfd5e1748cf1962bb1062c0c99abb9ecb4606cb051"}, + {file = "django_prose-2.1.0.tar.gz", hash = "sha256:000c554496c2f61358c2602e21b54677bb02a727662ec9783dba5e35acfe4af8"}, +] + +[package.dependencies] +bleach = ">=4.0" +django = ">=3.2" + [[package]] name = "django-silk" version = "5.3.2" @@ -2388,7 +2420,6 @@ files = [ {file = "psycopg2-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:0435034157049f6846e95103bd8f5a668788dd913a7c30162ca9503fdf542cb4"}, {file = "psycopg2-2.9.10-cp312-cp312-win32.whl", hash = "sha256:65a63d7ab0e067e2cdb3cf266de39663203d38d6a8ed97f5ca0cb315c73fe067"}, {file = "psycopg2-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:4a579d6243da40a7b3182e0430493dbd55950c493d8c68f4eec0b302f6bbf20e"}, - {file = "psycopg2-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:91fd603a2155da8d0cfcdbf8ab24a2d54bca72795b90d2a3ed2b6da8d979dee2"}, {file = "psycopg2-2.9.10-cp39-cp39-win32.whl", hash = "sha256:9d5b3b94b79a844a986d029eee38998232451119ad653aea42bb9220a8c5066b"}, {file = "psycopg2-2.9.10-cp39-cp39-win_amd64.whl", hash = "sha256:88138c8dedcbfa96408023ea2b0c369eda40fe5d75002c0964c78f46f11fa442"}, {file = "psycopg2-2.9.10.tar.gz", hash = "sha256:12ec0b40b0273f95296233e8750441339298e6a572f7039da5b260e3c8b60e11"}, @@ -3727,4 +3758,4 @@ test = ["coverage (>=5.3)", "tomli (>=2.0.1)", "tox"] [metadata] lock-version = "2.0" python-versions = "<4,>= 3.11.*" -content-hash = "65c354dac0db4f63a224696ac67784137683c9a22538b43bfb3b05a42d5f9ac5" +content-hash = "dfb80745978d1701d345390c2568087f3bb4be1f8659612f3977fab228bbbd70" diff --git a/pyproject.toml b/pyproject.toml index 83fad232c..88f2885cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,6 +92,7 @@ bs4 = "^0.0.2" ######################### django-hijack = "^3.7.1" pandas = "^2.2.3" +django-prose = "^2.1.0" [tool.poetry.group.dev.dependencies] sqlfluff = "*" diff --git a/requirements.txt b/requirements.txt index b999a4167..0fe9618ff 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,6 +7,7 @@ async-timeout==5.0.1 ; python_version >= "3.11" and python_full_version < "3.11. autopep8==2.3.1 ; python_version >= "3.11" and python_version < "4" beautifulsoup4==4.12.3 ; python_version >= "3.11" and python_version < "4" billiard==4.2.1 ; python_version >= "3.11" and python_version < "4" +bleach==6.2.0 ; python_version >= "3.11" and python_version < "4.0" boto3==1.35.92 ; python_version >= "3.11" and python_version < "4" botocore==1.35.92 ; python_version >= "3.11" and python_version < "4" bs4==0.0.2 ; python_version >= "3.11" and python_version < "4" @@ -34,6 +35,7 @@ django-filter==24.3 ; python_version >= "3.11" and python_version < "4" django-hijack==3.7.1 ; python_version >= "3.11" and python_version < "4" django-js-asset==2.2.0 ; python_version >= "3.11" and python_version < "4" django-phonenumber-field[phonenumbers]==8.0.0 ; python_version >= "3.11" and python_version < "4" +django-prose==2.1.0 ; python_version >= "3.11" and python_version < "4.0" django-silk==5.3.2 ; python_version >= "3.11" and python_version < "4" django-simple-history==3.7.0 ; python_version >= "3.11" and python_version < "4" django-storages==1.14.4 ; python_version >= "3.11" and python_version < "4"