diff --git a/common/djangoapps/contentserver/middleware.py b/common/djangoapps/contentserver/middleware.py index d89e3fdd23..0174c39fea 100644 --- a/common/djangoapps/contentserver/middleware.py +++ b/common/djangoapps/contentserver/middleware.py @@ -1,4 +1,6 @@ from django.http import HttpResponse, HttpResponseNotModified +from django.shortcuts import redirect +from student.models import CourseEnrollment from xmodule.contentstore.django import contentstore from xmodule.contentstore.content import StaticContent, XASSET_LOCATION_TAG @@ -20,7 +22,8 @@ class StaticContentServer(object): return response # first look in our cache so we don't have to round-trip to the DB - content = get_cached_content(loc) + #content = get_cached_content(loc) + content = None if content is None: # nope, not in cache, let's fetch from DB try: @@ -41,6 +44,15 @@ class StaticContentServer(object): # NOP here, but we may wish to add a "cache-hit" counter in the future pass + # Check that user has access to content + if getattr(content, "locked", False): + if not hasattr(request, "user") or not request.user.is_authenticated(): + return redirect('root') + course_id = "/".join([loc.org, loc.course, loc.name]) + if not CourseEnrollment.is_enrolled(request.user, course_id): + return redirect('dashboard') + + # see if the last-modified at hasn't changed, if not return a 302 (Not Modified) # convert over the DB persistent last modified timestamp to a HTTP compatible diff --git a/common/djangoapps/contentserver/tests/__init__.py b/common/djangoapps/contentserver/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/common/djangoapps/contentserver/tests/test.py b/common/djangoapps/contentserver/tests/test.py new file mode 100644 index 0000000000..d084494be3 --- /dev/null +++ b/common/djangoapps/contentserver/tests/test.py @@ -0,0 +1,118 @@ +""" +Tests for StaticContentServer +""" +import copy +import logging +from uuid import uuid4 +from path import path +from pymongo import MongoClient + +from django.contrib.auth.models import User +from django.conf import settings +from django.core.urlresolvers import reverse +from django.test.client import Client +from django.test.utils import override_settings + +from student.models import CourseEnrollment + +from xmodule.contentstore.django import contentstore, _CONTENTSTORE +from xmodule.modulestore import Location +from xmodule.contentstore.content import StaticContent +from xmodule.modulestore.django import modulestore +from xmodule.modulestore.tests.django_utils import (studio_store_config, + ModuleStoreTestCase) +from xmodule.modulestore.xml_importer import import_from_xml + +log = logging.getLogger(__name__) + +TEST_DATA_CONTENTSTORE = copy.deepcopy(settings.CONTENTSTORE) +TEST_DATA_CONTENTSTORE['OPTIONS']['db'] = 'test_xcontent_%s' % uuid4().hex + +TEST_MODULESTORE = studio_store_config(settings.TEST_ROOT / "data") + + +@override_settings(CONTENTSTORE=TEST_DATA_CONTENTSTORE, MODULESTORE=TEST_MODULESTORE) +class ContentStoreToyCourseTest(ModuleStoreTestCase): + """ + Tests that use the toy course. + """ + + def setUp(self): + """ + Create user and login. + """ + + settings.MODULESTORE['default']['OPTIONS']['fs_root'] = path('common/test/data') + settings.MODULESTORE['direct']['OPTIONS']['fs_root'] = path('common/test/data') + + self.client = Client() + + loc = Location('c4x', 'edX', 'toy', 'asset', 'sample_static.txt' ) + self.loc = loc + + rel_url = StaticContent.get_url_path_from_location(loc) + base = "http://127.0.0.1:8000" + + self.contentstore = contentstore() + import_from_xml(modulestore('direct'), 'common/test/data/', ['toy'], + static_content_store=self.contentstore, verbose=True) + self.url = base + rel_url + + def tearDown(self): + + MongoClient().drop_database(TEST_DATA_CONTENTSTORE['OPTIONS']['db']) + _CONTENTSTORE.clear() + + def test_aunlocked_asset(self): + """ + Test that unlocked assets are being served. + """ + # Unlock the asset + self.contentstore.set_attr(self.loc, 'locked', False) + resp = self.client.get(self.url) + self.assertEqual(resp.status_code, 200) + + + def test_locked_asset(self): + """ + Test that locked assets behave appropriately in case: + (1) User is not logged in + (2) User is logged in in but not registerd for the course + (3) User is logged in and registered + """ + + # Lock the asset + self.contentstore.set_attr(self.loc, 'locked', True) + + + # Case (1) + resp = self.client.get(self.url) + self.assertEqual(resp.status_code, 302) + self.assertTrue(resp.has_header("LOCATION")) + + # Case (2) + # Create user and login + uname = 'testuser' + email = 'test+courses@edx.org' + password = 'foo' + user = User.objects.create_user(uname, email, password) + user.is_active = True + user.save() + self.client.login(username=uname, password=password) + log.debug("User logged in") + + resp = self.client.get(self.url) + log.debug("Received response %s", resp) + self.assertEqual(resp.status_code, 302) + self.assertTrue(resp.has_header("LOCATION")) + self.assertIn("dashboard", resp["LOCATION"]) + + # Case (3) + # Enroll student + course_id = "/".join([self.loc.org, self.loc.course, self.loc.name]) + self.assertTrue(CourseEnrollment.enroll(user, course_id)) + self.assertTrue(CourseEnrollment.is_enrolled(user, course_id)) + + resp = self.client.get(self.url) + self.assertEqual(resp.status_code, 200) + diff --git a/lms/envs/test.py b/lms/envs/test.py index 94feffdf3e..45e934ec1f 100644 --- a/lms/envs/test.py +++ b/lms/envs/test.py @@ -97,6 +97,13 @@ MODULESTORE = { } } +CONTENTSTORE = { + 'ENGINE': 'xmodule.contentstore.mongo.MongoContentStore', + 'OPTIONS': { + 'host': 'localhost', + 'db': 'xcontent', + } +} DATABASES = { 'default': {