Compare commits

...

11 Commits

15 changed files with 108 additions and 71 deletions

View File

@ -13,7 +13,6 @@ services:
tmpfs: tmpfs:
- /tmp - /tmp
depends_on: depends_on:
- redis
- db - db
ports: ports:
- 127.0.0.1:8000:8000 - 127.0.0.1:8000:8000

View File

@ -1,16 +1,11 @@
{ {
"$schema": "https://docs.renovatebot.com/renovate-schema.json", "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [ "extends": [
"config:base" "config:base",
"replacements:all",
"workarounds:all"
], ],
"prConcurrentLimit": 0, "prConcurrentLimit": 0,
"packageRules": [
{
"matchUpdateTypes": ["patch"],
"schedule": ["every weekend"],
"enabled": false
}
],
"regexManagers": [ "regexManagers": [
{ {
"fileMatch": ["^Dockerfile$"], "fileMatch": ["^Dockerfile$"],
@ -18,5 +13,6 @@
"depNameTemplate": "just-containers/s6-overlay", "depNameTemplate": "just-containers/s6-overlay",
"datasourceTemplate": "github-releases" "datasourceTemplate": "github-releases"
} }
] ],
"dependencyDashboardApproval": true
} }

View File

@ -2,7 +2,7 @@ Django==5.0.4
wagtail==5.2.5 wagtail==5.2.5
django-environ==0.11.2 django-environ==0.11.2
whitenoise[brotli]==6.6.0 whitenoise[brotli]==6.6.0
Pygments==2.17.2 Pygments==2.18.0
beautifulsoup4 beautifulsoup4
lxml==5.2.1 lxml==5.2.1
requests requests
@ -29,7 +29,8 @@ django-proxy==1.2.2
wagtail-lite-youtube-embed==0.1.0 wagtail-lite-youtube-embed==0.1.0
django-minify-html==1.7.1 django-minify-html==1.7.1
metadata-parser==0.12.1 metadata-parser==0.12.1
django-tasks==0.1.1 django-tasks==0.2.0
lightningcss==0.2.0
# DRF OpenAPI dependencies # DRF OpenAPI dependencies
uritemplate uritemplate

View File

@ -1,35 +0,0 @@
#commento {
.commento-profile-button {
@include dark-mode {
fill: $dark-mode-text;
}
}
.commento-name,
#commento-mod-tools-lock-button,
.commento-login-text,
.commento-anonymous-checkbox-container label {
@include dark-mode {
color: $dark-mode-text;
}
}
#commento-textarea-root,
#commento-guest-details-input-root,
.commento-textarea-container textarea {
@include dark-mode {
background-color: $black;
color: $dark-mode-text;
}
}
.commento-card {
@include dark-mode {
border-top: 1px solid color.adjust($black, $alpha: -0.4);
p {
color: $dark-mode-text;
}
}
}
}

View File

@ -0,0 +1,46 @@
#comments {
margin-top: 2rem;
}
.comentario-text-muted,
.comentario-root,
.comentario-card .comentario-name {
@include dark-mode {
color: $dark-mode-text !important;
}
}
.comentario-add-comment-host,
.comentario-comment-editor textarea,
.comentario-toolbar.comentario-disabled {
background-color: transparent !important;
}
.comentario-add-comment-host:not(.comentario-editor-inserted) {
border: 1px solid color.adjust($white, $alpha: -0.5) !important;
}
.comentario-comment-editor textarea {
background-color: transparent !important;
@include dark-mode {
color: $dark-mode-text !important;
}
}
.comentario-footer a {
color: $link !important;
}
.comentario-btn-link {
color: $link !important;
}
.comentario-card {
@include dark-mode {
border-top: 1px solid color.adjust($white, $alpha: -0.5);
p {
color: $dark-mode-text;
}
}
}

View File

@ -15,8 +15,8 @@ section#similar-content {
} }
.media { .media {
@include desktop { transform: scale(85%);
transform: scale(85%); margin-top: 0;
} padding-top: 0;
} }
} }

View File

@ -19,7 +19,7 @@
@import "spotify"; @import "spotify";
@import "404"; @import "404";
@import "password_required"; @import "password_required";
@import "commento"; @import "comments";
@import "similar_content"; @import "similar_content";
@import "support_pill"; @import "support_pill";

View File

@ -7,7 +7,7 @@ from django.db.models.functions import Cast, Coalesce
from django.http import HttpRequest, HttpResponse, HttpResponsePermanentRedirect from django.http import HttpRequest, HttpResponse, HttpResponsePermanentRedirect
from django.utils import timezone from django.utils import timezone
from django.utils.functional import cached_property from django.utils.functional import cached_property
from metadata_parser import MetadataParser from metadata_parser import ParsedResult
from modelcluster.fields import ParentalManyToManyField from modelcluster.fields import ParentalManyToManyField
from wagtail.admin.panels import FieldPanel from wagtail.admin.panels import FieldPanel
from wagtail.models import Page, PageQuerySet, Site from wagtail.models import Page, PageQuerySet, Site
@ -239,7 +239,7 @@ class ExternalBlogPostPage(BaseContentPage):
return tags return tags
@cached_property @cached_property
def metadata(self) -> MetadataParser: def metadata(self) -> ParsedResult:
return get_page_metadata(self.external_url) return get_page_metadata(self.external_url)
@cached_property @cached_property

View File

@ -2,6 +2,16 @@
{% load wagtail_cache navbar_tags %} {% load wagtail_cache navbar_tags %}
{% block post_toc %}
<hr class="dropdown-divider" />
<li>
<a href="#similar-content">Similar content</a>
</li>
<li>
<a href="#comments">Comments</a>
</li>
{% endblock %}
{% block post_content %} {% block post_content %}
{% if not request.is_preview %} {% if not request.is_preview %}
{% include "common/shareon.html" %} {% include "common/shareon.html" %}

View File

@ -1,3 +1,5 @@
import pickle
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
@ -96,7 +98,9 @@ class ExternalBlogPostPageTestCase(TestCase):
def setUpTestData(cls) -> None: def setUpTestData(cls) -> None:
cls.home_page = HomePage.objects.get() cls.home_page = HomePage.objects.get()
cls.blog_post_list_page = BlogPostListPageFactory(parent=cls.home_page) cls.blog_post_list_page = BlogPostListPageFactory(parent=cls.home_page)
cls.page = ExternalBlogPostPageFactory(parent=cls.blog_post_list_page) cls.page = ExternalBlogPostPageFactory(
parent=cls.blog_post_list_page, external_url="https://example.com"
)
def test_redirects(self) -> None: def test_redirects(self) -> None:
with self.assertNumQueries(10): with self.assertNumQueries(10):
@ -107,3 +111,11 @@ class ExternalBlogPostPageTestCase(TestCase):
status_code=301, status_code=301,
fetch_redirect_response=False, fetch_redirect_response=False,
) )
def test_metadata(self) -> None:
metadata = self.page.metadata
self.assertIsNone(metadata.soup)
# Confirm it can pickle
pickle.dumps(metadata)

View File

@ -1,5 +1,5 @@
<section class="container" id="comments"> <section class="container" id="comments">
<div id="commento"></div> <comentario-comments></comentario-comments>
</section> </section>
<script async defer src="https://commento.theorangeone.net/js/commento.js"></script> <script async defer src="https://comentario.theorangeone.net/comentario.js"></script>

View File

@ -10,6 +10,13 @@
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block post_toc %}
<hr class="dropdown-divider" />
<li>
<a href="#comments">Comments</a>
</li>
{% endblock %}
{% block post_content %} {% block post_content %}
{% if not request.is_preview %} {% if not request.is_preview %}
{% include "common/shareon.html" %} {% include "common/shareon.html" %}

View File

@ -56,6 +56,7 @@
{% for toc_item in page.table_of_contents %} {% for toc_item in page.table_of_contents %}
{% include "common/toc-item.html" %} {% include "common/toc-item.html" %}
{% endfor %} {% endfor %}
{% block post_toc %}{% endblock %}
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -11,7 +11,7 @@ from django.http import QueryDict
from django.http.request import HttpRequest from django.http.request import HttpRequest
from django.utils.text import slugify from django.utils.text import slugify
from django_cache_decorator import django_cache_decorator from django_cache_decorator import django_cache_decorator
from metadata_parser import MetadataParser from metadata_parser import MetadataParser, ParsedResult
from wagtail.models import Page, Site from wagtail.models import Page, Site
from wagtail.models import get_page_models as get_wagtail_page_models from wagtail.models import get_page_models as get_wagtail_page_models
@ -128,8 +128,13 @@ def get_ai_robots_txt() -> str:
@django_cache_decorator(time=21600) @django_cache_decorator(time=21600)
def get_page_metadata(url: str) -> MetadataParser: def get_page_metadata(url: str) -> ParsedResult:
return MetadataParser(url=url, search_head_only=True) metadata = MetadataParser(url=url, search_head_only=True).parsed_result
# HACK: BeautifulSoup doesn't pickle nicely, and so can't be cached
metadata.soup = None
return metadata
def extend_query_params(url: str, params: dict[str, Any]) -> str: def extend_query_params(url: str, params: dict[str, Any]) -> str:

View File

@ -1,21 +1,16 @@
import lightningcss
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.utils.datastructures import OrderedSet
from django.views.decorators.cache import cache_control from django.views.decorators.cache import cache_control
from pygments.formatters.html import HtmlFormatter from pygments.formatters.html import HtmlFormatter
@cache_control(max_age=3600) @cache_control(max_age=3600)
def pygments_styles(request: HttpRequest) -> HttpResponse: def pygments_styles(request: HttpRequest) -> HttpResponse:
default_styles = ( default_styles = HtmlFormatter(style="default").get_style_defs(
HtmlFormatter(style="default") "html:not(.dark-mode) .highlight"
.get_style_defs("html:not(.dark-mode) .highlight")
.split("\n")
) )
dark_styles = ( dark_styles = HtmlFormatter(style="monokai").get_style_defs(
HtmlFormatter(style="monokai") "html.dark-mode .highlight"
.get_style_defs("html.dark-mode .highlight")
.split("\n")
)
return HttpResponse(
"".join(OrderedSet(default_styles + dark_styles)), content_type="text/css"
) )
compressed = lightningcss.process_stylesheet(default_styles + dark_styles)
return HttpResponse(compressed, content_type="text/css")