import inspect from django.http import HttpResponseRedirect from django.utils.http import urlquote from django.utils.functional import wraps from django.db.models import Model from django.apps import apps from django.shortcuts import get_object_or_404 from django.conf import settings from django.contrib.auth import REDIRECT_FIELD_NAME from authority.utils import get_check from authority.views import permission_denied try: basestring except NameError: basestring = str def permission_required(perm, *lookup_variables, **kwargs): """ Decorator for views that checks whether a user has a particular permission enabled, redirecting to the log-in page if necessary. """ login_url = kwargs.pop("login_url", settings.LOGIN_URL) redirect_field_name = kwargs.pop("redirect_field_name", REDIRECT_FIELD_NAME) redirect_to_login = kwargs.pop("redirect_to_login", True) def decorate(view_func): def decorated(request, *args, **kwargs): if request.user.is_authenticated: params = [] for lookup_variable in lookup_variables: if isinstance(lookup_variable, basestring): value = kwargs.get(lookup_variable, None) if value is None: continue params.append(value) elif isinstance(lookup_variable, (tuple, list)): model, lookup, varname = lookup_variable value = kwargs.get(varname, None) if value is None: continue if isinstance(model, basestring): model_class = apps.get_model(*model.split(".")) else: model_class = model if model_class is None: raise ValueError( "The given argument '%s' is not a valid model." % model ) if inspect.isclass(model_class) and not issubclass( model_class, Model ): raise ValueError( "The argument %s needs to be a model." % model ) obj = get_object_or_404(model_class, **{lookup: value}) params.append(obj) check = get_check(request.user, perm) granted = False if check is not None: granted = check(*params) if granted or request.user.has_perm(perm): return view_func(request, *args, **kwargs) if redirect_to_login: path = urlquote(request.get_full_path()) tup = login_url, redirect_field_name, path return HttpResponseRedirect("%s?%s=%s" % tup) return permission_denied(request) return wraps(view_func)(decorated) return decorate def permission_required_or_403(perm, *args, **kwargs): """ Decorator that wraps the permission_required decorator and returns a permission denied (403) page instead of redirecting to the login URL. """ kwargs["redirect_to_login"] = False return permission_required(perm, *args, **kwargs)