コード例 #1
0
    def get_settings_url_for_category(cls, category, child, parent):
        """
        Returns the URLs that the user needs to go to in order to change settings.
        Chapters and Problems need urls that match for their parents:
            - Chapters: Course url
            - Problems: Unit url
        """

        if category in ['chapter', 'sequential', 'vertical']:
            return xblock_studio_url(child)
        else:
            return xblock_studio_url(parent)
コード例 #2
0
    def get_settings_url_for_category(cls, category, child, parent):
        """
        Returns the URLs that the user needs to go to in order to change settings.
        Chapters and Problems need urls that match for their parents:
            - Chapters: Course url
            - Problems: Unit url
        """

        if category in ['chapter', 'sequential', 'vertical']:
            return xblock_studio_url(child)
        else:
            return xblock_studio_url(parent)
コード例 #3
0
ファイル: utils.py プロジェクト: xiaojunxi2008/edx-platform
 def get_page_html(self, xblock):
     """
     Returns the HTML for the page representing the xblock.
     """
     url = xblock_studio_url(xblock)
     self.assertIsNotNone(url)
     resp = self.client.get_html(url)
     self.assertEqual(resp.status_code, 200)
     return resp.content.decode(resp.charset)
コード例 #4
0
ファイル: utils.py プロジェクト: BenjiLee/edx-platform
 def get_page_html(self, xblock):
     """
     Returns the HTML for the page representing the xblock.
     """
     url = xblock_studio_url(xblock)
     self.assertIsNotNone(url)
     resp = self.client.get_html(url)
     self.assertEqual(resp.status_code, 200)
     return resp.content
コード例 #5
0
 def _test_html_content(self, xblock, expected_section_tag, expected_breadcrumbs):
     """
     Get the HTML for a container page and verify the section tag is correct
     and the breadcrumbs trail is correct.
     """
     url = xblock_studio_url(xblock, self.course)
     resp = self.client.get_html(url)
     self.assertEqual(resp.status_code, 200)
     html = resp.content
     self.assertIn(expected_section_tag, html)
     # Verify the navigation link at the top of the page is correct.
     self.assertRegexpMatches(html, expected_breadcrumbs)
コード例 #6
0
    def test_xblock_studio_url(self):

        # Verify course URL
        self.assertEqual(xblock_studio_url(self.course),
                         u'/course/MITx/999/Robot_Super_Course')

        # Verify chapter URL
        chapter = ItemFactory.create(parent_location=self.course.location, category='chapter',
                                     display_name="Week 1")
        self.assertIsNone(xblock_studio_url(chapter))

        # Verify lesson URL
        sequential = ItemFactory.create(parent_location=chapter.location, category='sequential',
                                        display_name="Lesson 1")
        self.assertIsNone(xblock_studio_url(sequential))

        # Verify vertical URL
        vertical = ItemFactory.create(parent_location=sequential.location, category='vertical',
                                      display_name='Unit')
        self.assertEqual(xblock_studio_url(vertical),
                         u'/unit/i4x://MITx/999/vertical/Unit')

        # Verify child vertical URL
        child_vertical = ItemFactory.create(parent_location=vertical.location, category='vertical',
                                            display_name='Child Vertical')
        self.assertEqual(xblock_studio_url(child_vertical),
                         u'/container/i4x://MITx/999/vertical/Child_Vertical')

        # Verify video URL
        video = ItemFactory.create(parent_location=child_vertical.location, category="video",
                                   display_name="My Video")
        self.assertIsNone(xblock_studio_url(video))
コード例 #7
0
ファイル: test_helpers.py プロジェクト: pwilkins/edx-platform
    def test_xblock_studio_url(self):

        # Verify course URL
        course_url = u"/course/{}".format(unicode(self.course.id))
        self.assertEqual(xblock_studio_url(self.course), course_url)

        # Verify chapter URL
        chapter = ItemFactory.create(parent_location=self.course.location, category="chapter", display_name="Week 1")
        self.assertEqual(xblock_studio_url(chapter), u"{}?show={}".format(course_url, http.urlquote(chapter.location)))

        # Verify sequential URL
        sequential = ItemFactory.create(
            parent_location=chapter.location, category="sequential", display_name="Lesson 1"
        )
        self.assertEqual(
            xblock_studio_url(sequential), u"{}?show={}".format(course_url, http.urlquote(sequential.location))
        )

        # Verify unit URL
        vertical = ItemFactory.create(parent_location=sequential.location, category="vertical", display_name="Unit")
        self.assertEqual(xblock_studio_url(vertical), u"/container/{}".format(vertical.location))

        # Verify child vertical URL
        child_vertical = ItemFactory.create(
            parent_location=vertical.location, category="vertical", display_name="Child Vertical"
        )
        self.assertEqual(xblock_studio_url(child_vertical), u"/container/{}".format(child_vertical.location))

        # Verify video URL
        video = ItemFactory.create(parent_location=child_vertical.location, category="video", display_name="My Video")
        self.assertIsNone(xblock_studio_url(video))
コード例 #8
0
ファイル: test_helpers.py プロジェクト: 1amongus/edx-platform
    def test_xblock_studio_url(self):

        # Verify course URL
        self.assertEqual(xblock_studio_url(self.course),
                         u'/course/slashes:MITx+999+Robot_Super_Course')

        # Verify chapter URL
        chapter = ItemFactory.create(parent_location=self.course.location, category='chapter',
                                     display_name="Week 1")
        self.assertIsNone(xblock_studio_url(chapter))

        # Verify lesson URL
        sequential = ItemFactory.create(parent_location=chapter.location, category='sequential',
                                        display_name="Lesson 1")
        self.assertIsNone(xblock_studio_url(sequential))

        # Verify vertical URL
        vertical = ItemFactory.create(parent_location=sequential.location, category='vertical',
                                      display_name='Unit')
        self.assertEqual(xblock_studio_url(vertical),
                         u'/unit/location:MITx+999+Robot_Super_Course+vertical+Unit')

        # Verify child vertical URL
        child_vertical = ItemFactory.create(parent_location=vertical.location, category='vertical',
                                            display_name='Child Vertical')
        self.assertEqual(xblock_studio_url(child_vertical),
                         u'/container/location:MITx+999+Robot_Super_Course+vertical+Child_Vertical')

        # Verify video URL
        video = ItemFactory.create(parent_location=child_vertical.location, category="video",
                                   display_name="My Video")
        self.assertIsNone(xblock_studio_url(video))
コード例 #9
0
 def _test_html_content(self, xblock, expected_section_tag, expected_breadcrumbs):
     """
     Get the HTML for a container page and verify the section tag is correct
     and the breadcrumbs trail is correct.
     """
     url = xblock_studio_url(xblock, self.course)
     resp = self.client.get_html(url)
     self.assertEqual(resp.status_code, 200)
     html = resp.content
     self.assertIn(expected_section_tag, html)
     # Verify the navigation link at the top of the page is correct.
     self.assertRegexpMatches(html, expected_breadcrumbs)
     # Verify the link that allows users to change publish status.
     expected_unit_link = 'This content is published with unit <a href="/unit/MITx.999.Robot_Super_Course/branch/draft/block/Unit">Unit</a>.'
     self.assertIn(expected_unit_link, html)
コード例 #10
0
    def test_xblock_studio_url(self):

        # Verify course URL
        course_url = u'/course/{}'.format(unicode(self.course.id))
        self.assertEqual(xblock_studio_url(self.course), course_url)

        # Verify chapter URL
        chapter = ItemFactory.create(parent_location=self.course.location,
                                     category='chapter',
                                     display_name="Week 1")
        self.assertEqual(
            xblock_studio_url(chapter),
            u'{}?show={}'.format(course_url, http.urlquote(chapter.location)))

        # Verify sequential URL
        sequential = ItemFactory.create(parent_location=chapter.location,
                                        category='sequential',
                                        display_name="Lesson 1")
        self.assertEqual(
            xblock_studio_url(sequential),
            u'{}?show={}'.format(course_url,
                                 http.urlquote(sequential.location)))

        # Verify unit URL
        vertical = ItemFactory.create(parent_location=sequential.location,
                                      category='vertical',
                                      display_name='Unit')
        self.assertEqual(xblock_studio_url(vertical),
                         u'/container/{}'.format(vertical.location))

        # Verify child vertical URL
        child_vertical = ItemFactory.create(parent_location=vertical.location,
                                            category='vertical',
                                            display_name='Child Vertical')
        self.assertEqual(xblock_studio_url(child_vertical),
                         u'/container/{}'.format(child_vertical.location))

        # Verify video URL
        video = ItemFactory.create(parent_location=child_vertical.location,
                                   category="video",
                                   display_name="My Video")
        self.assertIsNone(xblock_studio_url(video))

        # Verify library URL
        library = LibraryFactory.create()
        expected_url = u'/library/{}'.format(
            unicode(library.location.library_key))
        self.assertEqual(xblock_studio_url(library), expected_url)
コード例 #11
0
ファイル: test_helpers.py プロジェクト: 10clouds/edx-platform
    def test_xblock_studio_url(self):

        # Verify course URL
        course_url = u'/course/{}'.format(unicode(self.course.id))
        self.assertEqual(xblock_studio_url(self.course), course_url)

        # Verify chapter URL
        chapter = ItemFactory.create(parent_location=self.course.location, category='chapter',
                                     display_name="Week 1")
        self.assertEqual(
            xblock_studio_url(chapter),
            u'{}?show={}'.format(course_url, http.urlquote(chapter.location))
        )

        # Verify sequential URL
        sequential = ItemFactory.create(parent_location=chapter.location, category='sequential',
                                        display_name="Lesson 1")
        self.assertEqual(
            xblock_studio_url(sequential),
            u'{}?show={}'.format(course_url, http.urlquote(sequential.location))
        )

        # Verify unit URL
        vertical = ItemFactory.create(parent_location=sequential.location, category='vertical',
                                      display_name='Unit')
        self.assertEqual(xblock_studio_url(vertical), u'/container/{}'.format(vertical.location))

        # Verify child vertical URL
        child_vertical = ItemFactory.create(parent_location=vertical.location, category='vertical',
                                            display_name='Child Vertical')
        self.assertEqual(xblock_studio_url(child_vertical), u'/container/{}'.format(child_vertical.location))

        # Verify video URL
        video = ItemFactory.create(parent_location=child_vertical.location, category="video",
                                   display_name="My Video")
        self.assertIsNone(xblock_studio_url(video))

        # Verify library URL
        library = LibraryFactory.create()
        expected_url = u'/library/{}'.format(unicode(library.location.library_key))
        self.assertEqual(xblock_studio_url(library), expected_url)
コード例 #12
0
 def _test_html_content(self, xblock, branch_name, expected_section_tag, expected_breadcrumbs):
     """
     Get the HTML for a container page and verify the section tag is correct
     and the breadcrumbs trail is correct.
     """
     url = xblock_studio_url(xblock, self.course)
     publish_state = compute_publish_state(xblock)
     resp = self.client.get_html(url)
     self.assertEqual(resp.status_code, 200)
     html = resp.content
     self.assertIn(expected_section_tag, html)
     # Verify the navigation link at the top of the page is correct.
     self.assertRegexpMatches(html, expected_breadcrumbs)
     # Verify the link that allows users to change publish status.
     expected_message = None
     if publish_state == PublishState.public:
         expected_message = 'you need to edit unit <a href="/unit/{branch_name}/Unit">Unit</a> as a draft.'
     else:
         expected_message = 'your changes will be published with unit <a href="/unit/{branch_name}/Unit">Unit</a>.'
     expected_unit_link = expected_message.format(
         branch_name=branch_name
     )
     self.assertIn(expected_unit_link, html)
コード例 #13
0
    def test_xblock_studio_url(self):

        # Verify course URL
        self.assertEqual(xblock_studio_url(self.course),
                         u'/course/MITx/999/Robot_Super_Course')

        # Verify chapter URL
        chapter = ItemFactory.create(parent_location=self.course.location, category='chapter',
                                     display_name="Week 1")
        self.assertEqual(xblock_studio_url(chapter),
                         u'/course/MITx/999/Robot_Super_Course?show={escaped_usage_key}'.format(
                             escaped_usage_key='i4x%3A//MITx/999/chapter/Week_1'
                         ))

        # Verify sequential URL
        sequential = ItemFactory.create(parent_location=chapter.location, category='sequential',
                                        display_name="Lesson 1")
        self.assertEqual(xblock_studio_url(sequential),
                         u'/course/MITx/999/Robot_Super_Course?show={escaped_usage_key}'.format(
                             escaped_usage_key='i4x%3A//MITx/999/sequential/Lesson_1'
                         ))

        # Verify unit URL
        vertical = ItemFactory.create(parent_location=sequential.location, category='vertical',
                                      display_name='Unit')
        self.assertEqual(xblock_studio_url(vertical),
                         u'/container/i4x://MITx/999/vertical/Unit')

        # Verify child vertical URL
        child_vertical = ItemFactory.create(parent_location=vertical.location, category='vertical',
                                            display_name='Child Vertical')
        self.assertEqual(xblock_studio_url(child_vertical),
                         u'/container/i4x://MITx/999/vertical/Child_Vertical')

        # Verify video URL
        video = ItemFactory.create(parent_location=child_vertical.location, category="video",
                                   display_name="My Video")
        self.assertIsNone(xblock_studio_url(video))
コード例 #14
0
def create_xblock_info(xblock,
                       data=None,
                       metadata=None,
                       include_ancestor_info=False,
                       include_child_info=False,
                       course_outline=False,
                       include_children_predicate=NEVER,
                       parent_xblock=None,
                       graders=None):
    """
    Creates the information needed for client-side XBlockInfo.

    If data or metadata are not specified, their information will not be added
    (regardless of whether or not the xblock actually has data or metadata).

    There are three optional boolean parameters:
      include_ancestor_info - if true, ancestor info is added to the response
      include_child_info - if true, direct child info is included in the response
      course_outline - if true, the xblock is being rendered on behalf of the course outline.
        There are certain expensive computations that do not need to be included in this case.

    In addition, an optional include_children_predicate argument can be provided to define whether or
    not a particular xblock should have its children included.
    """
    is_library_block = isinstance(xblock.location, LibraryUsageLocator)
    is_xblock_unit = is_unit(xblock, parent_xblock)
    # this should not be calculated for Sections and Subsections on Unit page or for library blocks
    has_changes = None
    if (is_xblock_unit or course_outline) and not is_library_block:
        has_changes = modulestore().has_changes(xblock)

    if graders is None:
        if not is_library_block:
            graders = CourseGradingModel.fetch(
                xblock.location.course_key).graders
        else:
            graders = []

    # Filter the graders data as needed
    graders = _filter_entrance_exam_grader(graders)

    # Compute the child info first so it can be included in aggregate information for the parent
    should_visit_children = include_child_info and (
        course_outline and not is_xblock_unit or not course_outline)
    if should_visit_children and xblock.has_children:
        child_info = _create_xblock_child_info(
            xblock,
            course_outline,
            graders,
            include_children_predicate=include_children_predicate,
        )
    else:
        child_info = None

    if xblock.category != 'course':
        visibility_state = _compute_visibility_state(
            xblock, child_info, is_xblock_unit and has_changes)
    else:
        visibility_state = None
    published = modulestore().has_published_version(
        xblock) if not is_library_block else None

    # defining the default value 'True' for delete, drag and add new child actions in xblock_actions for each xblock.
    xblock_actions = {
        'deletable': True,
        'draggable': True,
        'childAddable': True
    }
    explanatory_message = None
    # is_entrance_exam is inherited metadata.
    if xblock.category == 'chapter' and getattr(xblock, "is_entrance_exam",
                                                None):
        # Entrance exam section should not be deletable, draggable and not have 'New Subsection' button.
        xblock_actions['deletable'] = xblock_actions[
            'childAddable'] = xblock_actions['draggable'] = False
        if parent_xblock is None:
            parent_xblock = get_parent_xblock(xblock)

        explanatory_message = _(
            'Students must score {score}% or higher to access course materials.'
        ).format(score=int(parent_xblock.entrance_exam_minimum_score_pct *
                           100))

    xblock_info = {
        "id":
        unicode(xblock.location),
        "display_name":
        xblock.display_name_with_default,
        "category":
        xblock.category,
        "edited_on":
        get_default_time_display(xblock.subtree_edited_on)
        if xblock.subtree_edited_on else None,
        "published":
        published,
        "published_on":
        get_default_time_display(xblock.published_on)
        if published and xblock.published_on else None,
        "studio_url":
        xblock_studio_url(xblock, parent_xblock),
        "released_to_students":
        datetime.now(UTC) > xblock.start,
        "release_date":
        _get_release_date(xblock),
        "visibility_state":
        visibility_state,
        "has_explicit_staff_lock":
        xblock.fields['visible_to_staff_only'].is_set_on(xblock),
        "start":
        xblock.fields['start'].to_json(xblock.start),
        "graded":
        xblock.graded,
        "due_date":
        get_default_time_display(xblock.due),
        "due":
        xblock.fields['due'].to_json(xblock.due),
        "format":
        xblock.format,
        "course_graders":
        json.dumps([grader.get('type') for grader in graders]),
        "has_changes":
        has_changes,
        "actions":
        xblock_actions,
        "explanatory_message":
        explanatory_message
    }

    # Entrance exam subsection should be hidden. in_entrance_exam is inherited metadata, all children will have it.
    if xblock.category == 'sequential' and getattr(xblock, "in_entrance_exam",
                                                   False):
        xblock_info["is_header_visible"] = False

    if data is not None:
        xblock_info["data"] = data
    if metadata is not None:
        xblock_info["metadata"] = metadata
    if include_ancestor_info:
        xblock_info['ancestor_info'] = _create_xblock_ancestor_info(
            xblock, course_outline)
    if child_info:
        xblock_info['child_info'] = child_info
    if visibility_state == VisibilityState.staff_only:
        xblock_info["ancestor_has_staff_lock"] = ancestor_has_staff_lock(
            xblock, parent_xblock)
    else:
        xblock_info["ancestor_has_staff_lock"] = False

    if course_outline:
        if xblock_info["has_explicit_staff_lock"]:
            xblock_info["staff_only_message"] = True
        elif child_info and child_info["children"]:
            xblock_info["staff_only_message"] = all([
                child["staff_only_message"] for child in child_info["children"]
            ])
        else:
            xblock_info["staff_only_message"] = False

    return xblock_info
コード例 #15
0
ファイル: item.py プロジェクト: 189140879/edx-platform
def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=False, include_child_info=False,
                       course_outline=False, include_children_predicate=NEVER, parent_xblock=None, graders=None,
                       user=None):
    """
    Creates the information needed for client-side XBlockInfo.

    If data or metadata are not specified, their information will not be added
    (regardless of whether or not the xblock actually has data or metadata).

    There are three optional boolean parameters:
      include_ancestor_info - if true, ancestor info is added to the response
      include_child_info - if true, direct child info is included in the response
      course_outline - if true, the xblock is being rendered on behalf of the course outline.
        There are certain expensive computations that do not need to be included in this case.

    In addition, an optional include_children_predicate argument can be provided to define whether or
    not a particular xblock should have its children included.
    """
    is_library_block = isinstance(xblock.location, LibraryUsageLocator)
    is_xblock_unit = is_unit(xblock, parent_xblock)
    # this should not be calculated for Sections and Subsections on Unit page or for library blocks
    has_changes = None
    if (is_xblock_unit or course_outline) and not is_library_block:
        has_changes = modulestore().has_changes(xblock)

    if graders is None:
        if not is_library_block:
            graders = CourseGradingModel.fetch(xblock.location.course_key).graders
        else:
            graders = []

    # Filter the graders data as needed
    graders = _filter_entrance_exam_grader(graders)

    # Compute the child info first so it can be included in aggregate information for the parent
    should_visit_children = include_child_info and (course_outline and not is_xblock_unit or not course_outline)
    if should_visit_children and xblock.has_children:
        child_info = _create_xblock_child_info(
            xblock,
            course_outline,
            graders,
            include_children_predicate=include_children_predicate,
            user=user
        )
    else:
        child_info = None

    if xblock.category != 'course':
        visibility_state = _compute_visibility_state(xblock, child_info, is_xblock_unit and has_changes)
    else:
        visibility_state = None
    published = modulestore().has_published_version(xblock) if not is_library_block else None

    # defining the default value 'True' for delete, drag and add new child actions in xblock_actions for each xblock.
    xblock_actions = {'deletable': True, 'draggable': True, 'childAddable': True}
    explanatory_message = None
    # is_entrance_exam is inherited metadata.
    if xblock.category == 'chapter' and getattr(xblock, "is_entrance_exam", None):
        # Entrance exam section should not be deletable, draggable and not have 'New Subsection' button.
        xblock_actions['deletable'] = xblock_actions['childAddable'] = xblock_actions['draggable'] = False
        if parent_xblock is None:
            parent_xblock = get_parent_xblock(xblock)

        # Translators: The {pct_sign} here represents the percent sign, i.e., '%'
        # in many languages. This is used to avoid Transifex's misinterpreting of
        # '% o'. The percent sign is also translatable as a standalone string.
        explanatory_message = _('Students must score {score}{pct_sign} or higher to access course materials.').format(
            score=int(parent_xblock.entrance_exam_minimum_score_pct * 100),
            # Translators: This is the percent sign. It will be used to represent
            # a percent value out of 100, e.g. "58%" means "58/100".
            pct_sign=_('%'))

    xblock_info = {
        "id": unicode(xblock.location),
        "display_name": xblock.display_name_with_default,
        "category": xblock.category,
        "edited_on": get_default_time_display(xblock.subtree_edited_on) if xblock.subtree_edited_on else None,
        "published": published,
        "published_on": get_default_time_display(xblock.published_on) if published and xblock.published_on else None,
        "studio_url": xblock_studio_url(xblock, parent_xblock),
        "released_to_students": datetime.now(UTC) > xblock.start,
        "release_date": _get_release_date(xblock, user),
        "visibility_state": visibility_state,
        "has_explicit_staff_lock": xblock.fields['visible_to_staff_only'].is_set_on(xblock),
        "start": xblock.fields['start'].to_json(xblock.start),
        "graded": xblock.graded,
        "due_date": get_default_time_display(xblock.due),
        "due": xblock.fields['due'].to_json(xblock.due),
        "format": xblock.format,
        "course_graders": json.dumps([grader.get('type') for grader in graders]),
        "has_changes": has_changes,
        "actions": xblock_actions,
        "explanatory_message": explanatory_message
    }

    # Entrance exam subsection should be hidden. in_entrance_exam is inherited metadata, all children will have it.
    if xblock.category == 'sequential' and getattr(xblock, "in_entrance_exam", False):
        xblock_info["is_header_visible"] = False

    if data is not None:
        xblock_info["data"] = data
    if metadata is not None:
        xblock_info["metadata"] = metadata
    if include_ancestor_info:
        xblock_info['ancestor_info'] = _create_xblock_ancestor_info(xblock, course_outline)
    if child_info:
        xblock_info['child_info'] = child_info
    if visibility_state == VisibilityState.staff_only:
        xblock_info["ancestor_has_staff_lock"] = ancestor_has_staff_lock(xblock, parent_xblock)
    else:
        xblock_info["ancestor_has_staff_lock"] = False

    if course_outline:
        if xblock_info["has_explicit_staff_lock"]:
            xblock_info["staff_only_message"] = True
        elif child_info and child_info["children"]:
            xblock_info["staff_only_message"] = all([child["staff_only_message"] for child in child_info["children"]])
        else:
            xblock_info["staff_only_message"] = False

    return xblock_info
コード例 #16
0
ファイル: item.py プロジェクト: wanduow/edx-platform
def create_xblock_info(xblock,
                       data=None,
                       metadata=None,
                       include_ancestor_info=False,
                       include_child_info=False,
                       course_outline=False,
                       include_children_predicate=NEVER,
                       parent_xblock=None,
                       graders=None):
    """
    Creates the information needed for client-side XBlockInfo.

    If data or metadata are not specified, their information will not be added
    (regardless of whether or not the xblock actually has data or metadata).

    There are three optional boolean parameters:
      include_ancestor_info - if true, ancestor info is added to the response
      include_child_info - if true, direct child info is included in the response
      course_outline - if true, the xblock is being rendered on behalf of the course outline.
        There are certain expensive computations that do not need to be included in this case.

    In addition, an optional include_children_predicate argument can be provided to define whether or
    not a particular xblock should have its children included.
    """
    is_library_block = isinstance(xblock.location, LibraryUsageLocator)
    is_xblock_unit = is_unit(xblock, parent_xblock)
    # this should not be calculated for Sections and Subsections on Unit page or for library blocks
    has_changes = None
    if (is_xblock_unit or course_outline) and not is_library_block:
        has_changes = modulestore().has_changes(xblock)

    if graders is None:
        if not is_library_block:
            graders = CourseGradingModel.fetch(
                xblock.location.course_key).graders
        else:
            graders = []

    # Filter the graders data as needed
    graders = _filter_entrance_exam_grader(graders)

    # Compute the child info first so it can be included in aggregate information for the parent
    should_visit_children = include_child_info and (
        course_outline and not is_xblock_unit or not course_outline)
    if should_visit_children and xblock.has_children:
        child_info = _create_xblock_child_info(
            xblock,
            course_outline,
            graders,
            include_children_predicate=include_children_predicate,
        )
    else:
        child_info = None

    if xblock.category != 'course':
        visibility_state = _compute_visibility_state(
            xblock, child_info, is_xblock_unit and has_changes)
    else:
        visibility_state = None
    published = modulestore().has_published_version(
        xblock) if not is_library_block else None

    #instead of adding a new feature directly into xblock-info, we should add them into override_type.
    override_type = {}
    if getattr(xblock, "is_entrance_exam", None):
        override_type['is_entrance_exam'] = xblock.is_entrance_exam

    xblock_info = {
        "id":
        unicode(xblock.location),
        "display_name":
        xblock.display_name_with_default,
        "category":
        xblock.category,
        "edited_on":
        get_default_time_display(xblock.subtree_edited_on)
        if xblock.subtree_edited_on else None,
        "published":
        published,
        "published_on":
        get_default_time_display(xblock.published_on)
        if published and xblock.published_on else None,
        "studio_url":
        xblock_studio_url(xblock, parent_xblock),
        "released_to_students":
        datetime.now(UTC) > xblock.start,
        "release_date":
        _get_release_date(xblock),
        "visibility_state":
        visibility_state,
        "has_explicit_staff_lock":
        xblock.fields['visible_to_staff_only'].is_set_on(xblock),
        "start":
        xblock.fields['start'].to_json(xblock.start),
        "graded":
        xblock.graded,
        "due_date":
        get_default_time_display(xblock.due),
        "due":
        xblock.fields['due'].to_json(xblock.due),
        "format":
        xblock.format,
        "course_graders":
        json.dumps([grader.get('type') for grader in graders]),
        "has_changes":
        has_changes,
        "override_type":
        override_type,
    }
    if data is not None:
        xblock_info["data"] = data
    if metadata is not None:
        xblock_info["metadata"] = metadata
    if include_ancestor_info:
        xblock_info['ancestor_info'] = _create_xblock_ancestor_info(
            xblock, course_outline)
    if child_info:
        xblock_info['child_info'] = child_info
    if visibility_state == VisibilityState.staff_only:
        xblock_info["ancestor_has_staff_lock"] = ancestor_has_staff_lock(
            xblock, parent_xblock)
    else:
        xblock_info["ancestor_has_staff_lock"] = False

    if course_outline:
        if xblock_info["has_explicit_staff_lock"]:
            xblock_info["staff_only_message"] = True
        elif child_info and child_info["children"]:
            xblock_info["staff_only_message"] = all([
                child["staff_only_message"] for child in child_info["children"]
            ])
        else:
            xblock_info["staff_only_message"] = False

    return xblock_info
コード例 #17
0
 def test_container_html(self):
     url = xblock_studio_url(self.child_vertical)
     resp = self.client.get_html(url)
     self.assertEqual(resp.status_code, 200)
     html = resp.content
     self.assertIn('<section class="wrapper-xblock level-page" data-locator="MITx.999.Robot_Super_Course/branch/published/block/Child_Vertical"/>', html)
コード例 #18
0
ファイル: item.py プロジェクト: aoifec/edx-platform
def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=False, include_child_info=False,
                       course_outline=False, include_children_predicate=NEVER, parent_xblock=None, graders=None):
    """
    Creates the information needed for client-side XBlockInfo.

    If data or metadata are not specified, their information will not be added
    (regardless of whether or not the xblock actually has data or metadata).

    There are three optional boolean parameters:
      include_ancestor_info - if true, ancestor info is added to the response
      include_child_info - if true, direct child info is included in the response
      course_outline - if true, the xblock is being rendered on behalf of the course outline.
        There are certain expensive computations that do not need to be included in this case.

    In addition, an optional include_children_predicate argument can be provided to define whether or
    not a particular xblock should have its children included.
    """
    is_library_block = isinstance(xblock.location, LibraryUsageLocator)
    is_xblock_unit = is_unit(xblock, parent_xblock)
    # this should not be calculated for Sections and Subsections on Unit page or for library blocks
    has_changes = None
    if (is_xblock_unit or course_outline) and not is_library_block:
        has_changes = modulestore().has_changes(xblock)

    if graders is None:
        if not is_library_block:
            graders = CourseGradingModel.fetch(xblock.location.course_key).graders
        else:
            graders = []

    # Filter the graders data as needed
    graders = _filter_entrance_exam_grader(graders)

    # Compute the child info first so it can be included in aggregate information for the parent
    should_visit_children = include_child_info and (course_outline and not is_xblock_unit or not course_outline)
    if should_visit_children and xblock.has_children:
        child_info = _create_xblock_child_info(
            xblock,
            course_outline,
            graders,
            include_children_predicate=include_children_predicate,
        )
    else:
        child_info = None

    if xblock.category != 'course':
        visibility_state = _compute_visibility_state(xblock, child_info, is_xblock_unit and has_changes)
    else:
        visibility_state = None
    published = modulestore().has_published_version(xblock) if not is_library_block else None

    #instead of adding a new feature directly into xblock-info, we should add them into override_type.
    override_type = {}
    if getattr(xblock, "is_entrance_exam", None):
        override_type['is_entrance_exam'] = xblock.is_entrance_exam

    xblock_info = {
        "id": unicode(xblock.location),
        "display_name": xblock.display_name_with_default,
        "category": xblock.category,
        "edited_on": get_default_time_display(xblock.subtree_edited_on) if xblock.subtree_edited_on else None,
        "published": published,
        "published_on": get_default_time_display(xblock.published_on) if published and xblock.published_on else None,
        "studio_url": xblock_studio_url(xblock, parent_xblock),
        "released_to_students": datetime.now(UTC) > xblock.start,
        "release_date": _get_release_date(xblock),
        "visibility_state": visibility_state,
        "has_explicit_staff_lock": xblock.fields['visible_to_staff_only'].is_set_on(xblock),
        "start": xblock.fields['start'].to_json(xblock.start),
        "graded": xblock.graded,
        "due_date": get_default_time_display(xblock.due),
        "due": xblock.fields['due'].to_json(xblock.due),
        "format": xblock.format,
        "course_graders": json.dumps([grader.get('type') for grader in graders]),
        "has_changes": has_changes,
        "override_type": override_type,
    }
    if data is not None:
        xblock_info["data"] = data
    if metadata is not None:
        xblock_info["metadata"] = metadata
    if include_ancestor_info:
        xblock_info['ancestor_info'] = _create_xblock_ancestor_info(xblock, course_outline)
    if child_info:
        xblock_info['child_info'] = child_info
    if visibility_state == VisibilityState.staff_only:
        xblock_info["ancestor_has_staff_lock"] = ancestor_has_staff_lock(xblock, parent_xblock)
    else:
        xblock_info["ancestor_has_staff_lock"] = False

    if course_outline:
        if xblock_info["has_explicit_staff_lock"]:
            xblock_info["staff_only_message"] = True
        elif child_info and child_info["children"]:
            xblock_info["staff_only_message"] = all([child["staff_only_message"] for child in child_info["children"]])
        else:
            xblock_info["staff_only_message"] = False

    return xblock_info
コード例 #19
0
def create_xblock_info(xblock,
                       data=None,
                       metadata=None,
                       include_ancestor_info=False,
                       include_child_info=False,
                       course_outline=False,
                       include_children_predicate=NEVER,
                       parent_xblock=None,
                       graders=None):
    """
    Creates the information needed for client-side XBlockInfo.

    If data or metadata are not specified, their information will not be added
    (regardless of whether or not the xblock actually has data or metadata).

    There are three optional boolean parameters:
      include_ancestor_info - if true, ancestor info is added to the response
      include_child_info - if true, direct child info is included in the response
      course_outline - if true, the xblock is being rendered on behalf of the course outline.
        There are certain expensive computations that do not need to be included in this case.

    In addition, an optional include_children_predicate argument can be provided to define whether or
    not a particular xblock should have its children included.
    """
    def safe_get_username(user_id):
        """
        Guard against bad user_ids, like the infamous "**replace_user**".
        Note that this will ignore our special known IDs (ModuleStoreEnum.UserID).
        We should consider adding special handling for those values.

        :param user_id: the user id to get the username of
        :return: username, or None if the user does not exist or user_id is None
        """
        if user_id:
            try:
                return User.objects.get(id=user_id).username
            except:  # pylint: disable=bare-except
                pass

        return None

    is_xblock_unit = is_unit(xblock, parent_xblock)
    is_unit_with_changes = is_xblock_unit and modulestore().has_changes(xblock)

    if graders is None:
        graders = CourseGradingModel.fetch(xblock.location.course_key).graders

    # Compute the child info first so it can be included in aggregate information for the parent
    should_visit_children = include_child_info and (
        course_outline and not is_xblock_unit or not course_outline)
    if should_visit_children and xblock.has_children:
        child_info = _create_xblock_child_info(
            xblock,
            course_outline,
            graders,
            include_children_predicate=include_children_predicate,
        )
    else:
        child_info = None

    # Treat DEFAULT_START_DATE as a magic number that means the release date has not been set
    release_date = get_default_time_display(
        xblock.start) if xblock.start != DEFAULT_START_DATE else None
    published = modulestore().compute_publish_state(
        xblock) != PublishState.private

    xblock_info = {
        "id":
        unicode(xblock.location),
        "display_name":
        xblock.display_name_with_default,
        "category":
        xblock.category,
        "edited_on":
        get_default_time_display(xblock.subtree_edited_on)
        if xblock.subtree_edited_on else None,
        "published":
        published,
        "published_on":
        get_default_time_display(xblock.published_date)
        if xblock.published_date else None,
        'studio_url':
        xblock_studio_url(xblock, parent_xblock),
        "released_to_students":
        datetime.now(UTC) > xblock.start,
        "release_date":
        release_date,
        "visibility_state":
        _compute_visibility_state(xblock, child_info, is_unit_with_changes)
        if not xblock.category == 'course' else None,
        "start":
        xblock.fields['start'].to_json(xblock.start),
        "graded":
        xblock.graded,
        "due_date":
        get_default_time_display(xblock.due),
        "due":
        xblock.fields['due'].to_json(xblock.due),
        "format":
        xblock.format,
        "course_graders":
        json.dumps([grader.get('type') for grader in graders]),
    }
    if data is not None:
        xblock_info["data"] = data
    if metadata is not None:
        xblock_info["metadata"] = metadata
    if include_ancestor_info:
        xblock_info['ancestor_info'] = _create_xblock_ancestor_info(
            xblock, course_outline)
    if child_info:
        xblock_info['child_info'] = child_info
    # Currently, 'edited_by', 'published_by', and 'release_date_from', and 'has_changes' are only used by the
    # container page when rendering a unit. Since they are expensive to compute, only include them for units
    # that are not being rendered on the course outline.
    if is_xblock_unit and not course_outline:
        xblock_info["edited_by"] = safe_get_username(xblock.subtree_edited_by)
        xblock_info["published_by"] = safe_get_username(xblock.published_by)
        xblock_info[
            "currently_visible_to_students"] = is_currently_visible_to_students(
                xblock)
        xblock_info['has_changes'] = is_unit_with_changes
        if release_date:
            xblock_info["release_date_from"] = _get_release_date_from(xblock)

    return xblock_info
コード例 #20
0
def create_xblock_info(xblock,
                       data=None,
                       metadata=None,
                       include_ancestor_info=False,
                       include_child_info=False,
                       course_outline=False,
                       include_children_predicate=NEVER,
                       parent_xblock=None,
                       graders=None):
    """
    Creates the information needed for client-side XBlockInfo.

    If data or metadata are not specified, their information will not be added
    (regardless of whether or not the xblock actually has data or metadata).

    There are three optional boolean parameters:
      include_ancestor_info - if true, ancestor info is added to the response
      include_child_info - if true, direct child info is included in the response
      course_outline - if true, the xblock is being rendered on behalf of the course outline.
        There are certain expensive computations that do not need to be included in this case.

    In addition, an optional include_children_predicate argument can be provided to define whether or
    not a particular xblock should have its children included.
    """
    def safe_get_username(user_id):
        """
        Guard against bad user_ids, like the infamous "**replace_user**".
        Note that this will ignore our special known IDs (ModuleStoreEnum.UserID).
        We should consider adding special handling for those values.

        :param user_id: the user id to get the username of
        :return: username, or None if the user does not exist or user_id is None
        """
        if user_id:
            try:
                return User.objects.get(id=user_id).username
            except:  # pylint: disable=bare-except
                pass

        return None

    is_xblock_unit = is_unit(xblock, parent_xblock)
    # this should not be calculated for Sections and Subsections on Unit page
    has_changes = modulestore().has_changes(xblock) if (
        is_xblock_unit or course_outline) else None

    if graders is None:
        graders = CourseGradingModel.fetch(xblock.location.course_key).graders

    # Compute the child info first so it can be included in aggregate information for the parent
    should_visit_children = include_child_info and (
        course_outline and not is_xblock_unit or not course_outline)
    if should_visit_children and xblock.has_children:
        child_info = _create_xblock_child_info(
            xblock,
            course_outline,
            graders,
            include_children_predicate=include_children_predicate,
        )
    else:
        child_info = None

    # Treat DEFAULT_START_DATE as a magic number that means the release date has not been set
    release_date = get_default_time_display(
        xblock.start) if xblock.start != DEFAULT_START_DATE else None
    if xblock.category != 'course':
        visibility_state = _compute_visibility_state(
            xblock, child_info, is_xblock_unit and has_changes)
    else:
        visibility_state = None
    published = modulestore().has_published_version(xblock)

    xblock_info = {
        "id":
        unicode(xblock.location),
        "display_name":
        xblock.display_name_with_default,
        "category":
        xblock.category,
        "edited_on":
        get_default_time_display(xblock.subtree_edited_on)
        if xblock.subtree_edited_on else None,
        "published":
        published,
        "published_on":
        get_default_time_display(xblock.published_on)
        if xblock.published_on else None,
        "studio_url":
        xblock_studio_url(xblock, parent_xblock),
        "released_to_students":
        datetime.now(UTC) > xblock.start,
        "release_date":
        release_date,
        "visibility_state":
        visibility_state,
        "lti_enabled":
        xblock.fields['lti_enabled'].is_set_on(xblock),
        "lti_url":
        "",
        "lti_key":
        "",
        "lti_secret":
        "",
        "has_explicit_staff_lock":
        xblock.fields['visible_to_staff_only'].is_set_on(xblock),
        "start":
        xblock.fields['start'].to_json(xblock.start),
        "graded":
        xblock.graded,
        "due_date":
        get_default_time_display(xblock.due),
        "due":
        xblock.fields['due'].to_json(xblock.due),
        "format":
        xblock.format,
        "course_graders":
        json.dumps([grader.get('type') for grader in graders]),
        "has_changes":
        has_changes,
    }

    if settings.FEATURES.get('ENABLE_AS_LTI_TOOL_PROVIDER', False):
        store = modulestore()
        course = store.get_course(xblock.location.course_key)
        if course.lti_enabled:
            course_id = xblock.location.course_key
            usr = int(xblock.subtree_edited_by)
            existing_components = LTIComponent.objects.filter(
                course_id=course_id, module_id=xblock.location, user_id=usr)
            if xblock.fields['lti_enabled'].is_set_on(xblock):
                if len(existing_components) == 0:
                    key = ''.join(
                        random.SystemRandom().choice(string.ascii_uppercase +
                                                     string.digits)
                        for _ in range(8))
                    secret = ''.join(
                        random.SystemRandom().choice(string.ascii_uppercase +
                                                     string.digits)
                        for _ in range(16))
                    lti_component = LTIComponent(user_id=usr,
                                                 course_id=course_id,
                                                 module_id=str(
                                                     xblock.location),
                                                 key=key,
                                                 secret=secret)
                    lti_component.save()
                else:
                    key = existing_components[0].key
                    secret = existing_components[0].secret
                xblock_info["lti_url"] = str(xblock.location)
                xblock_info["lti_key"] = key
                xblock_info["lti_secret"] = secret
            else:
                if len(existing_components) > 0:
                    for existing_component in existing_components:
                        existing_components.delete()
        else:
            xblock_info["lti_url"] = "disabled"
            xblock_info["lti_key"] = "disabled"
            xblock_info["lti_secret"] = "disabled"
    else:
        xblock_info["lti_url"] = "disabled"
        xblock_info["lti_key"] = "disabled"
        xblock_info["lti_secret"] = "disabled"

    if data is not None:
        xblock_info["data"] = data
    if metadata is not None:
        xblock_info["metadata"] = metadata
    if include_ancestor_info:
        xblock_info['ancestor_info'] = _create_xblock_ancestor_info(
            xblock, course_outline)
    if child_info:
        xblock_info['child_info'] = child_info
    if visibility_state == VisibilityState.staff_only:
        xblock_info["ancestor_has_staff_lock"] = ancestor_has_staff_lock(
            xblock, parent_xblock)
    else:
        xblock_info["ancestor_has_staff_lock"] = False

    # Currently, 'edited_by', 'published_by', and 'release_date_from' are only used by the
    # container page when rendering a unit. Since they are expensive to compute, only include them for units
    # that are not being rendered on the course outline.
    if is_xblock_unit and not course_outline:
        xblock_info["edited_by"] = safe_get_username(xblock.subtree_edited_by)
        xblock_info["published_by"] = safe_get_username(xblock.published_by)
        xblock_info[
            "currently_visible_to_students"] = is_currently_visible_to_students(
                xblock)
        if release_date:
            xblock_info["release_date_from"] = _get_release_date_from(xblock)
        if visibility_state == VisibilityState.staff_only:
            xblock_info["staff_lock_from"] = _get_staff_lock_from(xblock)
        else:
            xblock_info["staff_lock_from"] = None
    if course_outline:
        if xblock_info["has_explicit_staff_lock"]:
            xblock_info["staff_only_message"] = True
        elif child_info and child_info["children"]:
            xblock_info["staff_only_message"] = all([
                child["staff_only_message"] for child in child_info["children"]
            ])
        else:
            xblock_info["staff_only_message"] = False

    return xblock_info
コード例 #21
0
ファイル: item.py プロジェクト: GeertHa/edx-platform
def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=False, include_child_info=False,
                       course_outline=False, include_children_predicate=NEVER, parent_xblock=None, graders=None):
    """
    Creates the information needed for client-side XBlockInfo.

    If data or metadata are not specified, their information will not be added
    (regardless of whether or not the xblock actually has data or metadata).

    There are three optional boolean parameters:
      include_ancestor_info - if true, ancestor info is added to the response
      include_child_info - if true, direct child info is included in the response
      course_outline - if true, the xblock is being rendered on behalf of the course outline.
        There are certain expensive computations that do not need to be included in this case.

    In addition, an optional include_children_predicate argument can be provided to define whether or
    not a particular xblock should have its children included.
    """

    def safe_get_username(user_id):
        """
        Guard against bad user_ids, like the infamous "**replace_user**".
        Note that this will ignore our special known IDs (ModuleStoreEnum.UserID).
        We should consider adding special handling for those values.

        :param user_id: the user id to get the username of
        :return: username, or None if the user does not exist or user_id is None
        """
        if user_id:
            try:
                return User.objects.get(id=user_id).username
            except:  # pylint: disable=bare-except
                pass

        return None

    is_xblock_unit = is_unit(xblock, parent_xblock)
    has_changes = modulestore().has_changes(xblock)

    if graders is None:
        graders = CourseGradingModel.fetch(xblock.location.course_key).graders

    # Compute the child info first so it can be included in aggregate information for the parent
    should_visit_children = include_child_info and (course_outline and not is_xblock_unit or not course_outline)
    if should_visit_children and xblock.has_children:
        child_info = _create_xblock_child_info(
            xblock,
            course_outline,
            graders,
            include_children_predicate=include_children_predicate,
        )
    else:
        child_info = None

    # Treat DEFAULT_START_DATE as a magic number that means the release date has not been set
    release_date = get_default_time_display(xblock.start) if xblock.start != DEFAULT_START_DATE else None
    if xblock.category != 'course':
        visibility_state = _compute_visibility_state(xblock, child_info, is_xblock_unit and has_changes)
    else:
        visibility_state = None
    published = modulestore().has_published_version(xblock)

    xblock_info = {
        "id": unicode(xblock.location),
        "display_name": xblock.display_name_with_default,
        "category": xblock.category,
        "edited_on": get_default_time_display(xblock.subtree_edited_on) if xblock.subtree_edited_on else None,
        "published": published,
        "published_on": get_default_time_display(xblock.published_date) if xblock.published_date else None,
        "studio_url": xblock_studio_url(xblock, parent_xblock),
        "released_to_students": datetime.now(UTC) > xblock.start,
        "release_date": release_date,
        "visibility_state": visibility_state,
        "has_explicit_staff_lock": xblock.fields['visible_to_staff_only'].is_set_on(xblock),
        "start": xblock.fields['start'].to_json(xblock.start),
        "graded": xblock.graded,
        "due_date": get_default_time_display(xblock.due),
        "due": xblock.fields['due'].to_json(xblock.due),
        "format": xblock.format,
        "course_graders": json.dumps([grader.get('type') for grader in graders]),
        "has_changes": has_changes,
    }
    if data is not None:
        xblock_info["data"] = data
    if metadata is not None:
        xblock_info["metadata"] = metadata
    if include_ancestor_info:
        xblock_info['ancestor_info'] = _create_xblock_ancestor_info(xblock, course_outline)
    if child_info:
        xblock_info['child_info'] = child_info
    if visibility_state == VisibilityState.staff_only:
        xblock_info["ancestor_has_staff_lock"] = ancestor_has_staff_lock(xblock, parent_xblock)
    else:
        xblock_info["ancestor_has_staff_lock"] = False

    # Currently, 'edited_by', 'published_by', and 'release_date_from' are only used by the
    # container page when rendering a unit. Since they are expensive to compute, only include them for units
    # that are not being rendered on the course outline.
    if is_xblock_unit and not course_outline:
        xblock_info["edited_by"] = safe_get_username(xblock.subtree_edited_by)
        xblock_info["published_by"] = safe_get_username(xblock.published_by)
        xblock_info["currently_visible_to_students"] = is_currently_visible_to_students(xblock)
        if release_date:
            xblock_info["release_date_from"] = _get_release_date_from(xblock)
        if visibility_state == VisibilityState.staff_only:
            xblock_info["staff_lock_from"] = _get_staff_lock_from(xblock)
        else:
            xblock_info["staff_lock_from"] = None
    if course_outline:
        if xblock_info["has_explicit_staff_lock"]:
            xblock_info["staff_only_message"] = True
        elif child_info and child_info["children"]:
            xblock_info["staff_only_message"] = all([child["staff_only_message"] for child in child_info["children"]])
        else:
            xblock_info["staff_only_message"] = False

    return xblock_info
コード例 #22
0
    def test_xblock_studio_url(self):
        course = self.course

        # Verify course URL
        self.assertEqual(
            xblock_studio_url(course), u"/course/MITx.999.Robot_Super_Course/branch/published/block/Robot_Super_Course"
        )

        # Verify chapter URL
        chapter = ItemFactory.create(parent_location=self.course.location, category="chapter", display_name="Week 1")
        self.assertIsNone(xblock_studio_url(chapter))
        self.assertIsNone(xblock_studio_url(chapter, course))

        # Verify lesson URL
        sequential = ItemFactory.create(
            parent_location=chapter.location, category="sequential", display_name="Lesson 1"
        )
        self.assertIsNone(xblock_studio_url(sequential))
        self.assertIsNone(xblock_studio_url(sequential, course))

        # Verify vertical URL
        vertical = ItemFactory.create(parent_location=sequential.location, category="vertical", display_name="Unit")
        self.assertEqual(xblock_studio_url(vertical), u"/unit/MITx.999.Robot_Super_Course/branch/published/block/Unit")
        self.assertEqual(
            xblock_studio_url(vertical, course), u"/unit/MITx.999.Robot_Super_Course/branch/published/block/Unit"
        )

        # Verify child vertical URL
        child_vertical = ItemFactory.create(
            parent_location=vertical.location, category="vertical", display_name="Child Vertical"
        )
        self.assertEqual(
            xblock_studio_url(child_vertical),
            u"/container/MITx.999.Robot_Super_Course/branch/published/block/Child_Vertical",
        )
        self.assertEqual(
            xblock_studio_url(child_vertical, course),
            u"/container/MITx.999.Robot_Super_Course/branch/published/block/Child_Vertical",
        )

        # Verify video URL
        video = ItemFactory.create(parent_location=child_vertical.location, category="video", display_name="My Video")
        self.assertIsNone(xblock_studio_url(video))
        self.assertIsNone(xblock_studio_url(video, course))