Support level support for Studio xblock creation.
TNL-4670
This commit is contained in:
@@ -691,7 +691,6 @@ class MiscCourseTests(ContentStoreTestCase):
|
||||
# Test that malicious code does not appear in html
|
||||
self.assertNotIn(malicious_code, resp.content)
|
||||
|
||||
@patch('django.conf.settings.DEPRECATED_ADVANCED_COMPONENT_TYPES', [])
|
||||
def test_advanced_components_in_edit_unit(self):
|
||||
# This could be made better, but for now let's just assert that we see the advanced modules mentioned in the page
|
||||
# response HTML
|
||||
|
||||
@@ -21,6 +21,7 @@ from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
|
||||
from openedx.core.djangoapps.models.course_details import CourseDetails
|
||||
from student.roles import CourseInstructorRole, CourseStaffRole
|
||||
from student.tests.factories import UserFactory
|
||||
from xblock_django.models import XBlockStudioConfigurationFlag
|
||||
from xmodule.fields import Date
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
@@ -784,6 +785,15 @@ class CourseMetadataEditingTest(CourseTestCase):
|
||||
)
|
||||
self.assertNotIn('edxnotes', test_model)
|
||||
|
||||
def test_allow_unsupported_xblocks(self):
|
||||
"""
|
||||
allow_unsupported_xblocks is only shown in Advanced Settings if
|
||||
XBlockStudioConfigurationFlag is enabled.
|
||||
"""
|
||||
self.assertNotIn('allow_unsupported_xblocks', CourseMetadata.fetch(self.fullcourse))
|
||||
XBlockStudioConfigurationFlag(enabled=True).save()
|
||||
self.assertIn('allow_unsupported_xblocks', CourseMetadata.fetch(self.fullcourse))
|
||||
|
||||
def test_validate_from_json_correct_inputs(self):
|
||||
is_valid, errors, test_model = CourseMetadata.validate_and_update_from_json(
|
||||
self.course,
|
||||
|
||||
@@ -27,7 +27,10 @@ from opaque_keys.edx.keys import UsageKey
|
||||
|
||||
from student.auth import has_course_author_access
|
||||
from django.utils.translation import ugettext as _
|
||||
from xblock_django.models import XBlockDisableConfig
|
||||
|
||||
from xblock_django.api import disabled_xblocks, authorable_xblocks
|
||||
from xblock_django.models import XBlockStudioConfigurationFlag
|
||||
|
||||
|
||||
__all__ = [
|
||||
'container_handler',
|
||||
@@ -47,17 +50,41 @@ CONTAINER_TEMPLATES = [
|
||||
"basic-modal", "modal-button", "edit-xblock-modal",
|
||||
"editor-mode-button", "upload-dialog",
|
||||
"add-xblock-component", "add-xblock-component-button", "add-xblock-component-menu",
|
||||
"add-xblock-component-menu-problem", "xblock-string-field-editor", "publish-xblock", "publish-history",
|
||||
"add-xblock-component-support-legend", "add-xblock-component-support-level", "add-xblock-component-menu-problem",
|
||||
"xblock-string-field-editor", "publish-xblock", "publish-history",
|
||||
"unit-outline", "container-message", "license-selector",
|
||||
]
|
||||
|
||||
|
||||
def _advanced_component_types():
|
||||
def _advanced_component_types(show_unsupported):
|
||||
"""
|
||||
Return advanced component types which can be created.
|
||||
|
||||
Args:
|
||||
show_unsupported: if True, unsupported XBlocks may be included in the return value
|
||||
|
||||
Returns:
|
||||
A dict of authorable XBlock types and their support levels (see XBlockStudioConfiguration). For example:
|
||||
{
|
||||
"done": "us", # unsupported
|
||||
"discussion: "fs" # fully supported
|
||||
}
|
||||
Note that the support level will be "True" for all XBlocks if XBlockStudioConfigurationFlag
|
||||
is not enabled.
|
||||
"""
|
||||
disabled_create_block_types = XBlockDisableConfig.disabled_create_block_types()
|
||||
return [c_type for c_type in ADVANCED_COMPONENT_TYPES if c_type not in disabled_create_block_types]
|
||||
enabled_block_types = _filter_disabled_blocks(ADVANCED_COMPONENT_TYPES)
|
||||
if XBlockStudioConfigurationFlag.is_enabled():
|
||||
authorable_blocks = authorable_xblocks(allow_unsupported=show_unsupported)
|
||||
filtered_blocks = {}
|
||||
for block in authorable_blocks:
|
||||
if block.name in enabled_block_types:
|
||||
filtered_blocks[block.name] = block.support_level
|
||||
return filtered_blocks
|
||||
else:
|
||||
all_blocks = {}
|
||||
for block_name in enabled_block_types:
|
||||
all_blocks[block_name] = True
|
||||
return all_blocks
|
||||
|
||||
|
||||
def _load_mixed_class(category):
|
||||
@@ -152,13 +179,14 @@ def get_component_templates(courselike, library=False):
|
||||
"""
|
||||
Returns the applicable component templates that can be used by the specified course or library.
|
||||
"""
|
||||
def create_template_dict(name, cat, boilerplate_name=None, tab="common", hinted=False):
|
||||
def create_template_dict(name, category, support_level, boilerplate_name=None, tab="common", hinted=False):
|
||||
"""
|
||||
Creates a component template dict.
|
||||
|
||||
Parameters
|
||||
display_name: the user-visible name of the component
|
||||
category: the type of component (problem, html, etc.)
|
||||
support_level: the support level of this component
|
||||
boilerplate_name: name of boilerplate for filling in default values. May be None.
|
||||
hinted: True if hinted problem else False
|
||||
tab: common(default)/advanced, which tab it goes in
|
||||
@@ -166,10 +194,50 @@ def get_component_templates(courselike, library=False):
|
||||
"""
|
||||
return {
|
||||
"display_name": name,
|
||||
"category": cat,
|
||||
"category": category,
|
||||
"boilerplate_name": boilerplate_name,
|
||||
"hinted": hinted,
|
||||
"tab": tab
|
||||
"tab": tab,
|
||||
"support_level": support_level
|
||||
}
|
||||
|
||||
def component_support_level(editable_types, name, template=None):
|
||||
"""
|
||||
Returns the support level for the given xblock name/template combination.
|
||||
|
||||
Args:
|
||||
editable_types: a QuerySet of xblocks with their support levels
|
||||
name: the name of the xblock
|
||||
template: optional template for the xblock
|
||||
|
||||
Returns:
|
||||
If XBlockStudioConfigurationFlag is enabled, returns the support level
|
||||
(see XBlockStudioConfiguration) or False if this xblock name/template combination
|
||||
has no Studio support at all. If XBlockStudioConfigurationFlag is disabled,
|
||||
simply returns True.
|
||||
"""
|
||||
# If the Studio support feature is disabled, return True for all.
|
||||
if not XBlockStudioConfigurationFlag.is_enabled():
|
||||
return True
|
||||
if template is None:
|
||||
template = ""
|
||||
extension_index = template.rfind(".yaml")
|
||||
if extension_index >= 0:
|
||||
template = template[0:extension_index]
|
||||
for block in editable_types:
|
||||
if block.name == name and block.template == template:
|
||||
return block.support_level
|
||||
|
||||
return False
|
||||
|
||||
def create_support_legend_dict():
|
||||
"""
|
||||
Returns a dict of settings information for the display of the support level legend.
|
||||
"""
|
||||
return {
|
||||
"show_legend": XBlockStudioConfigurationFlag.is_enabled(),
|
||||
"allow_unsupported_xblocks": allow_unsupported,
|
||||
"documentation_label": _("{platform_name} Support Levels:").format(platform_name=settings.PLATFORM_NAME)
|
||||
}
|
||||
|
||||
component_display_names = {
|
||||
@@ -189,57 +257,92 @@ def get_component_templates(courselike, library=False):
|
||||
if library:
|
||||
component_types = [component for component in component_types if component != 'discussion']
|
||||
|
||||
component_types = _filter_disabled_blocks(component_types)
|
||||
|
||||
# Content Libraries currently don't allow opting in to unsupported xblocks/problem types.
|
||||
allow_unsupported = getattr(courselike, "allow_unsupported_xblocks", False)
|
||||
|
||||
for category in component_types:
|
||||
authorable_variations = authorable_xblocks(allow_unsupported=allow_unsupported, name=category)
|
||||
support_level_without_template = component_support_level(authorable_variations, category)
|
||||
templates_for_category = []
|
||||
component_class = _load_mixed_class(category)
|
||||
# add the default template with localized display name
|
||||
# TODO: Once mixins are defined per-application, rather than per-runtime,
|
||||
# this should use a cms mixed-in class. (cpennington)
|
||||
display_name = xblock_type_display_name(category, _('Blank')) # this is the Blank Advanced problem
|
||||
templates_for_category.append(create_template_dict(display_name, category, None, 'advanced'))
|
||||
categories.add(category)
|
||||
|
||||
if support_level_without_template:
|
||||
# add the default template with localized display name
|
||||
# TODO: Once mixins are defined per-application, rather than per-runtime,
|
||||
# this should use a cms mixed-in class. (cpennington)
|
||||
display_name = xblock_type_display_name(category, _('Blank')) # this is the Blank Advanced problem
|
||||
templates_for_category.append(
|
||||
create_template_dict(display_name, category, support_level_without_template, None, 'advanced')
|
||||
)
|
||||
categories.add(category)
|
||||
|
||||
# add boilerplates
|
||||
if hasattr(component_class, 'templates'):
|
||||
for template in component_class.templates():
|
||||
filter_templates = getattr(component_class, 'filter_templates', None)
|
||||
if not filter_templates or filter_templates(template, courselike):
|
||||
# Tab can be 'common' 'advanced'
|
||||
# Default setting is common/advanced depending on the presence of markdown
|
||||
tab = 'common'
|
||||
if template['metadata'].get('markdown') is None:
|
||||
tab = 'advanced'
|
||||
hinted = template.get('hinted', False)
|
||||
|
||||
templates_for_category.append(
|
||||
create_template_dict(
|
||||
_(template['metadata'].get('display_name')), # pylint: disable=translation-of-non-string
|
||||
category,
|
||||
template.get('template_id'),
|
||||
tab,
|
||||
hinted,
|
||||
)
|
||||
template_id = template.get('template_id')
|
||||
support_level_with_template = component_support_level(
|
||||
authorable_variations, category, template_id
|
||||
)
|
||||
if support_level_with_template:
|
||||
# Tab can be 'common' 'advanced'
|
||||
# Default setting is common/advanced depending on the presence of markdown
|
||||
tab = 'common'
|
||||
if template['metadata'].get('markdown') is None:
|
||||
tab = 'advanced'
|
||||
hinted = template.get('hinted', False)
|
||||
|
||||
# Add any advanced problem types
|
||||
templates_for_category.append(
|
||||
create_template_dict(
|
||||
_(template['metadata'].get('display_name')), # pylint: disable=translation-of-non-string
|
||||
category,
|
||||
support_level_with_template,
|
||||
template_id,
|
||||
tab,
|
||||
hinted,
|
||||
)
|
||||
)
|
||||
|
||||
# Add any advanced problem types. Note that these are different xblocks being stored as Advanced Problems.
|
||||
if category == 'problem':
|
||||
for advanced_problem_type in ADVANCED_PROBLEM_TYPES:
|
||||
disabled_block_names = [block.name for block in disabled_xblocks()]
|
||||
advanced_problem_types = [advanced_problem_type for advanced_problem_type in ADVANCED_PROBLEM_TYPES
|
||||
if advanced_problem_type['component'] not in disabled_block_names]
|
||||
for advanced_problem_type in advanced_problem_types:
|
||||
component = advanced_problem_type['component']
|
||||
boilerplate_name = advanced_problem_type['boilerplate_name']
|
||||
try:
|
||||
component_display_name = xblock_type_display_name(component)
|
||||
except PluginMissingError:
|
||||
log.warning('Unable to load xblock type %s to read display_name', component, exc_info=True)
|
||||
else:
|
||||
templates_for_category.append(
|
||||
create_template_dict(component_display_name, component, boilerplate_name, 'advanced')
|
||||
)
|
||||
categories.add(component)
|
||||
|
||||
authorable_advanced_component_variations = authorable_xblocks(
|
||||
allow_unsupported=allow_unsupported, name=component
|
||||
)
|
||||
advanced_component_support_level = component_support_level(
|
||||
authorable_advanced_component_variations, component, boilerplate_name
|
||||
)
|
||||
if advanced_component_support_level:
|
||||
try:
|
||||
component_display_name = xblock_type_display_name(component)
|
||||
except PluginMissingError:
|
||||
log.warning('Unable to load xblock type %s to read display_name', component, exc_info=True)
|
||||
else:
|
||||
templates_for_category.append(
|
||||
create_template_dict(
|
||||
component_display_name,
|
||||
component,
|
||||
advanced_component_support_level,
|
||||
boilerplate_name,
|
||||
'advanced'
|
||||
)
|
||||
)
|
||||
categories.add(component)
|
||||
|
||||
component_templates.append({
|
||||
"type": category,
|
||||
"templates": templates_for_category,
|
||||
"display_name": component_display_names[category]
|
||||
"display_name": component_display_names[category],
|
||||
"support_legend": create_support_legend_dict()
|
||||
})
|
||||
|
||||
# Libraries do not support advanced components at this time.
|
||||
@@ -251,19 +354,25 @@ def get_component_templates(courselike, library=False):
|
||||
# are the names of the modules in ADVANCED_COMPONENT_TYPES that should be
|
||||
# enabled for the course.
|
||||
course_advanced_keys = courselike.advanced_modules
|
||||
advanced_component_templates = {"type": "advanced", "templates": [], "display_name": _("Advanced")}
|
||||
advanced_component_types = _advanced_component_types()
|
||||
advanced_component_templates = {
|
||||
"type": "advanced",
|
||||
"templates": [],
|
||||
"display_name": _("Advanced"),
|
||||
"support_legend": create_support_legend_dict()
|
||||
}
|
||||
advanced_component_types = _advanced_component_types(allow_unsupported)
|
||||
# Set component types according to course policy file
|
||||
if isinstance(course_advanced_keys, list):
|
||||
for category in course_advanced_keys:
|
||||
if category in advanced_component_types and category not in categories:
|
||||
if category in advanced_component_types.keys() and category not in categories:
|
||||
# boilerplates not supported for advanced components
|
||||
try:
|
||||
component_display_name = xblock_type_display_name(category, default_display_name=category)
|
||||
advanced_component_templates['templates'].append(
|
||||
create_template_dict(
|
||||
component_display_name,
|
||||
category
|
||||
category,
|
||||
advanced_component_types[category]
|
||||
)
|
||||
)
|
||||
categories.add(category)
|
||||
@@ -288,6 +397,14 @@ def get_component_templates(courselike, library=False):
|
||||
return component_templates
|
||||
|
||||
|
||||
def _filter_disabled_blocks(all_blocks):
|
||||
"""
|
||||
Filter out disabled xblocks from the provided list of xblock names.
|
||||
"""
|
||||
disabled_block_names = [block.name for block in disabled_xblocks()]
|
||||
return [block_name for block_name in all_blocks if block_name not in disabled_block_names]
|
||||
|
||||
|
||||
@login_required
|
||||
def _get_item_in_course(request, usage_key):
|
||||
"""
|
||||
|
||||
@@ -24,7 +24,7 @@ from contentstore.views.item import (
|
||||
)
|
||||
from contentstore.tests.utils import CourseTestCase
|
||||
from student.tests.factories import UserFactory
|
||||
from xblock_django.models import XBlockDisableConfig
|
||||
from xblock_django.models import XBlockConfiguration, XBlockStudioConfiguration, XBlockStudioConfigurationFlag
|
||||
from xmodule.capa_module import CapaDescriptor
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
@@ -1457,12 +1457,19 @@ class TestComponentTemplates(CourseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestComponentTemplates, self).setUp()
|
||||
self.templates = get_component_templates(self.course)
|
||||
# Advanced Module support levels.
|
||||
XBlockStudioConfiguration.objects.create(name='poll', enabled=True, support_level="fs")
|
||||
XBlockStudioConfiguration.objects.create(name='survey', enabled=True, support_level="ps")
|
||||
XBlockStudioConfiguration.objects.create(name='annotatable', enabled=True, support_level="us")
|
||||
# Basic component support levels.
|
||||
XBlockStudioConfiguration.objects.create(name='html', enabled=True, support_level="fs")
|
||||
XBlockStudioConfiguration.objects.create(name='discussion', enabled=True, support_level="ps")
|
||||
XBlockStudioConfiguration.objects.create(name='problem', enabled=True, support_level="us")
|
||||
XBlockStudioConfiguration.objects.create(name='video', enabled=True, support_level="us")
|
||||
# XBlock masquerading as a problem
|
||||
XBlockStudioConfiguration.objects.create(name='openassessment', enabled=True, support_level="us")
|
||||
|
||||
# Initialize the deprecated modules settings with empty list
|
||||
XBlockDisableConfig.objects.create(
|
||||
disabled_create_blocks='', enabled=True
|
||||
)
|
||||
self.templates = get_component_templates(self.course)
|
||||
|
||||
def get_templates_of_type(self, template_type):
|
||||
"""
|
||||
@@ -1481,12 +1488,40 @@ class TestComponentTemplates(CourseTestCase):
|
||||
"""
|
||||
Test the handling of the basic component templates.
|
||||
"""
|
||||
self.assertIsNotNone(self.get_templates_of_type('discussion'))
|
||||
self.assertIsNotNone(self.get_templates_of_type('html'))
|
||||
self.assertIsNotNone(self.get_templates_of_type('problem'))
|
||||
self.assertIsNotNone(self.get_templates_of_type('video'))
|
||||
self._verify_basic_component("discussion", "Discussion")
|
||||
self._verify_basic_component("video", "Video")
|
||||
self.assertGreater(self.get_templates_of_type('html'), 0)
|
||||
self.assertGreater(self.get_templates_of_type('problem'), 0)
|
||||
self.assertIsNone(self.get_templates_of_type('advanced'))
|
||||
|
||||
# Now fully disable video through XBlockConfiguration
|
||||
XBlockConfiguration.objects.create(name='video', enabled=False)
|
||||
self.templates = get_component_templates(self.course)
|
||||
self.assertIsNone(self.get_templates_of_type('video'))
|
||||
|
||||
def test_basic_components_support_levels(self):
|
||||
"""
|
||||
Test that support levels can be set on basic component templates.
|
||||
"""
|
||||
XBlockStudioConfigurationFlag.objects.create(enabled=True)
|
||||
self.templates = get_component_templates(self.course)
|
||||
self._verify_basic_component("discussion", "Discussion", "ps")
|
||||
self.assertEqual([], self.get_templates_of_type("video"))
|
||||
self.assertEqual([], self.get_templates_of_type("problem"))
|
||||
|
||||
self.course.allow_unsupported_xblocks = True
|
||||
self.templates = get_component_templates(self.course)
|
||||
self._verify_basic_component("video", "Video", "us")
|
||||
problem_templates = self.get_templates_of_type('problem')
|
||||
problem_no_boilerplate = self.get_template(problem_templates, u'Blank Advanced Problem')
|
||||
self.assertIsNotNone(problem_no_boilerplate)
|
||||
self.assertEqual('us', problem_no_boilerplate['support_level'])
|
||||
|
||||
# Now fully disable video through XBlockConfiguration
|
||||
XBlockConfiguration.objects.create(name='video', enabled=False)
|
||||
self.templates = get_component_templates(self.course)
|
||||
self.assertIsNone(self.get_templates_of_type('video'))
|
||||
|
||||
def test_advanced_components(self):
|
||||
"""
|
||||
Test the handling of advanced component templates.
|
||||
@@ -1510,6 +1545,11 @@ class TestComponentTemplates(CourseTestCase):
|
||||
self.assertNotEqual(only_template.get('category'), 'video')
|
||||
self.assertNotEqual(only_template.get('category'), 'openassessment')
|
||||
|
||||
# Now fully disable word_cloud through XBlockConfiguration
|
||||
XBlockConfiguration.objects.create(name='word_cloud', enabled=False)
|
||||
self.templates = get_component_templates(self.course)
|
||||
self.assertIsNone(self.get_templates_of_type('advanced'))
|
||||
|
||||
def test_advanced_problems(self):
|
||||
"""
|
||||
Test the handling of advanced problem templates.
|
||||
@@ -1520,44 +1560,101 @@ class TestComponentTemplates(CourseTestCase):
|
||||
self.assertEqual(circuit_template.get('category'), 'problem')
|
||||
self.assertEqual(circuit_template.get('boilerplate_name'), 'circuitschematic.yaml')
|
||||
|
||||
@patch('django.conf.settings.DEPRECATED_ADVANCED_COMPONENT_TYPES', [])
|
||||
def test_deprecated_no_advance_component_button(self):
|
||||
"""
|
||||
Test that there will be no `Advanced` button on unit page if units are
|
||||
deprecated provided that they are the only modules in `Advanced Module List`
|
||||
Test that there will be no `Advanced` button on unit page if xblocks have disabled
|
||||
Studio support given that they are the only modules in `Advanced Module List`
|
||||
"""
|
||||
XBlockDisableConfig.objects.create(disabled_create_blocks='poll survey', enabled=True)
|
||||
# Update poll and survey to have "enabled=False".
|
||||
XBlockStudioConfiguration.objects.create(name='poll', enabled=False, support_level="fs")
|
||||
XBlockStudioConfiguration.objects.create(name='survey', enabled=False, support_level="fs")
|
||||
XBlockStudioConfigurationFlag.objects.create(enabled=True)
|
||||
self.course.advanced_modules.extend(['poll', 'survey'])
|
||||
templates = get_component_templates(self.course)
|
||||
button_names = [template['display_name'] for template in templates]
|
||||
self.assertNotIn('Advanced', button_names)
|
||||
|
||||
@patch('django.conf.settings.DEPRECATED_ADVANCED_COMPONENT_TYPES', [])
|
||||
def test_cannot_create_deprecated_problems(self):
|
||||
"""
|
||||
Test that we can't create problems if they are deprecated
|
||||
Test that xblocks that have Studio support disabled do not show on the "new component" menu.
|
||||
"""
|
||||
XBlockDisableConfig.objects.create(disabled_create_blocks='poll survey', enabled=True)
|
||||
# Update poll to have "enabled=False".
|
||||
XBlockStudioConfiguration.objects.create(name='poll', enabled=False, support_level="fs")
|
||||
XBlockStudioConfigurationFlag.objects.create(enabled=True)
|
||||
self.course.advanced_modules.extend(['annotatable', 'poll', 'survey'])
|
||||
templates = get_component_templates(self.course)
|
||||
button_names = [template['display_name'] for template in templates]
|
||||
self.assertIn('Advanced', button_names)
|
||||
self.assertEqual(len(templates[0]['templates']), 1)
|
||||
template_display_names = [template['display_name'] for template in templates[0]['templates']]
|
||||
self.assertEqual(template_display_names, ['Annotation'])
|
||||
# Annotatable doesn't show up because it is unsupported (in test setUp).
|
||||
self._verify_advanced_xblocks(['Survey'], ['ps'])
|
||||
|
||||
@patch('django.conf.settings.DEPRECATED_ADVANCED_COMPONENT_TYPES', ['poll'])
|
||||
def test_create_non_deprecated_problems(self):
|
||||
# Now enable unsupported components.
|
||||
self.course.allow_unsupported_xblocks = True
|
||||
self._verify_advanced_xblocks(['Annotation', 'Survey'], ['us', 'ps'])
|
||||
|
||||
# Now disable Annotatable completely through XBlockConfiguration
|
||||
XBlockConfiguration.objects.create(name='annotatable', enabled=False)
|
||||
self._verify_advanced_xblocks(['Survey'], ['ps'])
|
||||
|
||||
def test_create_support_level_flag_off(self):
|
||||
"""
|
||||
Test that we can create problems if they are not deprecated
|
||||
Test that we can create any advanced xblock (that isn't completely disabled through
|
||||
XBlockConfiguration) if XBlockStudioConfigurationFlag is False.
|
||||
"""
|
||||
XBlockStudioConfigurationFlag.objects.create(enabled=False)
|
||||
self.course.advanced_modules.extend(['annotatable', 'survey'])
|
||||
self._verify_advanced_xblocks(['Annotation', 'Survey'], [True, True])
|
||||
|
||||
def test_xblock_masquerading_as_problem(self):
|
||||
"""
|
||||
Test the integration of xblocks masquerading as problems.
|
||||
"""
|
||||
def get_openassessment():
|
||||
""" Helper method to return the openassessment template from problem list """
|
||||
self.templates = get_component_templates(self.course)
|
||||
problem_templates = self.get_templates_of_type('problem')
|
||||
return self.get_template(problem_templates, u'Peer Assessment')
|
||||
|
||||
def verify_openassessment_present(support_level):
|
||||
""" Helper method to verify that openassessment template is present """
|
||||
openassessment = get_openassessment()
|
||||
self.assertIsNotNone(openassessment)
|
||||
self.assertEqual(openassessment.get('category'), 'openassessment')
|
||||
self.assertEqual(openassessment.get('support_level'), support_level)
|
||||
|
||||
verify_openassessment_present(True)
|
||||
|
||||
# Now enable XBlockStudioConfigurationFlag. The openassessment block is marked
|
||||
# unsupported, so will no longer show up.
|
||||
XBlockStudioConfigurationFlag.objects.create(enabled=True)
|
||||
self.assertIsNone(get_openassessment())
|
||||
|
||||
# Now allow unsupported components.
|
||||
self.course.allow_unsupported_xblocks = True
|
||||
verify_openassessment_present('us')
|
||||
|
||||
# Now disable openassessment completely through XBlockConfiguration
|
||||
XBlockConfiguration.objects.create(name='openassessment', enabled=False)
|
||||
self.assertIsNone(get_openassessment())
|
||||
|
||||
def _verify_advanced_xblocks(self, expected_xblocks, expected_support_levels):
|
||||
"""
|
||||
Verify the names of the advanced xblocks showing in the "new component" menu.
|
||||
"""
|
||||
self.course.advanced_modules.extend(['annotatable', 'poll', 'survey'])
|
||||
templates = get_component_templates(self.course)
|
||||
button_names = [template['display_name'] for template in templates]
|
||||
self.assertIn('Advanced', button_names)
|
||||
self.assertEqual(len(templates[0]['templates']), 2)
|
||||
self.assertEqual(len(templates[0]['templates']), len(expected_xblocks))
|
||||
template_display_names = [template['display_name'] for template in templates[0]['templates']]
|
||||
self.assertEqual(template_display_names, ['Annotation', 'Survey'])
|
||||
self.assertEqual(template_display_names, expected_xblocks)
|
||||
template_support_levels = [template['support_level'] for template in templates[0]['templates']]
|
||||
self.assertEqual(template_support_levels, expected_support_levels)
|
||||
|
||||
def _verify_basic_component(self, component_type, display_name, support_level=True):
|
||||
"""
|
||||
Verify the display name and support level of basic components (that have no boilerplates).
|
||||
"""
|
||||
templates = self.get_templates_of_type(component_type)
|
||||
self.assertEqual(1, len(templates))
|
||||
self.assertEqual(display_name, templates[0]['display_name'])
|
||||
self.assertEqual(support_level, templates[0]['support_level'])
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
|
||||
Reference in New Issue
Block a user