Commit cc7017e8 by cahrens

Updates to support templates.

parent e047a30b
...@@ -57,10 +57,17 @@ def _advanced_component_types(show_unsupported): ...@@ -57,10 +57,17 @@ def _advanced_component_types(show_unsupported):
Return advanced component types which can be created. Return advanced component types which can be created.
""" """
if XBlockConfigFlag.is_enabled(): if XBlockConfigFlag.is_enabled():
authorable_xblock_types = [block.name for block in XBlockConfig.authorable_xblocks(show_unsupported)] authorable_blocks = {}
return [c_type for c_type in ADVANCED_COMPONENT_TYPES if c_type in authorable_xblock_types] for block in XBlockConfig.authorable_xblocks(show_unsupported):
if block.name in ADVANCED_COMPONENT_TYPES:
authorable_blocks[block.name] = block.support_level
return authorable_blocks
else: else:
return [c_type for c_type in ADVANCED_COMPONENT_TYPES] authorable_blocks = {}
for c_type in ADVANCED_COMPONENT_TYPES:
authorable_blocks[c_type] = True
return authorable_blocks
def _load_mixed_class(category): def _load_mixed_class(category):
...@@ -155,7 +162,7 @@ def get_component_templates(courselike, library=False): ...@@ -155,7 +162,7 @@ def get_component_templates(courselike, library=False):
""" """
Returns the applicable component templates that can be used by the specified course or library. 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, cat, boilerplate_name=None, tab="common", hinted=False, support_level="full"):
""" """
Creates a component template dict. Creates a component template dict.
...@@ -172,9 +179,24 @@ def get_component_templates(courselike, library=False): ...@@ -172,9 +179,24 @@ def get_component_templates(courselike, library=False):
"category": cat, "category": cat,
"boilerplate_name": boilerplate_name, "boilerplate_name": boilerplate_name,
"hinted": hinted, "hinted": hinted,
"tab": tab "tab": tab,
"support_level": support_level
} }
def component_editable(enabled_types, template=None):
if not XBlockConfigFlag.is_enabled():
return True
if template is None:
template = ""
extension_index = template.rfind(".yaml")
if extension_index:
template = template[0:extension_index]
for block in enabled_types:
if block.template==template:
return block.support_level
return False
component_display_names = { component_display_names = {
'discussion': _("Discussion"), 'discussion': _("Discussion"),
'html': _("HTML"), 'html': _("HTML"),
...@@ -192,53 +214,63 @@ def get_component_templates(courselike, library=False): ...@@ -192,53 +214,63 @@ def get_component_templates(courselike, library=False):
if library: if library:
component_types = [component for component in component_types if component != 'discussion'] component_types = [component for component in component_types if component != 'discussion']
limited_support_opt_in = not courselike.enforce_supported_xblocks
for category in component_types: for category in component_types:
enabled_types = XBlockConfig.authorable_xblocks(limited_support_opt_in=limited_support_opt_in, name=category)
templates_for_category = [] templates_for_category = []
component_class = _load_mixed_class(category) component_class = _load_mixed_class(category)
# add the default template with localized display name # add the default template with localized display name
# TODO: Once mixins are defined per-application, rather than per-runtime, # TODO: Once mixins are defined per-application, rather than per-runtime,
# this should use a cms mixed-in class. (cpennington) # this should use a cms mixed-in class. (cpennington)
display_name = xblock_type_display_name(category, _('Blank')) # this is the Blank Advanced problem supported = component_editable(enabled_types)
templates_for_category.append(create_template_dict(display_name, category, None, 'advanced')) if supported:
categories.add(category) 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', support_level=supported))
categories.add(category)
# add boilerplates # add boilerplates
if hasattr(component_class, 'templates'): if hasattr(component_class, 'templates'):
for template in component_class.templates(): for template in component_class.templates():
filter_templates = getattr(component_class, 'filter_templates', None) filter_templates = getattr(component_class, 'filter_templates', None)
if not filter_templates or filter_templates(template, courselike): if not filter_templates or filter_templates(template, courselike):
# Tab can be 'common' 'advanced' supported = component_editable(enabled_types, template.get('template_id'))
# Default setting is common/advanced depending on the presence of markdown if supported:
tab = 'common' # Tab can be 'common' 'advanced'
if template['metadata'].get('markdown') is None: # Default setting is common/advanced depending on the presence of markdown
tab = 'advanced' tab = 'common'
hinted = template.get('hinted', False) if template['metadata'].get('markdown') is None:
tab = 'advanced'
templates_for_category.append( hinted = template.get('hinted', False)
create_template_dict(
_(template['metadata'].get('display_name')), # pylint: disable=translation-of-non-string templates_for_category.append(
category, create_template_dict(
template.get('template_id'), _(template['metadata'].get('display_name')), # pylint: disable=translation-of-non-string
tab, category,
hinted, template.get('template_id'),
tab,
hinted,
supported
)
) )
)
# Add any advanced problem types. Note that this are different xblocks being stored as Advanced Problems. # Add any advanced problem types. Note that this are different xblocks being stored as Advanced Problems.
if category == 'problem': if category == 'problem':
for advanced_problem_type in ADVANCED_PROBLEM_TYPES: for advanced_problem_type in ADVANCED_PROBLEM_TYPES:
# TODO: check the state of these also, since they are actually xblocks?
component = advanced_problem_type['component'] component = advanced_problem_type['component']
advanced_enabled_types = XBlockConfig.authorable_xblocks(limited_support_opt_in=limited_support_opt_in, name=component)
boilerplate_name = advanced_problem_type['boilerplate_name'] boilerplate_name = advanced_problem_type['boilerplate_name']
try:
component_display_name = xblock_type_display_name(component) supported = component_editable(advanced_enabled_types, boilerplate_name)
except PluginMissingError: if supported:
log.warning('Unable to load xblock type %s to read display_name', component, exc_info=True) try:
else: component_display_name = xblock_type_display_name(component)
templates_for_category.append( except PluginMissingError:
create_template_dict(component_display_name, component, boilerplate_name, 'advanced') log.warning('Unable to load xblock type %s to read display_name', component, exc_info=True)
) else:
categories.add(component) templates_for_category.append(
create_template_dict(component_display_name, component, boilerplate_name, 'advanced', support_level=supported)
)
categories.add(component)
component_templates.append({ component_templates.append({
"type": category, "type": category,
...@@ -257,18 +289,21 @@ def get_component_templates(courselike, library=False): ...@@ -257,18 +289,21 @@ def get_component_templates(courselike, library=False):
course_advanced_keys = courselike.advanced_modules course_advanced_keys = courselike.advanced_modules
advanced_component_templates = {"type": "advanced", "templates": [], "display_name": _("Advanced")} advanced_component_templates = {"type": "advanced", "templates": [], "display_name": _("Advanced")}
# TODO: pass in the value for this course of whether or not unsupported xblocks can be displayed. # TODO: pass in the value for this course of whether or not unsupported xblocks can be displayed.
advanced_component_types = _advanced_component_types(False) advanced_component_types = _advanced_component_types(limited_support_opt_in)
# Set component types according to course policy file # Set component types according to course policy file
if isinstance(course_advanced_keys, list): if isinstance(course_advanced_keys, list):
for category in course_advanced_keys: 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 # boilerplates not supported for advanced components
try: try:
component_display_name = xblock_type_display_name(category, default_display_name=category) component_display_name = xblock_type_display_name(category, default_display_name=category)
advanced_component_templates['templates'].append( advanced_component_templates['templates'].append(
create_template_dict( create_template_dict(
component_display_name, component_display_name,
category category,
support_level=advanced_component_types[category]
) )
) )
categories.add(category) categories.add(category)
......
...@@ -76,7 +76,7 @@ for log_name, log_level in LOG_OVERRIDES: ...@@ -76,7 +76,7 @@ for log_name, log_level in LOG_OVERRIDES:
FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] = True FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] = True
# Enable milestones app # Enable milestones app
FEATURES['MILESTONES_APP'] = True FEATURES['MILESTONES_APP'] = False
# Enable pre-requisite course # Enable pre-requisite course
FEATURES['ENABLE_PREREQUISITE_COURSES'] = True FEATURES['ENABLE_PREREQUISITE_COURSES'] = True
...@@ -113,7 +113,7 @@ YOUTUBE['TEXT_API']['url'] = "127.0.0.1:{0}/test_transcripts_youtube/".format(YO ...@@ -113,7 +113,7 @@ YOUTUBE['TEXT_API']['url'] = "127.0.0.1:{0}/test_transcripts_youtube/".format(YO
FEATURES['ENABLE_COURSEWARE_INDEX'] = True FEATURES['ENABLE_COURSEWARE_INDEX'] = True
FEATURES['ENABLE_LIBRARY_INDEX'] = True FEATURES['ENABLE_LIBRARY_INDEX'] = True
FEATURES['ORGANIZATIONS_APP'] = True FEATURES['ORGANIZATIONS_APP'] = False
SEARCH_ENGINE = "search.tests.mock_search_engine.MockSearchEngine" SEARCH_ENGINE = "search.tests.mock_search_engine.MockSearchEngine"
# Path at which to store the mock index # Path at which to store the mock index
MOCK_SEARCH_BACKING_FILE = ( MOCK_SEARCH_BACKING_FILE = (
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
<li class="editor-md empty"> <li class="editor-md empty">
<button type="button" class="button-component" data-category="<%= templates[i].category %>"> <button type="button" class="button-component" data-category="<%= templates[i].category %>">
<span class="name"><%= templates[i].display_name %></span> <span class="name"><%= templates[i].display_name %></span>
<% if (templates[i].support_level !== true){ %>
<span class="support">(<%-templates[i].support_level %>)</span>
<% } %>
</button> </button>
</li> </li>
<% } else { %> <% } else { %>
...@@ -28,6 +31,9 @@ ...@@ -28,6 +31,9 @@
<button type="button" class="button-component" data-category="<%= templates[i].category %>" <button type="button" class="button-component" data-category="<%= templates[i].category %>"
data-boilerplate="<%= templates[i].boilerplate_name %>"> data-boilerplate="<%= templates[i].boilerplate_name %>">
<span class="name"><%= templates[i].display_name %></span> <span class="name"><%= templates[i].display_name %></span>
<% if (templates[i].support_level !== true){ %>
<span class="support">(<%- templates[i].support_level %>)</span>
<% } %>
</button> </button>
</li> </li>
<% } %> <% } %>
...@@ -43,6 +49,9 @@ ...@@ -43,6 +49,9 @@
<button type="button" class="button-component" data-category="<%= templates[i].category %>" <button type="button" class="button-component" data-category="<%= templates[i].category %>"
data-boilerplate="<%= templates[i].boilerplate_name %>"> data-boilerplate="<%= templates[i].boilerplate_name %>">
<span class="name"><%= templates[i].display_name %></span> <span class="name"><%= templates[i].display_name %></span>
<% if (templates[i].support_level !== true){ %>
<span class="support">(<%- templates[i].support_level %>)</span>
<% } %>
</button> </button>
</li> </li>
<% } %> <% } %>
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
<li class="editor-md empty"> <li class="editor-md empty">
<button type="button" class="button-component" data-category="<%= templates[i].category %>"> <button type="button" class="button-component" data-category="<%= templates[i].category %>">
<span class="name"><%= templates[i].display_name %></span> <span class="name"><%= templates[i].display_name %></span>
<% if (templates[i].support_level !== true){ %>
<span class="support">(<%-templates[i].support_level%>)</span>
<% } %>
</button> </button>
</li> </li>
<% } else { %> <% } else { %>
...@@ -19,6 +22,9 @@ ...@@ -19,6 +22,9 @@
<button type="button" class="button-component" data-category="<%= templates[i].category %>" <button type="button" class="button-component" data-category="<%= templates[i].category %>"
data-boilerplate="<%= templates[i].boilerplate_name %>"> data-boilerplate="<%= templates[i].boilerplate_name %>">
<span class="name"><%= templates[i].display_name %></span> <span class="name"><%= templates[i].display_name %></span>
<% if (templates[i].support_level !== true){ %>
<span class="support">(<%- templates[i].support_level %>)</span>
<% } %>
</button> </button>
</li> </li>
<% } %> <% } %>
......
...@@ -9,7 +9,7 @@ from xblock_django.models import XBlockDisableConfig, XBlockConfig, XBlockConfig ...@@ -9,7 +9,7 @@ from xblock_django.models import XBlockDisableConfig, XBlockConfig, XBlockConfig
class XBlockConfigAdmin(admin.ModelAdmin): class XBlockConfigAdmin(admin.ModelAdmin):
"""Admin for XBlock Configuration""" """Admin for XBlock Configuration"""
list_display = ('name', 'support_level', 'deprecated') list_display = ('name', 'template', 'support_level', 'deprecated')
admin.site.register(XBlockDisableConfig, ConfigurationModelAdmin) admin.site.register(XBlockDisableConfig, ConfigurationModelAdmin)
admin.site.register(XBlockConfigFlag, ConfigurationModelAdmin) admin.site.register(XBlockConfigFlag, ConfigurationModelAdmin)
......
...@@ -100,12 +100,21 @@ class XBlockConfig(models.Model): ...@@ -100,12 +100,21 @@ class XBlockConfig(models.Model):
(DISABLED, _('Disabled')), (DISABLED, _('Disabled')),
) )
name = models.CharField(max_length=255, primary_key=True) name = models.CharField(max_length=255, null=False)
template = models.CharField(max_length=255, blank=True, default='')
support_level = models.CharField(max_length=2, choices=SUPPORT_CHOICES, default=UNSUPPORTED_NO_OPT_IN) support_level = models.CharField(max_length=2, choices=SUPPORT_CHOICES, default=UNSUPPORTED_NO_OPT_IN)
deprecated = models.BooleanField(default=False, verbose_name=_('show deprecation messaging in Studio')) deprecated = models.BooleanField(
default=False,
verbose_name=_('show deprecation messaging in Studio'),
help_text=_("Only xblocks listed in a course's Advanced Module List can be flagged as deprecated. Note that deprecation is by xblock name, and is not specific to template.")
)
# TODO: error if deprecated is set on core xblock types?
# TODO: error if disabled is set on core xblock types (or something with a template)?
class Meta(object): class Meta(object):
app_label = "xblock_django" app_label = "xblock_django"
unique_together = ("name", "template")
@classmethod @classmethod
def deprecated_xblocks(cls): def deprecated_xblocks(cls):
...@@ -120,12 +129,16 @@ class XBlockConfig(models.Model): ...@@ -120,12 +129,16 @@ class XBlockConfig(models.Model):
return cls.objects.filter(support_level=cls.DISABLED) return cls.objects.filter(support_level=cls.DISABLED)
@classmethod @classmethod
def authorable_xblocks(cls, limited_support_opt_in=False): def authorable_xblocks(cls, limited_support_opt_in=False, name=None):
""" Return list of xblocks that can be created in Studio """ """ Return list of xblocks that can be created in Studio """
blocks = cls.objects.exclude(support_level=cls.DISABLED).exclude(support_level=cls.UNSUPPORTED_NO_OPT_IN) blocks = cls.objects.exclude(support_level=cls.DISABLED).exclude(support_level=cls.UNSUPPORTED_NO_OPT_IN)
if not limited_support_opt_in: if not limited_support_opt_in:
blocks.exclude(support_level=cls.UNSUPPORTED_OPT_IN) blocks = blocks.exclude(support_level=cls.UNSUPPORTED_OPT_IN)
if name:
blocks = blocks.filter(name=name)
return blocks return blocks
......
...@@ -413,6 +413,11 @@ class CourseFields(object): ...@@ -413,6 +413,11 @@ class CourseFields(object):
help=_("Enter the names of the advanced components to use in your course."), help=_("Enter the names of the advanced components to use in your course."),
scope=Scope.settings scope=Scope.settings
) )
enforce_supported_xblocks = Boolean(
display_name=_("Only allow the creation of fully supported components"),
help=_("Only allow the creation of fully supported and accessible components in Studio. Scary legal text..."),
scope=Scope.settings, default=True
)
has_children = True has_children = True
info_sidebar_name = String( info_sidebar_name = String(
display_name=_("Course Home Sidebar Name"), display_name=_("Course Home Sidebar Name"),
......
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