Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions openedx/core/djangoapps/content_libraries/api/libraries.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ def get_library(library_key: LibraryLocatorV2) -> ContentLibraryMetadata:


def create_library(
org: str,
org: Organization,
slug: str,
title: str,
description: str = "",
Expand Down Expand Up @@ -424,20 +424,19 @@ def create_library(
validate_unicode_slug(slug)
try:
with transaction.atomic():
learning_package = authoring_api.create_learning_package(
key=ContentLibrary.make_library_key(org.short_name, slug),
title=title,
description=description,
)
ref = ContentLibrary.objects.create(
org=org,
slug=slug,
allow_public_learning=allow_public_learning,
allow_public_read=allow_public_read,
license=library_license,
learning_package=learning_package,
)
learning_package = authoring_api.create_learning_package(
key=str(ref.library_key),
title=title,
description=description,
)
ref.learning_package = learning_package
ref.save()

except IntegrityError:
raise LibraryAlreadyExists(slug) # lint-amnesty, pylint: disable=raise-missing-from
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Generated by Django 4.2.23 on 2025-10-17 18:13

from django.db import migrations, models
import django.db.models.deletion


def remove_blockstore_libraries(apps, schema_editor):
"""
Remove old Blockstore-based libraries

Content Libraries are always created with a LearningPackage these days, but
this model was once used for Blockstore-based libraries that did not use
LearningPackages at all. Very few instances ever used those libraries, and
those libraries will in a broken state anyway because Blockstore support has
long since been removed from edx-platform.

We are deleting these ContentLibrary entries so that we can enforce that all
libraries going forward must specify a LearningPackage.
"""
ContentLibrary = apps.get_model("content_libraries", "ContentLibrary")
ContentLibrary.objects.filter(learning_package__isnull=True).delete()


class Migration(migrations.Migration):

dependencies = [
('content_libraries', '0011_remove_contentlibrary_bundle_uuid_and_more'),
]

operations = [
migrations.RunPython(remove_blockstore_libraries, migrations.RunPython.noop),
migrations.AlterField(
model_name='contentlibrary',
name='learning_package',
field=models.OneToOneField(on_delete=django.db.models.deletion.RESTRICT, to='oel_publishing.learningpackage'),
),
]
18 changes: 12 additions & 6 deletions openedx/core/djangoapps/content_libraries/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,7 @@ class ContentLibrary(models.Model):
# We can't delete the LearningPackage that holds a Library's content
# unless we're deleting both at the same time.
on_delete=models.RESTRICT,
# This is nullable mostly for backwards compatibility, though it should
# be possible to have the abstract notion of a Library with no actual
# content in it yet.
null=True,
default=None,
null=False,
)

# How is this library going to be used?
Expand Down Expand Up @@ -154,7 +150,17 @@ def library_key(self):
"""
Get the LibraryLocatorV2 opaque key for this library
"""
return LibraryLocatorV2(org=self.org.short_name, slug=self.slug)
return self.make_library_key(org=self.org.short_name, slug=self.slug)

@staticmethod
def make_library_key(org, slug):
"""
Generate a LibraryLocatorV2 for any library.

This method exists mostly so that we can create the correct
LearningPackage key before the ContentLibrary exists.
"""
return LibraryLocatorV2(org=org, slug=slug)

@property
def allow_lti(self):
Expand Down
Loading
Loading