Studio support for cohorted courseware

TNL-652
This commit is contained in:
Andy Armstrong
2014-12-11 10:05:00 -05:00
parent 206ea8caeb
commit 4fa33e25ed
47 changed files with 1121 additions and 255 deletions

View File

@@ -0,0 +1,49 @@
"""
Mixin class that provides authoring capabilities for XBlocks.
"""
import logging
from xblock.core import XBlock
from xblock.fields import XBlockMixin
from xblock.fragment import Fragment
log = logging.getLogger(__name__)
VISIBILITY_VIEW = 'visibility_view'
@XBlock.needs("i18n")
class AuthoringMixin(XBlockMixin):
"""
Mixin class that provides authoring capabilities for XBlocks.
"""
_services_requested = {
'i18n': 'need',
}
def _get_studio_resource_url(self, relative_url):
"""
Returns the Studio URL to a static resource.
"""
# TODO: is there a cleaner way to do this?
from cms.envs.common import STATIC_URL
return STATIC_URL + relative_url
def visibility_view(self, _context=None):
"""
Render the view to manage an xblock's visibility settings in Studio.
Args:
_context: Not actively used for this view.
Returns:
(Fragment): An HTML fragment for editing the visibility of this XBlock.
"""
fragment = Fragment()
from contentstore.utils import reverse_course_url
fragment.add_content(self.system.render_template('visibility_editor.html', {
'xblock': self,
'manage_groups_url': reverse_course_url('group_configurations_list_handler', self.location.course_key),
}))
fragment.add_javascript_url(self._get_studio_resource_url('/js/xblock/authoring.js'))
fragment.initialize_js('VisibilityEditorInit')
return fragment

View File

@@ -0,0 +1,121 @@
from openedx.core.djangoapps.course_groups.partition_scheme import CohortPartitionScheme
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from xmodule.partitions.partitions import Group, UserPartition
class AuthoringMixinTestCase(ModuleStoreTestCase):
"""
Tests the studio authoring XBlock mixin.
"""
def setUp(self):
"""
Create a simple course with a video component.
"""
super(AuthoringMixinTestCase, self).setUp()
self.course = CourseFactory.create()
chapter = ItemFactory.create(
category='chapter',
parent_location=self.course.location,
display_name='Test Chapter'
)
sequential = ItemFactory.create(
category='sequential',
parent_location=chapter.location,
display_name='Test Sequential'
)
self.vertical = ItemFactory.create(
category='vertical',
parent_location=sequential.location,
display_name='Test Vertical'
)
self.video = ItemFactory.create(
category='video',
parent_location=self.vertical.location,
display_name='Test Vertical'
)
self.pet_groups = [Group(1, 'Cat Lovers'), Group(2, 'Dog Lovers')]
def create_cohorted_content_groups(self, groups):
"""
Create a cohorted content partition with specified groups.
"""
self.content_partition = UserPartition(
1,
'Content Groups',
'Contains Groups for Cohorted Courseware',
groups,
scheme_id='cohort'
)
self.course.user_partitions = [self.content_partition]
self.store.update_item(self.course, self.user.id)
def set_staff_only(self, item):
"""Make an item visible to staff only."""
item.visible_to_staff_only = True
self.store.update_item(item, self.user.id)
def set_group_access(self, item, group_ids):
"""
Set group_access for the specified item to the specified group
ids within the content partition.
"""
item.group_access[self.content_partition.id] = group_ids
self.store.update_item(item, self.user.id)
def verify_visibility_view_contains(self, item, substrings):
"""
Verify that an item's visibility view returns an html string
containing all the expected substrings.
"""
html = item.visibility_view().body_html()
for string in substrings:
self.assertIn(string, html)
def test_html_no_partition(self):
self.verify_visibility_view_contains(self.video, 'You have not set up any groups to manage visibility with.')
def test_html_empty_partition(self):
self.create_cohorted_content_groups([])
self.verify_visibility_view_contains(self.video, 'You have not set up any groups to manage visibility with.')
def test_html_populated_partition(self):
self.create_cohorted_content_groups(self.pet_groups)
self.verify_visibility_view_contains(self.video, ['Cat Lovers', 'Dog Lovers'])
def test_html_no_partition_staff_locked(self):
self.set_staff_only(self.vertical)
self.verify_visibility_view_contains(self.video, ['You have not set up any groups to manage visibility with.'])
def test_html_empty_partition_staff_locked(self):
self.create_cohorted_content_groups([])
self.set_staff_only(self.vertical)
self.verify_visibility_view_contains(self.video, 'You have not set up any groups to manage visibility with.')
def test_html_populated_partition_staff_locked(self):
self.create_cohorted_content_groups(self.pet_groups)
self.set_staff_only(self.vertical)
self.verify_visibility_view_contains(
self.video, ['The Unit this component is contained in is hidden from students.', 'Cat Lovers', 'Dog Lovers']
)
def test_html_false_content_group(self):
self.create_cohorted_content_groups(self.pet_groups)
self.set_group_access(self.video, ['false_group_id'])
self.verify_visibility_view_contains(
self.video, ['Cat Lovers', 'Dog Lovers', 'Content group no longer exists.']
)
def test_html_false_content_group_staff_locked(self):
self.create_cohorted_content_groups(self.pet_groups)
self.set_staff_only(self.vertical)
self.set_group_access(self.video, ['false_group_id'])
self.verify_visibility_view_contains(
self.video,
[
'Cat Lovers',
'Dog Lovers',
'The Unit this component is contained in is hidden from students.',
'Content group no longer exists.'
]
)