From 48e36bc5b9b89c0989fe62490b19febb14301dee Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 5 Jan 2024 15:30:31 +0000 Subject: [PATCH 01/10] Update to Wagtail 5.2 (and others) --- dev-requirements.txt | 2 +- requirements.txt | 18 +++++++++--------- website/blog/tests.py | 4 ++-- website/common/tests/test_pages.py | 4 ++-- website/common/tests/test_views.py | 2 +- website/contrib/unsplash/wagtail_hooks.py | 2 +- website/search/tests.py | 12 ++++++------ 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index cabaabc..f194596 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -6,7 +6,7 @@ django-browser-reload==1.11.0 django-debug-toolbar types-requests==2.31.0.1 mypy==1.5.1 -wagtail-factories==4.0.0 +wagtail-factories==4.1.0 coverage==7.3.0 djlint==1.31.0 types-pyyaml==6.0.12.9 diff --git a/requirements.txt b/requirements.txt index 2bc5147..5cbe020 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,25 +1,25 @@ -Django==3.2.22 -wagtail==4.1.8 +Django==5.0.1 +wagtail==5.2.2 django-environ==0.11.2 whitenoise[brotli]==6.5.0 Pygments==2.16.1 beautifulsoup4==4.11.2 lxml==4.9.1 requests==2.31.0 -wagtail-generic-chooser==0.5.1 +wagtail-generic-chooser==0.6 django-rq==2.8.0 django-redis==5.3.0 gunicorn==21.2.0 psycopg2==2.9.6 djangorestframework django-htmx==1.16.0 -wagtail-metadata==4.0.3 +wagtail-metadata==5.0.0 django-plausible==0.5.0 sentry-sdk==1.29.2 django-sri==0.7.0 -wagtail-2fa==1.6.5 +wagtail-2fa==1.6.9 django-health-check==3.17.0 -wagtail-autocomplete==0.10.0 +wagtail-autocomplete==0.11.0 Wand==0.6.11 django3-cache-decorator==0.5.2 django-cors-headers==4.2.0 @@ -34,7 +34,7 @@ uritemplate PyYAML # Use custom `wagtail-favicon` with performance improvements -git+https://github.com/RealOrangeOne/wagtail-favicon@4586efaac746085338fc7d61713006d9adc62d2e +git+https://github.com/RealOrangeOne/wagtail-favicon@b892165e047b35c46d7244109b9ad9226d32a213 -# Use custom `wagtail-draftail-snippet` with support for Wagtail 4.1 -git+https://github.com/RealOrangeOne/wagtail-draftail-snippet@0924ab12b1ca205b94ccd9a34ecc446d7ac422e5 +# Use custom `wagtail-draftail-snippet` with support for Wagtail 5.x +git+https://github.com/aaronhaslett/wagtail-draftail-snippet@347cf41b29e0aa1ef43b53632ef29f07967a19e1 diff --git a/website/blog/tests.py b/website/blog/tests.py index 1c9929a..f9006b3 100644 --- a/website/blog/tests.py +++ b/website/blog/tests.py @@ -18,7 +18,7 @@ class BlogPostPageTestCase(TestCase): self.assertEqual(response.status_code, 200) def test_queries(self) -> None: - with self.assertNumQueries(48): + with self.assertNumQueries(41): self.client.get(self.page.url) @@ -76,7 +76,7 @@ class BlogPostListPageTestCase(TestCase): self.assertEqual(len(response.context["listing_pages"]), 2) def test_queries(self) -> None: - with self.assertNumQueries(44): + with self.assertNumQueries(37): self.client.get(self.page.url) def test_feed_accessible(self) -> None: diff --git a/website/common/tests/test_pages.py b/website/common/tests/test_pages.py index 50c2c1a..e4eb406 100644 --- a/website/common/tests/test_pages.py +++ b/website/common/tests/test_pages.py @@ -36,7 +36,7 @@ class ContentPageTestCase(TestCase): self.assertEqual(response.status_code, 200) def test_queries(self) -> None: - with self.assertNumQueries(39): + with self.assertNumQueries(32): self.client.get(self.page.url) @@ -53,7 +53,7 @@ class ListingPageTestCase(TestCase): ContentPageFactory(parent=cls.page) def test_accessible(self) -> None: - with self.assertNumQueries(42): + with self.assertNumQueries(35): response = self.client.get(self.page.url) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.context["listing_pages"]), 2) diff --git a/website/common/tests/test_views.py b/website/common/tests/test_views.py index edc2cfb..d9438b5 100644 --- a/website/common/tests/test_views.py +++ b/website/common/tests/test_views.py @@ -22,7 +22,7 @@ class Error404PageTestCase(TestCase): ) def test_queries(self) -> None: - with self.assertNumQueries(22): + with self.assertNumQueries(16): self.client.get(self.url) diff --git a/website/contrib/unsplash/wagtail_hooks.py b/website/contrib/unsplash/wagtail_hooks.py index 4bd7fbd..39953fd 100644 --- a/website/contrib/unsplash/wagtail_hooks.py +++ b/website/contrib/unsplash/wagtail_hooks.py @@ -3,11 +3,11 @@ from typing import Type from django.core.exceptions import ValidationError from django.http.response import Http404 from django.utils.html import format_html +from wagtail import hooks from wagtail.admin.forms.models import WagtailAdminModelForm from wagtail.contrib.modeladmin.helpers import WagtailBackendSearchHandler from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register from wagtail.contrib.modeladmin.views import CreateView, EditView, IndexView -from wagtail.core import hooks from .models import UnsplashPhoto from .utils import get_unsplash_photo diff --git a/website/search/tests.py b/website/search/tests.py index 58ea34f..c3f53bf 100644 --- a/website/search/tests.py +++ b/website/search/tests.py @@ -56,7 +56,7 @@ class SearchPageResultsTestCase(TestCase): cls.url = cls.page.url + cls.page.reverse_subpage("results") def test_returns_results(self) -> None: - with self.assertNumQueries(24): + with self.assertNumQueries(23): response = self.client.get(self.url, {"q": "post"}, HTTP_HX_REQUEST="true") self.assertEqual(response.status_code, 200) @@ -90,7 +90,7 @@ class SearchPageResultsTestCase(TestCase): ) def test_too_high_page(self) -> None: - with self.assertNumQueries(49): + with self.assertNumQueries(42): response = self.client.get( self.url, {"q": "post", "page": 30}, HTTP_HX_REQUEST="true" ) @@ -111,21 +111,21 @@ class SearchPageResultsTestCase(TestCase): self.assertContains(response, "No results found") def test_no_query(self) -> None: - with self.assertNumQueries(7): + with self.assertNumQueries(6): response = self.client.get(self.url, HTTP_HX_REQUEST="true") self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "search/enter-search-term.html") def test_empty_query(self) -> None: - with self.assertNumQueries(7): + with self.assertNumQueries(6): response = self.client.get(self.url, {"q": ""}, HTTP_HX_REQUEST="true") self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "search/enter-search-term.html") def test_not_htmx(self) -> None: - with self.assertNumQueries(7): + with self.assertNumQueries(6): response = self.client.get(self.url) self.assertEqual(response.status_code, 400) @@ -140,7 +140,7 @@ class OpenSearchTestCase(TestCase): ContentPageFactory(parent=cls.home_page, title=f"Post {i}") def test_opensearch_description(self) -> None: - with self.assertNumQueries(11): + with self.assertNumQueries(8): response = self.client.get(reverse("opensearch")) self.assertEqual(response.status_code, 200) -- 2.45.2 From 518461a88f3e59c045b54e288240c69a69524cca Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 5 Jan 2024 15:44:45 +0000 Subject: [PATCH 02/10] Use wagtail's new built-in cache tags They're good, because I wrote them --- .../blog/templates/blog/blog_post_page.html | 30 ++++----- website/common/templates/base.html | 44 ++++++------- .../templates/common/content-details.html | 64 +++++++++---------- .../common/templates/common/listing-item.html | 46 ++++++------- website/common/templatetags/util_tags.py | 7 -- website/utils/context_processors.py | 5 +- 6 files changed, 93 insertions(+), 103 deletions(-) diff --git a/website/blog/templates/blog/blog_post_page.html b/website/blog/templates/blog/blog_post_page.html index 7c4928d..f6f2a2b 100644 --- a/website/blog/templates/blog/blog_post_page.html +++ b/website/blog/templates/blog/blog_post_page.html @@ -1,26 +1,26 @@ {% extends "common/content_page.html" %} -{% load cache util_tags %} +{% load wagtail_cache %} {% block post_content %} {{ block.super }} {% if not request.is_preview %} - {% cache FRAGMENT_CACHE_TTL|jitter:FRAGMENT_CACHE_TTL_JITTER "similar-content" page.id request.is_preview %} -
-

Similar content

+ {% wagtailpagecache FRAGMENT_CACHE_TTL "similar-content" %} +
+

Similar content

-

- View all → -

+

+ View all → +

- {% for page in page.get_similar_posts %} - {% block listing_item %} - {% include "common/listing-item.html" %} - {% endblock %} - {% endfor %} + {% for page in page.get_similar_posts %} + {% block listing_item %} + {% include "common/listing-item.html" %} + {% endblock %} + {% endfor %} -
- {% endcache %} - {% endif %} +
+ {% endwagtailpagecache %} +{% endif %} {% endblock %} diff --git a/website/common/templates/base.html b/website/common/templates/base.html index 90c9fc2..e3522c5 100644 --- a/website/common/templates/base.html +++ b/website/common/templates/base.html @@ -1,4 +1,4 @@ -{% load static wagtailcore_tags wagtailuserbar navbar_tags footer_tags plausible_wagtail favicon_tags sri cache %} +{% load static wagtailcore_tags wagtailuserbar navbar_tags footer_tags plausible_wagtail favicon_tags sri wagtail_cache %} @@ -32,31 +32,31 @@ {% wagtailuserbar %} - {% cache 1800 "navbar" request.is_preview %} - {% navbar %} - {% endcache %} + {% wagtailcache 1800 "navbar" %} + {% navbar %} + {% endwagtailcache %} - {% block main %} -
- {% block main_content %}{% endblock %} -
- {% endblock %} + {% block main %} +
+ {% block main_content %}{% endblock %} +
+ {% endblock %} - {% cache 1800 "footer" request.is_preview %} - {% footer %} - {% endcache %} + {% wagtailcache 1800 "footer" %} + {% footer %} +{% endwagtailcache %} - {# Not async to avoid bright flashes #} - {% sri_static "js/dark-mode.js" %} +{# Not async to avoid bright flashes #} +{% sri_static "js/dark-mode.js" %} - + - {% block extra_js %}{% endblock %} +{% block extra_js %}{% endblock %} - {% block plausible %} - {% if not request.user.is_authenticated or not request.is_preview %} - {% plausible %} - {% endif %} - {% endblock %} - +{% block plausible %} + {% if not request.user.is_authenticated or not request.is_preview %} + {% plausible %} + {% endif %} +{% endblock %} + diff --git a/website/common/templates/common/content-details.html b/website/common/templates/common/content-details.html index 109c179..e99f06b 100644 --- a/website/common/templates/common/content-details.html +++ b/website/common/templates/common/content-details.html @@ -1,36 +1,36 @@ -{% load wagtailcore_tags cache util_tags %} +{% load wagtailcore_tags wagtail_cache %} -{% cache FRAGMENT_CACHE_TTL|jitter:FRAGMENT_CACHE_TTL_JITTER "content-details" page.id request.is_preview %} -
- {% if page.date %} - - - - - {{ page.date|date:"Y-m-d" }} +{% wagtailpagecache FRAGMENT_CACHE_TTL "content-details" %} +
+ {% if page.date %} + + + - {% endif %} + {{ page.date|date:"Y-m-d" }} + + {% endif %} - {% if page.show_reading_time %} -
- - - - {{ page.reading_time_display }} -
- {% endif %} + {% if page.show_reading_time %} +
+ + + + {{ page.reading_time_display }} +
+ {% endif %} - {% if page.tags.all %} -
- - - - - - {% for tag in page.tags.all|dictsort:"slug" %} - #{{ tag.slug }} - {% endfor %} -
- {% endif %} -
-{% endcache %} + {% if page.tags.all %} +
+ + + + + + {% for tag in page.tags.all|dictsort:"slug" %} + #{{ tag.slug }} + {% endfor %} +
+ {% endif %} +
+{% endwagtailpagecache %} diff --git a/website/common/templates/common/listing-item.html b/website/common/templates/common/listing-item.html index 5d8eeb8..0321cb9 100644 --- a/website/common/templates/common/listing-item.html +++ b/website/common/templates/common/listing-item.html @@ -1,27 +1,27 @@ -{% load wagtailcore_tags cache util_tags %} +{% load wagtailcore_tags wagtail_cache util_tags %} -{% cache FRAGMENT_CACHE_TTL|jitter:FRAGMENT_CACHE_TTL_JITTER "listing-item" page.id request.is_preview breadcrumbs %} -
-
-
- {% if page.list_image_url %} - - - +{% wagtailpagecache FRAGMENT_CACHE_TTL "listing-item" breadcrumbs %} +
+
+
+ {% if page.list_image_url %} + + + + {% endif %} +
+
+
+ {% if breadcrumbs %} + {% include "common/breadcrumbs.html" with parents=page.get_parent_pages %} {% endif %} -
-
-
- {% if breadcrumbs %} - {% include "common/breadcrumbs.html" with parents=page.get_parent_pages %} - {% endif %} -

- {{ page.title }} -

- {% include "common/content-details.html" %} -

{{ page.summary }}

-
+

+ {{ page.title }} +

+ {% include "common/content-details.html" %} +

{{ page.summary }}

-
-{% endcache %} + + +{% endwagtailpagecache %} diff --git a/website/common/templatetags/util_tags.py b/website/common/templatetags/util_tags.py index 06e4b82..bc7e1cd 100644 --- a/website/common/templatetags/util_tags.py +++ b/website/common/templatetags/util_tags.py @@ -1,5 +1,3 @@ -import random - from django.template import Library from django.utils.encoding import force_str from wagtail.models import Page @@ -20,11 +18,6 @@ def pagefullurl(context: dict, page: Page) -> str: return page.get_full_url(context["request"]) -@register.filter() -def jitter(original: float, jitter: float) -> float: - return random.uniform(original + jitter, original - jitter) - - @register.filter() def extract_text(html: str | RichText) -> str: return utils.extract_text(force_str(html)) diff --git a/website/utils/context_processors.py b/website/utils/context_processors.py index 1406632..44a4117 100644 --- a/website/utils/context_processors.py +++ b/website/utils/context_processors.py @@ -3,12 +3,9 @@ from django.http.request import HttpRequest def global_vars(request: HttpRequest) -> dict: - # noop caching in preview - fragment_cache_ttl = 0 if getattr(request, "is_preview", False) else 3600 return { "SEO_INDEX": settings.SEO_INDEX, "DEBUG": settings.DEBUG, - "FRAGMENT_CACHE_TTL": fragment_cache_ttl, - "FRAGMENT_CACHE_TTL_JITTER": fragment_cache_ttl * 0.1, + "FRAGMENT_CACHE_TTL": 3600, "ACTIVITYPUB_HOST": settings.ACTIVITYPUB_HOST, } -- 2.45.2 From 8fe3cdbbc3f860f79620eb330cf1cecc82d08981 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 5 Jan 2024 15:46:38 +0000 Subject: [PATCH 03/10] Replace custom `pagefullurl` tag with built-in --- website/common/templates/common/shareon.html | 4 ++-- website/common/templatetags/util_tags.py | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/website/common/templates/common/shareon.html b/website/common/templates/common/shareon.html index 47651b8..a8e6cb0 100644 --- a/website/common/templates/common/shareon.html +++ b/website/common/templates/common/shareon.html @@ -1,8 +1,8 @@ -{% load util_tags %} +{% load wagtailcore_tags %}

Share this page

-
+
diff --git a/website/common/templatetags/util_tags.py b/website/common/templatetags/util_tags.py index bc7e1cd..f00edbe 100644 --- a/website/common/templatetags/util_tags.py +++ b/website/common/templatetags/util_tags.py @@ -1,6 +1,5 @@ from django.template import Library from django.utils.encoding import force_str -from wagtail.models import Page from wagtail.rich_text import RichText from website.common import utils @@ -13,11 +12,6 @@ def do_range(stop: int) -> range: return range(stop) -@register.simple_tag(takes_context=True) -def pagefullurl(context: dict, page: Page) -> str: - return page.get_full_url(context["request"]) - - @register.filter() def extract_text(html: str | RichText) -> str: return utils.extract_text(force_str(html)) -- 2.45.2 From 307cd7fe26adfbc6cf91ea7516ff10b9fd22e062 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 5 Jan 2024 15:56:39 +0000 Subject: [PATCH 04/10] Update dependencies --- dev-requirements.txt | 16 ++++++++-------- requirements.txt | 26 +++++++++++++------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index f194596..2830876 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,13 +1,13 @@ -r requirements.txt honcho==1.1.0 -black==23.7.0 -django-browser-reload==1.11.0 +black==23.12.1 +django-browser-reload==1.12.1 django-debug-toolbar -types-requests==2.31.0.1 -mypy==1.5.1 +types-requests +mypy==1.8.0 wagtail-factories==4.1.0 -coverage==7.3.0 -djlint==1.31.0 -types-pyyaml==6.0.12.9 -ruff==0.0.278 +coverage==7.4.0 +djlint==1.34.1 +types-pyyaml +ruff==0.1.11 diff --git a/requirements.txt b/requirements.txt index 5cbe020..e74b1a0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,30 +1,30 @@ Django==5.0.1 wagtail==5.2.2 django-environ==0.11.2 -whitenoise[brotli]==6.5.0 -Pygments==2.16.1 -beautifulsoup4==4.11.2 -lxml==4.9.1 -requests==2.31.0 +whitenoise[brotli]==6.6.0 +Pygments==2.17.2 +beautifulsoup4 +lxml==5.0.0 +requests wagtail-generic-chooser==0.6 -django-rq==2.8.0 -django-redis==5.3.0 +django-rq==2.10.1 +django-redis==5.4.0 gunicorn==21.2.0 -psycopg2==2.9.6 +psycopg2==2.9.9 djangorestframework -django-htmx==1.16.0 +django-htmx==1.17.2 wagtail-metadata==5.0.0 django-plausible==0.5.0 -sentry-sdk==1.29.2 +sentry-sdk django-sri==0.7.0 wagtail-2fa==1.6.9 django-health-check==3.17.0 wagtail-autocomplete==0.11.0 -Wand==0.6.11 +Wand==0.6.13 django3-cache-decorator==0.5.2 -django-cors-headers==4.2.0 +django-cors-headers==4.3.1 django-csp==3.7 -django-permissions-policy==4.17.0 +django-permissions-policy==4.18.0 django-enforce-host==1.1.0 django-proxy==1.2.2 wagtail-lite-youtube-embed==0.1.0 -- 2.45.2 From 166441b3e3ab2cf1fd9ad2f24321db7f85cf7e77 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 5 Jan 2024 15:59:23 +0000 Subject: [PATCH 05/10] Set CSRF cookie as httpOnly --- website/settings.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/website/settings.py b/website/settings.py index 34e8dea..5b944ea 100644 --- a/website/settings.py +++ b/website/settings.py @@ -398,9 +398,6 @@ SESSION_COOKIE_AGE = 2419200 # About a month CSRF_COOKIE_SECURE = not DEBUG SESSION_COOKIE_HTTPONLY = True -# https://github.com/wagtail/wagtail-autocomplete/issues/149 -CSRF_COOKIE_HTTPONLY = False - SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") PERMISSIONS_POLICY: dict[str, list] = { -- 2.45.2 From c8885d19d375c5bb4ea7bd62115cd4693d2e01ab Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 5 Jan 2024 16:17:12 +0000 Subject: [PATCH 06/10] Use correct heading tag for date subtitles --- website/blog/templates/blog/blog_post_list_page.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/blog/templates/blog/blog_post_list_page.html b/website/blog/templates/blog/blog_post_list_page.html index 9ab42d6..6327720 100644 --- a/website/blog/templates/blog/blog_post_list_page.html +++ b/website/blog/templates/blog/blog_post_list_page.html @@ -11,11 +11,11 @@
{% for page in listing_pages %} {% ifchanged %} -

+

-

+ {% endifchanged %} {% include "common/listing-item.html" %} -- 2.45.2 From 1ff31828f599885f324f77387e666f9b0ab84bd5 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 5 Jan 2024 16:21:42 +0000 Subject: [PATCH 07/10] Add labels to all pagination buttons --- website/common/templates/common/pagination.html | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/website/common/templates/common/pagination.html b/website/common/templates/common/pagination.html index 38c443f..89dffa8 100644 --- a/website/common/templates/common/pagination.html +++ b/website/common/templates/common/pagination.html @@ -1,14 +1,14 @@ {% load wagtailadmin_tags %} -
{% endblock %} diff --git a/website/search/tests.py b/website/search/tests.py index c3f53bf..c90d00c 100644 --- a/website/search/tests.py +++ b/website/search/tests.py @@ -41,7 +41,7 @@ class SearchPageTestCase(TestCase): self.assertEqual(search_input.attrs["value"], "") self.assertEqual(len(soup.select(search_input.attrs["hx-target"])), 1) - self.assertEqual(len(soup.select(search_input.attrs["hx-indicator"])), 1) + self.assertEqual(len(soup.select(search_input.attrs["hx-indicator"])), 2) class SearchPageResultsTestCase(TestCase): -- 2.45.2 From 7f40c00a49899eb681722d653d75e96c607ba1d4 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 5 Jan 2024 17:09:04 +0000 Subject: [PATCH 10/10] Update to Python 3.12 --- .gitlab-ci.yml | 4 ++-- Dockerfile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 34c356f..e0d107d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,7 +23,7 @@ static: expire_in: 2 hours pip: - image: python:3.11-slim + image: python:3.12-slim stage: build variables: PIP_CACHE_DIR: $CI_PROJECT_DIR/.pip-cache @@ -45,7 +45,7 @@ pip: expire_in: 2 hours .python_test_template: - image: python:3.11-slim + image: python:3.12-slim stage: test dependencies: - pip diff --git a/Dockerfile b/Dockerfile index cb9ff9c..ff5b868 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ COPY ./static/src ./static/src RUN npm run build # The actual container -FROM python:3.11-slim as production +FROM python:3.12-slim as production ENV VIRTUAL_ENV=/venv -- 2.45.2