Ejemplo n.º 1
0
def test_ambiguous_plugins():
    # We can load ok blocks even if there are bad blocks.
    cls = XBlock.load_class("good_block")
    assert_is(cls, UnambiguousBlock)

    # Trying to load bad blocks raises an exception.
    expected_msg = (
        "Ambiguous entry points for bad_block: "
        "xblock.test.test_plugin.AmbiguousBlock1, "
        "xblock.test.test_plugin.AmbiguousBlock2"
    )
    with assert_raises_regexp(AmbiguousPluginError, expected_msg):
        XBlock.load_class("bad_block")

    # We can use our own function as the select function.
    class MyOwnException(Exception):
        """We'll raise this from `boom`."""
        pass

    def boom(identifier, entry_points):
        """A select function to prove user-defined functions are called."""
        assert len(entry_points) == 2
        assert identifier == "bad_block"
        raise MyOwnException("This is boom")

    with assert_raises_regexp(MyOwnException, "This is boom"):
        XBlock.load_class("bad_block", select=boom)
Ejemplo n.º 2
0
def test_nosuch_plugin():
    # We can provide a default class to return for missing plugins.
    cls = XBlock.load_class("nosuch_block", default=UnambiguousBlock)
    assert_is(cls, UnambiguousBlock)

    # If we don't provide a default class, an exception is raised.
    with assert_raises_regexp(PluginMissingError, "nosuch_block"):
        XBlock.load_class("nosuch_block")
Ejemplo n.º 3
0
def test_nosuch_plugin():
    # We can provide a default class to return for missing plugins.
    cls = XBlock.load_class("nosuch_block", default=UnambiguousBlock)
    assert cls is UnambiguousBlock

    # If we don't provide a default class, an exception is raised.
    with pytest.raises(PluginMissingError, match="nosuch_block"):
        XBlock.load_class("nosuch_block")
Ejemplo n.º 4
0
def test_plugin_caching():
    plugin.PLUGIN_CACHE = {}
    assert_equals(_num_plugins_cached(), 0)

    XBlock.load_class("thumbs")
    assert_equals(_num_plugins_cached(), 1)

    XBlock.load_class("thumbs")
    assert_equals(_num_plugins_cached(), 1)
Ejemplo n.º 5
0
def test_plugin_caching():
    plugin.PLUGIN_CACHE = {}
    assert _num_plugins_cached() == 0

    XBlock.load_class("thumbs")
    assert _num_plugins_cached() == 1

    XBlock.load_class("thumbs")
    assert _num_plugins_cached() == 1
Ejemplo n.º 6
0
    def load_from_json(json_data, system, default_class=None, parent_xblock=None):
        """
        This method instantiates the correct subclass of XModuleDescriptor based
        on the contents of json_data. It does not persist it and can create one which
        has no usage id.

        parent_xblock is used to compute inherited metadata as well as to append the new xblock.

        json_data:
        - 'location' : must have this field
        - 'category': the xmodule category (required or location must be a Location)
        - 'metadata': a dict of locally set metadata (not inherited)
        - 'children': a list of children's usage_ids w/in this course
        - 'definition':
        - '_id' (optional): the usage_id of this. Will generate one if not given one.
        """
        class_ = XBlock.load_class(
            json_data.get("category", json_data.get("location", {}).get("category")),
            default_class,
            select=settings.XBLOCK_SELECT_FUNCTION,
        )
        usage_id = json_data.get("_id", None)
        if not "_inherited_settings" in json_data and parent_xblock is not None:
            json_data["_inherited_settings"] = parent_xblock.xblock_kvs.inherited_settings.copy()
            json_fields = json_data.get("fields", {})
            for field_name in inheritance.InheritanceMixin.fields:
                if field_name in json_fields:
                    json_data["_inherited_settings"][field_name] = json_fields[field_name]

        new_block = system.xblock_from_json(class_, usage_id, json_data)
        if parent_xblock is not None:
            parent_xblock.children.append(new_block.scope_ids.usage_id)
            # decache pending children field settings
            parent_xblock.save()
        return new_block
 def test_all_blocks_excluded_from_completion(self, blockclass):
     xblock = XBlock.load_class(blockclass)
     self.assertEqual(
         XBlockCompletionMode.get_mode(xblock),
         XBlockCompletionMode.EXCLUDED,
         "Block {!r} did not have completion mode 'excluded'".format(xblock),
     )
Ejemplo n.º 8
0
def xblock_type_display_name(xblock, default_display_name=None):
    """
    Returns the display name for the specified type of xblock. Note that an instance can be passed in
    for context dependent names, e.g. a vertical beneath a sequential is a Unit.

    :param xblock: An xblock instance or the type of xblock.
    :param default_display_name: The default value to return if no display name can be found.
    :return:
    """

    if hasattr(xblock, "category"):
        category = xblock.category
        if category == "vertical" and not is_unit(xblock):
            return _("Vertical")
    else:
        category = xblock
    if category == "chapter":
        return _("Section")
    elif category == "sequential":
        return _("Subsection")
    elif category == "vertical":
        return _("Unit")
    component_class = XBlock.load_class(category, select=settings.XBLOCK_SELECT_FUNCTION)
    if hasattr(component_class, "display_name") and component_class.display_name.default:
        return _(component_class.display_name.default)
    else:
        return default_display_name
Ejemplo n.º 9
0
def _load_mixed_class(category):
    """
    Load an XBlock by category name, and apply all defined mixins
    """
    component_class = XBlock.load_class(category, select=settings.XBLOCK_SELECT_FUNCTION)
    mixologist = Mixologist(settings.XBLOCK_MIXINS)
    return mixologist.mix(component_class)
Ejemplo n.º 10
0
    def setUp(self):
        super(TestCourseDetailSerializer, self).setUp()

        # update the expected_data to include the 'overview' data.
        about_descriptor = XBlock.load_class('about')
        overview_template = about_descriptor.get_template('overview.yaml')
        self.expected_data['overview'] = overview_template.get('data')
Ejemplo n.º 11
0
 def construct_xblock(self, plugin_name, field_data, scope_ids, default_class=None, *args, **kwargs):
     """
     Construct a new xblock of the type identified by plugin_name,
     passing *args and **kwargs into __init__
     """
     block_class = XBlock.load_class(plugin_name, default_class)
     return self.construct_xblock_from_class(cls=block_class, field_data=field_data, scope_ids=scope_ids, *args, **kwargs)
Ejemplo n.º 12
0
def create_block_from_xml(xml_data, system, org=None, course=None, default_class=None):
    """
    Create an XBlock instance from XML data.

    `xml_data' is a string containing valid xml.

    `system` is an XMLParsingSystem.

    `org` and `course` are optional strings that will be used in the generated
    block's url identifiers.

    `default_class` is the class to instantiate of the XML indicates a class
    that can't be loaded.

    Returns the fully instantiated XBlock.

    """
    node = etree.fromstring(xml_data)
    raw_class = XBlock.load_class(node.tag, default_class, select=prefer_xmodules)
    xblock_class = system.mixologist.mix(raw_class)

    # leave next line commented out - useful for low-level debugging
    # log.debug('[create_block_from_xml] tag=%s, class=%s' % (node.tag, xblock_class))

    url_name = node.get('url_name', node.get('slug'))
    location = Location('i4x', org, course, node.tag, url_name)

    scope_ids = ScopeIds(None, location.category, location, location)
    xblock = xblock_class.parse_xml(node, system, scope_ids)
    return xblock
Ejemplo n.º 13
0
def xblock_type_display_name(xblock, default_display_name=None):
    """
    Returns the display name for the specified type of xblock. Note that an instance can be passed in
    for context dependent names, e.g. a vertical beneath a sequential is a Unit.

    :param xblock: An xblock instance or the type of xblock.
    :param default_display_name: The default value to return if no display name can be found.
    :return:
    """

    if hasattr(xblock, 'category'):
        category = xblock.category
        if category == 'vertical' and not is_unit(xblock):
            return _('Vertical')
    else:
        category = xblock
    if category == 'chapter':
        return _('Section')
    elif category == 'sequential':
        return _('Subsection')
    elif category == 'vertical':
        return _('Unit')
    component_class = XBlock.load_class(category, select=settings.XBLOCK_SELECT_FUNCTION)
    if hasattr(component_class, 'display_name') and component_class.display_name.default:
        return _(component_class.display_name.default)    # pylint: disable=translation-of-non-string
    else:
        return default_display_name
Ejemplo n.º 14
0
Archivo: parse.py Proyecto: qvin/XBlock
def _process_node(node, usage_factory):
    """Give the XBlock classes a chance to manipulate the tree."""
    block_cls = XBlock.load_class(node.block_name)
    node = block_cls.preprocess_input(node, usage_factory)
    kids = [_process_node(kid, usage_factory) for kid in node.children]
    if any(old is not new for old, new in zip(node.children, kids)):
        node = usage_factory(node.block_name, kids, node.initial_state, node.def_id)
    node = block_cls.postprocess_input(node, usage_factory)
    return node
Ejemplo n.º 15
0
def create_xblock(usage, student_id=None):
    """Create an XBlock instance.

    This will be invoked to create new instances for every request.

    """
    block_cls = XBlock.load_class(usage.block_name)
    runtime = WorkbenchRuntime(block_cls, student_id, usage)
    model = DbModel(MEMORY_KVS, block_cls, student_id, usage)
    block = block_cls(runtime, model)
    return block
Ejemplo n.º 16
0
def package_resource(_request, block_type, resource):
    """
    Wrapper for `pkg_resources` that tries to access a resource and, if it
    is not found, raises an Http404 error.
    """
    try:
        xblock_class = XBlock.load_class(block_type)
        content = xblock_class.open_local_resource(resource)
    except Exception:  # pylint: disable-msg=broad-except
        raise Http404
    mimetype, _ = mimetypes.guess_type(resource)
    return HttpResponse(content, mimetype=mimetype)
Ejemplo n.º 17
0
 def construct_xblock(self, block_type, scope_ids, field_data=None, default_class=None, *args, **kwargs):
     r"""
     Construct a new xblock of the type identified by block_type,
     passing \*args and \*\*kwargs into `__init__`.
     """
     block_class = XBlock.load_class(block_type, default_class)
     return self.construct_xblock_from_class(
         cls=block_class,
         scope_ids=scope_ids,
         field_data=field_data,
         *args, **kwargs
     )
Ejemplo n.º 18
0
    def get(self, block_type, resource):
        xblock_class = XBlock.load_class(block_type)

        mimetype = mimetypes.guess_type(resource)[0]
        if mimetype is None:
            mimetype = 'application/octet-stream'

        self.response.status = 200
        self.response.headers['Content-Type'] = mimetype
        self.response.cache_control.no_cache = None
        self.response.cache_control.public = 'public'
        self.response.cache_control.max_age = 600
        self.response.write(xblock_class.open_local_resource(resource).read())
Ejemplo n.º 19
0
    def partition_fields_by_scope(self, category, fields):
        """
        Return dictionary of {scope: {field1: val, ..}..} for the fields of this potential xblock

        :param category: the xblock category
        :param fields: the dictionary of {fieldname: value}
        """
        if fields is None:
            return {}
        cls = self.mixologist.mix(XBlock.load_class(category, select=prefer_xmodules))
        result = collections.defaultdict(dict)
        for field_name, value in fields.iteritems():
            field = getattr(cls, field_name)
            result[field.scope][field_name] = value
        return result
Ejemplo n.º 20
0
def xblock_resource(request, block_type, uri):  # pylint: disable=unused-argument
    """
    Return a package resource for the specified XBlock.
    """
    try:
        xblock_class = XBlock.load_class(block_type, select=settings.XBLOCK_SELECT_FUNCTION)
        content = xblock_class.open_local_resource(uri)
    except IOError:
        log.info('Failed to load xblock resource', exc_info=True)
        raise Http404
    except Exception:  # pylint: disable=broad-except
        log.error('Failed to load xblock resource', exc_info=True)
        raise Http404
    mimetype, _ = mimetypes.guess_type(uri)
    return HttpResponse(content, mimetype=mimetype)
Ejemplo n.º 21
0
    def _usage_id_from_node(self, node):
        """Create a new usage id from an XML dom node.

        :param node: The DOM node to interpret.
        :type node: `lxml.etree.Element`

        """
        block_type = node.tag
        # TODO: a way for this node to be a usage to an existing definition?
        def_id = self.usage_store.create_definition(block_type)
        usage_id = self.usage_store.create_usage(def_id)
        keys = ScopeIds(UserScope.NONE, block_type, def_id, usage_id)
        block_class = self.mixologist.mix(XBlock.load_class(block_type))
        block = block_class.parse_xml(node, self, keys)
        block.save()
        return usage_id
Ejemplo n.º 22
0
def package_resource(_request, block_type, resource):
    """
    Wrapper for `pkg_resources` that tries to access a resource and, if it
    is not found, raises an Http404 error.
    """
    try:
        xblock_class = XBlock.load_class(block_type)
    except PluginMissingError:
        try:
            xblock_class = XBlockAside.load_class(block_type)
        except PluginMissingError:
            raise Http404
    try:
        content = xblock_class.open_local_resource(resource)
    except Exception:
        raise Http404
    mimetype, _ = mimetypes.guess_type(resource)
    return HttpResponse(content, content_type=mimetype)
Ejemplo n.º 23
0
def xblock_resource(request, block_type, uri):  # pylint: disable=unused-argument
    """
    Return a package resource for the specified XBlock.
    """
    try:
        # Figure out what the XBlock class is from the block type, and
        # then open whatever resource has been requested.
        xblock_class = XBlock.load_class(block_type, select=settings.XBLOCK_SELECT_FUNCTION)
        content = xblock_class.open_local_resource(uri)
    except IOError:
        log.info('Failed to load xblock resource', exc_info=True)
        raise Http404
    except Exception:
        log.error('Failed to load xblock resource', exc_info=True)
        raise Http404

    mimetype, _ = mimetypes.guess_type(uri)
    return HttpResponse(content, content_type=mimetype)
Ejemplo n.º 24
0
def _create_item(request):
    """View for create items."""
    parent_locator = BlockUsageLocator(request.json['parent_locator'])
    parent_location = loc_mapper().translate_locator_to_location(parent_locator)
    category = request.json['category']

    display_name = request.json.get('display_name')

    if not has_course_access(request.user, parent_location):
        raise PermissionDenied()

    parent = get_modulestore(category).get_item(parent_location)
    dest_location = parent_location.replace(category=category, name=uuid4().hex)

    # get the metadata, display_name, and definition from the request
    metadata = {}
    data = None
    template_id = request.json.get('boilerplate')
    if template_id is not None:
        clz = XBlock.load_class(category, select=prefer_xmodules)
        if clz is not None:
            template = clz.get_template(template_id)
            if template is not None:
                metadata = template.get('metadata', {})
                data = template.get('data')

    if display_name is not None:
        metadata['display_name'] = display_name

    get_modulestore(category).create_and_save_xmodule(
        dest_location,
        definition_data=data,
        metadata=metadata,
        system=parent.runtime,
    )

    # TODO replace w/ nicer accessor
    if not 'detached' in parent.runtime.load_block_type(category)._class_tags:
        get_modulestore(parent.location).update_children(parent_location, parent.children + [dest_location.url()])

    course_location = loc_mapper().translate_locator_to_location(parent_locator, get_course=True)
    locator = loc_mapper().translate_location(course_location.course_id, dest_location, False, True)
    return JsonResponse({"locator": unicode(locator)})
Ejemplo n.º 25
0
    def create_course(self, org, course, run, user_id, fields=None, runtime=None, **kwargs):
        """
        Creates any necessary other things for the course as a side effect and doesn't return
        anything useful. The real subclass should call this before it returns the course.
        """
        # clone a default 'about' overview module as well
        about_location = self.make_course_key(org, course, run).make_usage_key('about', 'overview')

        about_descriptor = XBlock.load_class('about')
        overview_template = about_descriptor.get_template('overview.yaml')
        self.create_item(
            user_id,
            about_location.course_key,
            about_location.block_type,
            block_id=about_location.block_id,
            definition_data={'data': overview_template.get('data')},
            metadata=overview_template.get('metadata'),
            runtime=runtime,
            continue_version=True,
        )
Ejemplo n.º 26
0
def xblock_resource(request, block_type, uri):  # pylint: disable=unused-argument
    """
    Return a package resource for the specified XBlock.
    """
    try:
        xblock_class = XBlock.load_class(block_type, select=settings.XBLOCK_SELECT_FUNCTION)
        # Note: in debug mode, return any file rather than going through the XBlock which
        # will only return public files. This allows unbundled files to be served up
        # during development.
        if settings.DEBUG:
            content = pkg_resources.resource_stream(xblock_class.__module__, uri)
        else:
            content = xblock_class.open_local_resource(uri)
    except IOError:
        log.info('Failed to load xblock resource', exc_info=True)
        raise Http404
    except Exception:  # pylint: disable=broad-except
        log.error('Failed to load xblock resource', exc_info=True)
        raise Http404

    mimetype, _ = mimetypes.guess_type(uri)
    return HttpResponse(content, content_type=mimetype)
Ejemplo n.º 27
0
def scorable_block_completion(sender, **kwargs):  # pylint: disable=unused-argument
    """
    When a problem is scored, submit a new BlockCompletion for that block.
    """
    if not waffle.waffle().is_enabled(waffle.ENABLE_COMPLETION_TRACKING):
        return
    course_key = CourseKey.from_string(kwargs['course_id'])
    block_key = UsageKey.from_string(kwargs['usage_id'])
    block_cls = XBlock.load_class(block_key.block_type)
    if getattr(block_cls, 'completion_mode', XBlockCompletionMode.COMPLETABLE) != XBlockCompletionMode.COMPLETABLE:
        return
    if getattr(block_cls, 'has_custom_completion', False):
        return
    user = User.objects.get(id=kwargs['user_id'])
    if kwargs.get('score_deleted'):
        completion = 0.0
    else:
        completion = 1.0
    BlockCompletion.objects.submit_completion(
        user=user,
        course_key=course_key,
        block_key=block_key,
        completion=completion,
    )
Ejemplo n.º 28
0
 def test_load_class(self):
     vc = XBlock.load_class('sequential')
     vc_str = "<class 'xmodule.seq_module.SequenceBlock'>"
     assert str(vc) == vc_str
Ejemplo n.º 29
0
    def _create(cls, target_class, **kwargs):
        """
        Uses ``**kwargs``:

        :parent_location: (required): the location of the parent module
            (e.g. the parent course or section)

        :category: the category of the resulting item.

        :data: (optional): the data for the item
            (e.g. XML problem definition for a problem item)

        :display_name: (optional): the display name of the item

        :metadata: (optional): dictionary of metadata attributes

        :boilerplate: (optional) the boilerplate for overriding field values

        :publish_item: (optional) whether or not to publish the item (default is True)

        :target_class: is ignored
        """

        # All class attributes (from this class and base classes) are
        # passed in via **kwargs. However, some of those aren't actual field values,
        # so pop those off for use separately

        # catch any old style users before they get into trouble
        assert 'template' not in kwargs
        parent_location = kwargs.pop('parent_location', None)
        data = kwargs.pop('data', None)
        category = kwargs.pop('category', None)
        display_name = kwargs.pop('display_name', None)
        metadata = kwargs.pop('metadata', {})
        location = kwargs.pop('location')
        user_id = kwargs.pop('user_id', ModuleStoreEnum.UserID.test)
        publish_item = kwargs.pop('publish_item', True)

        assert isinstance(location, UsageKey)
        assert location != parent_location

        store = kwargs.pop('modulestore')

        # This code was based off that in cms/djangoapps/contentstore/views.py
        parent = kwargs.pop('parent', None) or store.get_item(parent_location)

        with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):

            if 'boilerplate' in kwargs:
                template_id = kwargs.pop('boilerplate')
                clz = XBlock.load_class(category, select=prefer_xmodules)
                template = clz.get_template(template_id)
                assert template is not None
                metadata.update(template.get('metadata', {}))
                if not isinstance(data, basestring):
                    data.update(template.get('data'))

            # replace the display name with an optional parameter passed in from the caller
            if display_name is not None:
                metadata['display_name'] = display_name
            runtime = parent.runtime if parent else None
            store.create_item(
                user_id,
                location.course_key,
                location.block_type,
                block_id=location.block_id,
                metadata=metadata,
                definition_data=data,
                runtime=runtime
            )

            module = store.get_item(location)

            for attr, val in kwargs.items():
                setattr(module, attr, val)
            # Save the attributes we just set
            module.save()

            store.update_item(module, user_id)

            # VS[compat] cdodge: This is a hack because static_tabs also have references from the course module, so
            # if we add one then we need to also add it to the policy information (i.e. metadata)
            # we should remove this once we can break this reference from the course to static tabs
            if category == 'static_tab':
                course = store.get_course(location.course_key)
                course.tabs.append(
                    StaticTab(
                        name=display_name,
                        url_slug=location.name,
                    )
                )
                store.update_item(course, user_id)

            # parent and publish the item, so it can be accessed
            if 'detached' not in module._class_tags:
                parent.children.append(location)
                store.update_item(parent, user_id)
                if publish_item:
                    store.publish(parent.location, user_id)
            elif publish_item:
                store.publish(location, user_id)

        # return the published item
        return store.get_item(location)
Ejemplo n.º 30
0
 def setUp(self):
     super(TestCustomBackends, self).setUp()
     self.player = {}
     for backend in self.backends:
         player_class = XBlock.load_class(backend)
         self.player[backend] = player_class
Ejemplo n.º 31
0
    def _create(cls, target_class, **kwargs):
        """
        Uses ``**kwargs``:

        :parent_location: (required): the location of the parent module
            (e.g. the parent course or section)

        :category: the category of the resulting item.

        :data: (optional): the data for the item
            (e.g. XML problem definition for a problem item)

        :display_name: (optional): the display name of the item

        :metadata: (optional): dictionary of metadata attributes

        :boilerplate: (optional) the boilerplate for overriding field values

        :target_class: is ignored
        """

        # All class attributes (from this class and base classes) are
        # passed in via **kwargs. However, some of those aren't actual field values,
        # so pop those off for use separately

        # catch any old style users before they get into trouble
        assert 'template' not in kwargs
        parent_location = kwargs.pop('parent_location', None)
        data = kwargs.pop('data', None)
        category = kwargs.pop('category', None)
        display_name = kwargs.pop('display_name', None)
        metadata = kwargs.pop('metadata', {})
        location = kwargs.pop('location')

        assert isinstance(location, Location)
        assert location != parent_location

        store = kwargs.pop('modulestore')

        # This code was based off that in cms/djangoapps/contentstore/views.py
        parent = kwargs.pop('parent', None) or store.get_item(parent_location)

        if 'boilerplate' in kwargs:
            template_id = kwargs.pop('boilerplate')
            clz = XBlock.load_class(category, select=prefer_xmodules)
            template = clz.get_template(template_id)
            assert template is not None
            metadata.update(template.get('metadata', {}))
            if not isinstance(data, basestring):
                data.update(template.get('data'))

        # replace the display name with an optional parameter passed in from the caller
        if display_name is not None:
            metadata['display_name'] = display_name
        store.create_and_save_xmodule(location,
                                      metadata=metadata,
                                      definition_data=data)

        module = store.get_item(location)

        for attr, val in kwargs.items():
            setattr(module, attr, val)
        # Save the attributes we just set
        module.save()

        store.update_item(module)

        if 'detached' not in module._class_tags:
            parent.children.append(location)
            store.update_item(parent, '**replace_user**')

        return store.get_item(location)
Ejemplo n.º 32
0
    def _create(cls, target_class, **kwargs):
        """
        Uses ``**kwargs``:

        :parent_location: (required): the location of the parent module
            (e.g. the parent course or section)

        :category: the category of the resulting item.

        :data: (optional): the data for the item
            (e.g. XML problem definition for a problem item)

        :display_name: (optional): the display name of the item

        :metadata: (optional): dictionary of metadata attributes

        :boilerplate: (optional) the boilerplate for overriding field values

        :publish_item: (optional) whether or not to publish the item (default is True)

        :target_class: is ignored
        """

        # All class attributes (from this class and base classes) are
        # passed in via **kwargs. However, some of those aren't actual field values,
        # so pop those off for use separately

        # catch any old style users before they get into trouble
        assert 'template' not in kwargs
        parent_location = kwargs.pop('parent_location', None)
        data = kwargs.pop('data', None)
        category = kwargs.pop('category', None)
        display_name = kwargs.pop('display_name', None)
        metadata = kwargs.pop('metadata', {})
        location = kwargs.pop('location')
        user_id = kwargs.pop('user_id', ModuleStoreEnum.UserID.test)
        publish_item = kwargs.pop('publish_item', True)

        assert isinstance(location, UsageKey)
        assert location != parent_location

        store = kwargs.pop('modulestore')

        # This code was based off that in cms/djangoapps/contentstore/views.py
        parent = kwargs.pop('parent', None) or store.get_item(parent_location)

        with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):

            if 'boilerplate' in kwargs:
                template_id = kwargs.pop('boilerplate')
                clz = XBlock.load_class(category, select=prefer_xmodules)
                template = clz.get_template(template_id)
                assert template is not None
                metadata.update(template.get('metadata', {}))
                if not isinstance(data, basestring):
                    data.update(template.get('data'))

            # replace the display name with an optional parameter passed in from the caller
            if display_name is not None:
                metadata['display_name'] = display_name
            runtime = parent.runtime if parent else None
            store.create_item(
                user_id,
                location.course_key,
                location.block_type,
                block_id=location.block_id,
                metadata=metadata,
                definition_data=data,
                runtime=runtime
            )

            module = store.get_item(location)

            for attr, val in kwargs.items():
                setattr(module, attr, val)
            # Save the attributes we just set
            module.save()

            store.update_item(module, user_id)

            # VS[compat] cdodge: This is a hack because static_tabs also have references from the course module, so
            # if we add one then we need to also add it to the policy information (i.e. metadata)
            # we should remove this once we can break this reference from the course to static tabs
            if category == 'static_tab':
                course = store.get_course(location.course_key)
                course.tabs.append(
                    StaticTab(
                        name=display_name,
                        url_slug=location.name,
                    )
                )
                store.update_item(course, user_id)

            # parent and publish the item, so it can be accessed
            if 'detached' not in module._class_tags:
                parent.children.append(location)
                store.update_item(parent, user_id)
                if publish_item:
                    store.publish(parent.location, user_id)
            elif publish_item:
                store.publish(location, user_id)

        # return the published item
        return store.get_item(location)
Ejemplo n.º 33
0
 def load_block_type(self, block_type):
     """
     Returns a subclass of :class:`.XBlock` that corresponds to the specified `block_type`.
     """
     return XBlock.load_class(block_type, self.default_class, self.select)
Ejemplo n.º 34
0
    def _create(cls, target_class, **kwargs):
        """
        Uses ``**kwargs``:

        :parent_location: (required): the location of the parent module
            (e.g. the parent course or section)

        :category: the category of the resulting item.

        :data: (optional): the data for the item
            (e.g. XML problem definition for a problem item)

        :display_name: (optional): the display name of the item

        :metadata: (optional): dictionary of metadata attributes

        :boilerplate: (optional) the boilerplate for overriding field values

        :target_class: is ignored
        """

        # All class attributes (from this class and base classes) are
        # passed in via **kwargs. However, some of those aren't actual field values,
        # so pop those off for use separately

        # catch any old style users before they get into trouble
        assert 'template' not in kwargs
        parent_location = kwargs.pop('parent_location', None)
        data = kwargs.pop('data', None)
        category = kwargs.pop('category', None)
        display_name = kwargs.pop('display_name', None)
        metadata = kwargs.pop('metadata', {})
        location = kwargs.pop('location')

        assert isinstance(location, Location)
        assert location != parent_location

        store = kwargs.pop('modulestore')

        # This code was based off that in cms/djangoapps/contentstore/views.py
        parent = kwargs.pop('parent', None) or store.get_item(parent_location)

        if 'boilerplate' in kwargs:
            template_id = kwargs.pop('boilerplate')
            clz = XBlock.load_class(category, select=prefer_xmodules)
            template = clz.get_template(template_id)
            assert template is not None
            metadata.update(template.get('metadata', {}))
            if not isinstance(data, basestring):
                data.update(template.get('data'))

        # replace the display name with an optional parameter passed in from the caller
        if display_name is not None:
            metadata['display_name'] = display_name
        store.create_and_save_xmodule(location, metadata=metadata, definition_data=data)

        module = store.get_item(location)

        for attr, val in kwargs.items():
            setattr(module, attr, val)
        # Save the attributes we just set
        module.save()

        store.update_item(module)

        if 'detached' not in module._class_tags:
            parent.children.append(location)
            store.update_item(parent, '**replace_user**')

        return store.get_item(location)
Ejemplo n.º 35
0
 def load_block_type(self, block_type):
     """
     Returns a subclass of :class:`.XBlock` that corresponds to the specified `block_type`.
     """
     return XBlock.load_class(block_type, self.default_class, self.select)
Ejemplo n.º 36
0
    def _create(cls, target_class, **kwargs):  # lint-amnesty, pylint: disable=arguments-differ, too-many-statements, unused-argument
        """
        Uses ``**kwargs``:

        :parent_location: (required): the location of the parent module
            (e.g. the parent course or section)

        :category: the category of the resulting item.

        :data: (optional): the data for the item
            (e.g. XML problem definition for a problem item)

        :display_name: (optional): the display name of the item

        :metadata: (optional): dictionary of metadata attributes

        :boilerplate: (optional) the boilerplate for overriding field values

        :publish_item: (optional) whether or not to publish the item (default is True)

        :target_class: is ignored
        """

        # All class attributes (from this class and base classes) are
        # passed in via **kwargs. However, some of those aren't actual field values,
        # so pop those off for use separately

        # catch any old style users before they get into trouble
        assert 'template' not in kwargs
        parent_location = kwargs.pop('parent_location', None)
        data = kwargs.pop('data', None)
        category = kwargs.pop('category', None)
        display_name = kwargs.pop('display_name', None)
        metadata = kwargs.pop('metadata', {})
        location = kwargs.pop('location')
        user_id = kwargs.pop('user_id', ModuleStoreEnum.UserID.test)
        publish_item = kwargs.pop('publish_item', True)
        has_score = kwargs.pop('has_score', None)
        submission_start = kwargs.pop('submission_start', None)
        submission_end = kwargs.pop('submission_end', None)

        # Remove the descriptive_tag, it's just for generating display_name,
        # and doesn't need to be passed into the object constructor
        kwargs.pop('descriptive_tag')

        assert isinstance(location, UsageKey)
        assert location != parent_location

        store = kwargs.pop('modulestore')

        # This code was based off that in cms/djangoapps/contentstore/views.py
        parent = kwargs.pop('parent', None) or store.get_item(parent_location)

        if isinstance(data, (bytes, bytearray)):  # data appears as bytes and
            data = data.decode('utf-8')

        with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):

            if 'boilerplate' in kwargs:
                template_id = kwargs.pop('boilerplate')
                clz = XBlock.load_class(category, select=prefer_xmodules)
                template = clz.get_template(template_id)
                assert template is not None
                metadata.update(template.get('metadata', {}))
                if not isinstance(data, str):
                    data.update(template.get('data'))

            # replace the display name with an optional parameter passed in from the caller
            if display_name is not None:
                metadata['display_name'] = display_name

            module = store.create_child(
                user_id,
                parent.location,
                location.block_type,
                block_id=location.block_id,
                metadata=metadata,
                definition_data=data,
                runtime=parent.runtime,
                fields=kwargs,
            )

            if has_score:
                module.has_score = has_score
            if submission_start:
                module.submission_start = submission_start
            if submission_end:
                module.submission_end = submission_end
            store.update_item(module, user_id)

            # VS[compat] cdodge: This is a hack because static_tabs also have references from the course module, so
            # if we add one then we need to also add it to the policy information (i.e. metadata)
            # we should remove this once we can break this reference from the course to static tabs
            if category == 'static_tab':
                course = store.get_course(location.course_key)
                course.tabs.append(
                    CourseTab.load('static_tab',
                                   name='Static Tab',
                                   url_slug=location.block_id))
                store.update_item(course, user_id)

            # parent and publish the item, so it can be accessed
            if 'detached' not in module._class_tags:  # lint-amnesty, pylint: disable=protected-access
                parent.children.append(location)
                store.update_item(parent, user_id)
                if publish_item:
                    published_parent = store.publish(parent.location, user_id)
                    # module is last child of parent
                    return published_parent.get_children()[-1]
                else:
                    return store.get_item(location)
            elif publish_item:
                return store.publish(location, user_id)
            else:
                return module