Files
main-site/apps/blog/wagtail_hooks.py
Mark b897447296
Some checks failed
CI / nightly-e2e (pull_request) Has been skipped
CI / deploy (pull_request) Has been skipped
CI / ci (pull_request) Successful in 1m19s
CI / pr-e2e (pull_request) Failing after 2m13s
Address PR review feedback
- Gate e2e-admin superuser behind E2E_MODE env var (security)
- Add status and tag filters to ArticleFilterSet
- Set default_ordering to -published_date on listing viewset
- Add summary to ArticlePage.search_fields for search support
- Add 4 new tests for filters, ordering, and search fields

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-03 20:37:58 +00:00

132 lines
4.0 KiB
Python

import django_filters
from taggit.models import Tag
from wagtail import hooks
from wagtail.admin.filters import WagtailFilterSet
from wagtail.admin.ui.components import Component
from wagtail.admin.ui.tables import Column, DateColumn
from wagtail.admin.ui.tables.pages import BulkActionsColumn, PageStatusColumn, PageTitleColumn
from wagtail.admin.viewsets.pages import PageListingViewSet
from wagtail.snippets.models import register_snippet
from wagtail.snippets.views.snippets import SnippetViewSet
from apps.authors.models import Author
from apps.blog.models import ArticlePage, Category, TagMetadata
STATUS_CHOICES = [
("live", "Published"),
("draft", "Draft"),
("scheduled", "Scheduled"),
]
class TagMetadataViewSet(SnippetViewSet):
model = TagMetadata
icon = "tag"
list_display = ["tag", "colour"]
register_snippet(TagMetadataViewSet)
class CategoryViewSet(SnippetViewSet):
model = Category
icon = "folder-open-inverse"
list_display = ["name", "slug", "show_in_nav", "sort_order"]
list_filter = ["show_in_nav"]
ordering = ["sort_order", "name"]
register_snippet(CategoryViewSet)
# ── Articles page listing ────────────────────────────────────────────────────
class StatusFilter(django_filters.ChoiceFilter):
def filter(self, qs, value): # noqa: A003
if value == "live":
return qs.filter(live=True)
if value == "draft":
return qs.filter(live=False, go_live_at__isnull=True)
if value == "scheduled":
return qs.filter(live=False, go_live_at__isnull=False)
return qs
class ArticleFilterSet(WagtailFilterSet):
category = django_filters.ModelChoiceFilter(
queryset=Category.objects.all(),
empty_label="All categories",
)
author = django_filters.ModelChoiceFilter(
queryset=Author.objects.all(),
empty_label="All authors",
)
status = StatusFilter(
choices=STATUS_CHOICES,
empty_label="All statuses",
)
tag = django_filters.ModelChoiceFilter(
field_name="tags",
queryset=Tag.objects.all(),
empty_label="All tags",
)
class Meta:
model = ArticlePage
fields = []
class ArticlePageListingViewSet(PageListingViewSet):
model = ArticlePage
icon = "doc-full"
menu_label = "Articles"
menu_order = 200
add_to_admin_menu = True
name = "articles"
columns = [
BulkActionsColumn("bulk_actions"),
PageTitleColumn("title", classname="title"),
Column("author", label="Author", sort_key="author__name"),
Column("category", label="Category"),
DateColumn("published_date", label="Published", sort_key="published_date"),
PageStatusColumn("status", sort_key="live"),
]
filterset_class = ArticleFilterSet
default_ordering = "-published_date"
@hooks.register("register_admin_viewset")
def register_article_listing():
return ArticlePageListingViewSet("articles")
# ── Dashboard panel ──────────────────────────────────────────────────────────
class ArticlesSummaryPanel(Component):
name = "articles_summary"
template_name = "blog/panels/articles_summary.html"
order = 110
def get_context_data(self, parent_context):
context = super().get_context_data(parent_context)
context["drafts"] = (
ArticlePage.objects.not_live()
.order_by("-latest_revision_created_at")[:5]
)
context["scheduled"] = (
ArticlePage.objects.filter(go_live_at__isnull=False, live=False)
.order_by("go_live_at")[:5]
)
context["recent"] = (
ArticlePage.objects.live()
.order_by("-published_date")[:5]
)
return context
@hooks.register("construct_homepage_panels")
def add_articles_summary_panel(request, panels):
panels.append(ArticlesSummaryPanel())