Skip to content

Commit

Permalink
refactor: update to use Learning Core's new public API
Browse files Browse the repository at this point in the history
This also bumps our openedx-learning dependency to 0.10.0 (the first
version with the new openedx_learning.api package).
  • Loading branch information
ormsbee committed May 21, 2024
1 parent f820961 commit be03938
Show file tree
Hide file tree
Showing 13 changed files with 59 additions and 56 deletions.
6 changes: 3 additions & 3 deletions cms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -1881,9 +1881,9 @@
'openedx_events',

# Learning Core Apps, used by v2 content libraries (content_libraries app)
"openedx_learning.core.components",
"openedx_learning.core.contents",
"openedx_learning.core.publishing",
"openedx_learning.apps.authoring.components",
"openedx_learning.apps.authoring.contents",
"openedx_learning.apps.authoring.publishing",
]


Expand Down
6 changes: 3 additions & 3 deletions lms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3385,9 +3385,9 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring
'openedx_events',

# Learning Core Apps, used by v2 content libraries (content_libraries app)
"openedx_learning.core.components",
"openedx_learning.core.contents",
"openedx_learning.core.publishing",
"openedx_learning.apps.authoring.components",
"openedx_learning.apps.authoring.contents",
"openedx_learning.apps.authoring.publishing",
]


Expand Down
48 changes: 23 additions & 25 deletions openedx/core/djangoapps/content_libraries/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,8 @@
LIBRARY_BLOCK_DELETED,
LIBRARY_BLOCK_UPDATED,
)
from openedx_learning.core.publishing import api as publishing_api
from openedx_learning.core.contents import api as contents_api
from openedx_learning.core.components import api as components_api
from openedx_learning.core.components.models import Component
from openedx_learning.api import authoring as authoring_api
from openedx_learning.api.authoring_models import Component, MediaType
from organizations.models import Organization
from xblock.core import XBlock
from xblock.exceptions import XBlockNotFoundError
Expand Down Expand Up @@ -327,18 +325,18 @@ def get_library(library_key):
"""
ref = ContentLibrary.objects.get_by_key(library_key)
learning_package = ref.learning_package
num_blocks = publishing_api.get_all_drafts(learning_package.id).count()
last_publish_log = publishing_api.get_last_publish(learning_package.id)
has_unpublished_changes = publishing_api.get_entities_with_unpublished_changes(learning_package.id) \
.exists()
num_blocks = authoring_api.get_all_drafts(learning_package.id).count()
last_publish_log = authoring_api.get_last_publish(learning_package.id)
has_unpublished_changes = authoring_api.get_entities_with_unpublished_changes(learning_package.id) \
.exists()

# TODO: I'm doing this one to match already-existing behavior, but this is
# something that we should remove. It exists to accomodate some complexities
# with how Blockstore staged changes, but Learning Core works differently,
# and has_unpublished_changes should be sufficient.
# Ref: https://github.com/openedx/edx-platform/issues/34283
has_unpublished_deletes = publishing_api.get_entities_with_unpublished_deletes(learning_package.id) \
.exists()
has_unpublished_deletes = authoring_api.get_entities_with_unpublished_deletes(learning_package.id) \
.exists()

# Learning Core doesn't really have a notion of a global version number,but
# we can sort of approximate it by using the primary key of the last publish
Expand Down Expand Up @@ -415,7 +413,7 @@ def create_library(
allow_public_read=allow_public_read,
license=library_license,
)
learning_package = publishing_api.create_learning_package(
learning_package = authoring_api.create_learning_package(
key=str(ref.library_key),
title=title,
description=description,
Expand Down Expand Up @@ -556,7 +554,7 @@ def update_library(
content_lib.save()

if learning_pkg_changed:
publishing_api.update_learning_package(
authoring_api.update_learning_package(
content_lib.learning_package_id,
title=title,
description=description,
Expand Down Expand Up @@ -614,7 +612,7 @@ def get_library_components(library_key, text_search=None, block_types=None) -> Q
"""
lib = ContentLibrary.objects.get_by_key(library_key) # type: ignore[attr-defined]
learning_package = lib.learning_package
components = components_api.get_components(
components = authoring_api.get_components(
learning_package.id,
draft=True,
namespace='xblock.v1',
Expand Down Expand Up @@ -693,13 +691,13 @@ def set_library_block_olx(usage_key, new_olx_str):
now = datetime.now(tz=timezone.utc)

with transaction.atomic():
new_content = contents_api.get_or_create_text_content(
new_content = authoring_api.get_or_create_text_content(
component.learning_package_id,
get_or_create_olx_media_type(usage_key.block_type).id,
text=new_olx_str,
created=now,
)
components_api.create_next_version(
authoring_api.create_next_version(
component.pk,
title=new_title,
content_to_replace={
Expand Down Expand Up @@ -736,7 +734,7 @@ def create_library_block(library_key, block_type, definition_id):
)

# If adding a component would take us over our max, return an error.
component_count = publishing_api.get_all_drafts(ref.learning_package.id).count()
component_count = authoring_api.get_all_drafts(ref.learning_package.id).count()
if component_count + 1 > settings.MAX_BLOCKS_PER_CONTENT_LIBRARY:
raise BlockLimitReachedError(
_("Library cannot have more than {} Components").format(
Expand Down Expand Up @@ -785,14 +783,14 @@ def _component_exists(usage_key: UsageKeyV2) -> bool:
return True


def get_or_create_olx_media_type(block_type: str) -> contents_api.MediaType:
def get_or_create_olx_media_type(block_type: str) -> MediaType:
"""
Get or create a MediaType for the block type.
Learning Core stores all Content with a Media Type (a.k.a. MIME type). For
OLX, we use the "application/vnd.*" convention, per RFC 6838.
"""
return contents_api.get_or_create_media_type(
return authoring_api.get_or_create_media_type(
f"application/vnd.openedx.xblock.v1.{block_type}+xml"
)

Expand All @@ -819,24 +817,24 @@ def _create_component_for_block(content_lib, usage_key):
learning_package = content_lib.learning_package

with transaction.atomic():
component_type = components_api.get_or_create_component_type(
component_type = authoring_api.get_or_create_component_type(
"xblock.v1", usage_key.block_type
)
component, component_version = components_api.create_component_and_version(
component, component_version = authoring_api.create_component_and_version(
learning_package.id,
component_type=component_type,
local_key=usage_key.block_id,
title=display_name,
created=now,
created_by=None,
)
content = contents_api.get_or_create_text_content(
content = authoring_api.get_or_create_text_content(
learning_package.id,
get_or_create_olx_media_type(usage_key.block_type).id,
text=xml_text,
created=now,
)
components_api.create_component_version_content(
authoring_api.create_component_version_content(
component_version.pk,
content.id,
key="block.xml",
Expand All @@ -849,7 +847,7 @@ def delete_library_block(usage_key, remove_from_parent=True):
Delete the specified block from this library (soft delete).
"""
component = get_component_from_usage_key(usage_key)
publishing_api.soft_delete_draft(component.pk)
authoring_api.soft_delete_draft(component.pk)

LIBRARY_BLOCK_DELETED.send_event(
library_block=LibraryBlockData(
Expand Down Expand Up @@ -938,7 +936,7 @@ def publish_changes(library_key):
"""
learning_package = ContentLibrary.objects.get_by_key(library_key).learning_package

publishing_api.publish_all_drafts(learning_package.id)
authoring_api.publish_all_drafts(learning_package.id)

CONTENT_LIBRARY_UPDATED.send_event(
content_library=ContentLibraryData(
Expand All @@ -954,7 +952,7 @@ def revert_changes(library_key):
last published version.
"""
learning_package = ContentLibrary.objects.get_by_key(library_key).learning_package
publishing_api.reset_drafts_to_published(learning_package.id)
authoring_api.reset_drafts_to_published(learning_package.id)

CONTENT_LIBRARY_UPDATED.send_event(
content_library=ContentLibraryData(
Expand Down
4 changes: 2 additions & 2 deletions openedx/core/djangoapps/content_libraries/library_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from openedx.core.djangoapps.content_libraries.models import ContentLibrary
from openedx.core.djangoapps.xblock.api import LearningContext

from openedx_learning.core.components import api as components_api
from openedx_learning.api import authoring as authoring_api

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -87,7 +87,7 @@ def block_exists(self, usage_key):
if learning_package is None:
return False

return components_api.component_exists_by_key(
return authoring_api.component_exists_by_key(
learning_package.id,
namespace='xblock.v1',
type_name=usage_key.block_type,
Expand Down
2 changes: 1 addition & 1 deletion openedx/core/djangoapps/content_libraries/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
LIBRARY_TYPES, COMPLEX, LICENSE_OPTIONS,
ALL_RIGHTS_RESERVED,
)
from openedx_learning.core.publishing.models import LearningPackage
from openedx_learning.api.authoring_models import LearningPackage
from organizations.models import Organization # lint-amnesty, pylint: disable=wrong-import-order

from .apps import ContentLibrariesConfig
Expand Down
13 changes: 4 additions & 9 deletions openedx/core/djangoapps/xblock/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,21 @@

from django.urls import reverse
from django.utils.translation import gettext as _
from openedx_learning.core.components import api as components_api
from openedx_learning.core.components.models import Component
from openedx_learning.core.publishing import api as publishing_api
from openedx_learning.api import authoring as authoring_api
from openedx_learning.api.authoring_models import Component
from opaque_keys.edx.keys import UsageKeyV2
from opaque_keys.edx.locator import BundleDefinitionLocator, LibraryUsageLocatorV2

from rest_framework.exceptions import NotFound
from xblock.core import XBlock
from xblock.exceptions import NoSuchViewError
from xblock.plugin import PluginMissingError

from openedx.core.djangoapps.xblock.apps import get_xblock_app_config
from openedx.core.djangoapps.xblock.learning_context.manager import get_learning_context_impl

from openedx.core.djangoapps.xblock.runtime.learning_core_runtime import (
LearningCoreFieldData,
LearningCoreXBlockRuntime,
)


from openedx.core.djangoapps.xblock.runtime.runtime import XBlockRuntimeSystem as _XBlockRuntimeSystem
from .utils import get_secure_token_for_xblock_handler, get_xblock_id_for_anonymous_user

Expand Down Expand Up @@ -192,10 +187,10 @@ def get_component_from_usage_key(usage_key: UsageKeyV2) -> Component:
This is a lower-level function that will return a Component even if there is
no current draft version of that Component (because it's been soft-deleted).
"""
learning_package = publishing_api.get_learning_package_by_key(
learning_package = authoring_api.get_learning_package_by_key(
str(usage_key.context_key)
)
return components_api.get_component_by_key(
return authoring_api.get_component_by_key(
learning_package.id,
namespace='xblock.v1',
type_name=usage_key.block_type,
Expand Down
14 changes: 6 additions & 8 deletions openedx/core/djangoapps/xblock/runtime/learning_core_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
from django.core.exceptions import ObjectDoesNotExist
from django.db.transaction import atomic

from openedx_learning.core.components import api as components_api
from openedx_learning.core.contents import api as contents_api
from openedx_learning.core.publishing import api as publishing_api
from openedx_learning.api import authoring as authoring_api

from lxml import etree

Expand Down Expand Up @@ -239,16 +237,16 @@ def save_block(self, block):
usage_key = block.scope_ids.usage_id
with atomic():
component = self._get_component_from_usage_key(usage_key)
block_media_type = contents_api.get_or_create_media_type(
block_media_type = authoring_api.get_or_create_media_type(
f"application/vnd.openedx.xblock.v1.{usage_key.block_type}+xml"
)
content = contents_api.get_or_create_text_content(
content = authoring_api.get_or_create_text_content(
component.learning_package_id,
block_media_type.id,
text=serialized.olx_str,
created=now,
)
components_api.create_next_version(
authoring_api.create_next_version(
component.pk,
title=block.display_name,
content_to_replace={
Expand All @@ -267,9 +265,9 @@ def _get_component_from_usage_key(self, usage_key):
TODO: This is the third place where we're implementing this. Figure out
where the definitive place should be and have everything else call that.
"""
learning_package = publishing_api.get_learning_package_by_key(str(usage_key.lib_key))
learning_package = authoring_api.get_learning_package_by_key(str(usage_key.lib_key))
try:
component = components_api.get_component_by_key(
component = authoring_api.get_component_by_key(
learning_package.id,
namespace='xblock.v1',
type_name=usage_key.block_type,
Expand Down
2 changes: 1 addition & 1 deletion requirements/constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ libsass==0.10.0
click==8.1.6

# pinning this version to avoid updates while the library is being developed
openedx-learning==0.9.4
openedx-learning==0.10.0

# Open AI version 1.0.0 dropped support for openai.ChatCompletion which is currently in use in enterprise.
openai<=0.28.1
Expand Down
2 changes: 1 addition & 1 deletion requirements/edx/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,7 @@ openedx-filters==1.8.1
# -r requirements/edx/kernel.in
# lti-consumer-xblock
# ora2
openedx-learning==0.9.4
openedx-learning==0.10.0
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
Expand Down
2 changes: 1 addition & 1 deletion requirements/edx/development.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,7 @@ openedx-filters==1.8.1
# -r requirements/edx/testing.txt
# lti-consumer-xblock
# ora2
openedx-learning==0.9.4
openedx-learning==0.10.0
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
Expand Down
2 changes: 1 addition & 1 deletion requirements/edx/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ openedx-filters==1.8.1
# -r requirements/edx/base.txt
# lti-consumer-xblock
# ora2
openedx-learning==0.9.4
openedx-learning==0.10.0
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
Expand Down
2 changes: 1 addition & 1 deletion requirements/edx/testing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,7 @@ openedx-filters==1.8.1
# -r requirements/edx/base.txt
# lti-consumer-xblock
# ora2
openedx-learning==0.9.4
openedx-learning==0.10.0
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
Expand Down
12 changes: 12 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ root_packages =
lms
cms
openedx
openedx_learning
include_external_packages = True
contract_types =
# Our custom contract which checks that we're only importing from 'api.py'
Expand Down Expand Up @@ -185,3 +186,14 @@ allowed_modules =
# Only imports from api.py are allowed elsewhere in the code
# See https://open-edx-proposals.readthedocs.io/en/latest/best-practices/oep-0049-django-app-patterns.html#api-py
api

[importlinter:contract:3]
name = Do not import apps from openedx-learning (only import from openedx_learning.api.* and openedx_learning.lib.*).
type = forbidden
source_modules =
cms
lms
openedx
forbidden_modules =
openedx_learning.apps
allow_indirect_imports = True

0 comments on commit be03938

Please sign in to comment.