""" 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