Exemple #1
0
def _xblock_type_and_display_name(xblock):
    """
    Returns a string representation of the xblock's type and display name
    """
    return _('{section_or_subsection} "{display_name}"').format(
        section_or_subsection=xblock_type_display_name(xblock),
        display_name=xblock.display_name_with_default)
Exemple #2
0
def _xblock_type_and_display_name(xblock):
    """
    Returns a string representation of the xblock's type and display name
    """
    return _('{section_or_subsection} "{display_name}"').format(
        section_or_subsection=xblock_type_display_name(xblock),
        display_name=xblock.display_name_with_default)
Exemple #3
0
def _create_xblock_child_info(xblock, course_outline, graders, include_children_predicate=NEVER, user=None):
    """
    Returns information about the children of an xblock, as well as about the primary category
    of xblock expected as children.
    """
    child_info = {}
    child_category = xblock_primary_child_category(xblock)
    if child_category:
        child_info = {
            "category": child_category,
            "display_name": xblock_type_display_name(child_category, default_display_name=child_category),
        }
    if xblock.has_children and include_children_predicate(xblock):
        child_info["children"] = [
            create_xblock_info(
                child,
                include_child_info=True,
                course_outline=course_outline,
                include_children_predicate=include_children_predicate,
                parent_xblock=xblock,
                graders=graders,
                user=user,
            )
            for child in xblock.get_children()
        ]
    return child_info
Exemple #4
0
def _create_xblock_child_info(xblock,
                              course_outline,
                              graders,
                              include_children_predicate=NEVER):
    """
    Returns information about the children of an xblock, as well as about the primary category
    of xblock expected as children.
    """
    child_info = {}
    child_category = xblock_primary_child_category(xblock)
    if child_category:
        child_info = {
            'category':
            child_category,
            'display_name':
            xblock_type_display_name(child_category,
                                     default_display_name=child_category),
        }
    if xblock.has_children and include_children_predicate(xblock):
        child_info['children'] = [
            create_xblock_info(
                child,
                include_child_info=True,
                course_outline=course_outline,
                include_children_predicate=include_children_predicate,
                parent_xblock=xblock,
                graders=graders) for child in xblock.get_children()
        ]
    return child_info
Exemple #5
0
def _get_release_date_from(xblock):
    """
    Returns a string representation of the section or subsection that sets the xblock's release date
    """
    source = find_release_date_source(xblock)
    # Translators: this will be a part of the release date message.
    # For example, 'Released: Jul 02, 2014 at 4:00 UTC with Section "Week 1"'
    return _('{section_or_subsection} "{display_name}"').format(
        section_or_subsection=xblock_type_display_name(source),
        display_name=source.display_name_with_default)
Exemple #6
0
def _get_release_date_from(xblock):
    """
    Returns a string representation of the section or subsection that sets the xblock's release date
    """
    source = find_release_date_source(xblock)
    # Translators: this will be a part of the release date message.
    # For example, 'Released: Jul 02, 2014 at 4:00 UTC with Section "Week 1"'
    return _('{section_or_subsection} "{display_name}"').format(
        section_or_subsection=xblock_type_display_name(source),
        display_name=source.display_name_with_default)
Exemple #7
0
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):
        """
        Creates a component template dict.

        Parameters
            display_name: the user-visible name of the component
            category: the type of component (problem, html, etc.)
            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

        """
        return {
            "display_name": name,
            "category": cat,
            "boilerplate_name": boilerplate_name,
            "hinted": hinted,
            "tab": tab
        }

    component_display_names = {
        'discussion': _("Discussion"),
        'html': _("HTML"),
        'problem': _("Problem"),
        'video': _("Video")
    }

    component_templates = []
    categories = set()
    # The component_templates array is in the order of "advanced" (if present), followed
    # by the components in the order listed in COMPONENT_TYPES.
    component_types = COMPONENT_TYPES[:]

    # Libraries do not support discussions
    if library:
        component_types = [
            component for component in component_types
            if component != 'discussion'
        ]

    for category in component_types:
        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)

        # 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,
                        ))

        # Add any advanced problem types
        if category == 'problem':
            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)

        component_templates.append({
            "type":
            category,
            "templates":
            templates_for_category,
            "display_name":
            component_display_names[category]
        })

    # Libraries do not support advanced components at this time.
    if library:
        return component_templates

    # Check if there are any advanced modules specified in the course policy.
    # These modules should be specified as a list of strings, where the strings
    # 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()
    # 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:
                # 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))
                    categories.add(category)
                except PluginMissingError:
                    # dhm: I got this once but it can happen any time the
                    # course author configures an advanced component which does
                    # not exist on the server. This code here merely
                    # prevents any authors from trying to instantiate the
                    # non-existent component type by not showing it in the menu
                    log.warning(
                        "Advanced component %s does not exist. It will not be added to the Studio new component menu.",
                        category)
    else:
        log.error("Improper format for course advanced keys! %s",
                  course_advanced_keys)
    if len(advanced_component_templates['templates']) > 0:
        component_templates.insert(0, advanced_component_templates)

    return component_templates
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,
                             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

        """
        return {
            "display_name": name,
            "category": category,
            "boilerplate_name": boilerplate_name,
            "hinted": hinted,
            "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":
            _(u"{platform_name} Support Levels:").format(
                platform_name=settings.PLATFORM_NAME)
        }

    component_display_names = {
        'discussion': _("Discussion"),
        'html': _("HTML"),
        'problem': _("Problem"),
        'video': _("Video")
    }

    component_templates = []
    categories = set()
    # The component_templates array is in the order of "advanced" (if present), followed
    # by the components in the order listed in COMPONENT_TYPES.
    component_types = COMPONENT_TYPES[:]

    # Libraries do not support discussions
    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)

        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):
                    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)

                        templates_for_category.append(
                            create_template_dict(
                                _(template['metadata'].get('display_name')),
                                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,
        # currently not supported in libraries .
        if category == 'problem' and not library:
            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']

                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(
                            u'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],
            "support_legend":
            create_support_legend_dict()
        })

    # Libraries do not support advanced components at this time.
    if library:
        return component_templates

    # Check if there are any advanced modules specified in the course policy.
    # These modules should be specified as a list of strings, where the strings
    # 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"),
        "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.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,
                            advanced_component_types[category]))
                    categories.add(category)
                except PluginMissingError:
                    # dhm: I got this once but it can happen any time the
                    # course author configures an advanced component which does
                    # not exist on the server. This code here merely
                    # prevents any authors from trying to instantiate the
                    # non-existent component type by not showing it in the menu
                    log.warning(
                        u"Advanced component %s does not exist. It will not be added to the Studio new component menu.",
                        category)
    else:
        log.error(u"Improper format for course advanced keys! %s",
                  course_advanced_keys)
    if len(advanced_component_templates['templates']) > 0:
        component_templates.insert(0, advanced_component_templates)

    return component_templates
    def test_xblock_type_display_name(self):

        # Verify chapter type display name
        chapter = ItemFactory.create(parent_location=self.course.location, category="chapter")
        self.assertEqual(xblock_type_display_name(chapter), u"Section")
        self.assertEqual(xblock_type_display_name("chapter"), u"Section")

        # Verify sequential type display name
        sequential = ItemFactory.create(parent_location=chapter.location, category="sequential")
        self.assertEqual(xblock_type_display_name(sequential), u"Subsection")
        self.assertEqual(xblock_type_display_name("sequential"), u"Subsection")

        # Verify unit type display names
        vertical = ItemFactory.create(parent_location=sequential.location, category="vertical")
        self.assertEqual(xblock_type_display_name(vertical), u"Unit")
        self.assertEqual(xblock_type_display_name("vertical"), u"Unit")

        # Verify child vertical type display name
        child_vertical = ItemFactory.create(
            parent_location=vertical.location, category="vertical", display_name="Child Vertical"
        )
        self.assertEqual(xblock_type_display_name(child_vertical), u"Vertical")

        # Verify video type display names
        video = ItemFactory.create(parent_location=vertical.location, category="video")
        self.assertEqual(xblock_type_display_name(video), u"Video")
        self.assertEqual(xblock_type_display_name("video"), u"Video")

        # Verify split test type display names
        split_test = ItemFactory.create(parent_location=vertical.location, category="split_test")
        self.assertEqual(xblock_type_display_name(split_test), u"Content Experiment")
        self.assertEqual(xblock_type_display_name("split_test"), u"Content Experiment")
def get_component_templates(course):
    """
    Returns the applicable component templates that can be used by the specified course.
    """
    def create_template_dict(name, cat, boilerplate_name=None, is_common=False):
        """
        Creates a component template dict.

        Parameters
            display_name: the user-visible name of the component
            category: the type of component (problem, html, etc.)
            boilerplate_name: name of boilerplate for filling in default values. May be None.
            is_common: True if "common" problem, False if "advanced". May be None, as it is only used for problems.

        """
        return {
            "display_name": name,
            "category": cat,
            "boilerplate_name": boilerplate_name,
            "is_common": is_common
        }

    component_display_names = {
        'discussion': _("Discussion"),
        'html': _("HTML"),
        'problem': _("Problem"),
        'video': _("Video")
    }

    component_templates = []
    categories = set()
    # The component_templates array is in the order of "advanced" (if present), followed
    # by the components in the order listed in COMPONENT_TYPES.
    for category in COMPONENT_TYPES:
        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'))
        templates_for_category.append(create_template_dict(display_name, category))
        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, course):
                    templates_for_category.append(
                        create_template_dict(
                            _(template['metadata'].get('display_name')),
                            category,
                            template.get('template_id'),
                            template['metadata'].get('markdown') is not None
                        )
                    )

        # Add any advanced problem types
        if category == 'problem':
            for advanced_problem_type in ADVANCED_PROBLEM_TYPES:
                component = advanced_problem_type['component']
                boilerplate_name = advanced_problem_type['boilerplate_name']
                component_display_name = xblock_type_display_name(component)
                templates_for_category.append(create_template_dict(component_display_name, component, boilerplate_name))
                categories.add(component)

        component_templates.append({
            "type": category,
            "templates": templates_for_category,
            "display_name": component_display_names[category]
        })

    # Check if there are any advanced modules specified in the course policy.
    # These modules should be specified as a list of strings, where the strings
    # are the names of the modules in ADVANCED_COMPONENT_TYPES that should be
    # enabled for the course.
    course_advanced_keys = course.advanced_modules
    advanced_component_templates = {"type": "advanced", "templates": [], "display_name": _("Advanced")}
    # 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 not category 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
                        )
                    )
                    categories.add(category)
                except PluginMissingError:
                    # dhm: I got this once but it can happen any time the
                    # course author configures an advanced component which does
                    # not exist on the server. This code here merely
                    # prevents any authors from trying to instantiate the
                    # non-existent component type by not showing it in the menu
                    log.warning(
                        "Advanced component %s does not exist. It will not be added to the Studio new component menu.",
                        category
                    )
                    pass
    else:
        log.error(
            "Improper format for course advanced keys! %s",
            course_advanced_keys
        )
    if len(advanced_component_templates['templates']) > 0:
        component_templates.insert(0, advanced_component_templates)

    return component_templates
Exemple #11
0
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"):
        """
        Creates a component template dict.

        Parameters
            display_name: the user-visible name of the component
            category: the type of component (problem, html, etc.)
            boilerplate_name: name of boilerplate for filling in default values. May be None.
            tab: common(default)/advanced/hint, which tab it goes in

        """
        return {
            "display_name": name,
            "category": cat,
            "boilerplate_name": boilerplate_name,
            "tab": tab
        }

    component_display_names = {
        'discussion': _("Discussion"),
        'html': _("HTML"),
        'problem': _("Problem"),
        'video': _("Video")
    }

    component_templates = []
    categories = set()
    # The component_templates array is in the order of "advanced" (if present), followed
    # by the components in the order listed in COMPONENT_TYPES.
    component_types = COMPONENT_TYPES[:]

    # Libraries do not support discussions
    if library:
        component_types = [component for component in component_types if component != 'discussion']

    for category in component_types:
        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)

        # 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' 'hint'
                    # Default setting is common/advanced depending on the presence of markdown
                    tab = 'common'
                    if template['metadata'].get('markdown') is None:
                        tab = 'advanced'
                    # Then the problem can override that with a tab: attribute (note: not nested in metadata)
                    tab = template.get('tab', tab)

                    templates_for_category.append(
                        create_template_dict(
                            _(template['metadata'].get('display_name')),    # pylint: disable=translation-of-non-string
                            category,
                            template.get('template_id'),
                            tab
                        )
                    )

        # Add any advanced problem types
        if category == 'problem':
            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)

        component_templates.append({
            "type": category,
            "templates": templates_for_category,
            "display_name": component_display_names[category]
        })

    # Libraries do not support advanced components at this time.
    if library:
        return component_templates

    # Check if there are any advanced modules specified in the course policy.
    # These modules should be specified as a list of strings, where the strings
    # 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()
    # Set component types according to course policy file
    course_advanced_keys = course_advanced_keys or []
    course_advanced_keys = list(set(course_advanced_keys + XBLOCKS_ALWAYS_IN_STUDIO))
    if isinstance(course_advanced_keys, list):
        for category in course_advanced_keys:
            if category in advanced_component_types 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
                        )
                    )
                    categories.add(category)
                except PluginMissingError:
                    # dhm: I got this once but it can happen any time the
                    # course author configures an advanced component which does
                    # not exist on the server. This code here merely
                    # prevents any authors from trying to instantiate the
                    # non-existent component type by not showing it in the menu
                    log.warning(
                        "Advanced component %s does not exist. It will not be added to the Studio new component menu.",
                        category
                    )
    else:
        log.error(
            "Improper format for course advanced keys! %s",
            course_advanced_keys
        )
    if len(advanced_component_templates['templates']) > 0:
        component_templates.insert(0, advanced_component_templates)

    return component_templates
Exemple #12
0
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, 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

        """
        return {
            "display_name": name,
            "category": category,
            "boilerplate_name": boilerplate_name,
            "hinted": hinted,
            "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 = {
        'discussion': _("Discussion"),
        'html': _("HTML"),
        'problem': _("Problem"),
        'video': _("Video")
    }

    component_templates = []
    categories = set()
    # The component_templates array is in the order of "advanced" (if present), followed
    # by the components in the order listed in COMPONENT_TYPES.
    component_types = COMPONENT_TYPES[:]

    # Libraries do not support discussions
    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)

        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):
                    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)

                        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,
        # currently not supported in libraries .
        if category == 'problem' and not library:
            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']

                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],
            "support_legend": create_support_legend_dict()
        })

    # Libraries do not support advanced components at this time.
    if library:
        return component_templates

    # Check if there are any advanced modules specified in the course policy.
    # These modules should be specified as a list of strings, where the strings
    # 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"),
        "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.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,
                            advanced_component_types[category]
                        )
                    )
                    categories.add(category)
                except PluginMissingError:
                    # dhm: I got this once but it can happen any time the
                    # course author configures an advanced component which does
                    # not exist on the server. This code here merely
                    # prevents any authors from trying to instantiate the
                    # non-existent component type by not showing it in the menu
                    log.warning(
                        "Advanced component %s does not exist. It will not be added to the Studio new component menu.",
                        category
                    )
    else:
        log.error(
            "Improper format for course advanced keys! %s",
            course_advanced_keys
        )
    if len(advanced_component_templates['templates']) > 0:
        component_templates.insert(0, advanced_component_templates)

    return component_templates
Exemple #13
0
def get_component_templates(course):
    """
    Returns the applicable component templates that can be used by the specified course.
    """
    def create_template_dict(name, cat, boilerplate_name=None, is_common=False):
        """
        Creates a component template dict.

        Parameters
            display_name: the user-visible name of the component
            category: the type of component (problem, html, etc.)
            boilerplate_name: name of boilerplate for filling in default values. May be None.
            is_common: True if "common" problem, False if "advanced". May be None, as it is only used for problems.

        """
        return {
            "display_name": name,
            "category": cat,
            "boilerplate_name": boilerplate_name,
            "is_common": is_common
        }

    component_display_names = {
        'discussion': _("Discussion"),
        'html': _("HTML"),
        'problem': _("Problem"),
        'video': _("Video")
    }

    component_templates = []
    categories = set()
    # The component_templates array is in the order of "advanced" (if present), followed
    # by the components in the order listed in COMPONENT_TYPES.
    for category in COMPONENT_TYPES:
        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'))
        templates_for_category.append(create_template_dict(display_name, category))
        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, course):
                    templates_for_category.append(
                        create_template_dict(
                            _(template['metadata'].get('display_name')),
                            category,
                            template.get('template_id'),
                            template['metadata'].get('markdown') is not None
                        )
                    )

        # Add any advanced problem types
        if category == 'problem':
            for advanced_problem_type in ADVANCED_PROBLEM_TYPES:
                component = advanced_problem_type['component']
                boilerplate_name = advanced_problem_type['boilerplate_name']
                component_display_name = xblock_type_display_name(component)
                templates_for_category.append(create_template_dict(component_display_name, component, boilerplate_name))
                categories.add(component)

        component_templates.append({
            "type": category,
            "templates": templates_for_category,
            "display_name": component_display_names[category]
        })

    # Check if there are any advanced modules specified in the course policy.
    # These modules should be specified as a list of strings, where the strings
    # are the names of the modules in ADVANCED_COMPONENT_TYPES that should be
    # enabled for the course.
    course_advanced_keys = course.advanced_modules
    advanced_component_templates = {"type": "advanced", "templates": [], "display_name": _("Advanced")}
    # 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 not category 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
                        )
                    )
                    categories.add(category)
                except PluginMissingError:
                    # dhm: I got this once but it can happen any time the
                    # course author configures an advanced component which does
                    # not exist on the server. This code here merely
                    # prevents any authors from trying to instantiate the
                    # non-existent component type by not showing it in the menu
                    log.warning(
                        "Advanced component %s does not exist. It will not be added to the Studio new component menu.",
                        category
                    )
                    pass
    else:
        log.error(
            "Improper format for course advanced keys! %s",
            course_advanced_keys
        )
    if len(advanced_component_templates['templates']) > 0:
        component_templates.insert(0, advanced_component_templates)

    return component_templates
Exemple #14
0
    def test_xblock_type_display_name(self):

        # Verify chapter type display name
        chapter = ItemFactory.create(parent_location=self.course.location,
                                     category='chapter')
        self.assertEqual(xblock_type_display_name(chapter), u'Section')
        self.assertEqual(xblock_type_display_name('chapter'), u'Section')

        # Verify sequential type display name
        sequential = ItemFactory.create(parent_location=chapter.location,
                                        category='sequential')
        self.assertEqual(xblock_type_display_name(sequential), u'Subsection')
        self.assertEqual(xblock_type_display_name('sequential'), u'Subsection')

        # Verify unit type display names
        vertical = ItemFactory.create(parent_location=sequential.location,
                                      category='vertical')
        self.assertEqual(xblock_type_display_name(vertical), u'Unit')
        self.assertEqual(xblock_type_display_name('vertical'), u'Unit')

        # Verify child vertical type display name
        child_vertical = ItemFactory.create(parent_location=vertical.location,
                                            category='vertical',
                                            display_name='Child Vertical')
        self.assertEqual(xblock_type_display_name(child_vertical), u'Vertical')

        # Verify video type display names
        video = ItemFactory.create(parent_location=vertical.location,
                                   category="video")
        self.assertEqual(xblock_type_display_name(video), u'Video')
        self.assertEqual(xblock_type_display_name('video'), u'Video')

        # Verify split test type display names
        split_test = ItemFactory.create(parent_location=vertical.location,
                                        category="split_test")
        self.assertEqual(xblock_type_display_name(split_test),
                         u'Content Experiment')
        self.assertEqual(xblock_type_display_name('split_test'),
                         u'Content Experiment')
    def test_xblock_type_display_name(self):

        # Verify chapter type display name
        chapter = ItemFactory.create(parent_location=self.course.location, category='chapter')
        self.assertEqual(xblock_type_display_name(chapter), u'Section')
        self.assertEqual(xblock_type_display_name('chapter'), u'Section')

        # Verify sequential type display name
        sequential = ItemFactory.create(parent_location=chapter.location, category='sequential')
        self.assertEqual(xblock_type_display_name(sequential), u'Subsection')
        self.assertEqual(xblock_type_display_name('sequential'), u'Subsection')

        # Verify unit type display names
        vertical = ItemFactory.create(parent_location=sequential.location, category='vertical')
        self.assertEqual(xblock_type_display_name(vertical), u'Unit')
        self.assertEqual(xblock_type_display_name('vertical'), u'Unit')

        # Verify child vertical type display name
        child_vertical = ItemFactory.create(parent_location=vertical.location, category='vertical',
                                            display_name='Child Vertical')
        self.assertEqual(xblock_type_display_name(child_vertical), u'Vertical')

        # Verify video type display names
        video = ItemFactory.create(parent_location=vertical.location, category="video")
        self.assertEqual(xblock_type_display_name(video), u'Video')
        self.assertEqual(xblock_type_display_name('video'), u'Video')

        # Verify split test type display names
        split_test = ItemFactory.create(parent_location=vertical.location, category="split_test")
        self.assertEqual(xblock_type_display_name(split_test), u'Content Experiment')
        self.assertEqual(xblock_type_display_name('split_test'), u'Content Experiment')