feat!: Switch v2 libraries to Learning Core data models (#34066)

This moves the Content Libraries V2 backend from Blockstore [1] over to
Learning Core [2] For high-level overview and rationale of this move, see
the Blockstore DEPR [3]. There are several follow-up tasks [4], most notably
adding support for static assets in libraries.

BREAKING CHANGE: Existing V2 libraries, backed by Blockstore, will stop
working. They will continue to be listed in Studio, but their content
will be unavailable. They need to be deleted (via Django admin) or manually
migrated to Learning Core. We do not expect production sites to be in
this situation, as the feature has never left "experimental" status.

[1] https://github.com/openedx-unsupported/blockstore
[2] https://github.com/openedx/openedx-learning/
[3] https://github.com/openedx/public-engineering/issues/238
[4] https://github.com/openedx/edx-platform/issues/34283
This commit is contained in:
David Ormsbee
2024-02-22 11:38:05 -05:00
committed by GitHub
parent 65ea55c8aa
commit 86f1e5e8aa
38 changed files with 1208 additions and 3005 deletions

View File

@@ -11,15 +11,12 @@ from unittest import mock
import ddt
from django.conf import settings
from django.test import override_settings
from opaque_keys.edx.keys import UsageKey
from opaque_keys.edx.locator import LibraryLocator, LibraryLocatorV2
from common.djangoapps.student.roles import CourseInstructorRole
from common.djangoapps.student.tests.factories import UserFactory
from openedx.core.djangolib.testing.utils import skip_unless_cms
from openedx.core.djangoapps.content_libraries import api as library_api
from openedx.core.djangoapps.content_libraries.tests.base import ContentLibrariesRestApiTest
from openedx.core.djangoapps.xblock.api import load_block
from xmodule.library_tools import LibraryToolsService
from xmodule.modulestore.tests.factories import CourseFactory, LibraryFactory
from xmodule.modulestore.tests.utils import MixedSplitTestCase
@@ -129,66 +126,6 @@ class ContentLibraryToolsTest(MixedSplitTestCase, ContentLibrariesRestApiTest):
assert len(content_block.children) == 1
def test_update_children_for_v2_lib_recursive(self):
"""
Test update_children for a V2 library containing a unit.
Ensures that _import_from_blockstore works on nested blocks.
"""
# 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
lc_block = self.make_block(
"library_content",
course,
user_id=self.user_id,
max_count=1,
source_library_id=str(library["id"]),
)
# Import the unit block from the library to the course
self.tools.trigger_library_sync(lc_block, library_version=None)
lc_block = self.store.get_item(lc_block.location)
# Verify imported block with its children
assert len(lc_block.children) == 1
assert lc_block.children[0].category == 'unit'
imported_unit_block = self.store.get_item(lc_block.children[0])
assert len(imported_unit_block.children) == 1
assert imported_unit_block.children[0].category == 'html'
imported_html_block = self.store.get_item(imported_unit_block.children[0])
assert 'Hello world' in 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)
assert len(assets) == 1
assert assets[0].url in 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.trigger_library_sync(lc_block, library_version=None)
lc_block = self.store.get_item(lc_block.location)
assert len(lc_block.children) == 1
imported_unit_block = self.store.get_item(lc_block.children[0])
assert len(imported_unit_block.children) == 1
imported_html_block = self.store.get_item(imported_unit_block.children[0])
assert 'Hello world' not in imported_html_block.data
assert 'Foo bar' in imported_html_block.data
def test_update_children_for_v1_lib(self):
"""
Test update_children with V1 library as a source.