Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: update to use Learning Core's new public API #34815

Merged
merged 1 commit into from
May 21, 2024
Merged
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
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
Loading