- 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>
132 lines
4.0 KiB
Python
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())
|