Exemple #1
0
 def test_identical_olx(self):
     """
     Test library blocks with children that also have identical OLX. Since
     the blockstore runtime caches authored field data based on the hash of
     the OLX, this can catch some potential bugs, especially given that the
     "children" field stores usage IDs, not definition IDs.
     """
     # Create a unit containing a <problem>
     unit_block_key = library_api.create_library_block(self.library.key, "unit", "u1").usage_key
     library_api.create_library_block_child(unit_block_key, "problem", "p1")
     library_api.publish_changes(self.library.key)
     # Now do the same in a different library:
     library2 = library_api.create_library(
         collection_uuid=self.collection.uuid,
         org=self.organization,
         slug="idolx",
         title=("Identical OLX Test Lib 2"),
         description="",
         library_type=COMPLEX,
         allow_public_learning=True,
         allow_public_read=False,
         library_license=CC_4_BY,
     )
     unit_block2_key = library_api.create_library_block(library2.key, "unit", "u1").usage_key
     library_api.create_library_block_child(unit_block2_key, "problem", "p1")
     library_api.publish_changes(library2.key)
     # Load both blocks:
     unit_block = xblock_api.load_block(unit_block_key, self.student_a)
     unit_block2 = xblock_api.load_block(unit_block2_key, self.student_a)
     assert library_api.get_library_block_olx(unit_block_key) == library_api.get_library_block_olx(unit_block2_key)
     assert unit_block.children != unit_block2.children
Exemple #2
0
 def post(self, request, lib_key_str):
     """
     Add a new XBlock to this content library
     """
     library_key = LibraryLocatorV2.from_string(lib_key_str)
     api.require_permission_for_library_key(
         library_key, request.user,
         permissions.CAN_EDIT_THIS_CONTENT_LIBRARY)
     serializer = LibraryXBlockCreationSerializer(data=request.data)
     serializer.is_valid(raise_exception=True)
     parent_block_usage_str = serializer.validated_data.pop(
         "parent_block", None)
     if parent_block_usage_str:
         # Add this as a child of an existing block:
         parent_block_usage = LibraryUsageLocatorV2.from_string(
             parent_block_usage_str)
         if parent_block_usage.context_key != library_key:
             raise ValidationError(
                 detail={
                     "parent_block":
                     "Usage ID doesn't match library ID in the URL."
                 })
         result = api.create_library_block_child(
             parent_block_usage, **serializer.validated_data)
     else:
         # Create a new regular top-level block:
         try:
             result = api.create_library_block(library_key,
                                               **serializer.validated_data)
         except api.IncompatibleTypesError as err:
             raise ValidationError(detail={'block_type': str(err)}, )
     return Response(LibraryXBlockMetadataSerializer(result).data)
Exemple #3
0
    def test_xblock_metadata(self):
        """
        Test the XBlock metadata API
        """
        unit_block_key = library_api.create_library_block(
            self.library.key, "unit", "metadata-u1").usage_key
        problem_key = library_api.create_library_block_child(
            unit_block_key, "problem", "metadata-p1").usage_key
        new_olx = """
        <problem display_name="New Multi Choice Question" max_attempts="5">
            <multiplechoiceresponse>
                <p>This is a normal capa problem. It has "maximum attempts" set to **5**.</p>
                <label>Blockstore is designed to store.</label>
                <choicegroup type="MultipleChoice">
                    <choice correct="false">XBlock metadata only</choice>
                    <choice correct="true">XBlock data/metadata and associated static asset files</choice>
                    <choice correct="false">Static asset files for XBlocks and courseware</choice>
                    <choice correct="false">XModule metadata only</choice>
                </choicegroup>
            </multiplechoiceresponse>
        </problem>
        """.strip()
        library_api.set_library_block_olx(problem_key, new_olx)
        library_api.publish_changes(self.library.key)

        # Now view the problem as Alice:
        client = APIClient()
        client.login(username=self.student_a.username, password='******')

        # Check the metadata API for the unit:
        metadata_view_result = client.get(
            URL_BLOCK_METADATA_URL.format(block_key=unit_block_key),
            {"include": "children,editable_children"},
        )
        self.assertEqual(metadata_view_result.data["children"],
                         [str(problem_key)])
        self.assertEqual(metadata_view_result.data["editable_children"],
                         [str(problem_key)])

        # Check the metadata API for the problem:
        metadata_view_result = client.get(
            URL_BLOCK_METADATA_URL.format(block_key=problem_key),
            {"include": "student_view_data,index_dictionary"},
        )
        self.assertEqual(metadata_view_result.data["block_id"],
                         str(problem_key))
        self.assertEqual(metadata_view_result.data["display_name"],
                         "New Multi Choice Question")
        self.assertNotIn("children", metadata_view_result.data)
        self.assertNotIn("editable_children", metadata_view_result.data)
        self.assertDictContainsSubset(
            {
                "content_type": "CAPA",
                "problem_types": ["multiplechoiceresponse"],
            }, metadata_view_result.data["index_dictionary"])
        self.assertEqual(metadata_view_result.data["student_view_data"],
                         None)  # Capa doesn't provide student_view_data
    def test_complex_xblock_tree(self, _mock1, _mock2):
        """
        Test a Pathway with a deep XBlock tree and inter-bundle-links
        """
        # Create the following XBlock tree
        # Library 2
        #   unit "alpha"
        #     -> link to library 1's bundle ("link1")
        #       -> unit "beta" (in Library 1)
        #         -> html "gamma"
        # Then make sure we can add that whole hierarchy into a pathway.

        beta_key = library_api.create_library_block(self.lib1.key, "unit", "beta").usage_key
        gamma_key = library_api.create_library_block_child(beta_key, "html", "gamma").usage_key
        library_api.set_library_block_olx(gamma_key, '<html>This is gamma.</html>')
        library_api.publish_changes(self.lib1.key)
        library_api.create_bundle_link(self.lib2.key, 'link1', self.lib1.key)
        alpha_key = library_api.create_library_block(self.lib2.key, "unit", "alpha").usage_key
        library_api.set_library_block_olx(alpha_key, '''
            <unit display_name="alpha">
                <xblock-include source="link1" definition="unit/beta" usage_hint="beta" />
            </unit>
        ''')
        library_api.publish_changes(self.lib2.key)

        # Create a new pathway:
        response = self.client.post(URL_CREATE_PATHWAY, {
            "owner_user_id": self.user.id,
            "draft_data": {
                "title": "A Commplex Pathway",
                "description": "Complex pathway for testing",
                "data": {},
                "items": [
                    {"original_usage_id": str(alpha_key)},
                ],
            },
        }, format='json')
        self.assertEqual(response.status_code, 200)
        pathway_id = response.data["id"]
        pathway_url = URL_GET_PATHWAY.format(pathway_id=pathway_id)

        # Now publish the pathway:
        response = self.client.post(pathway_url + 'publish/')
        self.assertEqual(response.status_code, 200)
        # Get the resulting pathway:
        response = self.client.get(pathway_url)
        self.assertEqual(response.status_code, 200)

        # Get the usage ID of the root 'alpha' XBlock:
        alpha_key_pathway = UsageKey.from_string(response.data["published_data"]["items"][0]["usage_id"])
        self.assertNotEqual(alpha_key_pathway, alpha_key)

        block = xblock_api.load_block(alpha_key_pathway, user=self.other_user)
        # Render the block and all its children - make sure even the descendants are rendered:
        fragment = block.render('student_view', context={})
        self.assertIn('This is gamma.', fragment.content)