Skip to content

Commit

Permalink
Allowing logical expression on condition statements
Browse files Browse the repository at this point in the history
  • Loading branch information
tanonl committed Oct 13, 2020
1 parent 8772513 commit 199d53a
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 2 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ tqdm==4.32.1
twine==1.13.0
urllib3==1.25.3
webencodings==0.5.1
pyparsing==2.4.7
17 changes: 15 additions & 2 deletions rest_access_policy/access_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@

from django.conf import settings
from django.db.models import prefetch_related_objects
from rest_access_policy import AccessPolicyException
from pyparsing import infixNotation, opAssoc
from rest_framework import permissions

from rest_access_policy import AccessPolicyException
from .parsing import ConditionOperand, boolOperand, BoolNot, BoolAnd, BoolOr


class AccessPolicy(permissions.BasePermission):
statements = []
Expand Down Expand Up @@ -157,7 +160,17 @@ def _get_statements_matching_context_conditions(
fails = 0

for condition in statement["condition"]:
passed = self._check_condition(condition, request, view, action)

ConditionOperand.check_condition_fn = lambda _, cond: self._check_condition(cond, request, view, action)
boolOperand.setParseAction(ConditionOperand)

boolExpr = infixNotation(boolOperand, [
("not", 1, opAssoc.RIGHT, BoolNot),
("and", 2, opAssoc.LEFT, BoolAnd),
("or", 2, opAssoc.LEFT, BoolOr),
])

passed = bool(boolExpr.parseString(condition)[0])

if not passed:
fails += 1
Expand Down
67 changes: 67 additions & 0 deletions rest_access_policy/parsing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from pyparsing import Keyword, Word, alphanums


class ConditionOperand(object):
check_condition_fn = None

def __init__(self, t):
self.label = t[0]

assert self.check_condition_fn is not None, 'The check_condition_fn should should be set'
assert callable(self.check_condition_fn), 'The check_condition_fn should should be callable'

self.value = self.check_condition_fn(t[0])

def __bool__(self):
return self.value

def __str__(self):
return self.label

__repr__ = __str__
__nonzero__ = __bool__


class BoolBinOp(object):
def __init__(self, t):
self.args = t[0][0::2]

def __str__(self):
sep = " %s " % self.reprsymbol
return "(" + sep.join(map(str, self.args)) + ")"

def __bool__(self):
return self.evalop(bool(a) for a in self.args)

__nonzero__ = __bool__
__repr__ = __str__


class BoolAnd(BoolBinOp):
reprsymbol = '&'
evalop = all


class BoolOr(BoolBinOp):
reprsymbol = '|'
evalop = any


class BoolNot(object):
def __init__(self, t):
self.arg = t[0][1]

def __bool__(self):
v = bool(self.arg)
return not v

def __str__(self):
return "~" + str(self.arg)

__repr__ = __str__
__nonzero__ = __bool__


TRUE = Keyword("True")
FALSE = Keyword("False")
boolOperand = TRUE | FALSE | Word(alphanums + '_:.', max=256)

0 comments on commit 199d53a

Please sign in to comment.