Skip to content

Instantly share code, notes, and snippets.

@dest81
Last active April 20, 2021 06:40
Show Gist options
  • Save dest81/8696ad77588098d5d213f001b1cc7fcb to your computer and use it in GitHub Desktop.
Save dest81/8696ad77588098d5d213f001b1cc7fcb to your computer and use it in GitHub Desktop.
Wagtail Page Field Permission
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