Jonathan
Jonathan

Reputation: 163

Wagtail/Django: Query filter to return only the pages the user has acess/permissions?

I'm going through the documentation at: http://docs.wagtail.io/en/v2.7.1/reference/pages/queryset_reference.html.

Is there a filter to return only the pages the user has access to? I can only see public() and not_public().

I have some pages which privacy is set to Private (accessible to users in specific groups). And would like to exclude them from the query results.

Upvotes: 1

Views: 1115

Answers (1)

david
david

Reputation: 2171

There is no such filter in PageQuerySet. You can however create your own QuerySet that adds an authorized filter and use that. The following code comes from the Joyous events EventQuerySet and is based upon PageQuerySet.public_q and BaseViewRestriction.accept_request. It gets all the restrictions that could apply, excludes the ones that the user passes, and then filters out the pages with the remaining restrictions.

from wagtail.core.query import PageQuerySet
from wagtail.core.models import Page, PageManager, PageViewRestriction

class MyQuerySet(PageQuerySet):
    def authorized_q(self, request):
        PASSWORD = PageViewRestriction.PASSWORD
        LOGIN    = PageViewRestriction.LOGIN
        GROUPS   = PageViewRestriction.GROUPS
        KEY      = PageViewRestriction.passed_view_restrictions_session_key

        restrictions = PageViewRestriction.objects.all()
        passed = request.session.get(KEY, [])
        if passed:
            restrictions = restrictions.exclude(id__in=passed,
                                                restriction_type=PASSWORD)
        if request.user.is_authenticated:
            restrictions = restrictions.exclude(restriction_type=LOGIN)
        if request.user.is_superuser:
            restrictions = restrictions.exclude(restriction_type=GROUPS)
        else:
            membership = request.user.groups.all()
            if membership:
                restrictions = restrictions.exclude(groups__in=membership,
                                                    restriction_type=GROUPS)
        q = models.Q()
        for restriction in restrictions:
            q &= ~self.descendant_of_q(restriction.page, inclusive=True)
        return q

    def authorized(self, request):
        self.request = request
        if request is None:
            return self
        else:
            return self.filter(self.authorized_q(request))

You could then set this to be your model's default QuerySet.

class MyPage(Page):
    objects = PageManager.from_queryset(MyQuerySet)()

Then when filtering your MyPage objects you can say MyPage.objects.live().authorized(request).all()

Hope that is helpful. May contain bugs.

Upvotes: 2

Related Questions