Reputation: 13
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
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