Exemple #1
0
 def create_toy_course(self, org='edX', course='toy', run='2012_Fall'):
     """
     Create an equivalent to the toy xml course
     """
     #        with self.store.bulk_write_operations(self.store.make_course_key(org, course, run)):
     self.toy_loc = self.create_sample_course(
         org, course, run, TOY_BLOCK_INFO_TREE, {
             "textbooks": [[
                 "Textbook",
                 "https://s3.amazonaws.com/edx-textbooks/guttag_computation_v3/"
             ]],
             "wiki_slug":
             "toy",
             "display_name":
             "Toy Course",
             "graded":
             True,
             "tabs": [
                 CoursewareTab(),
                 CourseInfoTab(),
                 StaticTab(name="Syllabus", url_slug="syllabus"),
                 StaticTab(name="Resources", url_slug="resources"),
                 DiscussionTab(),
                 WikiTab(),
                 ProgressTab(),
             ],
             "discussion_topics": {
                 "General": {
                     "id": "i4x-edX-toy-course-2012_Fall"
                 }
             },
             "graceperiod":
             datetime.timedelta(days=2, seconds=21599),
             "start":
             datetime.datetime(2015, 07, 17, 12, tzinfo=pytz.utc),
             "xml_attributes": {
                 "filename":
                 ["course/2012_Fall.xml", "course/2012_Fall.xml"]
             },
             "pdf_textbooks": [{
                 "tab_title":
                 "Sample Multi Chapter Textbook",
                 "id":
                 "MyTextbook",
                 "chapters": [{
                     "url": "/static/Chapter1.pdf",
                     "title": "Chapter 1"
                 }, {
                     "url": "/static/Chapter2.pdf",
                     "title": "Chapter 2"
                 }]
             }],
             "course_image":
             "just_a_test.jpg",
         })
Exemple #2
0
    def create_and_save_xmodule(self, location, definition_data=None, metadata=None, system=None,
                                fields={}):
        """
        Create the new xmodule and save it. Does not return the new module because if the caller
        will insert it as a child, it's inherited metadata will completely change. The difference
        between this and just doing create_xmodule and update_item is this ensures static_tabs get
        pointed to by the course.

        :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
        """
        # 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.
        new_object = self.create_xmodule(location, definition_data, metadata, system, fields)
        location = new_object.scope_ids.usage_id
        self.update_item(new_object, allow_not_found=True)

        # 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
        # TODO move this special casing to app tier (similar to attaching new element to parent)
        if location.category == 'static_tab':
            course = self._get_course_for_item(location)
            course.tabs.append(
                StaticTab(
                    name=new_object.display_name,
                    url_slug=new_object.scope_ids.usage_id.name,
                )
            )
            self.update_item(course)

        return new_object
Exemple #3
0
def _create_item(request):
    """View for create items."""
    usage_key = usage_key_with_run(request.json['parent_locator'])
    category = request.json['category']

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

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

    store = modulestore()
    parent = store.get_item(usage_key)
    dest_usage_key = usage_key.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:
        clz = parent.runtime.load_block_type(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

    # TODO need to fix components that are sending definition_data as strings, instead of as dicts
    # For now, migrate them into dicts here.
    if isinstance(data, basestring):
        data = {'data': data}

    created_block = store.create_child(
        request.user.id,
        usage_key,
        dest_usage_key.block_type,
        block_id=dest_usage_key.block_id,
        definition_data=data,
        metadata=metadata,
        runtime=parent.runtime,
    )

    # 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':
        display_name = display_name or _("Empty") # Prevent name being None
        course = store.get_course(dest_usage_key.course_key)
        course.tabs.append(
            StaticTab(
                name=display_name,
                url_slug=dest_usage_key.name,
            )
        )
        store.update_item(course, request.user.id)

    return JsonResponse({"locator": unicode(created_block.location), "courseKey": unicode(created_block.location.course_key)})
Exemple #4
0
def _create_item(request):
    """View for create items."""
    usage_key = UsageKey.from_string(request.json['parent_locator'])
    # usage_key's course_key may have an empty run property
    usage_key = usage_key.replace(
        course_key=modulestore().fill_in_run(usage_key.course_key))
    category = request.json['category']

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

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

    store = modulestore()
    parent = store.get_item(usage_key)
    dest_usage_key = usage_key.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:
        clz = parent.runtime.load_block_type(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

    created_block = store.create_child(
        request.user.id,
        usage_key,
        dest_usage_key.block_type,
        block_id=dest_usage_key.block_id,
        definition_data=data,
        metadata=metadata,
        runtime=parent.runtime,
    )

    # 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(dest_usage_key.course_key)
        course.tabs.append(
            StaticTab(
                name=display_name,
                url_slug=dest_usage_key.name,
            ))
        store.update_item(course, request.user.id)

    return JsonResponse({
        "locator": unicode(created_block.location),
        "courseKey": unicode(created_block.location.course_key)
    })
Exemple #5
0
def get_tab_by_locator(tab_list, usage_key_string):
    """
    Look for a tab with the specified locator.  Returns the first matching tab.
    """
    tab_location = UsageKey.from_string(usage_key_string)
    item = modulestore().get_item(tab_location)
    static_tab = StaticTab(
        name=item.display_name,
        url_slug=item.location.name,
    )
    return CourseTabList.get_tab_by_id(tab_list, static_tab.tab_id)
Exemple #6
0
def get_tab_by_locator(tab_list, tab_locator):
    """
    Look for a tab with the specified locator.  Returns the first matching tab.
    """
    tab_location = loc_mapper().translate_locator_to_location(
        BlockUsageLocator(tab_locator))
    item = modulestore('direct').get_item(tab_location)
    static_tab = StaticTab(
        name=item.display_name,
        url_slug=item.location.name,
    )
    return CourseTabList.get_tab_by_id(tab_list, static_tab.tab_id)
Exemple #7
0
def get_tab_by_locator(
        tab_list: List[CourseTab],
        tab_location: Union[str, UsageKey]) -> Optional[CourseTab]:
    """
    Look for a tab with the specified locator.  Returns the first matching tab.
    """
    if isinstance(tab_location, str):
        tab_location = UsageKey.from_string(tab_location)
    item = modulestore().get_item(tab_location)
    static_tab = StaticTab(
        name=item.display_name,
        url_slug=item.location.name,
    )
    return CourseTabList.get_tab_by_id(tab_list, static_tab.tab_id)
Exemple #8
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)
Exemple #9
0
def create_xblock(parent_locator, user, category, display_name, boilerplate=None, is_entrance_exam=False):
    """
    Performs the actual grunt work of creating items/xblocks -- knows nothing about requests, views, etc.
    """
    store = modulestore()
    usage_key = usage_key_with_run(parent_locator)
    with store.bulk_operations(usage_key.course_key):
        parent = store.get_item(usage_key)
        dest_usage_key = usage_key.replace(category=category, name=uuid4().hex)

        # get the metadata, display_name, and definition from the caller
        metadata = {}
        data = None
        template_id = boilerplate
        if template_id:
            clz = parent.runtime.load_block_type(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

        # We should use the 'fields' kwarg for newer module settings/values (vs. metadata or data)
        fields = {}

        # Entrance Exams: Chapter module positioning
        child_position = None
        if ENTRANCE_EXAMS.is_enabled():
            if category == 'chapter' and is_entrance_exam:
                fields['is_entrance_exam'] = is_entrance_exam
                fields['in_entrance_exam'] = True  # Inherited metadata, all children will have it
                child_position = 0

        # TODO need to fix components that are sending definition_data as strings, instead of as dicts
        # For now, migrate them into dicts here.
        if isinstance(data, str):
            data = {'data': data}

        created_block = store.create_child(
            user.id,
            usage_key,
            dest_usage_key.block_type,
            block_id=dest_usage_key.block_id,
            fields=fields,
            definition_data=data,
            metadata=metadata,
            runtime=parent.runtime,
            position=child_position,
        )

        # Entrance Exams: Grader assignment
        if ENTRANCE_EXAMS.is_enabled():
            course_key = usage_key.course_key
            course = store.get_course(course_key)
            if hasattr(course, 'entrance_exam_enabled') and course.entrance_exam_enabled:
                if category == 'sequential' and parent_locator == course.entrance_exam_id:
                    # Clean up any pre-existing entrance exam graders
                    remove_entrance_exam_graders(course_key, user)
                    grader = {
                        "type": GRADER_TYPES['ENTRANCE_EXAM'],
                        "min_count": 0,
                        "drop_count": 0,
                        "short_label": "Entrance",
                        "weight": 0
                    }
                    grading_model = CourseGradingModel.update_grader_from_json(
                        course.id,
                        grader,
                        user
                    )
                    CourseGradingModel.update_section_grader_type(
                        created_block,
                        grading_model['type'],
                        user
                    )

        # 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':
            display_name = display_name or _("Empty")  # Prevent name being None
            course = store.get_course(dest_usage_key.course_key)
            course.tabs.append(
                StaticTab(
                    name=display_name,
                    url_slug=dest_usage_key.block_id,
                )
            )
            store.update_item(course, user.id)

        return created_block