Commit a9c4774f by Kyle McCormick

PLA-749 Fix student dashboard for users enrolled in CCX courses

parent 72ab1fbc
...@@ -557,9 +557,9 @@ class TestGetMembershipTriplets(ModuleStoreTestCase): ...@@ -557,9 +557,9 @@ class TestGetMembershipTriplets(ModuleStoreTestCase):
self.make_ccx_membership() self.make_ccx_membership()
triplets = self.call_fut() triplets = self.call_fut()
self.assertEqual(len(triplets), 1) self.assertEqual(len(triplets), 1)
ccx, membership, course = triplets[0] ccx, membership, course_overview = triplets[0]
self.assertEqual(ccx.id, self.ccx.id) self.assertEqual(ccx.id, self.ccx.id)
self.assertEqual(unicode(course.id), unicode(self.course.id)) self.assertEqual(unicode(course_overview.id), unicode(self.course.id))
self.assertEqual(membership.student, self.user) self.assertEqual(membership.student, self.user)
def test_has_membership_org_filtered(self): def test_has_membership_org_filtered(self):
......
...@@ -16,9 +16,11 @@ from courseware.tests.factories import StudentModuleFactory # pylint: disable=i ...@@ -16,9 +16,11 @@ from courseware.tests.factories import StudentModuleFactory # pylint: disable=i
from courseware.tests.helpers import LoginEnrollmentTestCase # pylint: disable=import-error from courseware.tests.helpers import LoginEnrollmentTestCase # pylint: disable=import-error
from courseware.tabs import get_course_tab_list from courseware.tabs import get_course_tab_list
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils.timezone import UTC
from django.test.utils import override_settings from django.test.utils import override_settings
from django.test import RequestFactory from django.test import RequestFactory
from edxmako.shortcuts import render_to_response # pylint: disable=import-error from edxmako.shortcuts import render_to_response # pylint: disable=import-error
from student.models import CourseEnrollment
from student.roles import CourseCcxCoachRole # pylint: disable=import-error from student.roles import CourseCcxCoachRole # pylint: disable=import-error
from student.tests.factories import ( # pylint: disable=import-error from student.tests.factories import ( # pylint: disable=import-error
AdminFactory, AdminFactory,
...@@ -27,6 +29,7 @@ from student.tests.factories import ( # pylint: disable=import-error ...@@ -27,6 +29,7 @@ from student.tests.factories import ( # pylint: disable=import-error
) )
from xmodule.x_module import XModuleMixin from xmodule.x_module import XModuleMixin
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.tests.django_utils import ( from xmodule.modulestore.tests.django_utils import (
ModuleStoreTestCase, ModuleStoreTestCase,
TEST_DATA_SPLIT_MODULESTORE) TEST_DATA_SPLIT_MODULESTORE)
...@@ -655,6 +658,43 @@ class CCXCoachTabTestCase(ModuleStoreTestCase): ...@@ -655,6 +658,43 @@ class CCXCoachTabTestCase(ModuleStoreTestCase):
) )
class TestStudentDashboardWithCCX(ModuleStoreTestCase):
"""
Test to ensure that the student dashboard works for users enrolled in CCX
courses.
"""
def setUp(self):
"""
Set up courses and enrollments.
"""
super(TestStudentDashboardWithCCX, self).setUp()
# Create a Draft Mongo and a Split Mongo course and enroll a student user in them.
self.student_password = "foobar"
self.student = UserFactory.create(username="test", password=self.student_password, is_staff=False)
self.draft_course = CourseFactory.create(default_store=ModuleStoreEnum.Type.mongo)
self.split_course = CourseFactory.create(default_store=ModuleStoreEnum.Type.split)
CourseEnrollment.enroll(self.student, self.draft_course.id)
CourseEnrollment.enroll(self.student, self.split_course.id)
# Create a CCX coach.
self.coach = AdminFactory.create()
role = CourseCcxCoachRole(self.split_course.id)
role.add_users(self.coach)
# Create a CCX course and enroll the user in it.
self.ccx = CcxFactory(course_id=self.split_course.id, coach=self.coach)
last_week = datetime.datetime.now(UTC()) - datetime.timedelta(days=7)
override_field_for_ccx(self.ccx, self.split_course, 'start', last_week) # Required by self.ccx.has_started().
CcxMembershipFactory(ccx=self.ccx, student=self.student, active=True)
def test_load_student_dashboard(self):
self.client.login(username=self.student.username, password=self.student_password)
response = self.client.get(reverse('dashboard'))
self.assertEqual(response.status_code, 200)
def flatten(seq): def flatten(seq):
""" """
For [[1, 2], [3, 4]] returns [1, 2, 3, 4]. Does not recurse. For [[1, 2], [3, 4]] returns [1, 2, 3, 4]. Does not recurse.
......
...@@ -10,6 +10,7 @@ from django.core.urlresolvers import reverse ...@@ -10,6 +10,7 @@ from django.core.urlresolvers import reverse
from django.core.mail import send_mail from django.core.mail import send_mail
from edxmako.shortcuts import render_to_string # pylint: disable=import-error from edxmako.shortcuts import render_to_string # pylint: disable=import-error
from microsite_configuration import microsite # pylint: disable=import-error from microsite_configuration import microsite # pylint: disable=import-error
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from xmodule.error_module import ErrorDescriptor from xmodule.error_module import ErrorDescriptor
from ccx_keys.locator import CCXLocator from ccx_keys.locator import CCXLocator
...@@ -240,29 +241,41 @@ def send_mail_to_student(student, param_dict): ...@@ -240,29 +241,41 @@ def send_mail_to_student(student, param_dict):
def get_ccx_membership_triplets(user, course_org_filter, org_filter_out_set): def get_ccx_membership_triplets(user, course_org_filter, org_filter_out_set):
""" """
Get the relevant set of (CustomCourseForEdX, CcxMembership, Course) Get the relevant set of (CustomCourseForEdX, CcxMembership, CourseOverview)
triplets to be displayed on a student's dashboard. triplets to be displayed on a student's dashboard.
""" """
error_message_format = "User {0} enrolled in {2} course {1}"
# only active memberships for now # only active memberships for now
for membership in CcxMembership.memberships_for_user(user): for membership in CcxMembership.memberships_for_user(user):
ccx = membership.ccx ccx = membership.ccx
store = modulestore()
with store.bulk_operations(ccx.course_id): try:
course = store.get_course(ccx.course_id) course_overview = CourseOverview.get_from_id(ccx.course_id)
if course and not isinstance(course, ErrorDescriptor): except CourseOverview.DoesNotExist:
log.error(error_message_format.format( # pylint: disable=logging-format-interpolation
user.username, ccx.course_id, "non-existent"
))
continue
except IOError:
log.error(error_message_format.format( # pylint: disable=logging-format-interpolation
user.username, ccx.course_id, "broken"
))
continue
# if we are in a Microsite, then filter out anything that is not # if we are in a Microsite, then filter out anything that is not
# attributed (by ORG) to that Microsite # attributed (by ORG) to that Microsite
if course_org_filter and course_org_filter != course.location.org: if course_org_filter and course_org_filter != course_overview.location.org:
continue continue
# Conversely, if we are not in a Microsite, then let's filter out any enrollments # Conversely, if we are not in a Microsite, then let's filter out any enrollments
# with courses attributed (by ORG) to Microsites # with courses attributed (by ORG) to Microsites
elif course.location.org in org_filter_out_set: elif course_overview.location.org in org_filter_out_set:
continue continue
# If, somehow, we've got a ccx that has been created for a # If, somehow, we've got a ccx that has been created for a
# course with a deprecated ID, we must filter it out. Emit a # course with a deprecated ID, we must filter it out. Emit a
# warning to the log so we can clean up. # warning to the log so we can clean up.
if course.location.deprecated: if course_overview.location.deprecated:
log.warning( log.warning(
"CCX %s exists for course %s with deprecated id", "CCX %s exists for course %s with deprecated id",
ccx, ccx,
...@@ -270,8 +283,4 @@ def get_ccx_membership_triplets(user, course_org_filter, org_filter_out_set): ...@@ -270,8 +283,4 @@ def get_ccx_membership_triplets(user, course_org_filter, org_filter_out_set):
) )
continue continue
yield (ccx, membership, course) yield (ccx, membership, course_overview)
else:
log.error("User {0} enrolled in {2} course {1}".format( # pylint: disable=logging-format-interpolation
user.username, ccx.course_id, "broken" if course else "non-existent"
))
...@@ -42,7 +42,7 @@ from ccx_keys.locator import CCXLocator ...@@ -42,7 +42,7 @@ from ccx_keys.locator import CCXLocator
% endif % endif
</h3> </h3>
<div class="course-info"> <div class="course-info">
<span class="info-university">${get_course_about_section(course, 'university')} - </span> <span class="info-university">${get_course_about_section(course_overview, 'university')} - </span>
<span class="info-course-id">${course_overview.display_number_with_default | h}</span> <span class="info-course-id">${course_overview.display_number_with_default | h}</span>
<span class="info-date-block" data-tooltip="Hi"> <span class="info-date-block" data-tooltip="Hi">
% if ccx.has_ended(): % if ccx.has_ended():
......
...@@ -88,10 +88,10 @@ from django.core.urlresolvers import reverse ...@@ -88,10 +88,10 @@ from django.core.urlresolvers import reverse
% endfor % endfor
% if settings.FEATURES.get('CUSTOM_COURSES_EDX', False): % if settings.FEATURES.get('CUSTOM_COURSES_EDX', False):
% for ccx, membership, course in ccx_membership_triplets: % for ccx, membership, course_overview in ccx_membership_triplets:
<% show_courseware_link = ccx.has_started() %> <% show_courseware_link = ccx.has_started() %>
<% is_course_blocked = False %> <% is_course_blocked = False %>
<%include file='ccx/_dashboard_ccx_listing.html' args="ccx=ccx, membership=membership, course_overview=enrollment.course_overview, show_courseware_link=show_courseware_link, is_course_blocked=is_course_blocked" /> <%include file='ccx/_dashboard_ccx_listing.html' args="ccx=ccx, membership=membership, course_overview=course_overview, show_courseware_link=show_courseware_link, is_course_blocked=is_course_blocked" />
% endfor % endfor
% endif % endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment