Commit db05aeb7 by Awais Jibran

Merge pull request #12384 from edx/aj/fix-cms-dashboard-for-ccx

Studio Edge cannot load the Course Dashboard for CCX courses.
parents 459a01ac 38f1c200
...@@ -16,18 +16,28 @@ from django.test.client import Client ...@@ -16,18 +16,28 @@ from django.test.client import Client
from common.test.utils import XssTestMixin from common.test.utils import XssTestMixin
from xmodule.course_module import CourseSummary from xmodule.course_module import CourseSummary
from contentstore.views.course import (_accessible_courses_list, _accessible_courses_list_from_groups, from contentstore.views.course import (
AccessListFallback, get_courses_accessible_to_user, _accessible_courses_list,
_accessible_courses_summary_list) _accessible_courses_list_from_groups,
AccessListFallback,
get_courses_accessible_to_user,
_accessible_courses_summary_list,
)
from contentstore.utils import delete_course_and_groups from contentstore.utils import delete_course_and_groups
from contentstore.tests.utils import AjaxEnabledTestClient from contentstore.tests.utils import AjaxEnabledTestClient
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
from student.roles import CourseInstructorRole, CourseStaffRole, GlobalStaff, OrgStaffRole, OrgInstructorRole from student.roles import (
CourseInstructorRole,
CourseStaffRole,
GlobalStaff,
OrgStaffRole,
OrgInstructorRole,
UserBasedRole,
)
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls
from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore import ModuleStoreEnum
from opaque_keys.edx.locations import CourseLocator from opaque_keys.edx.locations import CourseLocator
from opaque_keys.edx.keys import CourseKey
from xmodule.error_module import ErrorDescriptor from xmodule.error_module import ErrorDescriptor
from course_action_state.models import CourseRerunState from course_action_state.models import CourseRerunState
...@@ -65,12 +75,14 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -65,12 +75,14 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
run=course_location.run, run=course_location.run,
default_store=store default_store=store
) )
self._add_role_access_to_user(user, course.id)
return course
def _add_role_access_to_user(self, user, course_id):
""" Assign access roles to user in the course. """
if user is not None: if user is not None:
for role in [CourseInstructorRole, CourseStaffRole]: for role in [CourseInstructorRole, CourseStaffRole]:
role(course.id).add_users(user) role(course_id).add_users(user)
return course
def tearDown(self): def tearDown(self):
""" """
...@@ -133,36 +145,40 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -133,36 +145,40 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
# check both course lists have same courses # check both course lists have same courses
self.assertEqual(courses_list, courses_list_by_groups) self.assertEqual(courses_list, courses_list_by_groups)
def test_get_course_list_when_ccx(self): def test_courses_list_with_ccx_courses(self):
""" """
Assert that courses with CCXLocator are filter in course listing. Tests that CCX courses are filtered in course listing.
""" """
# Create a course and assign access roles to user.
course_location = self.store.make_course_key('Org1', 'Course1', 'Run1') course_location = self.store.make_course_key('Org1', 'Course1', 'Run1')
self._create_course_with_access_groups(course_location, self.user) course = self._create_course_with_access_groups(course_location, self.user)
# get courses through iterating all courses # Create a ccx course key and add assign access roles to user.
courses_list, __ = _accessible_courses_list(self.request) ccx_course_key = CCXLocator.from_course_locator(course.id, '1')
self._add_role_access_to_user(self.user, ccx_course_key)
# Test that CCX courses are filtered out.
courses_list, __ = _accessible_courses_list_from_groups(self.request)
self.assertEqual(len(courses_list), 1) self.assertEqual(len(courses_list), 1)
self.assertNotIn(
ccx_course_key,
[course.id for course in courses_list]
)
# get courses by reversing group name formats # Get all courses which user has access.
courses_list_by_groups, __ = _accessible_courses_list_from_groups(self.request) instructor_courses = UserBasedRole(self.user, CourseInstructorRole.ROLE).courses_with_role()
self.assertEqual(len(courses_list_by_groups), 1) staff_courses = UserBasedRole(self.user, CourseStaffRole.ROLE).courses_with_role()
all_courses = (instructor_courses | staff_courses)
# assert no course in listing with ccx id # Verify that CCX course exists in access but filtered by `_accessible_courses_list_from_groups`.
ccx_course = Mock() self.assertIn(
course_key = CourseKey.from_string('course-v1:FakeOrg+CN1+CR-FALLNEVER1') ccx_course_key,
ccx_course.id = CCXLocator.from_course_locator(course_key, u"1") [access.course_id for access in all_courses]
)
with patch(
'xmodule.modulestore.mixed.MixedModuleStore.get_course',
return_value=ccx_course
), patch(
'xmodule.modulestore.mixed.MixedModuleStore.get_courses',
Mock(return_value=[ccx_course])
):
courses_list, __ = _accessible_courses_list_from_groups(self.request)
self.assertEqual(len(courses_list), 0)
# Verify that CCX courses are filtered out while iterating over all courses
mocked_ccx_course = Mock(id=ccx_course_key)
with patch('xmodule.modulestore.mixed.MixedModuleStore.get_courses', return_value=[mocked_ccx_course]):
courses_list, __ = _accessible_courses_list(self.request) courses_list, __ = _accessible_courses_list(self.request)
self.assertEqual(len(courses_list), 0) self.assertEqual(len(courses_list), 0)
......
...@@ -412,12 +412,16 @@ def _accessible_courses_list_from_groups(request): ...@@ -412,12 +412,16 @@ def _accessible_courses_list_from_groups(request):
""" """
List all courses available to the logged in user by reversing access group names List all courses available to the logged in user by reversing access group names
""" """
def filter_ccx(course_access):
""" CCXs cannot be edited in Studio and should not be shown in this dashboard """
return not isinstance(course_access.course_id, CCXLocator)
courses_list = {} courses_list = {}
in_process_course_actions = [] in_process_course_actions = []
instructor_courses = UserBasedRole(request.user, CourseInstructorRole.ROLE).courses_with_role() instructor_courses = UserBasedRole(request.user, CourseInstructorRole.ROLE).courses_with_role()
staff_courses = UserBasedRole(request.user, CourseStaffRole.ROLE).courses_with_role() staff_courses = UserBasedRole(request.user, CourseStaffRole.ROLE).courses_with_role()
all_courses = instructor_courses | staff_courses all_courses = filter(filter_ccx, instructor_courses | staff_courses)
for course_access in all_courses: for course_access in all_courses:
course_key = course_access.course_id course_key = course_access.course_id
...@@ -440,9 +444,7 @@ def _accessible_courses_list_from_groups(request): ...@@ -440,9 +444,7 @@ def _accessible_courses_list_from_groups(request):
# If a user has access to a course that doesn't exist, don't do anything with that course # If a user has access to a course that doesn't exist, don't do anything with that course
pass pass
# Custom Courses for edX (CCX) is an edX feature for re-using course content. if course is not None and not isinstance(course, ErrorDescriptor):
# CCXs cannot be edited in Studio (aka cms) and should not be shown in this dashboard.
if course is not None and not isinstance(course, ErrorDescriptor) and not isinstance(course.id, CCXLocator):
# ignore deleted, errored or ccx courses # ignore deleted, errored or ccx courses
courses_list[course_key] = course courses_list[course_key] = course
......
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