""" 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_to_response
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 univ_oahpa.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