""" Replacement authentication decorators that work around redirection loops,
as well as the trackGrade decorator. """
try:
from functools import wraps
except ImportError:
from django.utils.functional import wraps
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseForbidden, HttpResponseRedirect
from django.utils.http import urlquote
__all__ = ['login_required', 'permission_required', 'user_passes_test', 'trackGrade']
###
### Authentication decorators
###
def user_passes_test(test_func, login_url=None,
redirect_field_name=REDIRECT_FIELD_NAME):
"""Replacement for django.contrib.auth.decorators.user_passes_test that
returns 403 Forbidden if the user is already logged in.
"""
if not login_url:
from django.conf import settings
login_url = settings.LOGIN_URL
def decorator(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
if test_func(request.user):
return view_func(request, *args, **kwargs)
elif request.user.is_authenticated():
return HttpResponseForbidden('
Permission denied
')
else:
path = '%s?%s=%s' % (login_url, redirect_field_name,
urlquote(request.get_full_path()))
return HttpResponseRedirect(path)
return wrapper
return decorator
def permission_required(perm, login_url=None):
"""Replacement for django.contrib.auth.decorators.permission_required that
returns 403 Forbidden if the user is already logged in.
"""
return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)
###
### Grade tracking
###
class trackGrade(object):
""" This decorator expects that an HttpResponse has a context attribute,
which it uses to retrieve the context. This is passed on to trackGrade.
In order to use this import the following things
from courses.views import render
from courses.decorators import trackGrade
And then decorate a view function, passing a log entry heading to the
decorator.
@trackGrade("Leksa")
def leksa_game(request, place=False):
...
Currently the more detailed behavior of log subheadings is defined in
courses.views.trackGrade.
"""
def __init__(self, log_name):
self.log_name = log_name
def __call__(self, view_function):
""" This must return the HttpResponse from the original function
"""
def decorated_function(*args, **kwargs):
from courses.views import trackGrade
# grab the request, and execute the view function as normal
request = args[0]
response = view_function(*args, **kwargs)
# It may be that the view somehow doesn't have a context argument,
# in this case we don't want to track or return anything
try:
context = response.context
except:
context = False
if context:
if self.log_name:
trackGrade(self.log_name, request, context)
return response
return decorated_function