Merge pull request #2017 from edx/fix/cdodge/textbooks-not-exporting
Fix/cdodge/textbooks not exporting
This commit is contained in:
@@ -220,6 +220,14 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
|
|||||||
num_drafts = self._get_draft_counts(course)
|
num_drafts = self._get_draft_counts(course)
|
||||||
self.assertEqual(num_drafts, 1)
|
self.assertEqual(num_drafts, 1)
|
||||||
|
|
||||||
|
def test_import_textbook_as_content_element(self):
|
||||||
|
import_from_xml(modulestore(), 'common/test/data/', ['full'])
|
||||||
|
|
||||||
|
module_store = modulestore('direct')
|
||||||
|
course = module_store.get_item(Location(['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None]))
|
||||||
|
|
||||||
|
self.assertGreater(len(course.textbooks), 0)
|
||||||
|
|
||||||
def test_static_tab_reordering(self):
|
def test_static_tab_reordering(self):
|
||||||
import_from_xml(modulestore(), 'common/test/data/', ['full'])
|
import_from_xml(modulestore(), 'common/test/data/', ['full'])
|
||||||
|
|
||||||
@@ -293,7 +301,6 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
|
|||||||
# make sure the parent no longer points to the child object which was deleted
|
# make sure the parent no longer points to the child object which was deleted
|
||||||
self.assertFalse(sequential.location.url() in chapter.children)
|
self.assertFalse(sequential.location.url() in chapter.children)
|
||||||
|
|
||||||
|
|
||||||
def test_about_overrides(self):
|
def test_about_overrides(self):
|
||||||
'''
|
'''
|
||||||
This test case verifies that a course can use specialized override for about data, e.g. /about/Fall_2012/effort.html
|
This test case verifies that a course can use specialized override for about data, e.g. /about/Fall_2012/effort.html
|
||||||
@@ -490,6 +497,11 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
|
|||||||
|
|
||||||
self.assertTrue(getattr(test_private_vertical, 'is_draft', False))
|
self.assertTrue(getattr(test_private_vertical, 'is_draft', False))
|
||||||
|
|
||||||
|
# make sure the textbook survived the export/import
|
||||||
|
course = module_store.get_item(Location(['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None]))
|
||||||
|
|
||||||
|
self.assertGreater(len(course.textbooks), 0)
|
||||||
|
|
||||||
shutil.rmtree(root_dir)
|
shutil.rmtree(root_dir)
|
||||||
|
|
||||||
def test_course_handouts_rewrites(self):
|
def test_course_handouts_rewrites(self):
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ class CourseUpdateTest(CourseTestCase):
|
|||||||
'''Go through each interface and ensure it works.'''
|
'''Go through each interface and ensure it works.'''
|
||||||
# first get the update to force the creation
|
# first get the update to force the creation
|
||||||
url = reverse('course_info',
|
url = reverse('course_info',
|
||||||
kwargs={'org': self.course_location.org,
|
kwargs={'org': self.course_location.org,
|
||||||
'course': self.course_location.course,
|
'course': self.course_location.course,
|
||||||
'name': self.course_location.name})
|
'name': self.course_location.name})
|
||||||
self.client.get(url)
|
self.client.get(url)
|
||||||
|
|
||||||
init_content = '<iframe width="560" height="315" src="http://www.youtube.com/embed/RocY-Jd93XU" frameborder="0">'
|
init_content = '<iframe width="560" height="315" src="http://www.youtube.com/embed/RocY-Jd93XU" frameborder="0">'
|
||||||
@@ -20,9 +20,9 @@ class CourseUpdateTest(CourseTestCase):
|
|||||||
payload = {'content': content,
|
payload = {'content': content,
|
||||||
'date': 'January 8, 2013'}
|
'date': 'January 8, 2013'}
|
||||||
url = reverse('course_info_json',
|
url = reverse('course_info_json',
|
||||||
kwargs={'org': self.course_location.org,
|
kwargs={'org': self.course_location.org,
|
||||||
'course': self.course_location.course,
|
'course': self.course_location.course,
|
||||||
'provided_id': ''})
|
'provided_id': ''})
|
||||||
|
|
||||||
resp = self.client.post(url, json.dumps(payload), "application/json")
|
resp = self.client.post(url, json.dumps(payload), "application/json")
|
||||||
|
|
||||||
@@ -31,25 +31,25 @@ class CourseUpdateTest(CourseTestCase):
|
|||||||
self.assertHTMLEqual(payload['content'], content)
|
self.assertHTMLEqual(payload['content'], content)
|
||||||
|
|
||||||
first_update_url = reverse('course_info_json',
|
first_update_url = reverse('course_info_json',
|
||||||
kwargs={'org': self.course_location.org,
|
kwargs={'org': self.course_location.org,
|
||||||
'course': self.course_location.course,
|
'course': self.course_location.course,
|
||||||
'provided_id': payload['id']})
|
'provided_id': payload['id']})
|
||||||
content += '<div>div <p>p<br/></p></div>'
|
content += '<div>div <p>p<br/></p></div>'
|
||||||
payload['content'] = content
|
payload['content'] = content
|
||||||
resp = self.client.post(first_update_url, json.dumps(payload),
|
resp = self.client.post(first_update_url, json.dumps(payload),
|
||||||
"application/json")
|
"application/json")
|
||||||
|
|
||||||
self.assertHTMLEqual(content, json.loads(resp.content)['content'],
|
self.assertHTMLEqual(content, json.loads(resp.content)['content'],
|
||||||
"iframe w/ div")
|
"iframe w/ div")
|
||||||
|
|
||||||
# now put in an evil update
|
# now put in an evil update
|
||||||
content = '<ol/>'
|
content = '<ol/>'
|
||||||
payload = {'content': content,
|
payload = {'content': content,
|
||||||
'date': 'January 11, 2013'}
|
'date': 'January 11, 2013'}
|
||||||
url = reverse('course_info_json',
|
url = reverse('course_info_json',
|
||||||
kwargs={'org': self.course_location.org,
|
kwargs={'org': self.course_location.org,
|
||||||
'course': self.course_location.course,
|
'course': self.course_location.course,
|
||||||
'provided_id': ''})
|
'provided_id': ''})
|
||||||
|
|
||||||
resp = self.client.post(url, json.dumps(payload), "application/json")
|
resp = self.client.post(url, json.dumps(payload), "application/json")
|
||||||
|
|
||||||
@@ -58,25 +58,24 @@ class CourseUpdateTest(CourseTestCase):
|
|||||||
self.assertHTMLEqual(content, payload['content'], "self closing ol")
|
self.assertHTMLEqual(content, payload['content'], "self closing ol")
|
||||||
|
|
||||||
url = reverse('course_info_json',
|
url = reverse('course_info_json',
|
||||||
kwargs={'org': self.course_location.org,
|
kwargs={'org': self.course_location.org,
|
||||||
'course': self.course_location.course,
|
'course': self.course_location.course,
|
||||||
'provided_id': ''})
|
'provided_id': ''})
|
||||||
resp = self.client.get(url)
|
resp = self.client.get(url)
|
||||||
payload = json.loads(resp.content)
|
payload = json.loads(resp.content)
|
||||||
self.assertTrue(len(payload) == 2)
|
self.assertTrue(len(payload) == 2)
|
||||||
|
|
||||||
# can't test non-json paylod b/c expect_json throws error
|
# can't test non-json paylod b/c expect_json throws error
|
||||||
# try json w/o required fields
|
# try json w/o required fields
|
||||||
self.assertContains(
|
self.assertContains(self.client.post(url, json.dumps({'garbage': 1}),
|
||||||
self.client.post(url, json.dumps({'garbage': 1}),
|
"application/json"),
|
||||||
"application/json"),
|
'Failed to save', status_code=400)
|
||||||
'Failed to save', status_code=400)
|
|
||||||
|
|
||||||
# now try to update a non-existent update
|
# now try to update a non-existent update
|
||||||
url = reverse('course_info_json',
|
url = reverse('course_info_json',
|
||||||
kwargs={'org': self.course_location.org,
|
kwargs={'org': self.course_location.org,
|
||||||
'course': self.course_location.course,
|
'course': self.course_location.course,
|
||||||
'provided_id': '9'})
|
'provided_id': '9'})
|
||||||
content = 'blah blah'
|
content = 'blah blah'
|
||||||
payload = {'content': content,
|
payload = {'content': content,
|
||||||
'date': 'January 21, 2013'}
|
'date': 'January 21, 2013'}
|
||||||
@@ -89,8 +88,8 @@ class CourseUpdateTest(CourseTestCase):
|
|||||||
payload = {'content': content,
|
payload = {'content': content,
|
||||||
'date': 'January 11, 2013'}
|
'date': 'January 11, 2013'}
|
||||||
url = reverse('course_info_json', kwargs={'org': self.course_location.org,
|
url = reverse('course_info_json', kwargs={'org': self.course_location.org,
|
||||||
'course': self.course_location.course,
|
'course': self.course_location.course,
|
||||||
'provided_id': ''})
|
'provided_id': ''})
|
||||||
|
|
||||||
self.assertContains(
|
self.assertContains(
|
||||||
self.client.post(url, json.dumps(payload), "application/json"),
|
self.client.post(url, json.dumps(payload), "application/json"),
|
||||||
@@ -101,8 +100,8 @@ class CourseUpdateTest(CourseTestCase):
|
|||||||
payload = {'content': content,
|
payload = {'content': content,
|
||||||
'date': 'January 11, 2013'}
|
'date': 'January 11, 2013'}
|
||||||
url = reverse('course_info_json', kwargs={'org': self.course_location.org,
|
url = reverse('course_info_json', kwargs={'org': self.course_location.org,
|
||||||
'course': self.course_location.course,
|
'course': self.course_location.course,
|
||||||
'provided_id': ''})
|
'provided_id': ''})
|
||||||
|
|
||||||
resp = self.client.post(url, json.dumps(payload), "application/json")
|
resp = self.client.post(url, json.dumps(payload), "application/json")
|
||||||
payload = json.loads(resp.content)
|
payload = json.loads(resp.content)
|
||||||
@@ -110,8 +109,8 @@ class CourseUpdateTest(CourseTestCase):
|
|||||||
|
|
||||||
# now try to delete a non-existent update
|
# now try to delete a non-existent update
|
||||||
url = reverse('course_info_json', kwargs={'org': self.course_location.org,
|
url = reverse('course_info_json', kwargs={'org': self.course_location.org,
|
||||||
'course': self.course_location.course,
|
'course': self.course_location.course,
|
||||||
'provided_id': '19'})
|
'provided_id': '19'})
|
||||||
payload = {'content': content,
|
payload = {'content': content,
|
||||||
'date': 'January 21, 2013'}
|
'date': 'January 21, 2013'}
|
||||||
self.assertContains(self.client.delete(url), "delete", status_code=400)
|
self.assertContains(self.client.delete(url), "delete", status_code=400)
|
||||||
@@ -121,25 +120,25 @@ class CourseUpdateTest(CourseTestCase):
|
|||||||
payload = {'content': content,
|
payload = {'content': content,
|
||||||
'date': 'January 28, 2013'}
|
'date': 'January 28, 2013'}
|
||||||
url = reverse('course_info_json', kwargs={'org': self.course_location.org,
|
url = reverse('course_info_json', kwargs={'org': self.course_location.org,
|
||||||
'course': self.course_location.course,
|
'course': self.course_location.course,
|
||||||
'provided_id': ''})
|
'provided_id': ''})
|
||||||
resp = self.client.post(url, json.dumps(payload), "application/json")
|
resp = self.client.post(url, json.dumps(payload), "application/json")
|
||||||
payload = json.loads(resp.content)
|
payload = json.loads(resp.content)
|
||||||
this_id = payload['id']
|
this_id = payload['id']
|
||||||
self.assertHTMLEqual(content, payload['content'], "single iframe")
|
self.assertHTMLEqual(content, payload['content'], "single iframe")
|
||||||
# first count the entries
|
# first count the entries
|
||||||
url = reverse('course_info_json',
|
url = reverse('course_info_json',
|
||||||
kwargs={'org': self.course_location.org,
|
kwargs={'org': self.course_location.org,
|
||||||
'course': self.course_location.course,
|
'course': self.course_location.course,
|
||||||
'provided_id': ''})
|
'provided_id': ''})
|
||||||
resp = self.client.get(url)
|
resp = self.client.get(url)
|
||||||
payload = json.loads(resp.content)
|
payload = json.loads(resp.content)
|
||||||
before_delete = len(payload)
|
before_delete = len(payload)
|
||||||
|
|
||||||
url = reverse('course_info_json',
|
url = reverse('course_info_json',
|
||||||
kwargs={'org': self.course_location.org,
|
kwargs={'org': self.course_location.org,
|
||||||
'course': self.course_location.course,
|
'course': self.course_location.course,
|
||||||
'provided_id': this_id})
|
'provided_id': this_id})
|
||||||
resp = self.client.delete(url)
|
resp = self.client.delete(url)
|
||||||
payload = json.loads(resp.content)
|
payload = json.loads(resp.content)
|
||||||
self.assertTrue(len(payload) == before_delete - 1)
|
self.assertTrue(len(payload) == before_delete - 1)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from django.test.client import Client
|
|||||||
|
|
||||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||||
|
|
||||||
|
|
||||||
class InternationalizationTest(ModuleStoreTestCase):
|
class InternationalizationTest(ModuleStoreTestCase):
|
||||||
"""
|
"""
|
||||||
Tests to validate Internationalization.
|
Tests to validate Internationalization.
|
||||||
@@ -38,34 +39,33 @@ class InternationalizationTest(ModuleStoreTestCase):
|
|||||||
'org': 'MITx',
|
'org': 'MITx',
|
||||||
'number': '999',
|
'number': '999',
|
||||||
'display_name': 'Robot Super Course',
|
'display_name': 'Robot Super Course',
|
||||||
}
|
}
|
||||||
|
|
||||||
def test_course_plain_english(self):
|
def test_course_plain_english(self):
|
||||||
"""Test viewing the index page with no courses"""
|
"""Test viewing the index page with no courses"""
|
||||||
self.client = Client()
|
self.client = Client()
|
||||||
self.client.login(username=self.uname, password=self.password)
|
self.client.login(username=self.uname, password=self.password)
|
||||||
|
|
||||||
resp = self.client.get(reverse('index'))
|
resp = self.client.get(reverse('index'))
|
||||||
self.assertContains(resp,
|
self.assertContains(resp,
|
||||||
'<h1 class="title-1">My Courses</h1>',
|
'<h1 class="title-1">My Courses</h1>',
|
||||||
status_code=200,
|
status_code=200,
|
||||||
html=True)
|
html=True)
|
||||||
|
|
||||||
def test_course_explicit_english(self):
|
def test_course_explicit_english(self):
|
||||||
"""Test viewing the index page with no courses"""
|
"""Test viewing the index page with no courses"""
|
||||||
self.client = Client()
|
self.client = Client()
|
||||||
self.client.login(username=self.uname, password=self.password)
|
self.client.login(username=self.uname, password=self.password)
|
||||||
|
|
||||||
resp = self.client.get(reverse('index'),
|
resp = self.client.get(reverse('index'),
|
||||||
{},
|
{},
|
||||||
HTTP_ACCEPT_LANGUAGE='en'
|
HTTP_ACCEPT_LANGUAGE='en'
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertContains(resp,
|
self.assertContains(resp,
|
||||||
'<h1 class="title-1">My Courses</h1>',
|
'<h1 class="title-1">My Courses</h1>',
|
||||||
status_code=200,
|
status_code=200,
|
||||||
html=True)
|
html=True)
|
||||||
|
|
||||||
|
|
||||||
# ****
|
# ****
|
||||||
# NOTE:
|
# NOTE:
|
||||||
@@ -74,14 +74,13 @@ class InternationalizationTest(ModuleStoreTestCase):
|
|||||||
# This test will break when we replace this fake 'test' language
|
# This test will break when we replace this fake 'test' language
|
||||||
# with actual French. This test will need to be updated with
|
# with actual French. This test will need to be updated with
|
||||||
# actual French at that time.
|
# actual French at that time.
|
||||||
|
|
||||||
# Test temporarily disable since it depends on creation of dummy strings
|
# Test temporarily disable since it depends on creation of dummy strings
|
||||||
@skip
|
@skip
|
||||||
def test_course_with_accents (self):
|
def test_course_with_accents(self):
|
||||||
"""Test viewing the index page with no courses"""
|
"""Test viewing the index page with no courses"""
|
||||||
self.client = Client()
|
self.client = Client()
|
||||||
self.client.login(username=self.uname, password=self.password)
|
self.client.login(username=self.uname, password=self.password)
|
||||||
|
|
||||||
resp = self.client.get(reverse('index'),
|
resp = self.client.get(reverse('index'),
|
||||||
{},
|
{},
|
||||||
HTTP_ACCEPT_LANGUAGE='fr'
|
HTTP_ACCEPT_LANGUAGE='fr'
|
||||||
@@ -90,8 +89,8 @@ class InternationalizationTest(ModuleStoreTestCase):
|
|||||||
TEST_STRING = u'<h1 class="title-1">' \
|
TEST_STRING = u'<h1 class="title-1">' \
|
||||||
+ u'My \xc7\xf6\xfcrs\xe9s L#' \
|
+ u'My \xc7\xf6\xfcrs\xe9s L#' \
|
||||||
+ u'</h1>'
|
+ u'</h1>'
|
||||||
|
|
||||||
self.assertContains(resp,
|
self.assertContains(resp,
|
||||||
TEST_STRING,
|
TEST_STRING,
|
||||||
status_code=200,
|
status_code=200,
|
||||||
html=True)
|
html=True)
|
||||||
|
|||||||
@@ -382,6 +382,19 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
|
|||||||
|
|
||||||
return definition, children
|
return definition, children
|
||||||
|
|
||||||
|
def definition_to_xml(self, resource_fs):
|
||||||
|
xml_object = super(CourseDescriptor, self).definition_to_xml(resource_fs)
|
||||||
|
|
||||||
|
if len(self.textbooks) > 0:
|
||||||
|
textbook_xml_object = etree.Element('textbook')
|
||||||
|
for textbook in self.textbooks:
|
||||||
|
textbook_xml_object.set('title', textbook.title)
|
||||||
|
textbook_xml_object.set('book_url', textbook.book_url)
|
||||||
|
|
||||||
|
xml_object.append(textbook_xml_object)
|
||||||
|
|
||||||
|
return xml_object
|
||||||
|
|
||||||
def has_ended(self):
|
def has_ended(self):
|
||||||
"""
|
"""
|
||||||
Returns True if the current time is after the specified course end date.
|
Returns True if the current time is after the specified course end date.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<course filename="6.002_Spring_2012" slug="6.002_Spring_2012" graceperiod="1 day 12 hours 59 minutes 59 seconds" showanswer="attempted" rerandomize="never" name="6.002 Spring 2012" start="2015-07-17T12:00" course="full" org="edX"/>
|
<course filename="6.002_Spring_2012" slug="6.002_Spring_2012" graceperiod="1 day 12 hours 59 minutes 59 seconds" showanswer="attempted" rerandomize="never" name="6.002 Spring 2012" start="2015-07-17T12:00" course="full" org="edX" />
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<sequential>
|
<course>
|
||||||
|
<textbook title="Textbook" book_url="https://s3.amazonaws.com/edx-textbooks/guttag_computation_v3/"/>
|
||||||
<chapter filename="Overview" slug="Overview" graceperiod="1 day 12 hours 59 minutes 59 seconds" showanswer="attempted" rerandomize="never" name="Overview"/>
|
<chapter filename="Overview" slug="Overview" graceperiod="1 day 12 hours 59 minutes 59 seconds" showanswer="attempted" rerandomize="never" name="Overview"/>
|
||||||
<chapter filename="Week_1" slug="Week_1" graceperiod="1 day 12 hours 59 minutes 59 seconds" showanswer="attempted" rerandomize="never" name="Week 1"/>
|
<chapter filename="Week_1" slug="Week_1" graceperiod="1 day 12 hours 59 minutes 59 seconds" showanswer="attempted" rerandomize="never" name="Week 1"/>
|
||||||
<chapter slug="Midterm_Exam" graceperiod="1 day 12 hours 59 minutes 59 seconds" showanswer="attempted" rerandomize="never" name="Midterm Exam">
|
<chapter slug="Midterm_Exam" graceperiod="1 day 12 hours 59 minutes 59 seconds" showanswer="attempted" rerandomize="never" name="Midterm Exam">
|
||||||
@@ -9,4 +10,4 @@
|
|||||||
<vertical filename="vertical_98" slug="vertical_1124" graceperiod="0 day 0 hours 5 minutes 0 seconds" showanswer="attempted" rerandomize="per_student" due="April 30, 12:00" graded="true"/>
|
<vertical filename="vertical_98" slug="vertical_1124" graceperiod="0 day 0 hours 5 minutes 0 seconds" showanswer="attempted" rerandomize="per_student" due="April 30, 12:00" graded="true"/>
|
||||||
</sequential>
|
</sequential>
|
||||||
</chapter>
|
</chapter>
|
||||||
</sequential>
|
</course>
|
||||||
|
|||||||
@@ -399,6 +399,14 @@ class TestCoursesLoadTestCase_MongoModulestore(PageLoaderTestCase):
|
|||||||
import_from_xml(module_store, TEST_DATA_DIR, ['toy'])
|
import_from_xml(module_store, TEST_DATA_DIR, ['toy'])
|
||||||
self.check_random_page_loads(module_store)
|
self.check_random_page_loads(module_store)
|
||||||
|
|
||||||
|
def test_full_textbooks_loads(self):
|
||||||
|
module_store = modulestore()
|
||||||
|
import_from_xml(module_store, TEST_DATA_DIR, ['full'])
|
||||||
|
|
||||||
|
course = module_store.get_item(Location(['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None]))
|
||||||
|
|
||||||
|
self.assertGreater(len(course.textbooks), 0)
|
||||||
|
|
||||||
|
|
||||||
@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE)
|
@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE)
|
||||||
class TestNavigation(LoginEnrollmentTestCase):
|
class TestNavigation(LoginEnrollmentTestCase):
|
||||||
|
|||||||
Reference in New Issue
Block a user