Last active
April 20, 2021 06:40
-
-
Save dest81/8696ad77588098d5d213f001b1cc7fcb to your computer and use it in GitHub Desktop.
Wagtail Page Field Permission
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class BlogPage(Page): | |
... | |
edit_permissions = [ | |
Permission( | |
action="hide", | |
groups=["Authors"], | |
fields=["slug", "seo_title", "tags"] | |
) | |
] | |
edit_handler = RestrictedTabbedInterface([ | |
... | |
]) | |
# override get_edit_handler | |
# original method is wrapped into @cache_classmethod which causes issues | |
@classmethod | |
def get_edit_handler(cls): | |
return cls.edit_handler.bind_to(model=cls) | |
# should be converted into dataclass | |
class Permission: | |
def __init__(self, action, groups, fields): | |
self.action = action | |
self.groups = groups | |
self.fields = fields | |
def __repr__(self): | |
return(f"Permission(action={self.action}, groups={self.groups}, " | |
f"fields={self.fields})") | |
class RestrictedTabbedInterface(TabbedInterface): | |
def filter_fields(self, parent, special_fields, hide_all): | |
items = [] | |
# iterate through children. | |
for item in parent.children: | |
if hasattr(item, "children"): | |
# TabbedInterface, ObjectList, MultiFieldPanel | |
parent_fields = self.filter_fields( | |
item, special_fields, hide_all | |
) | |
if parent_fields: | |
items.append(parent_fields) | |
continue | |
if hasattr(item, "field_name"): | |
# inherited from FieldPanel | |
field_name = item.field_name | |
elif hasattr(item, "relation_name"): | |
# InlineFieldPanel | |
field_name = item.relation_name | |
elif hasattr(item, "classname"): | |
# PrivacyModalPanel, PublishingPanel | |
field_name = item.classname | |
else: | |
# didn't test with HelpPanel, FieldRowPanel | |
if not hide_all: | |
# unknown item, let's do not touch it | |
items.append(item) | |
continue | |
if hide_all: | |
if field_name in special_fields: | |
items.append(item) | |
else: | |
if field_name not in special_fields: | |
items.append(item) | |
# show parent only if there are items in it | |
if not items: | |
return None | |
parent.children = items | |
return parent | |
def apply_permissions(self): | |
# method removes or adds fields according to edit_permissions | |
# some things could go wrong in case | |
# if user has more than one role and those roles have to be restricted | |
# I would suggest to put Permission(s) with more important group higher | |
# in the edit_permissions list - it means first group match will be | |
# taken and permission(s) for lower group will be ingnored | |
if not self.request: | |
return | |
if self.request.user.is_superuser: | |
return | |
if not hasattr(self.model, "edit_permissions"): | |
return | |
permissions = self.model.edit_permissions | |
user_groups = self.request.user.groups.values_list("name", flat=True) | |
# we show all fields by default | |
hide_all = False | |
# list of fields need action(hide or show) | |
special_fields = [] | |
for perm in permissions: | |
if not isinstance(perm, Permission): | |
# show/raise error | |
pass | |
if len(set(user_groups).intersection(perm.groups)) == 0: | |
# user's groups are not in the list | |
# no action needed | |
continue | |
# action can be: | |
# - show: show only those fields | |
# - hide: hide only those fields | |
if perm.action == "show": | |
hide_all = True | |
special_fields = perm.fields | |
# this is kind of limitation | |
# stop iterating after first match otherwise it could cause | |
# unpredictable issues | |
break | |
if not special_fields: | |
return | |
panel = self.filter_fields(self, special_fields, hide_all) | |
self.children = panel.children | |
def on_model_bound(self): | |
self.apply_permissions() | |
super().on_model_bound() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment