Esempio n. 1
0
 def assets(self):
     """ Returns every block assets from Blockstore """
     if not hasattr(self, '_assets') or not self._assets:  # pylint: disable=access-member-before-definition
         self._assets = library_api.get_library_block_static_asset_files(  # pylint: disable=attribute-defined-outside-init,   # noqa: E501
             self.location,  # pylint: disable=no-member
         )
     return self._assets
Esempio n. 2
0
 def get(self, request, usage_key_str):
     """
     List the static asset files belonging to this block.
     """
     key = LibraryUsageLocatorV2.from_string(usage_key_str)
     api.require_permission_for_library_key(key.lib_key, request.user, permissions.CAN_VIEW_THIS_CONTENT_LIBRARY)
     files = api.get_library_block_static_asset_files(key)
     return Response(LibraryXBlockStaticFilesSerializer({"files": files}).data)
Esempio n. 3
0
 def get(self, request, usage_key_str, file_path):
     """
     Get a static asset file belonging to this block.
     """
     key = LibraryUsageLocatorV2.from_string(usage_key_str)
     api.require_permission_for_library_key(key.lib_key, request.user, permissions.CAN_VIEW_THIS_CONTENT_LIBRARY)
     files = api.get_library_block_static_asset_files(key)
     for f in files:
         if f.path == file_path:
             return Response(LibraryXBlockStaticFileSerializer(f).data)
     raise NotFound
Esempio n. 4
0
    def test_import_from_blockstore(self):
        # Create a blockstore content library
        library = self._create_library(slug="testlib1_import", title="A Test Library", description="Testing XBlocks")
        # Create a unit block with an HTML block in it.
        unit_block_id = self._add_block_to_library(library["id"], "unit", "unit1")["id"]
        html_block_id = self._add_block_to_library(library["id"], "html", "html1", parent_block=unit_block_id)["id"]
        html_block = load_block(UsageKey.from_string(html_block_id), self.user)
        # Add assets and content to the HTML block
        self._set_library_block_asset(html_block_id, "test.txt", b"data", expect_response=200)
        self._set_library_block_olx(html_block_id, '<html><a href="/static/test.txt">Hello world</a></html>')

        # Create a modulestore course
        course = CourseFactory.create(modulestore=self.store, user_id=self.user.id)
        CourseInstructorRole(course.id).add_users(self.user)
        # Add Source from library block to the course
        sourced_block = self.make_block("library_sourced", course, user_id=self.user.id)

        # Import the unit block from the library to the course
        self.tools.import_from_blockstore(sourced_block, unit_block_id)

        # Verify imported block with its children
        self.assertEqual(len(sourced_block.children), 1)
        self.assertEqual(sourced_block.children[0].category, 'unit')

        imported_unit_block = self.store.get_item(sourced_block.children[0])
        self.assertEqual(len(imported_unit_block.children), 1)
        self.assertEqual(imported_unit_block.children[0].category, 'html')

        imported_html_block = self.store.get_item(imported_unit_block.children[0])
        self.assertIn('Hello world', imported_html_block.data)

        # Check that assets were imported and static paths were modified after importing
        assets = library_api.get_library_block_static_asset_files(html_block.scope_ids.usage_id)
        self.assertEqual(len(assets), 1)
        self.assertIn(assets[0].url, imported_html_block.data)

        # Check that reimporting updates the target block
        self._set_library_block_olx(html_block_id, '<html><a href="/static/test.txt">Foo bar</a></html>')
        self.tools.import_from_blockstore(sourced_block, unit_block_id)

        self.assertEqual(len(sourced_block.children), 1)
        imported_unit_block = self.store.get_item(sourced_block.children[0])
        self.assertEqual(len(imported_unit_block.children), 1)
        imported_html_block = self.store.get_item(imported_unit_block.children[0])
        self.assertNotIn('Hello world', imported_html_block.data)
        self.assertIn('Foo bar', imported_html_block.data)
Esempio n. 5
0
    def _import_block(self, source_block, dest_parent_key):
        """
        Recursively import a blockstore block and its children. See import_from_blockstore above.
        """
        def generate_block_key(source_key, dest_parent_key):
            """
            Deterministically generate an ID for the new block and return the key
            """
            block_id = (
                dest_parent_key.block_id[:10] + '-' +
                hashlib.sha1(str(source_key).encode('utf-8')).hexdigest()[:10])
            return dest_parent_key.context_key.make_usage_key(
                source_key.block_type, block_id)

        source_key = source_block.scope_ids.usage_id
        new_block_key = generate_block_key(source_key, dest_parent_key)
        try:
            new_block = self.store.get_item(new_block_key)
            if new_block.parent != dest_parent_key:
                raise ValueError(
                    "Expected existing block {} to be a child of {} but instead it's a child of {}"
                    .format(
                        new_block_key,
                        dest_parent_key,
                        new_block.parent,
                    ))
        except ItemNotFoundError:
            new_block = self.store.create_child(
                user_id=self.user_id,
                parent_usage_key=dest_parent_key,
                block_type=source_key.block_type,
                block_id=new_block_key.block_id,
            )

        # Prepare a list of this block's static assets; any assets that are referenced as /static/{path} (the
        # recommended way for referencing them) will stop working, and so we rewrite the url when importing.
        # Copying assets not advised because modulestore doesn't namespace assets to each block like blockstore, which
        # might cause conflicts when the same filename is used across imported blocks.
        if isinstance(source_key, LibraryUsageLocatorV2):
            all_assets = library_api.get_library_block_static_asset_files(
                source_key)
        else:
            all_assets = []

        for field_name, field in source_block.fields.items():
            if field.scope not in (Scope.settings, Scope.content):
                continue  # Only copy authored field data
            if field.is_set_on(source_block) or field.is_set_on(new_block):
                field_value = getattr(source_block, field_name)
                if isinstance(field_value, str):
                    # If string field (which may also be JSON/XML data), rewrite /static/... URLs to point to blockstore
                    for asset in all_assets:
                        field_value = field_value.replace(
                            '/static/{}'.format(asset.path), asset.url)
                setattr(new_block, field_name, field_value)
        new_block.save()
        self.store.update_item(new_block, self.user_id)

        if new_block.has_children:
            # Delete existing children in the new block, which can be reimported again if they still exist in the
            # source library
            for existing_child_key in new_block.children:
                self.store.delete_item(existing_child_key, self.user_id)
            # Now import the children
            for child in source_block.get_children():
                self._import_block(child, new_block_key)

        return new_block_key