Skip to content

Instantly share code, notes, and snippets.

@keystroke3
Created July 16, 2022 23:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save keystroke3/3166c27ed58abae849f9967d9044db75 to your computer and use it in GitHub Desktop.
Save keystroke3/3166c27ed58abae849f9967d9044db75 to your computer and use it in GitHub Desktop.
Customizable django rest framework abstract permissions class
from rest_framework import permissions
class IsRole(permissions.BasePermission):
"""Checks if the user making request matches the specified role.
If yes, permissions are granted accordingly. The user must be logged
in, so all anonymous requests are denied.
Returns:
bool: if user matches role and thus has permissions
"""
allow_staff = None
staff_roles = None
role = None
allow_roles = None
owner_field = None
deny_actions = None
def has_permission(self, request, view):
self.get_or_set_attributes(request, view)
if request.user.is_anonymous:
return False
if self.deny_actions == None:
self.deny_actions = getattr(view, "deny_actions", None)
if self.deny_actions:
return self.is_action_denied(request, view)
if self.allow_staff and self.staff_roles == None:
raise ValueError("'staff_role' cannot null when 'allow_staff' is true")
if self.allow_staff and request.user.role in self.staff_roles:
return True
if self.allow_roles and request.user.role in self.allowed_roles:
return True
if self.role and self.has_role(request):
return True
def has_object_permission(self, request, view, obj):
if self.allow_roles and request.user.role in self.allow_roles:
return True
if self.allow_staff and request.user.role in self.staff_roles:
return True
owner = getattr(obj, self.owner_field or self.role.lower())
return owner.id == request.user.id
def is_action_denied(self, request, view):
if isinstance(self.deny_actions, dict):
actions = self.deny_actions.get(request.user.role, None)
elif isinstance(self.deny_actions, list | tuple):
actions = self.deny_actions
else:
raise TypeError(
f"Invalid type {type(self.deny_actions)} for deny_actions. Expected iterable"
)
if actions and view.action in actions:
return False
return True
def get_or_set_attributes(self, request, view):
for attribute in dir(self):
if not attribute.startswith("_"):
value = getattr(self, attribute)
if value == None:
setattr(self, attribute, getattr(view, attribute, None))
print(attribute, getattr(self, attribute))
@classmethod
def has_role(self, request, role: str = None) -> bool:
if role == None:
role = self.role
return request.user.role == role
# Example permission classes
IsClient(IsRole):
role = "CLIENT
IsStaff(IsRole):
allow_staff = True
IsStaffReadOnly(IsStaff):
deny_actions = ('update', 'partial_update', 'delete')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment