Upgrade to Wagtail 5.2 #100
23 changed files with 171 additions and 184 deletions
|
@ -23,7 +23,7 @@ static:
|
||||||
expire_in: 2 hours
|
expire_in: 2 hours
|
||||||
|
|
||||||
pip:
|
pip:
|
||||||
image: python:3.11-slim
|
image: python:3.12-slim
|
||||||
stage: build
|
stage: build
|
||||||
variables:
|
variables:
|
||||||
PIP_CACHE_DIR: $CI_PROJECT_DIR/.pip-cache
|
PIP_CACHE_DIR: $CI_PROJECT_DIR/.pip-cache
|
||||||
|
@ -45,7 +45,7 @@ pip:
|
||||||
expire_in: 2 hours
|
expire_in: 2 hours
|
||||||
|
|
||||||
.python_test_template:
|
.python_test_template:
|
||||||
image: python:3.11-slim
|
image: python:3.12-slim
|
||||||
stage: test
|
stage: test
|
||||||
dependencies:
|
dependencies:
|
||||||
- pip
|
- pip
|
||||||
|
|
|
@ -11,7 +11,7 @@ COPY ./static/src ./static/src
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# The actual container
|
# The actual container
|
||||||
FROM python:3.11-slim as production
|
FROM python:3.12-slim as production
|
||||||
|
|
||||||
ENV VIRTUAL_ENV=/venv
|
ENV VIRTUAL_ENV=/venv
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
-r requirements.txt
|
-r requirements.txt
|
||||||
|
|
||||||
honcho==1.1.0
|
honcho==1.1.0
|
||||||
black==23.7.0
|
black==23.12.1
|
||||||
django-browser-reload==1.11.0
|
django-browser-reload==1.12.1
|
||||||
django-debug-toolbar
|
django-debug-toolbar
|
||||||
types-requests==2.31.0.1
|
types-requests
|
||||||
mypy==1.5.1
|
mypy==1.8.0
|
||||||
wagtail-factories==4.0.0
|
wagtail-factories==4.1.0
|
||||||
coverage==7.3.0
|
coverage==7.4.0
|
||||||
djlint==1.31.0
|
djlint==1.34.1
|
||||||
types-pyyaml==6.0.12.9
|
types-pyyaml
|
||||||
ruff==0.0.278
|
ruff==0.1.11
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
Django==3.2.22
|
Django==5.0.1
|
||||||
wagtail==4.1.8
|
wagtail==5.2.2
|
||||||
django-environ==0.11.2
|
django-environ==0.11.2
|
||||||
whitenoise[brotli]==6.5.0
|
whitenoise[brotli]==6.6.0
|
||||||
Pygments==2.16.1
|
Pygments==2.17.2
|
||||||
beautifulsoup4==4.11.2
|
beautifulsoup4
|
||||||
lxml==4.9.1
|
lxml==5.0.0
|
||||||
requests==2.31.0
|
requests
|
||||||
wagtail-generic-chooser==0.5.1
|
wagtail-generic-chooser==0.6
|
||||||
django-rq==2.8.0
|
django-rq==2.10.1
|
||||||
django-redis==5.3.0
|
django-redis==5.4.0
|
||||||
gunicorn==21.2.0
|
gunicorn==21.2.0
|
||||||
psycopg2==2.9.6
|
psycopg2==2.9.9
|
||||||
djangorestframework
|
djangorestframework
|
||||||
django-htmx==1.16.0
|
django-htmx==1.17.2
|
||||||
wagtail-metadata==4.0.3
|
wagtail-metadata==5.0.0
|
||||||
django-plausible==0.5.0
|
django-plausible==0.5.0
|
||||||
sentry-sdk==1.29.2
|
sentry-sdk
|
||||||
django-sri==0.7.0
|
django-sri==0.7.0
|
||||||
wagtail-2fa==1.6.5
|
wagtail-2fa==1.6.9
|
||||||
django-health-check==3.17.0
|
django-health-check==3.17.0
|
||||||
wagtail-autocomplete==0.10.0
|
wagtail-autocomplete==0.11.0
|
||||||
Wand==0.6.11
|
Wand==0.6.13
|
||||||
django3-cache-decorator==0.5.2
|
django3-cache-decorator==0.5.2
|
||||||
django-cors-headers==4.2.0
|
django-cors-headers==4.3.1
|
||||||
django-csp==3.7
|
django-csp==3.7
|
||||||
django-permissions-policy==4.17.0
|
django-permissions-policy==4.18.0
|
||||||
django-enforce-host==1.1.0
|
django-enforce-host==1.1.0
|
||||||
django-proxy==1.2.2
|
django-proxy==1.2.2
|
||||||
wagtail-lite-youtube-embed==0.1.0
|
wagtail-lite-youtube-embed==0.1.0
|
||||||
|
@ -34,7 +34,7 @@ uritemplate
|
||||||
PyYAML
|
PyYAML
|
||||||
|
|
||||||
# Use custom `wagtail-favicon` with performance improvements
|
# 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
|
# Use custom `wagtail-draftail-snippet` with support for Wagtail 5.x
|
||||||
git+https://github.com/RealOrangeOne/wagtail-draftail-snippet@0924ab12b1ca205b94ccd9a34ecc446d7ac422e5
|
git+https://github.com/aaronhaslett/wagtail-draftail-snippet@347cf41b29e0aa1ef43b53632ef29f07967a19e1
|
||||||
|
|
|
@ -14,10 +14,6 @@ body.page-searchpage {
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.htmx-request i {
|
|
||||||
animation: search-loading 1.5s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-results > p {
|
#search-results > p {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -47,9 +43,19 @@ body.page-searchpage {
|
||||||
#search-page-indicator {
|
#search-page-indicator {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
|
font-size: $size-3;
|
||||||
|
|
||||||
&:not(.htmx-request) {
|
&:not(.htmx-request) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The search icon is hidden during requests
|
||||||
|
#search-icon {
|
||||||
|
opacity: 1 !important;
|
||||||
|
|
||||||
|
&.htmx-request {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
<section class="container">
|
<section class="container">
|
||||||
{% for page in listing_pages %}
|
{% for page in listing_pages %}
|
||||||
{% ifchanged %}
|
{% ifchanged %}
|
||||||
<h3 id="date-{{ page.date|date:'Y-m' }}" class="date-header">
|
<h2 id="date-{{ page.date|date:'Y-m' }}" class="date-header">
|
||||||
<time datetime="{{ page.date|date:'Y-m' }}" title="{{ page.date|date:'F Y' }}">
|
<time datetime="{{ page.date|date:'Y-m' }}" title="{{ page.date|date:'F Y' }}">
|
||||||
{{ page.date|date:"Y-m" }}
|
{{ page.date|date:"Y-m" }}
|
||||||
</time>
|
</time>
|
||||||
</h3>
|
</h2>
|
||||||
{% endifchanged %}
|
{% endifchanged %}
|
||||||
|
|
||||||
{% include "common/listing-item.html" %}
|
{% include "common/listing-item.html" %}
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
{% extends "common/content_page.html" %}
|
{% extends "common/content_page.html" %}
|
||||||
|
|
||||||
{% load cache util_tags %}
|
{% load wagtail_cache %}
|
||||||
|
|
||||||
{% block post_content %}
|
{% block post_content %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
|
|
||||||
{% if not request.is_preview %}
|
{% if not request.is_preview %}
|
||||||
{% cache FRAGMENT_CACHE_TTL|jitter:FRAGMENT_CACHE_TTL_JITTER "similar-content" page.id request.is_preview %}
|
{% wagtailpagecache FRAGMENT_CACHE_TTL "similar-content" %}
|
||||||
<section class="container similar-content" id="similar-content">
|
<section class="container similar-content" id="similar-content">
|
||||||
<h2 class="subtitle is-size-2">Similar content</h2>
|
<h2 class="subtitle is-size-2">Similar content</h2>
|
||||||
|
|
||||||
<p class="view-all">
|
<p class="view-all">
|
||||||
<a href="{{ page.blog_post_list_page_url }}">View all →</a>
|
<a href="{{ page.blog_post_list_page_url }}">View all →</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% for page in page.get_similar_posts %}
|
{% for page in page.get_similar_posts %}
|
||||||
{% block listing_item %}
|
{% block listing_item %}
|
||||||
{% include "common/listing-item.html" %}
|
{% include "common/listing-item.html" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
{% endcache %}
|
{% endwagtailpagecache %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="media">
|
<div class="media">
|
||||||
<div class="media-content">
|
<div class="media-content">
|
||||||
<p class="title is-4">
|
<h2 class="title is-4">
|
||||||
<a href="{% pageurl page %}">{{ page.title }}</a>
|
<a href="{% pageurl page %}">{{ page.title }}</a>
|
||||||
</p>
|
</h2>
|
||||||
<p class="subtitle is-6">{{ page.summary }}</p>
|
<p class="subtitle is-6">{{ page.summary }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="media-right">
|
<div class="media-right">
|
||||||
|
|
|
@ -18,7 +18,7 @@ class BlogPostPageTestCase(TestCase):
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_queries(self) -> None:
|
def test_queries(self) -> None:
|
||||||
with self.assertNumQueries(48):
|
with self.assertNumQueries(41):
|
||||||
self.client.get(self.page.url)
|
self.client.get(self.page.url)
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ class BlogPostListPageTestCase(TestCase):
|
||||||
self.assertEqual(len(response.context["listing_pages"]), 2)
|
self.assertEqual(len(response.context["listing_pages"]), 2)
|
||||||
|
|
||||||
def test_queries(self) -> None:
|
def test_queries(self) -> None:
|
||||||
with self.assertNumQueries(44):
|
with self.assertNumQueries(37):
|
||||||
self.client.get(self.page.url)
|
self.client.get(self.page.url)
|
||||||
|
|
||||||
def test_feed_accessible(self) -> None:
|
def test_feed_accessible(self) -> None:
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en-GB">
|
<html lang="en-GB">
|
||||||
|
@ -32,31 +32,31 @@
|
||||||
<body class="{% block body_class %}{% endblock %}">
|
<body class="{% block body_class %}{% endblock %}">
|
||||||
{% wagtailuserbar %}
|
{% wagtailuserbar %}
|
||||||
|
|
||||||
{% cache 1800 "navbar" request.is_preview %}
|
{% wagtailcache 1800 "navbar" %}
|
||||||
{% navbar %}
|
{% navbar %}
|
||||||
{% endcache %}
|
{% endwagtailcache %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<main>
|
<main>
|
||||||
{% block main_content %}{% endblock %}
|
{% block main_content %}{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% cache 1800 "footer" request.is_preview %}
|
{% wagtailcache 1800 "footer" %}
|
||||||
{% footer %}
|
{% footer %}
|
||||||
{% endcache %}
|
{% endwagtailcache %}
|
||||||
|
|
||||||
{# Not async to avoid bright flashes #}
|
{# Not async to avoid bright flashes #}
|
||||||
{% sri_static "js/dark-mode.js" %}
|
{% sri_static "js/dark-mode.js" %}
|
||||||
|
|
||||||
<script async defer type="text/javascript" src="{% static 'js/base.js' %}" integrity="{% sri_integrity_static 'js/base.js' %}"></script>
|
<script async defer type="text/javascript" src="{% static 'js/base.js' %}" integrity="{% sri_integrity_static 'js/base.js' %}"></script>
|
||||||
|
|
||||||
{% block extra_js %}{% endblock %}
|
{% block extra_js %}{% endblock %}
|
||||||
|
|
||||||
{% block plausible %}
|
{% block plausible %}
|
||||||
{% if not request.user.is_authenticated or not request.is_preview %}
|
{% if not request.user.is_authenticated or not request.is_preview %}
|
||||||
{% plausible %}
|
{% plausible %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</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 %}
|
{% wagtailpagecache FRAGMENT_CACHE_TTL "content-details" %}
|
||||||
<div class="content-details field is-grouped">
|
<div class="content-details field is-grouped">
|
||||||
{% if page.date %}
|
{% if page.date %}
|
||||||
<span class="icon-text">
|
<span class="icon-text">
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<i class="far fa-lg fa-calendar-alt"></i>
|
<i class="far fa-lg fa-calendar-alt"></i>
|
||||||
</span>
|
|
||||||
<span>{{ page.date|date:"Y-m-d" }}</span>
|
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
<span>{{ page.date|date:"Y-m-d" }}</span>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if page.show_reading_time %}
|
{% if page.show_reading_time %}
|
||||||
<div class="icon-text" {% if page.word_count %}title="{{ page.word_count }} words"{% endif %}>
|
<div class="icon-text" {% if page.word_count %}title="{{ page.word_count }} words"{% endif %}>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<i class="far fa-lg fa-clock"></i>
|
<i class="far fa-lg fa-clock"></i>
|
||||||
</span>
|
</span>
|
||||||
<span>{{ page.reading_time_display }}</span>
|
<span>{{ page.reading_time_display }}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if page.tags.all %}
|
{% if page.tags.all %}
|
||||||
<div class="icon-text is-family-code">
|
<div class="icon-text is-family-code">
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<a href="{{ page.tag_list_page_url }}" title="View all tags">
|
<a href="{{ page.tag_list_page_url }}" title="View all tags">
|
||||||
<i class="fas fa-lg fa-tags"></i>
|
<i class="fas fa-lg fa-tags"></i>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{% for tag in page.tags.all|dictsort:"slug" %}
|
{% for tag in page.tags.all|dictsort:"slug" %}
|
||||||
<span><a title="{{ tag.name }}" href="{% pageurl tag %}">#{{ tag.slug }}</a></span>
|
<span><a title="{{ tag.name }}" href="{% pageurl tag %}">#{{ tag.slug }}</a></span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endcache %}
|
{% endwagtailpagecache %}
|
||||||
|
|
|
@ -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 %}
|
{% wagtailpagecache FRAGMENT_CACHE_TTL "listing-item" breadcrumbs %}
|
||||||
<article class="media listing-item">
|
<article class="media listing-item">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<figure class="media-left column is-3 image-column">
|
<figure class="media-left column is-3 image-column">
|
||||||
{% if page.list_image_url %}
|
{% if page.list_image_url %}
|
||||||
<a href="{% pageurl page %}" class="image" title="{{ page.title }}">
|
<a href="{% pageurl page %}" class="image" title="{{ page.title }}">
|
||||||
<img src="{{ page.list_image_url }}" alt="" loading="lazy" decoding="async" />
|
<img src="{{ page.list_image_url }}" alt="" loading="lazy" decoding="async" />
|
||||||
</a>
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</figure>
|
||||||
|
<div class="media-content column">
|
||||||
|
<div>
|
||||||
|
{% if breadcrumbs %}
|
||||||
|
{% include "common/breadcrumbs.html" with parents=page.get_parent_pages %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</figure>
|
<h2 class="title is-3">
|
||||||
<div class="media-content column">
|
<a href="{% pageurl page %}">{{ page.title }}</a>
|
||||||
<div>
|
</h2>
|
||||||
{% if breadcrumbs %}
|
{% include "common/content-details.html" %}
|
||||||
{% include "common/breadcrumbs.html" with parents=page.get_parent_pages %}
|
<p>{{ page.summary }}</p>
|
||||||
{% endif %}
|
|
||||||
<h2 class="title is-3">
|
|
||||||
<a href="{% pageurl page %}">{{ page.title }}</a>
|
|
||||||
</h2>
|
|
||||||
{% include "common/content-details.html" %}
|
|
||||||
<p>{{ page.summary }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</div>
|
||||||
{% endcache %}
|
</article>
|
||||||
|
{% endwagtailpagecache %}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
{% load wagtailadmin_tags %}
|
{% load wagtailadmin_tags %}
|
||||||
|
|
||||||
<nav class="pagination is-centered" role="navigation" aria-label="pagination">
|
<nav class="pagination is-centered" role="navigation" title="pagination">
|
||||||
{% if page.has_previous %}
|
{% if page.has_previous %}
|
||||||
<a class="pagination-previous" href="{% querystring page=page.previous_page_number %}"><i class="fas fa-arrow-left" aria-hidden="true"></i></a>
|
<a class="pagination-previous" title="Go to page {{ page.previous_page_number }}" href="{% querystring page=page.previous_page_number %}"><i class="fas fa-arrow-left" aria-hidden="true"></i></a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="pagination-previous is-disabled"><i class="fas fa-arrow-left" aria-hidden="true"></i></span>
|
<span class="pagination-previous is-disabled"><i class="fas fa-arrow-left" aria-hidden="true"></i></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if page.has_next %}
|
{% if page.has_next %}
|
||||||
<a class="pagination-next" href="{% querystring page=page.next_page_number %}"><i class="fas fa-arrow-right" aria-hidden="true"></i></a>
|
<a class="pagination-next" title="Go to page {{ page.next_page_number }}" href="{% querystring page=page.next_page_number %}"><i class="fas fa-arrow-right" aria-hidden="true"></i></a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="pagination-next is-disabled"><i class="fas fa-arrow-right" aria-hidden="true"></i></span>
|
<span class="pagination-next is-disabled"><i class="fas fa-arrow-right" aria-hidden="true"></i></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
<ul class="pagination-list">
|
<ul class="pagination-list">
|
||||||
{% if page.has_previous and page.previous_page_number != 1 %}
|
{% if page.has_previous and page.previous_page_number != 1 %}
|
||||||
<li>
|
<li>
|
||||||
<a class="pagination-link" aria-label="Goto page 1" href="{% querystring page=1 %}">1</a>
|
<a class="pagination-link" aria-label="Go to page 1" href="{% querystring page=1 %}">1</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="pagination-ellipsis">…</span>
|
<span class="pagination-ellipsis">…</span>
|
||||||
|
@ -25,17 +25,17 @@
|
||||||
|
|
||||||
{% if page.has_previous %}
|
{% if page.has_previous %}
|
||||||
<li>
|
<li>
|
||||||
<a class="pagination-link" aria-label="Goto page {{ page.previous_page_number }}" href="{% querystring page=page.previous_page_number %}">{{ page.previous_page_number }}</a>
|
<a class="pagination-link" title="Go to page {{ page.previous_page_number }}" href="{% querystring page=page.previous_page_number %}">{{ page.previous_page_number }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a class="pagination-link is-current" aria-label="Page {{ page.number }}" aria-current="page" href="{% querystring page=page.number %}">{{ page.number }}</a>
|
<a class="pagination-link is-current" title="Page {{ page.number }}" aria-current="page" href="{% querystring page=page.number %}">{{ page.number }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% if page.has_next %}
|
{% if page.has_next %}
|
||||||
<li>
|
<li>
|
||||||
<a class="pagination-link" aria-label="Goto page {{ page.next_page_number }}" href="{% querystring page=page.next_page_number %}">{{ page.next_page_number }}</a>
|
<a class="pagination-link" title="Go to page {{ page.next_page_number }}" href="{% querystring page=page.next_page_number %}">{{ page.next_page_number }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
<span class="pagination-ellipsis">…</span>
|
<span class="pagination-ellipsis">…</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="pagination-link" aria-label="Goto page {{ page.paginator.num_pages }}" href="{% querystring page=page.paginator.num_pages %}">{{ page.paginator.num_pages }}</a>
|
<a class="pagination-link" title="Go to page {{ page.paginator.num_pages }}" href="{% querystring page=page.paginator.num_pages %}">{{ page.paginator.num_pages }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{% load util_tags %}
|
{% load wagtailcore_tags %}
|
||||||
|
|
||||||
<section class="container has-text-centered shareon-container" id="shareon">
|
<section class="container has-text-centered shareon-container" id="shareon">
|
||||||
<p>Share this page</p>
|
<p>Share this page</p>
|
||||||
<div class="shareon" data-title="{{ page.title }}" data-url="{% pagefullurl page %}">
|
<div class="shareon" data-title="{{ page.title }}" data-url="{% fullpageurl page %}">
|
||||||
<a class="facebook" title="Share on Facebook"></a>
|
<a class="facebook" title="Share on Facebook"></a>
|
||||||
<a class="linkedin" title="Share on LinkedIn"></a>
|
<a class="linkedin" title="Share on LinkedIn"></a>
|
||||||
<a class="mastodon" title="Share on Mastodon"></a>
|
<a class="mastodon" title="Share on Mastodon"></a>
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
import random
|
|
||||||
|
|
||||||
from django.template import Library
|
from django.template import Library
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
from wagtail.models import Page
|
|
||||||
from wagtail.rich_text import RichText
|
from wagtail.rich_text import RichText
|
||||||
|
|
||||||
from website.common import utils
|
from website.common import utils
|
||||||
|
@ -15,16 +12,6 @@ def do_range(stop: int) -> range:
|
||||||
return range(stop)
|
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 jitter(original: float, jitter: float) -> float:
|
|
||||||
return random.uniform(original + jitter, original - jitter)
|
|
||||||
|
|
||||||
|
|
||||||
@register.filter()
|
@register.filter()
|
||||||
def extract_text(html: str | RichText) -> str:
|
def extract_text(html: str | RichText) -> str:
|
||||||
return utils.extract_text(force_str(html))
|
return utils.extract_text(force_str(html))
|
||||||
|
|
|
@ -36,7 +36,7 @@ class ContentPageTestCase(TestCase):
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_queries(self) -> None:
|
def test_queries(self) -> None:
|
||||||
with self.assertNumQueries(39):
|
with self.assertNumQueries(32):
|
||||||
self.client.get(self.page.url)
|
self.client.get(self.page.url)
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ class ListingPageTestCase(TestCase):
|
||||||
ContentPageFactory(parent=cls.page)
|
ContentPageFactory(parent=cls.page)
|
||||||
|
|
||||||
def test_accessible(self) -> None:
|
def test_accessible(self) -> None:
|
||||||
with self.assertNumQueries(42):
|
with self.assertNumQueries(35):
|
||||||
response = self.client.get(self.page.url)
|
response = self.client.get(self.page.url)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(len(response.context["listing_pages"]), 2)
|
self.assertEqual(len(response.context["listing_pages"]), 2)
|
||||||
|
|
|
@ -22,7 +22,7 @@ class Error404PageTestCase(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_queries(self) -> None:
|
def test_queries(self) -> None:
|
||||||
with self.assertNumQueries(22):
|
with self.assertNumQueries(16):
|
||||||
self.client.get(self.url)
|
self.client.get(self.url)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,12 @@
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="media">
|
<div class="media">
|
||||||
<div class="media-content">
|
<div class="media-content">
|
||||||
<p class="title is-4">
|
<h3 class="title is-4">
|
||||||
<a href="{{ account.url }}">
|
<a href="{{ account.url }}">
|
||||||
{% if account.icon %}<i class="{{ account.icon }}"></i>{% endif %}
|
{% if account.icon %}<i class="{{ account.icon }}"></i>{% endif %}
|
||||||
{{ account.name }}
|
{{ account.name }}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</h3>
|
||||||
<p class="subtitle is-6">{{ account.username }}</p>
|
<p class="subtitle is-6">{{ account.username }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,11 +3,11 @@ from typing import Type
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.http.response import Http404
|
from django.http.response import Http404
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
|
from wagtail import hooks
|
||||||
from wagtail.admin.forms.models import WagtailAdminModelForm
|
from wagtail.admin.forms.models import WagtailAdminModelForm
|
||||||
from wagtail.contrib.modeladmin.helpers import WagtailBackendSearchHandler
|
from wagtail.contrib.modeladmin.helpers import WagtailBackendSearchHandler
|
||||||
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
|
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
|
||||||
from wagtail.contrib.modeladmin.views import CreateView, EditView, IndexView
|
from wagtail.contrib.modeladmin.views import CreateView, EditView, IndexView
|
||||||
from wagtail.core import hooks
|
|
||||||
|
|
||||||
from .models import UnsplashPhoto
|
from .models import UnsplashPhoto
|
||||||
from .utils import get_unsplash_photo
|
from .utils import get_unsplash_photo
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
<section class="container search-controls">
|
<section class="container search-controls">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<p class="control has-icons-left has-icons-right">
|
<p class="control has-icons-left has-icons-right">
|
||||||
<input type="search" class="input" name="q" placeholder="Search" hx-get="{{ search_url }}" hx-trigger="keyup changed delay:200ms, search{% if search_query %}, load{% endif %}" hx-target="#search-results" autocomplete="off" value="{{ search_query }}" hx-indicator="#search-indicator" />
|
<input type="search" class="input" name="q" placeholder="Search" hx-get="{{ search_url }}" hx-trigger="keyup changed delay:200ms, search{% if search_query %}, load{% endif %}" hx-target="#search-results" autocomplete="off" value="{{ search_query }}" hx-indicator=".search-indicator" />
|
||||||
<span class="icon is-small is-left">
|
<span class="icon is-small is-left htmx-indicator search-indicator" id="search-icon">
|
||||||
<i class="fas fa-search"></i>
|
<i class="fas fa-search"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="icon is-small is-right htmx-indicator" id="search-indicator">
|
<span class="icon is-small is-left htmx-indicator search-indicator">
|
||||||
<i class="fas fa-circle-notch"></i>
|
<i class="fas fa-spinner fa-pulse"></i>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="htmx-indicator" id="search-page-indicator">
|
<div class="htmx-indicator" id="search-page-indicator">
|
||||||
<i class="fas fa-circle-notch"></i>
|
<i class="fas fa-spinner fa-pulse"></i>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -41,7 +41,7 @@ class SearchPageTestCase(TestCase):
|
||||||
self.assertEqual(search_input.attrs["value"], "")
|
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-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):
|
class SearchPageResultsTestCase(TestCase):
|
||||||
|
@ -56,7 +56,7 @@ class SearchPageResultsTestCase(TestCase):
|
||||||
cls.url = cls.page.url + cls.page.reverse_subpage("results")
|
cls.url = cls.page.url + cls.page.reverse_subpage("results")
|
||||||
|
|
||||||
def test_returns_results(self) -> None:
|
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")
|
response = self.client.get(self.url, {"q": "post"}, HTTP_HX_REQUEST="true")
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ class SearchPageResultsTestCase(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_too_high_page(self) -> None:
|
def test_too_high_page(self) -> None:
|
||||||
with self.assertNumQueries(49):
|
with self.assertNumQueries(42):
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
self.url, {"q": "post", "page": 30}, HTTP_HX_REQUEST="true"
|
self.url, {"q": "post", "page": 30}, HTTP_HX_REQUEST="true"
|
||||||
)
|
)
|
||||||
|
@ -111,21 +111,21 @@ class SearchPageResultsTestCase(TestCase):
|
||||||
self.assertContains(response, "No results found")
|
self.assertContains(response, "No results found")
|
||||||
|
|
||||||
def test_no_query(self) -> None:
|
def test_no_query(self) -> None:
|
||||||
with self.assertNumQueries(7):
|
with self.assertNumQueries(6):
|
||||||
response = self.client.get(self.url, HTTP_HX_REQUEST="true")
|
response = self.client.get(self.url, HTTP_HX_REQUEST="true")
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
self.assertTemplateUsed(response, "search/enter-search-term.html")
|
self.assertTemplateUsed(response, "search/enter-search-term.html")
|
||||||
|
|
||||||
def test_empty_query(self) -> None:
|
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")
|
response = self.client.get(self.url, {"q": ""}, HTTP_HX_REQUEST="true")
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
self.assertTemplateUsed(response, "search/enter-search-term.html")
|
self.assertTemplateUsed(response, "search/enter-search-term.html")
|
||||||
|
|
||||||
def test_not_htmx(self) -> None:
|
def test_not_htmx(self) -> None:
|
||||||
with self.assertNumQueries(7):
|
with self.assertNumQueries(6):
|
||||||
response = self.client.get(self.url)
|
response = self.client.get(self.url)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ class OpenSearchTestCase(TestCase):
|
||||||
ContentPageFactory(parent=cls.home_page, title=f"Post {i}")
|
ContentPageFactory(parent=cls.home_page, title=f"Post {i}")
|
||||||
|
|
||||||
def test_opensearch_description(self) -> None:
|
def test_opensearch_description(self) -> None:
|
||||||
with self.assertNumQueries(11):
|
with self.assertNumQueries(8):
|
||||||
response = self.client.get(reverse("opensearch"))
|
response = self.client.get(reverse("opensearch"))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
|
|
@ -398,9 +398,6 @@ SESSION_COOKIE_AGE = 2419200 # About a month
|
||||||
CSRF_COOKIE_SECURE = not DEBUG
|
CSRF_COOKIE_SECURE = not DEBUG
|
||||||
SESSION_COOKIE_HTTPONLY = True
|
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")
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
|
|
||||||
PERMISSIONS_POLICY: dict[str, list] = {
|
PERMISSIONS_POLICY: dict[str, list] = {
|
||||||
|
|
|
@ -3,12 +3,9 @@ from django.http.request import HttpRequest
|
||||||
|
|
||||||
|
|
||||||
def global_vars(request: HttpRequest) -> dict:
|
def global_vars(request: HttpRequest) -> dict:
|
||||||
# noop caching in preview
|
|
||||||
fragment_cache_ttl = 0 if getattr(request, "is_preview", False) else 3600
|
|
||||||
return {
|
return {
|
||||||
"SEO_INDEX": settings.SEO_INDEX,
|
"SEO_INDEX": settings.SEO_INDEX,
|
||||||
"DEBUG": settings.DEBUG,
|
"DEBUG": settings.DEBUG,
|
||||||
"FRAGMENT_CACHE_TTL": fragment_cache_ttl,
|
"FRAGMENT_CACHE_TTL": 3600,
|
||||||
"FRAGMENT_CACHE_TTL_JITTER": fragment_cache_ttl * 0.1,
|
|
||||||
"ACTIVITYPUB_HOST": settings.ACTIVITYPUB_HOST,
|
"ACTIVITYPUB_HOST": settings.ACTIVITYPUB_HOST,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue