Source

django-permissions / permissions / decorator.py

Full commit

from django.http import HttpResponseRedirect
from django.utils.http import urlquote
from django.utils.functional import wraps
from django.db.models import Model, get_model
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.http import HttpResponseRedirect, HttpResponseForbidden

from permissions.settings import RETURN_403
from permissions.exceptions import TooManyArguments
from permissions.models import Permission



def permission_required(perm, *lookups, **kwargs):
    """
    Decorator for views that checks whether a user has a particular permission
    enabled.

    :param perm: should follow the syntax app_name.model_name.permission_codename

    :param lookups: should be a list, of which each element should follow the
    syntax (model_field_name,{args_key as int|kwargs_key as str}).

    :param login_url: if denied, user would be redirected to location set by
      this parameter. Defaults to ``django.conf.settings.LOGIN_URL``.
    :param redirect_field_name: name of the parameter passed if redirected.
      Defaults to ``django.contrib.auth.REDIRECT_FIELD_NAME``.

    Examples::

        @permission_required('auth.User.change_user, ('username', 'username'))
        def my_view(request, username):
            user = get_object_or_404(User, username=username)
            return user.get_absolute_url()

        @permission_required('auth.User.change_user',('username', 'username'), ('groups__name', 'group_name'))
        def my_view(request, username, group_name):
            user = get_object_or_404(User, username=username,
                group__name=group_name)
            return user.get_absolute_url()

        @permission_required('auth.User.change_user',('username', 1), ('groups__name', 2)
        def my_view(request, username, group_name):
            user = get_object_or_404(User, username=username,
                group__name=group_name)
            return user.get_absolute_url()

    """
    login_url = kwargs.pop('login_url', settings.LOGIN_URL)
    redirect_field_name = kwargs.pop('redirect_field_name', REDIRECT_FIELD_NAME)
    return_403 = kwargs.pop('return_403',RETURN_403)
    if kwargs:
        raise ValueError('The provided keyword arguemnts %s are not accepted for this decorator.' %str(kwargs))
    try:
        app_name,model_name,codename=perm.split('.')
    except:
        raise ValueError('The given argument %s cannot be parsed into app_name.model_name.codename.' % perm)
    model = get_model(app_name,model_name)   
    def decorator(view_func):
        def _wrapped_view(request, *args, **kwargs):
            if not request.user.is_authenticated() and not return_403:
                return HttpResponseRedirect("%s?%s=%s" % (login_url, redirect_field_name,urlquote(request.get_full_path())))
            try:
                obj=model.objects.get(**dict([(k,type(v)==int and args[v] or kwargs[v]) for k,v in lookups]))
            except:
                obj=None
                raise
            if request.user.has_perm(codename,obj):
                 return view_func(request, *args, **kwargs)
            return HttpResponseForbidden()
        return wraps(view_func)(_wrapped_view)
    return decorator