def filter_queryset(self, request, queryset, view): if request.GET.get('for_explorer'): if not hasattr(queryset, '_filtered_by_child_of'): raise BadRequestError("filtering by for_explorer without child_of is not supported") parent_page = queryset._filtered_by_child_of for hook in hooks.get_hooks('construct_explorer_page_queryset'): queryset = hook(parent_page, queryset, request) user_perms = UserPagePermissionsProxy(request.user) queryset = queryset & user_perms.explorable_pages() return queryset
def test_explorable_pages_with_permission_gap_in_hierarchy(self): corporate_editor = get_user_model().objects.get(username='******') user_perms = UserPagePermissionsProxy(corporate_editor) about_us_page = Page.objects.get(url_path='/home/about-us/') businessy_events = Page.objects.get(url_path='/home/events/businessy-events/') events_page = Page.objects.get(url_path='/home/events/') explorable_pages = user_perms.explorable_pages() self.assertTrue(explorable_pages.filter(id=about_us_page.id).exists()) self.assertTrue(explorable_pages.filter(id=businessy_events.id).exists()) self.assertTrue(explorable_pages.filter(id=events_page.id).exists())
def test_explorable_pages(self): event_editor = get_user_model().objects.get(username='******') christmas_page = EventPage.objects.get(url_path='/home/events/christmas/') unpublished_event_page = EventPage.objects.get(url_path='/home/events/tentative-unpublished-event/') someone_elses_event_page = EventPage.objects.get(url_path='/home/events/someone-elses-event/') about_us_page = Page.objects.get(url_path='/home/about-us/') user_perms = UserPagePermissionsProxy(event_editor) explorable_pages = user_perms.explorable_pages() # Verify all pages below /home/events/ are explorable self.assertTrue(explorable_pages.filter(id=christmas_page.id).exists()) self.assertTrue(explorable_pages.filter(id=unpublished_event_page.id).exists()) self.assertTrue(explorable_pages.filter(id=someone_elses_event_page.id).exists()) # Verify page outside /events/ tree are not explorable self.assertFalse(explorable_pages.filter(id=about_us_page.id).exists())
def filter_queryset(self, request, queryset, view): if request.GET.get('for_explorer'): if not hasattr(queryset, '_filtered_by_child_of'): raise BadRequestError( "filtering by for_explorer without child_of is not supported" ) parent_page = queryset._filtered_by_child_of ##TODO: This is where the code is broken, see: https://github.com/wagtail/wagtail/blob/17e541715a80a43bc4eb1f1b07183bf22bb1869a/wagtail/contrib/modeladmin/options.py#L49 # for hook in hooks.get_hooks('construct_explorer_page_queryset'): # queryset = hook(parent_page, queryset, request) user_perms = UserPagePermissionsProxy(request.user) # This is returning an empty list! WRONG! #print(user_perms.explorable_pages()) queryset = queryset & user_perms.explorable_pages() return queryset
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() # This will always succeed because of the @user_passes_test above. root_page = get_explorable_root_page(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 user_perms = UserPagePermissionsProxy(request.user) pages = ( parent_page.get_children().prefetch_related( "content_type", "sites_rooted_here" ) & user_perms.explorable_pages() ) # 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' if do_paginate or pages.count() < 100: # Retrieve pages in their most specific form, so that custom # get_admin_display_title and get_url_parts methods on subclasses are respected. # However, skip this on unpaginated listings with >100 child pages as this could # be a significant performance hit. (This should only happen on the reorder view, # and hopefully no-one is having to do manual reordering on listings that large...) pages = pages.specific(defer=True) # allow hooks to modify the queryset for hook in hooks.get_hooks('construct_explorer_page_queryset'): pages = hook(parent_page, pages, request) # Pagination if do_paginate: paginator = Paginator(pages, per_page=50) pages = paginator.get_page(request.GET.get('p')) return render(request, 'wagtailadmin/pages/index.html', { 'parent_page': parent_page.specific, 'ordering': ordering, 'pagination_query_params': "ordering=%s" % ordering, 'pages': pages, 'do_paginate': do_paginate, })
def get_base_queryset(self, models=None): queryset = super().get_base_queryset(models=models) user_perms = UserPagePermissionsProxy(self.request.user) queryset = queryset & user_perms.explorable_pages() return queryset
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() # This will always succeed because of the @user_passes_test above. root_page = get_explorable_root_page(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 user_perms = UserPagePermissionsProxy(request.user) pages = (parent_page.get_children().prefetch_related( "content_type", "sites_rooted_here") & user_perms.explorable_pages()) # 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) # Pagination if do_paginate: paginator = Paginator(pages, per_page=50) pages = paginator.get_page(request.GET.get('p')) context = { 'parent_page': parent_page.specific, 'ordering': ordering, 'pagination_query_params': "ordering=%s" % ordering, 'pages': pages, 'do_paginate': do_paginate, 'locale': None, 'translations': [], } if getattr(settings, 'WAGTAIL_I18N_ENABLED', False) and 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')], }) return TemplateResponse(request, 'wagtailadmin/pages/index.html', context)
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() # This will always succeed because of the @user_passes_test above. root_page = get_explorable_root_page(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 user_perms = UserPagePermissionsProxy(request.user) pages = (parent_page.get_children().prefetch_related( "content_type", "sites_rooted_here") & user_perms.explorable_pages()) # 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) pages = paginator.get_page(request.GET.get("p")) show_ordering_column = request.GET.get("ordering") == "ord" context = { "parent_page": parent_page.specific, "ordering": ordering, "pagination_query_params": "ordering=%s" % ordering, "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)