diff --git a/common/djangoapps/student/tests/test_certificates.py b/common/djangoapps/student/tests/test_certificates.py
new file mode 100644
index 0000000000..4a440f7ed9
--- /dev/null
+++ b/common/djangoapps/student/tests/test_certificates.py
@@ -0,0 +1,54 @@
+"""Tests for display of certificates on the student dashboard. """
+
+import unittest
+import ddt
+
+from django.conf import settings
+from django.core.urlresolvers import reverse
+
+from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
+from xmodule.modulestore.tests.factories import CourseFactory
+from student.tests.factories import UserFactory, CourseEnrollmentFactory
+from certificates.tests.factories import GeneratedCertificateFactory # pylint: disable=import-error
+
+
+@ddt.ddt
+@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
+class CertificateDisplayTest(ModuleStoreTestCase):
+ """Tests display of certificates on the student dashboard. """
+
+ USERNAME = "test_user"
+ PASSWORD = "password"
+ DOWNLOAD_URL = "http://www.example.com/certificate.pdf"
+
+ def setUp(self):
+ super(CertificateDisplayTest, self).setUp()
+ self.user = UserFactory.create(username=self.USERNAME, password=self.PASSWORD)
+ result = self.client.login(username=self.USERNAME, password=self.PASSWORD)
+ self.assertTrue(result, msg="Could not log in")
+
+ self.course = CourseFactory()
+ self.course.certificates_display_behavior = "early_with_info"
+ self.update_course(self.course, self.user.username)
+
+ @ddt.data('verified', 'professional')
+ def test_display_verified_certificate(self, enrollment_mode):
+ self._create_certificate(enrollment_mode)
+ self._check_can_download_certificate()
+
+ def _create_certificate(self, enrollment_mode):
+ """Simulate that the user has a generated certificate. """
+ CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id, mode=enrollment_mode)
+ GeneratedCertificateFactory(
+ user=self.user,
+ course_id=self.course.id,
+ mode=enrollment_mode,
+ download_url=self.DOWNLOAD_URL,
+ status="downloadable",
+ grade=0.98,
+ )
+
+ def _check_can_download_certificate(self):
+ response = self.client.get(reverse('dashboard'))
+ self.assertContains(response, u'Download Your ID Verified')
+ self.assertContains(response, self.DOWNLOAD_URL)
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_cross_modulestore_import_export.py b/common/lib/xmodule/xmodule/modulestore/tests/test_cross_modulestore_import_export.py
index 554e3c5fc2..fe9056b09a 100644
--- a/common/lib/xmodule/xmodule/modulestore/tests/test_cross_modulestore_import_export.py
+++ b/common/lib/xmodule/xmodule/modulestore/tests/test_cross_modulestore_import_export.py
@@ -13,6 +13,7 @@ and then for each combination of modulestores, performing the sequence:
"""
from contextlib import contextmanager, nested
import itertools
+import os
from path import path
import random
from shutil import rmtree
@@ -314,14 +315,15 @@ class MixedModulestoreBuilder(StoreBuilderBase):
# Split stores all asset metadata in the structure collection.
return store.db_connection.structures
-
MIXED_MODULESTORE_BOTH_SETUP = MixedModulestoreBuilder([
('draft', MongoModulestoreBuilder()),
('split', VersioningModulestoreBuilder())
])
+DRAFT_MODULESTORE_SETUP = MixedModulestoreBuilder([('draft', MongoModulestoreBuilder())])
+SPLIT_MODULESTORE_SETUP = MixedModulestoreBuilder([('split', VersioningModulestoreBuilder())])
MIXED_MODULESTORE_SETUPS = (
- MixedModulestoreBuilder([('draft', MongoModulestoreBuilder())]),
- MixedModulestoreBuilder([('split', VersioningModulestoreBuilder())]),
+ DRAFT_MODULESTORE_SETUP,
+ SPLIT_MODULESTORE_SETUP,
)
MIXED_MS_SETUPS_SHORT = (
'mixed_mongo',
@@ -347,6 +349,8 @@ COURSE_DATA_NAMES = (
'split_test_module_draft',
)
+EXPORTED_COURSE_DIR_NAME = 'exported_source_course'
+
@ddt.ddt
@attr('mongo')
@@ -397,14 +401,14 @@ class CrossStoreXMLRoundtrip(CourseComparisonTest, PartitionTestCase):
source_content,
source_course_key,
self.export_dir,
- 'exported_source_course',
+ EXPORTED_COURSE_DIR_NAME,
)
import_course_from_xml(
dest_store,
'test_user',
self.export_dir,
- source_dirs=['exported_source_course'],
+ source_dirs=[EXPORTED_COURSE_DIR_NAME],
static_content_store=dest_content,
target_id=dest_course_key,
raise_on_failure=True,
@@ -448,3 +452,58 @@ class CrossStoreXMLRoundtrip(CourseComparisonTest, PartitionTestCase):
dest_store,
dest_course_key,
)
+
+ def test_split_course_export_import(self):
+ # Construct the contentstore for storing the first import
+ with MongoContentstoreBuilder().build() as source_content:
+ # Construct the modulestore for storing the first import (using the previously created contentstore)
+ with SPLIT_MODULESTORE_SETUP.build(contentstore=source_content) as source_store:
+ # Construct the contentstore for storing the second import
+ with MongoContentstoreBuilder().build() as dest_content:
+ # Construct the modulestore for storing the second import (using the second contentstore)
+ with SPLIT_MODULESTORE_SETUP.build(contentstore=dest_content) as dest_store:
+ source_course_key = source_store.make_course_key('a', 'source', '2015_Fall')
+ dest_course_key = dest_store.make_course_key('a', 'dest', '2015_Fall')
+
+ import_course_from_xml(
+ source_store,
+ 'test_user',
+ TEST_DATA_DIR,
+ source_dirs=['split_course_with_static_tabs'],
+ static_content_store=source_content,
+ target_id=source_course_key,
+ raise_on_failure=True,
+ create_if_not_present=True,
+ )
+
+ export_course_to_xml(
+ source_store,
+ source_content,
+ source_course_key,
+ self.export_dir,
+ EXPORTED_COURSE_DIR_NAME,
+ )
+
+ source_course = source_store.get_course(source_course_key, depth=None, lazy=False)
+
+ self.assertEqual(source_course.url_name, 'course')
+
+ export_dir_path = path(self.export_dir)
+ policy_dir = export_dir_path / 'exported_source_course' / 'policies' / source_course.url_name
+ policy_path = policy_dir / 'policy.json'
+ self.assertTrue(os.path.exists(policy_path))
+
+ import_course_from_xml(
+ dest_store,
+ 'test_user',
+ self.export_dir,
+ source_dirs=[EXPORTED_COURSE_DIR_NAME],
+ static_content_store=dest_content,
+ target_id=dest_course_key,
+ raise_on_failure=True,
+ create_if_not_present=True,
+ )
+
+ dest_course = dest_store.get_course(dest_course_key, depth=None, lazy=False)
+
+ self.assertEqual(dest_course.url_name, 'course')
diff --git a/common/lib/xmodule/xmodule/modulestore/xml_exporter.py b/common/lib/xmodule/xmodule/modulestore/xml_exporter.py
index f62d0e3075..a3d95a9b78 100644
--- a/common/lib/xmodule/xmodule/modulestore/xml_exporter.py
+++ b/common/lib/xmodule/xmodule/modulestore/xml_exporter.py
@@ -264,8 +264,14 @@ class CourseExportManager(ExportManager):
'about', 'about', '.html'
)
+ course_policy_dir_name = courselike.location.run
+ if courselike.url_name != courselike.location.run and courselike.url_name == 'course':
+ # Use url_name for split mongo because course_run is not used when loading policies.
+ course_policy_dir_name = courselike.url_name
+
+ course_run_policy_dir = policies_dir.makeopendir(course_policy_dir_name)
+
# export the grading policy
- course_run_policy_dir = policies_dir.makeopendir(courselike.location.run)
with course_run_policy_dir.open('grading_policy.json', 'w') as grading_policy:
grading_policy.write(dumps(courselike.grading_policy, cls=EdxJSONEncoder, sort_keys=True, indent=4))
diff --git a/common/test/data/split_course_with_static_tabs/course.xml b/common/test/data/split_course_with_static_tabs/course.xml
new file mode 100644
index 0000000000..86b14ddc4e
--- /dev/null
+++ b/common/test/data/split_course_with_static_tabs/course.xml
@@ -0,0 +1,3 @@
+
Add the content you want students to see on this page.
diff --git a/lms/djangoapps/courseware/management/commands/tests/test_dump_course.py b/lms/djangoapps/courseware/management/commands/tests/test_dump_course.py index 2f2e986c8a..ef97b66e0b 100644 --- a/lms/djangoapps/courseware/management/commands/tests/test_dump_course.py +++ b/lms/djangoapps/courseware/management/commands/tests/test_dump_course.py @@ -44,6 +44,7 @@ class CommandsTestBase(ModuleStoreTestCase): """ __test__ = False + url_name = '2012_Fall' def setUp(self): super(CommandsTestBase, self).setUp() @@ -201,7 +202,7 @@ class CommandsTestBase(ModuleStoreTestCase): assert_in = self.assertIn assert_in('edX-simple-2012_Fall', names) - assert_in('edX-simple-2012_Fall/policies/2012_Fall/policy.json', names) + assert_in('edX-simple-2012_Fall/policies/{}/policy.json'.format(self.url_name), names) assert_in('edX-simple-2012_Fall/html/toylab.html', names) assert_in('edX-simple-2012_Fall/videosequence/A_simple_sequence.xml', names) assert_in('edX-simple-2012_Fall/sequential/Lecture_2.xml', names) @@ -232,3 +233,4 @@ class CommandSplitMongoTestCase(CommandsTestBase): """ MODULESTORE = TEST_DATA_SPLIT_MODULESTORE __test__ = True + url_name = 'course' diff --git a/lms/templates/dashboard/_dashboard_certificate_information.html b/lms/templates/dashboard/_dashboard_certificate_information.html index 676e4b91fd..798c12b5db 100644 --- a/lms/templates/dashboard/_dashboard_certificate_information.html +++ b/lms/templates/dashboard/_dashboard_certificate_information.html @@ -1,6 +1,9 @@ <%page args="cert_status, course, enrollment" /> -<%! from django.utils.translation import ugettext as _ %> +<%! +from django.utils.translation import ugettext as _ +from course_modes.models import CourseMode +%> <%namespace name='static' file='../static_content.html'/> <% @@ -61,7 +64,7 @@ else: ${_("Download Your {cert_name_short} (PDF)").format(cert_name_short=cert_name_short)} - % elif cert_status['show_download_url'] and enrollment.mode == 'verified': + % elif cert_status['show_download_url'] and enrollment.mode in CourseMode.VERIFIED_MODES: