diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py index 13079bf9b3..0cdaf7f7e3 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml.py +++ b/common/lib/xmodule/xmodule/modulestore/xml.py @@ -18,10 +18,9 @@ from xmodule.error_module import ErrorDescriptor from xmodule.errortracker import make_error_tracker, exc_info_to_str from xmodule.course_module import CourseDescriptor from xmodule.mako_module import MakoDescriptorSystem -from xmodule.x_module import XMLParsingSystem, prefer_xmodules, policy_key +from xmodule.x_module import XMLParsingSystem, policy_key from xmodule.html_module import HtmlDescriptor -from xblock.core import XBlock from xblock.fields import ScopeIds from xblock.field_data import DictFieldData from xblock.runtime import DictKeyValueStore, IdReader, IdGenerator @@ -222,6 +221,7 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem): # load_item should actually be get_instance, because it expects the course-specific # policy to be loaded. For now, just add the course_id here... def load_item(location): + """Return the XBlock for the specified location""" return xmlstore.get_instance(course_id, Location(location)) resources_fs = OSFS(xmlstore.data_dir / course_dir) @@ -509,6 +509,9 @@ class XMLModuleStore(ModuleStoreReadBase): course_id = CourseDescriptor.make_id(org, course, url_name) def get_policy(usage_id): + """ + Return the policy dictionary to be applied to the specified XBlock usage + """ return policy.get(policy_key(usage_id), {}) system = ImportSystem( @@ -570,9 +573,9 @@ class XMLModuleStore(ModuleStoreReadBase): html = f.read().decode('utf-8') # tabs are referenced in policy.json through a 'slug' which is just the filename without the .html suffix slug = os.path.splitext(os.path.basename(filepath))[0] - loc = course_descriptor.scope_ids.usage_id._replace(category=category, name=slug) - module = system.construct_xblock_from_class( - HtmlDescriptor, + loc = course_descriptor.scope_ids.usage_id.replace(category=category, name=slug) + module = system.construct_xblock( + category, # We're loading a descriptor, so student_id is meaningless # We also don't have separate notions of definition and usage ids yet, # so we use the location for both diff --git a/common/test/data/2014/about/overview.html b/common/test/data/2014/about/overview.html new file mode 100644 index 0000000000..baed9a00c5 --- /dev/null +++ b/common/test/data/2014/about/overview.html @@ -0,0 +1,47 @@ +
+

About This Course

+

Include your long course description here. The long course description should contain 150-400 words. about page 463139

+ +

This is paragraph 2 of the long course description. Add more paragraphs as needed. Make sure to enclose them in paragraph tags.

+
+ +
+

Prerequisites

+

Add information about course prerequisites here.

+
+ +
+

Course Staff

+
+
+ Course Staff Image #1 +
+ +

Staff Member #1

+

Biography of instructor/staff member #1

+
+ +
+
+ Course Staff Image #2 +
+ +

Staff Member #2

+

Biography of instructor/staff member #2

+
+
+ +
+
+

Frequently Asked Questions

+
+

Do I need to buy a textbook?

+

No, a free online version of Chemistry: Principles, Patterns, and Applications, First Edition by Bruce Averill and Patricia Eldredge will be available, though you can purchase a printed version (published by FlatWorld Knowledge) if you’d like.

+
+ +
+

Question #2

+

Your answer would be displayed here.

+
+
+
diff --git a/common/test/data/2014/course.xml b/common/test/data/2014/course.xml new file mode 100644 index 0000000000..1dd468c471 --- /dev/null +++ b/common/test/data/2014/course.xml @@ -0,0 +1 @@ + diff --git a/common/test/data/2014/course/2014.xml b/common/test/data/2014/course/2014.xml new file mode 100644 index 0000000000..8e012e2b0e --- /dev/null +++ b/common/test/data/2014/course/2014.xml @@ -0,0 +1 @@ + diff --git a/common/test/data/2014/info/handouts.html b/common/test/data/2014/info/handouts.html new file mode 100644 index 0000000000..ac601ba576 --- /dev/null +++ b/common/test/data/2014/info/handouts.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/common/test/data/2014/info/updates.html b/common/test/data/2014/info/updates.html new file mode 100644 index 0000000000..2e350c6d3f --- /dev/null +++ b/common/test/data/2014/info/updates.html @@ -0,0 +1 @@ +
    1. January 29, 2014

      course info 463139
    \ No newline at end of file diff --git a/common/test/data/2014/policies/2014/grading_policy.json b/common/test/data/2014/policies/2014/grading_policy.json new file mode 100644 index 0000000000..272cb4fec6 --- /dev/null +++ b/common/test/data/2014/policies/2014/grading_policy.json @@ -0,0 +1 @@ +{"GRADER": [{"short_label": "HW", "min_count": 12, "type": "Homework", "drop_count": 2, "weight": 0.15}, {"min_count": 12, "type": "Lab", "drop_count": 2, "weight": 0.15}, {"short_label": "Midterm", "min_count": 1, "type": "Midterm Exam", "drop_count": 0, "weight": 0.3}, {"short_label": "Final", "min_count": 1, "type": "Final Exam", "drop_count": 0, "weight": 0.4}], "GRADE_CUTOFFS": {"Pass": 0.5}} \ No newline at end of file diff --git a/common/test/data/2014/policies/2014/policy.json b/common/test/data/2014/policies/2014/policy.json new file mode 100644 index 0000000000..26c2f3993c --- /dev/null +++ b/common/test/data/2014/policies/2014/policy.json @@ -0,0 +1,39 @@ +{ + "course/2014": { + "discussion_topics": { + "General": { + "id": "i4x-edX-detached_pages-course-2014" + } + }, + "display_name": "detached_pages", + "end": "2014-01-22T05:00:00Z", + "start": "2013-01-01T00:00:00Z", + "tabs": [ + { + "name": "Courseware", + "type": "courseware" + }, + { + "name": "Course Info", + "type": "course_info" + }, + { + "name": "Discussion", + "type": "discussion" + }, + { + "name": "Wiki", + "type": "wiki" + }, + { + "name": "Progress", + "type": "progress" + }, + { + "name": "Empty", + "type": "static_tab", + "url_slug": "8e4cce2b4aaf4ba28b1220804619e41f" + } + ] + } +} \ No newline at end of file diff --git a/common/test/data/2014/policies/assets.json b/common/test/data/2014/policies/assets.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/common/test/data/2014/policies/assets.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/common/test/data/2014/tabs/8e4cce2b4aaf4ba28b1220804619e41f.html b/common/test/data/2014/tabs/8e4cce2b4aaf4ba28b1220804619e41f.html new file mode 100644 index 0000000000..db06449a3c --- /dev/null +++ b/common/test/data/2014/tabs/8e4cce2b4aaf4ba28b1220804619e41f.html @@ -0,0 +1 @@ +

    static 463139

    \ No newline at end of file diff --git a/lms/djangoapps/courseware/tests/modulestore_config.py b/lms/djangoapps/courseware/tests/modulestore_config.py index d82fd5f8da..c8d3cb7097 100644 --- a/lms/djangoapps/courseware/tests/modulestore_config.py +++ b/lms/djangoapps/courseware/tests/modulestore_config.py @@ -25,5 +25,6 @@ MAPPINGS = { 'edX/open_ended/2012_Fall': 'xml', 'edX/due_date/2013_fall': 'xml', 'edX/open_ended_nopath/2012_Fall': 'xml', + 'edX/detached_pages/2014': 'xml', } TEST_DATA_MIXED_MODULESTORE = mixed_store_config(TEST_DATA_DIR, MAPPINGS) diff --git a/lms/djangoapps/courseware/tests/test_about.py b/lms/djangoapps/courseware/tests/test_about.py index 7a4a036a17..9e6354dd3f 100644 --- a/lms/djangoapps/courseware/tests/test_about.py +++ b/lms/djangoapps/courseware/tests/test_about.py @@ -1,6 +1,7 @@ """ Test the about xblock """ +import mock from django.test.utils import override_settings from django.core.urlresolvers import reverse @@ -18,6 +19,10 @@ class AboutTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase): category="about", parent_location=self.course.location, data="OOGIE BLOOGIE", display_name="overview" ) + # The following XML course is closed; we're testing that + # an about page still appears when the course is already closed + self.xml_course_id = 'edX/detached_pages/2014' + self.xml_data = "about page 463139" def test_logged_in(self): self.setup_user() @@ -31,3 +36,18 @@ class AboutTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase): resp = self.client.get(url) self.assertEqual(resp.status_code, 200) self.assertIn("OOGIE BLOOGIE", resp.content) + + @mock.patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False}) + def test_logged_in_xml(self): + self.setup_user() + url = reverse('about_course', args=[self.xml_course_id]) + resp = self.client.get(url) + self.assertEqual(resp.status_code, 200) + self.assertIn(self.xml_data, resp.content) + + @mock.patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False}) + def test_anonymous_user_xml(self): + url = reverse('about_course', args=[self.xml_course_id]) + resp = self.client.get(url) + self.assertEqual(resp.status_code, 200) + self.assertIn(self.xml_data, resp.content) diff --git a/lms/djangoapps/courseware/tests/test_course_info.py b/lms/djangoapps/courseware/tests/test_course_info.py index b47c3a73ca..661bb28ca1 100644 --- a/lms/djangoapps/courseware/tests/test_course_info.py +++ b/lms/djangoapps/courseware/tests/test_course_info.py @@ -1,6 +1,7 @@ """ Test the course_info xblock """ +import mock from django.test.utils import override_settings from django.core.urlresolvers import reverse @@ -18,6 +19,10 @@ class CourseInfoTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase): category="course_info", parent_location=self.course.location, data="OOGIE BLOOGIE", display_name="updates" ) + # The following XML course is closed; we're testing that + # a course info page still appears when the course is already closed + self.xml_data = "course info 463139" + self.xml_course_id = "edX/detached_pages/2014" def test_logged_in(self): self.setup_user() @@ -31,3 +36,18 @@ class CourseInfoTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase): resp = self.client.get(url) self.assertEqual(resp.status_code, 200) self.assertNotIn("OOGIE BLOOGIE", resp.content) + + @mock.patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False}) + def test_logged_in_xml(self): + self.setup_user() + url = reverse('info', args=[self.xml_course_id]) + resp = self.client.get(url) + self.assertEqual(resp.status_code, 200) + self.assertIn(self.xml_data, resp.content) + + @mock.patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False}) + def test_anonymous_user_xml(self): + url = reverse('info', args=[self.xml_course_id]) + resp = self.client.get(url) + self.assertEqual(resp.status_code, 200) + self.assertNotIn(self.xml_data, resp.content) diff --git a/lms/djangoapps/courseware/tests/test_tabs.py b/lms/djangoapps/courseware/tests/test_tabs.py index 501185714b..31da4fd581 100644 --- a/lms/djangoapps/courseware/tests/test_tabs.py +++ b/lms/djangoapps/courseware/tests/test_tabs.py @@ -155,6 +155,11 @@ class StaticTabDateTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase): category="static_tab", parent_location=self.course.location, data="OOGIE BLOOGIE", display_name="new_tab" ) + # The following XML course is closed; we're testing that + # static tabs still appear when the course is already closed + self.xml_data = "static 463139" + self.xml_url = "8e4cce2b4aaf4ba28b1220804619e41f" + self.xml_course_id = 'edX/detached_pages/2014' def test_logged_in(self): self.setup_user() @@ -169,6 +174,21 @@ class StaticTabDateTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase): self.assertEqual(resp.status_code, 200) self.assertIn("OOGIE BLOOGIE", resp.content) + @patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False}) + def test_logged_in_xml(self): + self.setup_user() + url = reverse('static_tab', args=[self.xml_course_id, self.xml_url]) + resp = self.client.get(url) + self.assertEqual(resp.status_code, 200) + self.assertIn(self.xml_data, resp.content) + + @patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False}) + def test_anonymous_user_xml(self): + url = reverse('static_tab', args=[self.xml_course_id, self.xml_url]) + resp = self.client.get(url) + self.assertEqual(resp.status_code, 200) + self.assertIn(self.xml_data, resp.content) + class TextbooksTestCase(TestCase):