# -*- coding: utf-8 -*-
[docs]class BasePermissionChecker(object):
def __init__(self, *checkers):
self._checkers = list(checkers)
super(BasePermissionChecker, self).__init__()
[docs] def fill_cache(self, obj, sender):
cache = {}
for c in set(self.get_atomical_checkers()):
cache[c] = c(obj, sender)
return cache
[docs] def get_atomical_checkers(self):
for c in self._checkers:
if isinstance(c, BasePermissionChecker):
if c is self:
# recursive checker TODO: log with warning
continue
for child_c in c.get_atomical_checkers():
yield child_c
else:
yield c
[docs] def add_checker(self, checker):
self._checkers.append(checker)
def __and__(self, other):
return AndChecker(self, other)
__rand__ = __and__
def __invert__(self):
return NotChecker(self)
def __or__(self, other):
return OrChecker(self, other)
__ror__ = __or__
[docs]class AndChecker(BasePermissionChecker):
def __call__(self, obj, sender, cache=None):
if cache is None:
cache = self.fill_cache(obj, sender)
return all(
self.perform_child_checker(c, obj, sender, cache=cache)
for c in self._checkers)
def __iand__(self, other):
self.add_checker(other)
return self
[docs]class OrChecker(BasePermissionChecker):
def __call__(self, obj, sender, cache=None):
if cache is None:
cache = self.fill_cache(obj, sender)
return any(
self.perform_child_checker(c, obj, sender, cache=cache)
for c in self._checkers)
def __ior__(self, other):
self.add_checker(other)
return self
[docs]class NotChecker(BasePermissionChecker):
def __init__(self, checker):
self._invertable_checker = checker
super(NotChecker, self).__init__(checker)
def __call__(self, obj, sender, cache=None):
if cache is None:
cache = self.fill_cache(obj, sender)
return not self.perform_child_checker(self._invertable_checker,
obj, sender, cache=cache)
def __invert__(self):
return self._invertable_checker
# shortcut
C = AndChecker
# basic checkers
allow_to_all = OrChecker(lambda obj, sender: True)
restrict_to_all = OrChecker(lambda obj, sender: False)