Files
edx-platform/lms/djangoapps/course_wiki/middleware.py
2018-01-08 13:51:42 -05:00

112 lines
5.2 KiB
Python

"""Middleware for course_wiki"""
from urlparse import urlparse
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.http import Http404
from django.shortcuts import redirect
from six import text_type
from wiki.models import reverse
from courseware.access import has_access
from courseware.courses import get_course_overview_with_access, get_course_with_access
from openedx.features.enterprise_support.api import get_enterprise_consent_url
from student.models import CourseEnrollment
from util.request import course_id_from_url
class WikiAccessMiddleware(object):
"""
This middleware wraps calls to django-wiki in order to handle authentication and redirection
between the root wiki and the course wikis.
TODO: removing the "root wiki" would obviate the need for this middleware; it could be replaced
with a wrapper function around the wiki views. This is currently difficult or impossible to do
because there are two sets of wiki urls loaded in urls.py
"""
def _redirect_from_referrer(self, request, wiki_path):
"""
redirect to course wiki url if the referrer is from a course page
"""
course_id = course_id_from_url(request.META.get('HTTP_REFERER'))
if course_id:
# See if we are able to view the course. If we are, redirect to it
try:
get_course_overview_with_access(request.user, 'load', course_id)
return redirect("/courses/{course_id}/wiki/{path}".format(course_id=text_type(course_id), path=wiki_path))
except Http404:
# Even though we came from the course, we can't see it. So don't worry about it.
pass
def process_view(self, request, view_func, view_args, view_kwargs): # pylint: disable=unused-argument
"""
This function handles authentication logic for wiki urls and redirects from
the "root wiki" to the "course wiki" if the user accesses the wiki from a course url
"""
# we care only about requests to wiki urls
if not view_func.__module__.startswith('wiki.'):
return
# wiki pages are login required
if not request.user.is_authenticated():
return redirect(reverse('signin_user'), next=request.path)
course_id = course_id_from_url(request.path)
wiki_path = request.path.partition('/wiki/')[2]
if course_id:
# This is a /courses/org/name/run/wiki request
course_path = "/courses/{}".format(text_type(course_id))
# HACK: django-wiki monkeypatches the reverse function to enable
# urls to be rewritten
reverse._transform_url = lambda url: course_path + url # pylint: disable=protected-access
# Authorization Check
# Let's see if user is enrolled or the course allows for public access
try:
course = get_course_with_access(request.user, 'load', course_id)
except Http404:
# course does not exist. redirect to root wiki.
# clearing the referrer will cause process_response not to redirect
# back to a non-existent course
request.META['HTTP_REFERER'] = ''
return redirect('/wiki/{}'.format(wiki_path))
if not course.allow_public_wiki_access:
is_enrolled = CourseEnrollment.is_enrolled(request.user, course.id)
is_staff = has_access(request.user, 'staff', course)
if not (is_enrolled or is_staff):
# if a user is logged in, but not authorized to see a page,
# we'll redirect them to the course about page
return redirect('about_course', text_type(course_id))
# If we need enterprise data sharing consent for this course, then redirect to the form.
consent_url = get_enterprise_consent_url(request, text_type(course_id))
if consent_url:
return redirect(consent_url)
# set the course onto here so that the wiki template can show the course navigation
request.course = course
else:
# this is a request for /wiki/...
# Check to see if we don't allow top-level access to the wiki via the /wiki/xxxx/yyy/zzz URLs
# this will help prevent people from writing pell-mell to the Wiki in an unstructured way
if not settings.FEATURES.get('ALLOW_WIKI_ROOT_ACCESS', False):
raise PermissionDenied()
return self._redirect_from_referrer(request, wiki_path)
def process_response(self, request, response):
"""
Modify the redirect from /wiki/123 to /course/foo/bar/wiki/123/
if the referrer comes from a course page
"""
if response.status_code == 302 and response['Location'].startswith('/wiki/'):
wiki_path = urlparse(response['Location']).path.split('/wiki/', 1)[1]
response = self._redirect_from_referrer(request, wiki_path) or response
# END HACK: _transform_url must be set to a no-op function after it's done its work
reverse._transform_url = lambda url: url # pylint: disable=protected-access
return response