From 960c8619e5aa76dfb609f049c0bd83bde7c02b6e Mon Sep 17 00:00:00 2001 From: Bridger Maxwell Date: Mon, 16 Jul 2012 13:40:17 -0400 Subject: [PATCH] Added a cache_if_anonymous decorator. --- common/djangoapps/student/views.py | 9 +++-- common/djangoapps/util/cache.py | 40 ++++++++++++++++++++ lms/djangoapps/courseware/views.py | 7 ++-- lms/djangoapps/static_template_view/views.py | 16 ++------ 4 files changed, 53 insertions(+), 19 deletions(-) diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 68e11f098b..b47ee7eee6 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -20,11 +20,12 @@ from django.shortcuts import redirect from mitxmako.shortcuts import render_to_response, render_to_string from django.core.urlresolvers import reverse +from django_future.csrf import ensure_csrf_cookie +from student.models import Registration, UserProfile, PendingNameChange, PendingEmailChange, CourseEnrollment +from util.cache import cache_if_anonymous from xmodule.course_module import CourseDescriptor from xmodule.modulestore.django import modulestore -from django_future.csrf import ensure_csrf_cookie -from models import Registration, UserProfile, PendingNameChange, PendingEmailChange, CourseEnrollment log = logging.getLogger("mitx.student") @@ -39,6 +40,7 @@ def csrf_token(context): @ensure_csrf_cookie +@cache_if_anonymous def index(request): ''' Redirects to main page -- info page if user authenticated, or marketing if not ''' @@ -492,13 +494,14 @@ def accept_name_change(request): @ensure_csrf_cookie +@cache_if_anonymous def course_info(request, course_id): # This is the advertising page for a student to look at the course before signing up csrf_token = csrf(request)['csrf_token'] course_loc = CourseDescriptor.id_to_location(course_id) course = modulestore().get_item(course_loc) # TODO: Couse should be a model - return render_to_response('portal/course_about.html', {'csrf': csrf_token, 'course': course}) + return render_to_response('portal/course_about.html', {'course': course}) @login_required diff --git a/common/djangoapps/util/cache.py b/common/djangoapps/util/cache.py index c6f11f7d66..e253b5b633 100644 --- a/common/djangoapps/util/cache.py +++ b/common/djangoapps/util/cache.py @@ -5,6 +5,8 @@ invalidation. Import these instead of django.core.cache. Note that 'default' is being preserved for user session caching, which we're not migrating so as not to inconvenience users by logging them all out. """ +from functools import wraps + from django.core import cache # If we can't find a 'general' CACHE defined in settings.py, we simply fall back @@ -14,3 +16,41 @@ try: except Exception: cache = cache.cache +def cache_if_anonymous(view_func): + """ + Many of the pages in edX are identical when the user is not logged + in, but should not be cached when the user is logged in (because + of the navigation bar at the top with the username). + + The django middleware cache does not handle this correctly, because + we access the session to put the csrf token in the header. This adds + the cookie to the vary header, and so every page is cached seperately + for each user (because each user has a different csrf token). + + Note that this decorator should only be used on views that do not + contain the csrftoken within the html. The csrf token can be included + in the header by ordering the decorators as such: + + @ensure_csrftoken + @cache_if_anonymous + def myView(request): + """ + + @wraps(view_func) + def _decorated(request, *args, **kwargs): + if not request.user.is_authenticated(): + #Use the cache + cache_key = "cache_if_anonymous." + request.path + response = cache.get(cache_key) + if not response: + response = view_func(request, *args, **kwargs) + cache.set(cache_key, response, 60 * 3) + + return response + + else: + #Don't use the cache + return view_func(request, *args, **kwargs) + + return _decorated + \ No newline at end of file diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py index c011ac7be6..60dc8c0c5f 100644 --- a/lms/djangoapps/courseware/views.py +++ b/lms/djangoapps/courseware/views.py @@ -19,7 +19,7 @@ from multicourse import multicourse_settings from xmodule.modulestore.django import modulestore from xmodule.course_module import CourseDescriptor -from util.cache import cache +from util.cache import cache, cache_if_anonymous from student.models import UserTestGroup from courseware import grades @@ -51,11 +51,10 @@ def format_url_params(params): @ensure_csrf_cookie +@cache_if_anonymous def courses(request): - csrf_token = csrf(request)['csrf_token'] # TODO: Clean up how 'error' is done. - context = {'courses': modulestore().get_courses(), - 'csrf': csrf_token} + context = {'courses': modulestore().get_courses()} return render_to_response("courses.html", context) diff --git a/lms/djangoapps/static_template_view/views.py b/lms/djangoapps/static_template_view/views.py index bef0ab5280..4131434ab7 100644 --- a/lms/djangoapps/static_template_view/views.py +++ b/lms/djangoapps/static_template_view/views.py @@ -8,7 +8,7 @@ from django.shortcuts import redirect from django.conf import settings from django_future.csrf import ensure_csrf_cookie -from util.cache import cache +from util.cache import cache_if_anonymous valid_templates = [] @@ -29,6 +29,7 @@ def index(request, template): return redirect('/') @ensure_csrf_cookie +@cache_if_anonymous def render(request, template): """ This view function renders the template sent without checking that it @@ -36,17 +37,8 @@ def render(request, template): not be able to ender any arbitray template name. The correct usage would be: url(r'^jobs$', 'static_template_view.views.render', {'template': 'jobs.html'}, name="jobs") - """ - cache_key = "static_template_view_render." + template - use_cache = not request.user.is_authenticated() - - response = cache.get(cache_key) if use_cache else None - if not response: - response = render_to_response('static_templates/' + template, {}) - if use_cache: - cache.set(cache_key, response, 60 * 3) - - return response + """ + return render_to_response('static_templates/' + template, {}) valid_auth_templates=['help.html']