diff --git a/wagtail/admin/urls/__init__.py b/wagtail/admin/urls/__init__.py index 8d1abd9a38..6d664ecfc5 100644 --- a/wagtail/admin/urls/__init__.py +++ b/wagtail/admin/urls/__init__.py @@ -28,8 +28,12 @@ urlpatterns = [ path("api/", include(api_urls)), path("failwhale/", home.error_test, name="wagtailadmin_error_test"), # TODO: Move into wagtailadmin_pages namespace - path("pages/", listing.index, name="wagtailadmin_explore_root"), - path("pages//", listing.index, name="wagtailadmin_explore"), + path("pages/", listing.IndexView.as_view(), name="wagtailadmin_explore_root"), + path( + "pages//", + listing.IndexView.as_view(), + name="wagtailadmin_explore", + ), # bulk actions path( "bulk////", diff --git a/wagtail/admin/views/pages/listing.py b/wagtail/admin/views/pages/listing.py index 834626b2bb..7bbd2c8de1 100644 --- a/wagtail/admin/views/pages/listing.py +++ b/wagtail/admin/views/pages/listing.py @@ -5,6 +5,8 @@ from django.http import Http404 from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.urls import reverse +from django.utils.decorators import method_decorator +from django.views.generic import View from wagtail import hooks from wagtail.admin.auth import user_has_any_page_permission, user_passes_test @@ -12,134 +14,137 @@ from wagtail.admin.ui.side_panels import PageSidePanels from wagtail.permission_policies.pages import Page, PagePermissionPolicy -@user_passes_test(user_has_any_page_permission) -def index(request, parent_page_id=None): - if parent_page_id: - parent_page = get_object_or_404(Page, id=parent_page_id) - else: - parent_page = Page.get_first_root_node() - - permission_policy = PagePermissionPolicy() - - # This will always succeed because of the @user_passes_test above. - root_page = permission_policy.explorable_root_instance(request.user) - - # If this page isn't a descendant of the user's explorable root page, - # then redirect to that explorable root page instead. - if not (parent_page.pk == root_page.pk or parent_page.is_descendant_of(root_page)): - return redirect("wagtailadmin_explore", root_page.pk) - - parent_page = parent_page.specific - - pages = parent_page.get_children().prefetch_related( - "content_type", "sites_rooted_here" - ) & permission_policy.explorable_instances(request.user) - - # Get page ordering - ordering = request.GET.get("ordering", "-latest_revision_created_at") - if ordering not in [ - "title", - "-title", - "content_type", - "-content_type", - "live", - "-live", - "latest_revision_created_at", - "-latest_revision_created_at", - "ord", - ]: - ordering = "-latest_revision_created_at" - - if ordering == "ord": - # preserve the native ordering from get_children() - pass - elif ordering == "latest_revision_created_at": - # order by oldest revision first. - # Special case NULL entries - these should go at the top of the list. - # Do this by annotating with Count('latest_revision_created_at'), - # which returns 0 for these - pages = pages.annotate( - null_position=Count("latest_revision_created_at") - ).order_by("null_position", "latest_revision_created_at") - elif ordering == "-latest_revision_created_at": - # order by oldest revision first. - # Special case NULL entries - these should go at the end of the list. - pages = pages.annotate( - null_position=Count("latest_revision_created_at") - ).order_by("-null_position", "-latest_revision_created_at") - else: - pages = pages.order_by(ordering) - - # Don't paginate if sorting by page order - all pages must be shown to - # allow drag-and-drop reordering - do_paginate = ordering != "ord" - - # We want specific page instances, but do not need streamfield values here - pages = pages.defer_streamfields().specific() - - # allow hooks defer_streamfieldsyset - for hook in hooks.get_hooks("construct_explorer_page_queryset"): - pages = hook(parent_page, pages, request) - - # Annotate queryset with various states to be used later for performance optimisations - if getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True): - pages = pages.prefetch_workflow_states() - - pages = pages.annotate_site_root_state().annotate_approved_schedule() - - # Pagination - if do_paginate: - paginator = Paginator(pages, per_page=50) - try: - pages = paginator.page(request.GET.get("p", 1)) - except InvalidPage: - raise Http404 - - show_ordering_column = request.GET.get("ordering") == "ord" - - side_panels = PageSidePanels( - request, - parent_page.get_latest_revision_as_object(), - show_schedule_publishing_toggle=False, - live_page=parent_page.specific, - scheduled_page=parent_page.get_scheduled_revision_as_object(), - in_explorer=True, - preview_enabled=False, - comments_enabled=False, - ) - - context = { - "parent_page": parent_page.specific, - "ordering": ordering, - "side_panels": side_panels, - "pages": pages, - "do_paginate": do_paginate, - "locale": None, - "translations": [], - "show_ordering_column": show_ordering_column, - "show_bulk_actions": not show_ordering_column, - "show_locale_labels": False, - } - - if getattr(settings, "WAGTAIL_I18N_ENABLED", False): - if not parent_page.is_root(): - context.update( - { - "locale": parent_page.locale, - "translations": [ - { - "locale": translation.locale, - "url": reverse( - "wagtailadmin_explore", args=[translation.id] - ), - } - for translation in parent_page.get_translations() - .only("id", "locale") - .select_related("locale") - ], - } - ) +class IndexView(View): + @method_decorator(user_passes_test(user_has_any_page_permission)) + def get(self, request, parent_page_id=None): + if parent_page_id: + parent_page = get_object_or_404(Page, id=parent_page_id) else: - context["show_locale_labels"] = True + parent_page = Page.get_first_root_node() - return TemplateResponse(request, "wagtailadmin/pages/index.html", context) + permission_policy = PagePermissionPolicy() + + # This will always succeed because of the @user_passes_test above. + root_page = permission_policy.explorable_root_instance(request.user) + + # If this page isn't a descendant of the user's explorable root page, + # then redirect to that explorable root page instead. + if not ( + parent_page.pk == root_page.pk or parent_page.is_descendant_of(root_page) + ): + return redirect("wagtailadmin_explore", root_page.pk) + + parent_page = parent_page.specific + + pages = parent_page.get_children().prefetch_related( + "content_type", "sites_rooted_here" + ) & permission_policy.explorable_instances(request.user) + + # Get page ordering + ordering = request.GET.get("ordering", "-latest_revision_created_at") + if ordering not in [ + "title", + "-title", + "content_type", + "-content_type", + "live", + "-live", + "latest_revision_created_at", + "-latest_revision_created_at", + "ord", + ]: + ordering = "-latest_revision_created_at" + + if ordering == "ord": + # preserve the native ordering from get_children() + pass + elif ordering == "latest_revision_created_at": + # order by oldest revision first. + # Special case NULL entries - these should go at the top of the list. + # Do this by annotating with Count('latest_revision_created_at'), + # which returns 0 for these + pages = pages.annotate( + null_position=Count("latest_revision_created_at") + ).order_by("null_position", "latest_revision_created_at") + elif ordering == "-latest_revision_created_at": + # order by oldest revision first. + # Special case NULL entries - these should go at the end of the list. + pages = pages.annotate( + null_position=Count("latest_revision_created_at") + ).order_by("-null_position", "-latest_revision_created_at") + else: + pages = pages.order_by(ordering) + + # Don't paginate if sorting by page order - all pages must be shown to + # allow drag-and-drop reordering + do_paginate = ordering != "ord" + + # We want specific page instances, but do not need streamfield values here + pages = pages.defer_streamfields().specific() + + # allow hooks defer_streamfieldsyset + for hook in hooks.get_hooks("construct_explorer_page_queryset"): + pages = hook(parent_page, pages, request) + + # Annotate queryset with various states to be used later for performance optimisations + if getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True): + pages = pages.prefetch_workflow_states() + + pages = pages.annotate_site_root_state().annotate_approved_schedule() + + # Pagination + if do_paginate: + paginator = Paginator(pages, per_page=50) + try: + pages = paginator.page(request.GET.get("p", 1)) + except InvalidPage: + raise Http404 + + show_ordering_column = request.GET.get("ordering") == "ord" + + side_panels = PageSidePanels( + request, + parent_page.get_latest_revision_as_object(), + show_schedule_publishing_toggle=False, + live_page=parent_page.specific, + scheduled_page=parent_page.get_scheduled_revision_as_object(), + in_explorer=True, + preview_enabled=False, + comments_enabled=False, + ) + + context = { + "parent_page": parent_page.specific, + "ordering": ordering, + "side_panels": side_panels, + "pages": pages, + "do_paginate": do_paginate, + "locale": None, + "translations": [], + "show_ordering_column": show_ordering_column, + "show_bulk_actions": not show_ordering_column, + "show_locale_labels": False, + } + + if getattr(settings, "WAGTAIL_I18N_ENABLED", False): + if not parent_page.is_root(): + context.update( + { + "locale": parent_page.locale, + "translations": [ + { + "locale": translation.locale, + "url": reverse( + "wagtailadmin_explore", args=[translation.id] + ), + } + for translation in parent_page.get_translations() + .only("id", "locale") + .select_related("locale") + ], + } + ) + else: + context["show_locale_labels"] = True + + return TemplateResponse(request, "wagtailadmin/pages/index.html", context)