Fero Gachulinec
Fero Gachulinec

Reputation: 13

Wagtail admin - playing with urls

I created in wagtail a model called Regbox in model.py and also RegboxModelAdmin in wagtail_hooks.py. Wagtail admin includes item Regbox in wagtail side bar menu. Then I programmatically created a new collection, a new group with permissions add, edit, delete Regbox and this group is assigned to new user after registration. New user can add (edit and delete) new Regbox (model Regbox has forein key User) and this new user can see in wagtail admin only his own regboxes (I used queryset filter so that superuser could see all regboxes in wagtail admin and the current user only his own regboxes). But if this new user plays with urls in his browser he can see also other regboxes (not only his own regboxes). Simply he can change url from for example /regbox/edit/5/ to /regbox/edit/8/ and he can see this page although this page/regbox belongs to another user (it would need here Permission denied). Could someone please advice me how can I do it in wagtail admin so that any user can see only his own regbox pages ? Thanks

Upvotes: 1

Views: 1131

Answers (1)

Loïc Teixeira
Loïc Teixeira

Reputation: 1434

Permissions in Django (and Wagtail by extension) are handled on a per model basis, not per instance. Therefore, giving edit permissions on the Regbox to a user will allow him/her to edit every instances of that model. There are a few exceptions in Wagtail (like the Page model).

Anyway, you should be able to achieve what you want and add custom permission check by attaching a custom permission helper class to you ModelAdmin definition.

from wagtail.contrib.modeladmin.helpers import PermissionHelper
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
from .models import Regbox


class RegboxPermissionHelper(PermissionHelper):
    def user_is_owner(self, user, obj):
        if user.pk == obj.owner:
            return True
        else:
            return False

    def user_can_inspect_obj(self, user, obj):
        """
        Return a boolean to indicate whether `user` is permitted to 'inspect'
        a specific `self.model` instance.
        """
        return self.user_is_owner(user, obj) && super().user_can_inspect_obj(user, obj)

    def user_can_edit_obj(self, user, obj):
        """
        Return a boolean to indicate whether `user` is permitted to 'change'
        a specific `self.model` instance.
        """
        return self.user_is_owner(user, obj) && super().user_can_edit_obj(user, obj)

    def user_can_delete_obj(self, user, obj):
        """
        Return a boolean to indicate whether `user` is permitted to 'delete'
        a specific `self.model` instance.
        """
        return self.user_is_owner(user, obj) && super().user_can_delete_obj(user, obj)


class RegboxModelAdmin(ModelAdmin):
    model = Regbox
    permission_helper_class = RegboxPermissionHelper

modeladmin_register(RegboxModelAdmin)

As you can see, we create a new RegboxPermissionHelper helper class and define methods for the inspect, edit and delete permissions which first check that the user is the owner (this has been extracter to its own method) an then call super to let the original permission check happen. The call to super is important so it return false if the user is not the owner, but it will also return false the user is the owner but doesn't have a particular permission (e.g. you can create and edit but not delete).

FWIW, I think you are using the correct mechanism to filter the list view by filtering the queryset so don't change anything there.

Upvotes: 2

Related Questions