Source code for oioioi.base.permissions

# coding: utf-8
import functools

from django.contrib.auth.views import LogoutView, redirect_to_login
from django.core.exceptions import PermissionDenied
from django.template.response import TemplateResponse

from oioioi.base.utils import is_ajax


[docs]class AccessDenied(object): """A ``False``-like class with additional response to use as the access denied message. """ def __init__(self, response=None): self.response = response
[docs] def __nonzero__(self): return False
[docs]class Condition(object): r"""Class representing a condition (a function which returns a boolean based on its arguments) intended for use with views and menu items. Technically, an instance of this class is a callable object wrapping a function. Additionally, it implements basic logical operators: AND (&), OR (|), and (~) -- a logical negation. :param condition: the function to be wrapped :type condition: fun: \*args, \*\*kwargs → bool """ def __init__(self, condition, *args, **kwargs): super(Condition, self).__init__(*args, **kwargs) self.condition = condition
[docs] def __call__(self, *args, **kwargs): return self.condition(*args, **kwargs)
[docs] def __or__(self, other): if not isinstance(other, Condition): return NotImplemented condition_or = lambda *args, **kwargs: self(*args, **kwargs) or other( *args, **kwargs ) return Condition(condition_or)
[docs] def __and__(self, other): if not isinstance(other, Condition): return NotImplemented condition_and = lambda *args, **kwargs: self(*args, **kwargs) and other( *args, **kwargs ) return Condition(condition_and)
[docs] def __invert__(self): condition_inverted = lambda *args, **kwargs: not self(*args, **kwargs) return Condition(condition_inverted)
[docs]class RequestBasedCondition(Condition): """Subclass of the :class:`Condition` class. It is a special condition class representing a condition which takes request as its only argument. It allows the usage of :func:`oioioi.base.utils.request_cached`. """
[docs] def __call__(self, request, *args, **kwargs): return self.condition(request)
[docs]def make_condition(condition_class=Condition): """Decorator which transforms a function into an instance of a given ``condition_class`` (subclass of :class:`~Condition`). """ assert issubclass(condition_class, Condition) def wrap_condition(func): condition = condition_class(func) for attr in ('__name__', '__module__', '__doc__'): setattr(condition, attr, getattr(func, attr)) condition.__dict__.update(func.__dict__) return condition return wrap_condition
#: Shortcut for ``make_condition(RequestBasedCondition)``. #: See example usage below.
[docs]make_request_condition = make_condition(RequestBasedCondition)
[docs]def enforce_condition(condition, template=None, login_redirect=True): """Decorator for views that checks that the request passes the given ``condition``. ``condition`` must be an instance of :class:`Condition`. If the condition returns ``False`` and ``template`` is not ``None``, a suitable :class:`TemplateResponse` is returned. If ``template`` is ``None`` and the user is not authenticated and the ``login_redirect`` flag is set to ``True``, a redirect to the login page is issued, otherwise :exc:`PermissionDenied` is raised. If the condition returns an instance of :class:`AccessDenied` with a specific response to use, this response is used instead of calling the decorated view. :param condition: condition to check :type condition: :class:`Condition` :param template: template name to return when ``condition`` fails :type template: basestring """ assert isinstance(condition, Condition), ( 'condition passed to' ' enforce_condition must be an instance of the Condition class or' ' its subclass' ) def decorator(view_func): @functools.wraps(view_func) def _wrapped_view(request, *args, **kwargs): decision = condition(request, *args, **kwargs) if isinstance(decision, AccessDenied) and decision.response: return decision.response if decision: return view_func(request, *args, **kwargs) if template is not None: return TemplateResponse(request, template) elif ( not request.user.is_authenticated and not is_ajax(request) and login_redirect ): return redirect_to_login(request.path) else: raise PermissionDenied old_condition = getattr(view_func, 'condition', None) if old_condition is None: new_condition = condition else: new_condition = condition & old_condition _wrapped_view.condition = new_condition return _wrapped_view return decorator
@make_request_condition
[docs]def not_anonymous(request): """ Checks if user is logged in and if his account is active. Logs out inactive users, effectively blocking them from performing actions. :param request: :return: """ if request.user.is_authenticated: if request.user.is_active: return True else: LogoutView.as_view()(request) return False else: return False
@make_request_condition
[docs]def is_superuser(request): return request.user.is_superuser