コード例 #1
0
ファイル: test_crud.py プロジェクト: Negotiare/edx-platform
 def test_persist_dag(self):
     """
     try saving temporary xblocks
     """
     test_course = persistent_factories.PersistentCourseFactory.create(org='testx', prettyid='tempcourse',
         display_name='fun test course', user_id='testbot')
     test_chapter = XModuleDescriptor.load_from_json({'category': 'chapter',
         'metadata': {'display_name': 'chapter n'}},
         test_course.system, parent_xblock=test_course)
     test_def_content = '<problem>boo</problem>'
     test_problem = XModuleDescriptor.load_from_json({'category': 'problem',
         'definition': {'data': test_def_content}},
         test_course.system, parent_xblock=test_chapter)
     # better to pass in persisted parent over the subdag so
     # subdag gets the parent pointer (otherwise 2 ops, persist dag, update parent children,
     # persist parent
     persisted_course = modulestore('split').persist_xblock_dag(test_course, 'testbot')
     self.assertEqual(len(persisted_course.children), 1)
     persisted_chapter = persisted_course.get_children()[0]
     self.assertEqual(persisted_chapter.category, 'chapter')
     self.assertEqual(persisted_chapter.display_name, 'chapter n')
     self.assertEqual(len(persisted_chapter.children), 1)
     persisted_problem = persisted_chapter.get_children()[0]
     self.assertEqual(persisted_problem.category, 'problem')
     self.assertEqual(persisted_problem.data, test_def_content)
コード例 #2
0
ファイル: base.py プロジェクト: NakarinTalikan/edx-platform
    def create_xmodule(self, location, definition_data=None, metadata=None, system=None):
        """
        Create the new xmodule but don't save it. Returns the new module.

        :param location: a Location--must have a category
        :param definition_data: can be empty. The initial definition_data for the kvs
        :param metadata: can be empty, the initial metadata for the kvs
        :param system: if you already have an xmodule from the course, the xmodule.system value
        """
        if not isinstance(location, Location):
            location = Location(location)
        # differs from split mongo in that I believe most of this logic should be above the persistence
        # layer but added it here to enable quick conversion. I'll need to reconcile these.
        if metadata is None:
            metadata = {}
        if system is None:
            system = CachingDescriptorSystem(
                self,
                {},
                self.default_class,
                None,
                self.error_tracker,
                self.render_template,
                {}
            )
        xblock_class = XModuleDescriptor.load_class(location.category, self.default_class)
        if definition_data is None:
            if hasattr(xblock_class, 'data') and getattr(xblock_class, 'data').default is not None:
                definition_data = getattr(xblock_class, 'data').default
            else:
                definition_data = {}
        dbmodel = self._create_new_model_data(location.category, location, definition_data, metadata)
        xmodule = xblock_class(system, dbmodel)
        return xmodule
コード例 #3
0
def _list_descriptors():
    """Return a list of all registered XModuleDescriptor classes."""
    return [
        desc for desc in [
            desc for (_, desc) in XModuleDescriptor.load_classes()
        ]
    ]
コード例 #4
0
ファイル: item.py プロジェクト: haksel/edx-platform
def create_item(request):
    parent_location = Location(request.POST["parent_location"])
    category = request.POST["category"]

    display_name = request.POST.get("display_name")

    if not has_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.POST.get("boilerplate")
    if template_id is not None:
        clz = XModuleDescriptor.load_class(category)
        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.system
    )

    if category not in DETACHED_CATEGORIES:
        get_modulestore(parent.location).update_children(parent_location, parent.children + [dest_location.url()])

    return JsonResponse({"id": dest_location.url()})
コード例 #5
0
def _list_modules():
    """Return a list of all registered XModule classes."""
    return [
        desc.module_class for desc in [
            desc for (_, desc) in XModuleDescriptor.load_classes()
        ]
    ] + XBLOCK_CLASSES
コード例 #6
0
ファイル: component.py プロジェクト: SJinLee/edx-platform
def load_mixed_class(category):
    """
    Load an XBlock by category name, and apply all defined mixins
    """
    component_class = XModuleDescriptor.load_class(category)
    mixologist = Mixologist(settings.XBLOCK_MIXINS)
    return mixologist.mix(component_class)
コード例 #7
0
ファイル: test_crud.py プロジェクト: AzizYosofi/edx-platform
    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_ = XModuleDescriptor.load_class(
            json_data.get('category', json_data.get('location', {}).get('category')),
            default_class
        )
        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
コード例 #8
0
ファイル: xml.py プロジェクト: rsteven7/edx-platform
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 = XModuleDescriptor.load_class(node.tag, default_class)
    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
コード例 #9
0
ファイル: factories.py プロジェクト: Cabris/edx-platform
    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
        """

        DETACHED_CATEGORIES = ['about', 'static_tab', 'course_info']
        # catch any old style users before they get into trouble
        assert not 'template' in kwargs
        data = kwargs.get('data')
        category = kwargs.get('category')
        display_name = kwargs.get('display_name')
        metadata = kwargs.get('metadata', {})
        location = kwargs.get('location')
        if kwargs.get('boilerplate') is not None:
            template_id = kwargs.get('boilerplate')
            clz = XModuleDescriptor.load_class(category)
            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'))

        store = kwargs.get('modulestore')

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

        if location.category not in DETACHED_CATEGORIES:

            parent_location = Location(kwargs.get('parent_location'))
            assert location != parent_location

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

            parent.children.append(location.url())
            store.update_children(parent_location, parent.children)

        return store.get_item(location)
コード例 #10
0
ファイル: base.py プロジェクト: GSeralin/edx-platform
    def load_item(self, location):
        """
        Return an XModule instance for the specified location
        """
        location = Location(location)
        json_data = self.module_data.get(location)
        if json_data is None:
            module = self.modulestore.get_item(location)
            if module is not None:
                # update our own cache after going to the DB to get cache miss
                self.module_data.update(module.runtime.module_data)
            return module
        else:
            # load the module and apply the inherited metadata
            try:
                category = json_data['location']['category']
                class_ = XModuleDescriptor.load_class(
                    category,
                    self.default_class
                )
                definition = json_data.get('definition', {})
                metadata = json_data.get('metadata', {})
                for old_name, new_name in getattr(class_, 'metadata_translations', {}).items():
                    if old_name in metadata:
                        metadata[new_name] = metadata[old_name]
                        del metadata[old_name]

                kvs = MongoKeyValueStore(
                    definition.get('data', {}),
                    definition.get('children', []),
                    metadata,
                )

                field_data = DbModel(kvs)
                scope_ids = ScopeIds(None, category, location, location)
                module = self.construct_xblock_from_class(class_, field_data, scope_ids)
                if self.cached_metadata is not None:
                    # parent container pointers don't differentiate between draft and non-draft
                    # so when we do the lookup, we should do so with a non-draft location
                    non_draft_loc = location.replace(revision=None)

                    # Convert the serialized fields values in self.cached_metadata
                    # to python values
                    metadata_to_inherit = self.cached_metadata.get(non_draft_loc.url(), {})
                    inherit_metadata(module, metadata_to_inherit)
                # decache any computed pending field settings
                module.save()
                return module
            except:
                log.warning("Failed to load descriptor", exc_info=True)
                return ErrorDescriptor.from_json(
                    json_data,
                    self,
                    json_data['location'],
                    error_msg=exc_info_to_str(sys.exc_info())
                )
コード例 #11
0
ファイル: base.py プロジェクト: helanhe/edx-platform
    def _create_new_model_data(self, category, location, definition_data, metadata):
        """
        To instantiate a new xmodule which will be saved latter, set up the dbModel and kvs
        """
        kvs = MongoKeyValueStore(definition_data, [], metadata, location, category)

        class_ = XModuleDescriptor.load_class(category, self.default_class)
        model_data = DbModel(kvs, class_, None, MongoUsage(None, location))
        model_data["category"] = category
        model_data["location"] = location
        return model_data
コード例 #12
0
ファイル: base.py プロジェクト: NakarinTalikan/edx-platform
    def load_item(self, location):
        """
        Return an XModule instance for the specified location
        """
        location = Location(location)
        json_data = self.module_data.get(location)
        if json_data is None:
            module = self.modulestore.get_item(location)
            if module is not None:
                # update our own cache after going to the DB to get cache miss
                self.module_data.update(module.system.module_data)
            return module
        else:
            # load the module and apply the inherited metadata
            try:
                category = json_data['location']['category']
                class_ = XModuleDescriptor.load_class(
                    category,
                    self.default_class
                )
                definition = json_data.get('definition', {})
                metadata = json_data.get('metadata', {})
                for old_name, new_name in class_.metadata_translations.items():
                    if old_name in metadata:
                        metadata[new_name] = metadata[old_name]
                        del metadata[old_name]

                kvs = MongoKeyValueStore(
                    definition.get('data', {}),
                    definition.get('children', []),
                    metadata,
                    location,
                    category
                )

                model_data = DbModel(kvs, class_, None, MongoUsage(self.course_id, location))
                model_data['category'] = category
                model_data['location'] = location
                module = class_(self, model_data)
                if self.cached_metadata is not None:
                    # parent container pointers don't differentiate between draft and non-draft
                    # so when we do the lookup, we should do so with a non-draft location
                    non_draft_loc = location.replace(revision=None)
                    metadata_to_inherit = self.cached_metadata.get(non_draft_loc.url(), {})
                    inherit_metadata(module, metadata_to_inherit)
                return module
            except:
                log.warning("Failed to load descriptor", exc_info=True)
                return ErrorDescriptor.from_json(
                    json_data,
                    self,
                    json_data['location'],
                    error_msg=exc_info_to_str(sys.exc_info())
                )
コード例 #13
0
    def _load_item(self, usage_id, course_entry_override=None):
        # TODO ensure all callers of system.load_item pass just the id
        json_data = self.module_data.get(usage_id)
        if json_data is None:
            # deeper than initial descendant fetch or doesn't exist
            self.modulestore.cache_items(self, [usage_id], lazy=self.lazy)
            json_data = self.module_data.get(usage_id)
            if json_data is None:
                raise ItemNotFoundError

        class_ = XModuleDescriptor.load_class(json_data.get("category"), self.default_class)
        return self.xblock_from_json(class_, usage_id, json_data, course_entry_override)
コード例 #14
0
    def _load_item(self, usage_id, course_entry_override=None):
        # TODO ensure all callers of system.load_item pass just the id
        json_data = self.module_data.get(usage_id)
        if json_data is None:
            # deeper than initial descendant fetch or doesn't exist
            self.modulestore.cache_items(self, [usage_id], lazy=self.lazy)
            json_data = self.module_data.get(usage_id)
            if json_data is None:
                raise ItemNotFoundError

        class_ = XModuleDescriptor.load_class(json_data.get('category'),
                                              self.default_class)
        return self.xblock_from_json(class_, usage_id, json_data,
                                     course_entry_override)
コード例 #15
0
    def load_item(self, location):
        """
        Return an XModule instance for the specified location
        """
        location = Location(location)
        json_data = self.module_data.get(location)
        if json_data is None:
            module = self.modulestore.get_item(location)
            if module is not None:
                # update our own cache after going to the DB to get cache miss
                self.module_data.update(module.system.module_data)
            return module
        else:
            # load the module and apply the inherited metadata
            try:
                category = json_data['location']['category']
                class_ = XModuleDescriptor.load_class(category,
                                                      self.default_class)
                definition = json_data.get('definition', {})
                metadata = json_data.get('metadata', {})
                for old_name, new_name in class_.metadata_translations.items():
                    if old_name in metadata:
                        metadata[new_name] = metadata[old_name]
                        del metadata[old_name]

                kvs = MongoKeyValueStore(definition.get('data', {}),
                                         definition.get('children', []),
                                         metadata, location, category)

                model_data = DbModel(kvs, class_, None,
                                     MongoUsage(self.course_id, location))
                model_data['category'] = category
                model_data['location'] = location
                module = class_(self, model_data)
                if self.cached_metadata is not None:
                    # parent container pointers don't differentiate between draft and non-draft
                    # so when we do the lookup, we should do so with a non-draft location
                    non_draft_loc = location.replace(revision=None)
                    metadata_to_inherit = self.cached_metadata.get(
                        non_draft_loc.url(), {})
                    inherit_metadata(module, metadata_to_inherit)
                return module
            except:
                log.warning("Failed to load descriptor", exc_info=True)
                return ErrorDescriptor.from_json(json_data,
                                                 self,
                                                 json_data['location'],
                                                 error_msg=exc_info_to_str(
                                                     sys.exc_info()))
コード例 #16
0
ファイル: test_crud.py プロジェクト: Negotiare/edx-platform
    def test_temporary_xblocks(self):
        """
        Test using load_from_json to create non persisted xblocks
        """
        test_course = persistent_factories.PersistentCourseFactory.create(org='testx', prettyid='tempcourse',
            display_name='fun test course', user_id='testbot')

        test_chapter = XModuleDescriptor.load_from_json({'category': 'chapter',
            'metadata': {'display_name': 'chapter n'}},
            test_course.system, parent_xblock=test_course)
        self.assertIsInstance(test_chapter, SequenceDescriptor)
        self.assertEqual(test_chapter.display_name, 'chapter n')
        self.assertIn(test_chapter, test_course.get_children())

        # test w/ a definition (e.g., a problem)
        test_def_content = '<problem>boo</problem>'
        test_problem = XModuleDescriptor.load_from_json({'category': 'problem',
            'definition': {'data': test_def_content}},
            test_course.system, parent_xblock=test_chapter)
        self.assertIsInstance(test_problem, CapaDescriptor)
        self.assertEqual(test_problem.data, test_def_content)
        self.assertIn(test_problem, test_chapter.get_children())
        test_problem.display_name = 'test problem'
        self.assertEqual(test_problem.display_name, 'test problem')
コード例 #17
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_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 = XModuleDescriptor.load_class(category)
        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.system,
    )

    if category not in DETACHED_CATEGORIES:
        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)})
コード例 #18
0
    def _load_item(self, usage_id, course_entry_override=None):
        if isinstance(usage_id, BlockUsageLocator) and isinstance(usage_id.usage_id, LocalId):
            try:
                return self.local_modules[usage_id]
            except KeyError:
                raise ItemNotFoundError

        json_data = self.module_data.get(usage_id)
        if json_data is None:
            # deeper than initial descendant fetch or doesn't exist
            self.modulestore.cache_items(self, [usage_id], lazy=self.lazy)
            json_data = self.module_data.get(usage_id)
            if json_data is None:
                raise ItemNotFoundError(usage_id)

        class_ = XModuleDescriptor.load_class(json_data.get("category"), self.default_class)
        return self.xblock_from_json(class_, usage_id, json_data, course_entry_override)
コード例 #19
0
ファイル: base.py プロジェクト: GSeralin/edx-platform
    def create_xmodule(self, location, definition_data=None, metadata=None, system=None):
        """
        Create the new xmodule but don't save it. Returns the new module.

        :param location: a Location--must have a category
        :param definition_data: can be empty. The initial definition_data for the kvs
        :param metadata: can be empty, the initial metadata for the kvs
        :param system: if you already have an xblock from the course, the xblock.runtime value
        """
        if not isinstance(location, Location):
            location = Location(location)
        # differs from split mongo in that I believe most of this logic should be above the persistence
        # layer but added it here to enable quick conversion. I'll need to reconcile these.
        if metadata is None:
            metadata = {}
        if system is None:
            system = CachingDescriptorSystem(
                modulestore=self,
                module_data={},
                default_class=self.default_class,
                resources_fs=None,
                error_tracker=self.error_tracker,
                render_template=self.render_template,
                cached_metadata={},
                mixins=self.xblock_mixins,
            )
        xblock_class = XModuleDescriptor.load_class(location.category, self.default_class)
        if definition_data is None:
            if hasattr(xblock_class, 'data') and xblock_class.data.default is not None:
                definition_data = xblock_class.data.default
            else:
                definition_data = {}
        dbmodel = self._create_new_field_data(location.category, location, definition_data, metadata)
        xmodule = system.construct_xblock_from_class(
            xblock_class,
            dbmodel,

            # We're loading a descriptor, so student_id is meaningless
            # We also don't have separate notions of definition and usage ids yet,
            # so we use the location for both.
            ScopeIds(None, location.category, location, location)
        )
        # decache any pending field settings from init
        xmodule.save()
        return xmodule
コード例 #20
0
ファイル: item.py プロジェクト: pelikanchik/edx-platform
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)
    try:
        category = request.json['category']
    except KeyError:
        category = 'problem'

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

    if not has_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 = XModuleDescriptor.load_class(category)
        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.system,
    )

    if category not in DETACHED_CATEGORIES:
        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)})
コード例 #21
0
ファイル: item.py プロジェクト: haksel/edx-platform
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_access(request.user, parent_location):
        raise PermissionDenied()

    parent = get_modulestore(category).get_item(parent_location)
    # Necessary to set revision=None or else metadata inheritance does not work
    # (the ID with @draft will be used as the key in the inherited metadata map,
    # and that is not expected by the code that later references it).
    dest_location = parent_location.replace(category=category, name=uuid4().hex, revision=None)

    # 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 = XModuleDescriptor.load_class(category)
        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.system,
    )

    if category not in DETACHED_CATEGORIES:
        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({'id': dest_location.url(), "locator": unicode(locator)})
コード例 #22
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_ = XModuleDescriptor.load_class(
            json_data.get('category',
                          json_data.get('location', {}).get('category')),
            default_class)
        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.get_inherited_settings(
                ).copy()
            json_fields = json_data.get('fields', {})
            for field in inheritance.INHERITABLE_METADATA:
                if field in json_fields:
                    json_data['_inherited_settings'][field] = json_fields[
                        field]

        new_block = system.xblock_from_json(class_, usage_id, json_data)
        if parent_xblock is not None:
            children = parent_xblock.children
            children.append(new_block)
            # trigger setter method by using top level field access
            parent_xblock.children = children
            # decache pending children field settings (Note, truly persisting at this point would break b/c
            # persistence assumes children is a list of ids not actual xblocks)
            parent_xblock.save()
        return new_block
コード例 #23
0
ファイル: item.py プロジェクト: pr4v33n/edx-platform
def create_item(request):
    """View for create items."""
    parent_location = Location(request.json['parent_location'])
    category = request.json['category']

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

    if not has_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 = XModuleDescriptor.load_class(category)
        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.system,
    )

    if category not in DETACHED_CATEGORIES:
        get_modulestore(parent.location).update_children(parent_location, parent.children + [dest_location.url()])

    locator = loc_mapper().translate_location(
        get_course_for_item(parent_location).location.course_id, dest_location, False, True
    )
    return JsonResponse({'id': dest_location.url(), "update_url": locator.url_reverse("xblock")})
コード例 #24
0
    def _load_item(self, usage_id, course_entry_override=None):
        if isinstance(usage_id, BlockUsageLocator) and isinstance(
                usage_id.usage_id, LocalId):
            try:
                return self.local_modules[usage_id]
            except KeyError:
                raise ItemNotFoundError

        json_data = self.module_data.get(usage_id)
        if json_data is None:
            # deeper than initial descendant fetch or doesn't exist
            self.modulestore.cache_items(self, [usage_id], lazy=self.lazy)
            json_data = self.module_data.get(usage_id)
            if json_data is None:
                raise ItemNotFoundError(usage_id)

        class_ = XModuleDescriptor.load_class(json_data.get('category'),
                                              self.default_class)
        return self.xblock_from_json(class_, usage_id, json_data,
                                     course_entry_override)
コード例 #25
0
ファイル: base.py プロジェクト: pdehaye/theming-edx-platform
    def _create_new_model_data(self, category, location, definition_data, metadata):
        """
        To instantiate a new xmodule which will be saved latter, set up the dbModel and kvs
        """
        kvs = MongoKeyValueStore(
            definition_data,
            [],
            metadata,
            location,
            category
        )

        class_ = XModuleDescriptor.load_class(
            category,
            self.default_class
        )
        model_data = DbModel(kvs, class_, None, MongoUsage(None, location))
        model_data['category'] = category
        model_data['location'] = location
        return model_data
コード例 #26
0
def create_item(request):
    parent_location = Location(request.POST['parent_location'])
    category = request.POST['category']

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

    if not has_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.POST.get('boilerplate')
    if template_id is not None:
        clz = XModuleDescriptor.load_class(category)
        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.system,
    )

    if category not in DETACHED_CATEGORIES:
        get_modulestore(parent.location).update_children(
            parent_location, parent.children + [dest_location.url()])

    return JsonResponse({'id': dest_location.url()})
コード例 #27
0
ファイル: test_crud.py プロジェクト: danielnegri/edx-platform
    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_ = XModuleDescriptor.load_class(
            json_data.get('category',
                          json_data.get('location', {}).get('category')),
            default_class)
        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
コード例 #28
0
ファイル: test_crud.py プロジェクト: LukeLu1263/edx-platform
    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_ = XModuleDescriptor.load_class(
            json_data.get('category', json_data.get('location', {}).get('category')),
            default_class
        )
        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.get_inherited_settings().copy()
            json_fields = json_data.get('fields', {})
            for field in inheritance.INHERITABLE_METADATA:
                if field in json_fields:
                    json_data['_inherited_settings'][field] = json_fields[field]

        new_block = system.xblock_from_json(class_, usage_id, json_data)
        if parent_xblock is not None:
            children = parent_xblock.children
            children.append(new_block)
            # trigger setter method by using top level field access
            parent_xblock.children = children
            # decache pending children field settings (Note, truly persisting at this point would break b/c
            # persistence assumes children is a list of ids not actual xblocks)
            parent_xblock.save()
        return new_block
コード例 #29
0
ファイル: base.py プロジェクト: vnavanee/edx-platform
    def create_xmodule(self,
                       location,
                       definition_data=None,
                       metadata=None,
                       system=None):
        """
        Create the new xmodule but don't save it. Returns the new module.

        :param location: a Location--must have a category
        :param definition_data: can be empty. The initial definition_data for the kvs
        :param metadata: can be empty, the initial metadata for the kvs
        :param system: if you already have an xmodule from the course, the xmodule.system value
        """
        if not isinstance(location, Location):
            location = Location(location)
        # differs from split mongo in that I believe most of this logic should be above the persistence
        # layer but added it here to enable quick conversion. I'll need to reconcile these.
        if metadata is None:
            metadata = {}
        if system is None:
            system = CachingDescriptorSystem(self, {}, self.default_class,
                                             None, self.error_tracker,
                                             self.render_template, {})
        xblock_class = XModuleDescriptor.load_class(location.category,
                                                    self.default_class)
        if definition_data is None:
            if hasattr(xblock_class, 'data') and getattr(
                    xblock_class, 'data').default is not None:
                definition_data = getattr(xblock_class, 'data').default
            else:
                definition_data = {}
        dbmodel = self._create_new_model_data(location.category, location,
                                              definition_data, metadata)
        xmodule = xblock_class(system, dbmodel)
        # decache any pending field settings from init
        xmodule.save()
        return xmodule
コード例 #30
0
            mock_grade_histogram.return_value = []
            module = render.get_module(
                self.user,
                self.request,
                self.location,
                self.field_data_cache,
                self.course.id,
            )
            module.render('student_view')
            self.assertTrue(mock_grade_histogram.called)


PER_COURSE_ANONYMIZED_DESCRIPTORS = (LTIDescriptor, )

PER_STUDENT_ANONYMIZED_DESCRIPTORS = [
    class_ for (name, class_) in XModuleDescriptor.load_classes()
    if not issubclass(class_, PER_COURSE_ANONYMIZED_DESCRIPTORS)
]


@ddt
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
class TestAnonymousStudentId(ModuleStoreTestCase, LoginEnrollmentTestCase):
    """
    Test that anonymous_student_id is set correctly across a variety of XBlock types
    """
    def setUp(self):
        self.user = UserFactory()

    @patch('courseware.module_render.has_access', Mock(return_value=True))
    def _get_anonymous_id(self, course_id, xblock_class):
コード例 #31
0
            mock_grade_histogram.return_value = []
            module = render.get_module(
                self.user,
                self.request,
                self.location,
                self.field_data_cache,
                self.course.id,
            )
            module.render('student_view')
            self.assertTrue(mock_grade_histogram.called)


PER_COURSE_ANONYMIZED_DESCRIPTORS = (LTIDescriptor, )

PER_STUDENT_ANONYMIZED_DESCRIPTORS = [
    class_ for (name, class_) in XModuleDescriptor.load_classes()
    if not issubclass(class_, PER_COURSE_ANONYMIZED_DESCRIPTORS)
]


@ddt
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
class TestAnonymousStudentId(ModuleStoreTestCase, LoginEnrollmentTestCase):
    """
    Test that anonymous_student_id is set correctly across a variety of XBlock types
    """

    def setUp(self):
        self.user = UserFactory()

    @patch('courseware.module_render.has_access', Mock(return_value=True))
コード例 #32
0
ファイル: __init__.py プロジェクト: GSeralin/edx-platform
 def process_xml(self, xml):  # pylint: disable=method-hidden
     """Parse `xml` as an XModuleDescriptor, and add it to `self._descriptors`"""
     descriptor = XModuleDescriptor.load_from_xml(xml, self, self.org, self.course, self.default_class)
     self._descriptors[descriptor.location.url()] = descriptor
     return descriptor
コード例 #33
0
def _list_descriptors():
    """Return a list of all registered XModuleDescriptor classes."""
    return [
        desc
        for desc in [desc for (_, desc) in XModuleDescriptor.load_classes()]
    ]
コード例 #34
0
 def test_load_class(self):
     vc = XModuleDescriptor.load_class('sequential')
     vc_str = "<class 'xmodule.seq_module.SequenceDescriptor'>"
     assert str(vc) == vc_str
コード例 #35
0
def _list_descriptors():
    return [
        desc for desc in [
            desc for (_, desc) in XModuleDescriptor.load_classes()
        ]
    ]
コード例 #36
0
def _list_descriptors():
    return [desc for desc in [desc for (_, desc) in XModuleDescriptor.load_classes()]]
コード例 #37
0
def _list_descriptors():
    """Return a list of all registered XModuleDescriptor classes."""
    return sorted([desc for (_, desc) in XModuleDescriptor.load_classes()] +
                  XBLOCK_CLASSES,
                  key=str)
コード例 #38
0
ファイル: __init__.py プロジェクト: danielnegri/edx-platform
 def test_load_class(self):
     vc = XModuleDescriptor.load_class('video')
     vc_str = "<class 'xmodule.video_module.VideoDescriptor'>"
     self.assertEqual(str(vc), vc_str)
コード例 #39
0
ファイル: static_content.py プロジェクト: jlrivera81/incr-228
def _list_modules():
    """Return a list of all registered XModule classes."""
    return [
        desc.module_class
        for desc in [desc for (_, desc) in XModuleDescriptor.load_classes()]
    ] + XBLOCK_CLASSES
コード例 #40
0
def edit_unit(request, location):
    """
    Display an editing page for the specified module.

    Expects a GET request with the parameter `id`.

    id: A Location URL
    """
    try:
        course = get_course_for_item(location)
    except InvalidLocationError:
        return HttpResponseBadRequest()

    if not has_access(request.user, course.location):
        raise PermissionDenied()

    try:
        item = modulestore().get_item(location, depth=1)
    except ItemNotFoundError:
        return HttpResponseBadRequest()
    lms_link = get_lms_link_for_item(
            item.location,
            course_id=course.location.course_id
    )

    component_templates = defaultdict(list)
    for category in COMPONENT_TYPES:
        component_class = XModuleDescriptor.load_class(category)
        # add the default template
        component_templates[category].append((
            component_class.display_name.default or 'Blank',
            category,
            False,  # No defaults have markdown (hardcoded current default)
            None  # no boilerplate for overrides
        ))
        # add boilerplates
        for template in component_class.templates():
            component_templates[category].append((
                template['metadata'].get('display_name'),
                category,
                template['metadata'].get('markdown') is not None,
                template.get('template_id')
            ))

    # 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

    # 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:
                # Do I need to allow for boilerplates or just defaults on the
                # class? i.e., can an advanced have more than one entry in the
                # menu? one for default and others for prefilled boilerplates?
                try:
                    component_class = XModuleDescriptor.load_class(category)

                    component_templates['advanced'].append((
                        component_class.display_name.default or category,
                        category,
                        False,
                        None  # don't override default data
                        ))
                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
                    pass
    else:
        log.error(
            "Improper format for course advanced keys! %",
            course_advanced_keys
        )

    components = [
        component.location.url()
        for component
        in item.get_children()
    ]

    # TODO (cpennington): If we share units between courses,
    # this will need to change to check permissions correctly so as
    # to pick the correct parent subsection

    containing_subsection_locs = modulestore().get_parent_locations(
            location, None
    )
    containing_subsection = modulestore().get_item(containing_subsection_locs[0])
    containing_section_locs = modulestore().get_parent_locations(
            containing_subsection.location, None
    )
    containing_section = modulestore().get_item(containing_section_locs[0])

    # cdodge hack. We're having trouble previewing drafts via jump_to redirect
    # so let's generate the link url here

    # need to figure out where this item is in the list of children as the
    # preview will need this
    index = 1
    for child in containing_subsection.get_children():
        if child.location == item.location:
            break
        index = index + 1

    preview_lms_base = settings.MITX_FEATURES.get('PREVIEW_LMS_BASE')

    preview_lms_link = (
            '//{preview_lms_base}/courses/{org}/{course}/'
            '{course_name}/courseware/{section}/{subsection}/{index}'
        ).format(
            preview_lms_base=preview_lms_base,
            lms_base=settings.LMS_BASE,
            org=course.location.org,
            course=course.location.course,
            course_name=course.location.name,
            section=containing_section.location.name,
            subsection=containing_subsection.location.name,
            index=index
        )

    unit_state = compute_unit_state(item)

    return render_to_response('unit.html', {
        'context_course': course,
        'unit': item,
        'unit_location': location,
        'components': components,
        'component_templates': component_templates,
        'draft_preview_link': preview_lms_link,
        'published_preview_link': lms_link,
        'subsection': containing_subsection,
        'release_date': get_default_time_display(containing_subsection.lms.start)
            if containing_subsection.lms.start is not None else None,
        'section': containing_section,
        'new_unit_category': 'vertical',
        'unit_state': unit_state,
        'published_date': get_default_time_display(item.cms.published_date)
            if item.cms.published_date is not None else None
    })
コード例 #41
0
 def test_load_class(self):
     vc = XModuleDescriptor.load_class('sequential')
     vc_str = "<class 'xmodule.seq_module.SequenceDescriptor'>"
     self.assertEqual(str(vc), vc_str)
コード例 #42
0
ファイル: xml.py プロジェクト: samH99/LexisNexis
        def process_xml(xml):
            """Takes an xml string, and returns a XModuleDescriptor created from
            that xml.
            """
            def make_name_unique(xml_data):
                """
                Make sure that the url_name of xml_data is unique.  If a previously loaded
                unnamed descriptor stole this element's url_name, create a new one.

                Removes 'slug' attribute if present, and adds or overwrites the 'url_name' attribute.
                """
                # VS[compat]. Take this out once course conversion is done (perhaps leave the uniqueness check)

                # tags that really need unique names--they store (or should store) state.
                need_uniq_names = ('problem', 'sequential', 'video', 'course',
                                   'chapter', 'videosequence', 'poll_question',
                                   'timelimit')

                attr = xml_data.attrib
                tag = xml_data.tag
                id = lambda x: x
                # Things to try to get a name, in order  (key, cleaning function, remove key after reading?)
                lookups = [('url_name', id, False), ('slug', id, True),
                           ('name', Location.clean, False),
                           ('display_name', Location.clean, False)]

                url_name = None
                for key, clean, remove in lookups:
                    if key in attr:
                        url_name = clean(attr[key])
                        if remove:
                            del attr[key]
                        break

                def looks_like_fallback(url_name):
                    """Does this look like something that came from fallback_name()?"""
                    return (url_name is not None and url_name.startswith(tag)
                            and re.search('[0-9a-fA-F]{12}$', url_name))

                def fallback_name(orig_name=None):
                    """Return the fallback name for this module.  This is a function instead of a variable
                    because we want it to be lazy."""
                    if looks_like_fallback(orig_name):
                        # We're about to re-hash, in case something changed, so get rid of the tag_ and hash
                        orig_name = orig_name[len(tag) + 1:-12]
                    # append the hash of the content--the first 12 bytes should be plenty.
                    orig_name = "_" + orig_name if orig_name not in (
                        None, "") else ""
                    xml_bytes = xml.encode('utf8')
                    return tag + orig_name + "_" + hashlib.sha1(
                        xml_bytes).hexdigest()[:12]

                # Fallback if there was nothing we could use:
                if url_name is None or url_name == "":
                    url_name = fallback_name()
                    # Don't log a warning--we don't need this in the log.  Do
                    # put it in the error tracker--content folks need to see it.

                    if tag in need_uniq_names:
                        error_tracker(
                            "PROBLEM: no name of any kind specified for {tag}.  Student "
                            "state will not be properly tracked for this module.  Problem xml:"
                            " '{xml}...'".format(tag=tag, xml=xml[:100]))
                    else:
                        # TODO (vshnayder): We may want to enable this once course repos are cleaned up.
                        # (or we may want to give up on the requirement for non-state-relevant issues...)
                        # error_tracker("WARNING: no name specified for module. xml='{0}...'".format(xml[:100]))
                        pass

                # Make sure everything is unique
                if url_name in self.used_names[tag]:
                    # Always complain about modules that store state.  If it
                    # doesn't store state, don't complain about things that are
                    # hashed.
                    if tag in need_uniq_names:
                        msg = (
                            "Non-unique url_name in xml.  This may break state tracking for content."
                            "  url_name={0}.  Content={1}".format(
                                url_name, xml[:100]))
                        error_tracker("PROBLEM: " + msg)
                        log.warning(msg)
                        # Just set name to fallback_name--if there are multiple things with the same fallback name,
                        # they are actually identical, so it's fragile, but not immediately broken.

                        # TODO (vshnayder): if the tag is a pointer tag, this will
                        # break the content because we won't have the right link.
                        # That's also a legitimate attempt to reuse the same content
                        # from multiple places.  Once we actually allow that, we'll
                        # need to update this to complain about non-unique names for
                        # definitions, but allow multiple uses.
                        url_name = fallback_name(url_name)

                self.used_names[tag].add(url_name)
                xml_data.set('url_name', url_name)

            try:
                # VS[compat]
                # TODO (cpennington): Remove this once all fall 2012 courses
                # have been imported into the cms from xml
                xml = clean_out_mako_templating(xml)
                xml_data = etree.fromstring(xml)

                make_name_unique(xml_data)

                descriptor = XModuleDescriptor.load_from_xml(
                    etree.tostring(xml_data, encoding='unicode'), self,
                    self.org, self.course, xmlstore.default_class)
            except Exception as err:
                if not self.load_error_modules:
                    raise

                # Didn't load properly.  Fall back on loading as an error
                # descriptor.  This should never error due to formatting.

                msg = "Error loading from xml. " + str(err)[:200]
                log.warning(msg)
                # Normally, we don't want lots of exception traces in our logs from common
                # content problems.  But if you're debugging the xml loading code itself,
                # uncomment the next line.
                log.exception(msg)

                self.error_tracker(msg)
                err_msg = msg + "\n" + exc_info_to_str(sys.exc_info())
                descriptor = ErrorDescriptor.from_xml(xml, self, self.org,
                                                      self.course, err_msg)

            setattr(descriptor, 'data_dir', course_dir)

            xmlstore.modules[course_id][descriptor.location] = descriptor

            if hasattr(descriptor, 'children'):
                for child in descriptor.get_children():
                    parent_tracker.add_parent(child.location,
                                              descriptor.location)
            return descriptor
コード例 #43
0
def edit_unit(request, location):
    """
    Display an editing page for the specified module.

    Expects a GET request with the parameter `id`.

    id: A Location URL
    """
    try:
        course = get_course_for_item(location)
    except InvalidLocationError:
        return HttpResponseBadRequest()

    if not has_access(request.user, course.location):
        raise PermissionDenied()

    try:
        item = modulestore().get_item(location, depth=1)
    except ItemNotFoundError:
        return HttpResponseBadRequest()
    lms_link = get_lms_link_for_item(
            item.location,
            course_id=course.location.course_id
    )

    component_templates = defaultdict(list)
    for category in COMPONENT_TYPES:
        component_class = XModuleDescriptor.load_class(category)
        # add the default template
        component_templates[category].append((
            component_class.display_name.default or 'Blank',
            category,
            False,  # No defaults have markdown (hardcoded current default)
            None  # no boilerplate for overrides
        ))
        # add boilerplates
        for template in component_class.templates():
            component_templates[category].append((
                template['metadata'].get('display_name'),
                category,
                template['metadata'].get('markdown') is not None,
                template.get('template_id')
            ))

    # 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

    # 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:
                # Do I need to allow for boilerplates or just defaults on the
                # class? i.e., can an advanced have more than one entry in the
                # menu? one for default and others for prefilled boilerplates?
                try:
                    component_class = XModuleDescriptor.load_class(category)

                    component_templates['advanced'].append((
                        component_class.display_name.default or category,
                        category,
                        False,
                        None  # don't override default data
                        ))
                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
                    pass
    else:
        log.error(
            "Improper format for course advanced keys! %",
            course_advanced_keys
        )

    components = [
        component.location.url()
        for component
        in item.get_children()
    ]

    # TODO (cpennington): If we share units between courses,
    # this will need to change to check permissions correctly so as
    # to pick the correct parent subsection

    containing_subsection_locs = modulestore().get_parent_locations(
            location, None
    )
    containing_subsection = modulestore().get_item(containing_subsection_locs[0])
    containing_section_locs = modulestore().get_parent_locations(
            containing_subsection.location, None
    )
    containing_section = modulestore().get_item(containing_section_locs[0])

    # cdodge hack. We're having trouble previewing drafts via jump_to redirect
    # so let's generate the link url here

    # need to figure out where this item is in the list of children as the
    # preview will need this
    index = 1
    for child in containing_subsection.get_children():
        if child.location == item.location:
            break
        index = index + 1

    preview_lms_base = settings.MITX_FEATURES.get('PREVIEW_LMS_BASE')

    preview_lms_link = (
            '//{preview_lms_base}/courses/{org}/{course}/'
            '{course_name}/courseware/{section}/{subsection}/{index}'
        ).format(
            preview_lms_base=preview_lms_base,
            lms_base=settings.LMS_BASE,
            org=course.location.org,
            course=course.location.course,
            course_name=course.location.name,
            section=containing_section.location.name,
            subsection=containing_subsection.location.name,
            index=index
        )

    unit_state = compute_unit_state(item)

    return render_to_response('unit.html', {
        'context_course': course,
        'unit': item,
        'unit_location': location,
        'components': components,
        'component_templates': component_templates,
        'draft_preview_link': preview_lms_link,
        'published_preview_link': lms_link,
        'subsection': containing_subsection,
        'release_date': get_default_time_display(containing_subsection.lms.start)
            if containing_subsection.lms.start is not None else None,
        'section': containing_section,
        'new_unit_category': 'vertical',
        'unit_state': unit_state,
        'published_date': get_default_time_display(item.cms.published_date)
            if item.cms.published_date is not None else None
    })
コード例 #44
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

        DETACHED_CATEGORIES = ['about', 'static_tab', 'course_info']
        # catch any old style users before they get into trouble
        assert 'template' not in kwargs
        parent_location = 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 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 = XModuleDescriptor.load_class(category)
            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
        module = 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)
        module.save()

        store.save_xmodule(module)

        if location.category not in DETACHED_CATEGORIES:
            parent.children.append(location.url())
            store.update_children(parent_location, parent.children)

        return store.get_item(location)
コード例 #45
0
ファイル: xml.py プロジェクト: Fyre91/edx-platform
        def process_xml(xml):
            """Takes an xml string, and returns a XModuleDescriptor created from
            that xml.
            """

            def make_name_unique(xml_data):
                """
                Make sure that the url_name of xml_data is unique.  If a previously loaded
                unnamed descriptor stole this element's url_name, create a new one.

                Removes 'slug' attribute if present, and adds or overwrites the 'url_name' attribute.
                """
                # VS[compat]. Take this out once course conversion is done (perhaps leave the uniqueness check)

                # tags that really need unique names--they store (or should store) state.
                need_uniq_names = ('problem', 'sequential', 'video', 'course', 'chapter',
                                   'videosequence', 'poll_question', 'timelimit')

                attr = xml_data.attrib
                tag = xml_data.tag
                id = lambda x: x
                # Things to try to get a name, in order  (key, cleaning function, remove key after reading?)
                lookups = [('url_name', id, False),
                           ('slug', id, True),
                           ('name', Location.clean, False),
                           ('display_name', Location.clean, False)]

                url_name = None
                for key, clean, remove in lookups:
                    if key in attr:
                        url_name = clean(attr[key])
                        if remove:
                            del attr[key]
                        break

                def looks_like_fallback(url_name):
                    """Does this look like something that came from fallback_name()?"""
                    return (url_name is not None
                            and url_name.startswith(tag)
                            and re.search('[0-9a-fA-F]{12}$', url_name))

                def fallback_name(orig_name=None):
                    """Return the fallback name for this module.  This is a function instead of a variable
                    because we want it to be lazy."""
                    if looks_like_fallback(orig_name):
                        # We're about to re-hash, in case something changed, so get rid of the tag_ and hash
                        orig_name = orig_name[len(tag) + 1:-12]
                    # append the hash of the content--the first 12 bytes should be plenty.
                    orig_name = "_" + orig_name if orig_name not in (None, "") else ""
                    xml_bytes = xml.encode('utf8')
                    return tag + orig_name + "_" + hashlib.sha1(xml_bytes).hexdigest()[:12]

                # Fallback if there was nothing we could use:
                if url_name is None or url_name == "":
                    url_name = fallback_name()
                    # Don't log a warning--we don't need this in the log.  Do
                    # put it in the error tracker--content folks need to see it.

                    if tag in need_uniq_names:
                        error_tracker("PROBLEM: no name of any kind specified for {tag}.  Student "
                                      "state will not be properly tracked for this module.  Problem xml:"
                                      " '{xml}...'".format(tag=tag, xml=xml[:100]))
                    else:
                        # TODO (vshnayder): We may want to enable this once course repos are cleaned up.
                        # (or we may want to give up on the requirement for non-state-relevant issues...)
                        # error_tracker("WARNING: no name specified for module. xml='{0}...'".format(xml[:100]))
                        pass

                # Make sure everything is unique
                if url_name in self.used_names[tag]:
                    # Always complain about modules that store state.  If it
                    # doesn't store state, don't complain about things that are
                    # hashed.
                    if tag in need_uniq_names:
                        msg = ("Non-unique url_name in xml.  This may break state tracking for content."
                               "  url_name={0}.  Content={1}".format(url_name, xml[:100]))
                        error_tracker("PROBLEM: " + msg)
                        log.warning(msg)
                        # Just set name to fallback_name--if there are multiple things with the same fallback name,
                        # they are actually identical, so it's fragile, but not immediately broken.

                        # TODO (vshnayder): if the tag is a pointer tag, this will
                        # break the content because we won't have the right link.
                        # That's also a legitimate attempt to reuse the same content
                        # from multiple places.  Once we actually allow that, we'll
                        # need to update this to complain about non-unique names for
                        # definitions, but allow multiple uses.
                        url_name = fallback_name(url_name)

                self.used_names[tag].add(url_name)
                xml_data.set('url_name', url_name)

            try:
                # VS[compat]
                # TODO (cpennington): Remove this once all fall 2012 courses
                # have been imported into the cms from xml
                xml = clean_out_mako_templating(xml)
                xml_data = etree.fromstring(xml)

                make_name_unique(xml_data)

                descriptor = XModuleDescriptor.load_from_xml(
                    etree.tostring(xml_data, encoding='unicode'), self, self.org,
                    self.course, xmlstore.default_class)
            except Exception as err:
                if not self.load_error_modules:
                    raise

                # Didn't load properly.  Fall back on loading as an error
                # descriptor.  This should never error due to formatting.

                msg = "Error loading from xml. " + str(err)[:200]
                log.warning(msg)
                # Normally, we don't want lots of exception traces in our logs from common
                # content problems.  But if you're debugging the xml loading code itself,
                # uncomment the next line.
                log.exception(msg)

                self.error_tracker(msg)
                err_msg = msg + "\n" + exc_info_to_str(sys.exc_info())
                descriptor = ErrorDescriptor.from_xml(
                    xml,
                    self,
                    self.org,
                    self.course,
                    err_msg
                )

            setattr(descriptor, 'data_dir', course_dir)

            xmlstore.modules[course_id][descriptor.location] = descriptor

            if hasattr(descriptor, 'children'):
                for child in descriptor.get_children():
                    parent_tracker.add_parent(child.location, descriptor.location)
            return descriptor
コード例 #46
0
ファイル: __init__.py プロジェクト: MSOpenTech/edx-platform
 def test_load_class(self):
     vc = XModuleDescriptor.load_class('video')
     vc_str = "<class 'xmodule.video_module.video_module.VideoDescriptor'>"
     self.assertEqual(str(vc), vc_str)
コード例 #47
0
ファイル: factories.py プロジェクト: nettoyeur/edx-platform
    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

        DETACHED_CATEGORIES = ["about", "static_tab", "course_info"]
        # catch any old style users before they get into trouble
        assert "template" not in kwargs
        parent_location = 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 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 = XModuleDescriptor.load_class(category)
            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
        module = 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)
        module.save()

        store.save_xmodule(module)

        if location.category not in DETACHED_CATEGORIES:
            parent.children.append(location.url())
            store.update_children(parent_location, parent.children)

        return store.get_item(location)