# -*- coding: iso-8859-1 -*-
# $Id: has_perm.py 128 2008-10-02 11:28:43Z tguettler $
# $HeadURL: svn+ssh://svnserver/svn/djangotools/trunk/utils/has_perm.py $


u'''

has_perm.py: Check if a user can access a view without calling it

One of the goals:
 You can disable or hide a link if the user must not call it. 


Usage:

# file views.py
def myview(request, ...):

    return ...
myview.has_perm=STRING_BOOL_OR_METHOD

STRING_BOOL_OR_METHOD:
 - 'is_staff', 'is_superuser', 'is_authenticated'
 - True (everybody can access it), False (nobody can access it)
 - method which returns True, False or HttpResponse

If you install the HasPermMiddleware, you don't need to check access in your view method.

http://www.djangosnippets.org/snippets/1214/

'''

# Python
import logging

# Django
import django
from django.http import Http404
from django.core.urlresolvers import get_resolver
from django.contrib.auth.models import Permission

# Project
from django.conf import settings

def has_perm(request, url):
    sn=request.META['SCRIPT_NAME']
    if sn is None:
        sn=''
    else:
        assert url.startswith(sn), u'URL=%s does not start with SCRIPT_NAME=%s' % (
            url, sn)
    url_orig=url
    url=url[len(sn):]
    resolver=get_resolver(None)
    try:
        view_func, view_args, view_kwargs = resolver.resolve(url)
    except Http404, exc:
        raise Exception('could not resolve url: %r %r' % (url, url_orig))
    return not check_deny(request, view_func, view_args, view_kwargs)

def check_deny(request, view_func, view_args, view_kwargs):
    view_name='%s.%s' % (view_func.__module__, view_func.__name__)
    has_perm=getattr(view_func, 'has_perm', view_func)
    if has_perm is view_func:
        # Attribute does not exist
        raise AttributeError(u'View %s does not have attribute has_perm' % (
                view_name))
    if has_perm is True:
        return
    if has_perm is False:
        return True

    if isinstance(has_perm, basestring):
        count=has_perm.count('.')
        if count==1:
            if settings.DEBUG:
                app_label, codename = has_perm.split('.')
                perms=Permission.objects.filter(codename=codename, content_type__app_label=app_label)
                if not len(perms)==1:
                    raise Exception('permission string "%s": No or more than one permission objects found: %s' % (
                            has_perm, perms))
            if request.user.has_perm(has_perm):
                return
            else:
                return True