Skip to content

Commit

Permalink
Merge pull request #6 from yezyilomo/add_shortcircuiting
Browse files Browse the repository at this point in the history
Add shortcircuiting
  • Loading branch information
yezyilomo authored Apr 5, 2020
2 parents 1fdd9c4 + 142c1aa commit df59b2f
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 18 deletions.
2 changes: 1 addition & 1 deletion drf_guard/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
__title__ = 'DRF Guard'
__description__ = 'Flexible permissions for Django REST Framework'
__url__ = 'https://github.com/yezyilomo/drf-guard'
__version__ = '0.1.0'
__version__ = '0.1.1'
__author__ = 'Yezy Ilomo'
__author_email__ = 'yezileliilomo@hotmail.com'
__license__ = 'MIT'
Expand Down
28 changes: 23 additions & 5 deletions drf_guard/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,37 @@

class Operator():
@property
def has_operands(self):
def should_eval(self):
return hasattr(self, 'left_operand') and hasattr(self, 'right_operand')


class Or(Operator):
@property
def should_eval(self):
if getattr(self, 'left_operand', False):
# Shortcircuit
raise StopIteration(self.left_operand)
return super().should_eval

def eval(self):
return self.left_operand or self.right_operand


class And(Operator):
@property
def should_eval(self):
if not getattr(self, 'left_operand', True):
# Shortcircuit
raise StopIteration(self.left_operand)
return super().should_eval

def eval(self):
return self.left_operand and self.right_operand


class Not(Operator):
@property
def has_operands(self):
def should_eval(self):
return hasattr(self, 'right_operand')

def eval(self):
Expand Down Expand Up @@ -47,18 +61,22 @@ def reducer(self, left_operand, right_operand):

if isinstance(left_operand, Operator):
left_operand.right_operand = right_operand
if left_operand.has_operands:
if left_operand.should_eval:
return left_operand.eval()
return left_operand

if isinstance(right_operand, Operator):
right_operand.left_operand = left_operand
if right_operand.has_operands:
if right_operand.should_eval:
return right_operand.eval()
return right_operand

return left_operand and right_operand # Default operator for ','

def eval(self, sequence):
return reduce(self.reducer, sequence)
try:
return reduce(self.reducer, sequence)
except StopIteration as e:
# Return value due to shortcircuit
return e.args[0]

24 changes: 12 additions & 12 deletions drf_guard/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,6 @@ class HasRequiredPermissions(permissions.BasePermission):
"""
Ensure user is has required permissions.
"""
@classmethod
def has_required_permissions(cls, permissions, *args):
if permissions is None:
# Don't check the permissions
return True

reducer = Reducer()
return reducer([
cls.has_required_permission(permission, *args)
for permission in permissions
])

@classmethod
def has_required_permission(cls, permission, request, view, obj=None):
if isinstance(permission, str):
Expand All @@ -107,6 +95,18 @@ def has_required_permission(cls, permission, request, view, obj=None):
data_type = type(permission).__name__
raise TypeError("`%s` is invalid permission type." % data_type)

@classmethod
def has_required_permissions(cls, permissions, *args):
if permissions is None:
# Don't check the permissions
return True

reducer = Reducer()
return reducer([
cls.has_required_permission(permission, *args)
for permission in permissions
])

@staticmethod
def get_permissions(request, view):
# Get a mapping of methods -> required group.
Expand Down

0 comments on commit df59b2f

Please sign in to comment.