Merge pull request #21595 from open-craft/blockstore-key-changes

Blockstore opaque keys moved to external repo
This commit is contained in:
David Ormsbee
2019-09-13 17:50:38 -04:00
committed by GitHub
19 changed files with 38 additions and 406 deletions

View File

@@ -9,6 +9,7 @@ import attr
from django.core.validators import validate_unicode_slug
from django.db import IntegrityError
from lxml import etree
from opaque_keys.edx.locator import BundleDefinitionLocator, LibraryLocatorV2, LibraryUsageLocatorV2
from organizations.models import Organization
import six
from xblock.core import XBlock
@@ -17,7 +18,6 @@ from xblock.exceptions import XBlockNotFoundError
from cms.djangoapps.contentstore.views.helpers import xblock_type_display_name
from openedx.core.djangoapps.content_libraries.library_bundle import LibraryBundle
from openedx.core.djangoapps.xblock.api import get_block_display_name, load_block
from openedx.core.djangoapps.xblock.learning_context.keys import BundleDefinitionLocator
from openedx.core.djangoapps.xblock.learning_context.manager import get_learning_context_impl
from openedx.core.djangoapps.xblock.runtime.olx_parsing import XBlockInclude
from openedx.core.lib.blockstore_api import (
@@ -33,7 +33,6 @@ from openedx.core.lib.blockstore_api import (
delete_draft,
)
from openedx.core.djangolib.blockstore_cache import BundleCache
from .keys import LibraryLocatorV2, LibraryUsageLocatorV2
from .models import ContentLibrary, ContentLibraryPermission
log = logging.getLogger(__name__)
@@ -275,7 +274,7 @@ def get_library_block(usage_key):
def_key = lib_context.definition_for_usage(usage_key)
if def_key is None:
raise ContentLibraryBlockNotFound(usage_key)
lib_bundle = LibraryBundle(usage_key.library_slug, def_key.bundle_uuid, draft_name=DRAFT_NAME)
lib_bundle = LibraryBundle(usage_key.lib_key, def_key.bundle_uuid, draft_name=DRAFT_NAME)
return LibraryXBlockMetadata(
usage_key=usage_key,
def_key=def_key,
@@ -337,8 +336,7 @@ def create_library_block(library_key, block_type, definition_id):
# Make sure the new ID is not taken already:
new_usage_id = definition_id # Since this is a top level XBlock, usage_id == definition_id
usage_key = LibraryUsageLocatorV2(
library_org=library_key.org,
library_slug=library_key.slug,
lib_key=library_key,
block_type=block_type,
usage_id=new_usage_id,
)

View File

@@ -1,132 +0,0 @@
"""
Key/locator types for Blockstore-based content libraries
"""
# Disable warnings about _to_deprecated_string etc. which we don't want to implement:
# pylint: disable=abstract-method, no-member
from __future__ import absolute_import, division, print_function, unicode_literals
from opaque_keys import InvalidKeyError
from openedx.core.djangoapps.xblock.learning_context.keys import (
check_key_string_field,
BlockUsageKeyV2,
LearningContextKey,
)
class LibraryLocatorV2(LearningContextKey):
"""
A key that represents a Blockstore-based content library.
When serialized, these keys look like:
lib:MITx:reallyhardproblems
lib:hogwarts:p300-potions-exercises
"""
CANONICAL_NAMESPACE = 'lib'
KEY_FIELDS = ('org', 'slug')
__slots__ = KEY_FIELDS
CHECKED_INIT = False
def __init__(self, org, slug):
"""
Construct a GlobalUsageLocator
"""
check_key_string_field(org)
check_key_string_field(slug)
super(LibraryLocatorV2, self).__init__(org=org, slug=slug)
def _to_string(self):
"""
Serialize this key as a string
"""
return ":".join((self.org, self.slug))
@classmethod
def _from_string(cls, serialized):
"""
Instantiate this key from a serialized string
"""
try:
(org, slug) = serialized.split(':')
except ValueError:
raise InvalidKeyError(cls, serialized)
return cls(org=org, slug=slug)
def make_definition_usage(self, definition_key, usage_id=None):
"""
Return a usage key, given the given the specified definition key and
usage_id.
"""
return LibraryUsageLocatorV2(
library_org=self.org,
library_slug=self.slug,
block_type=definition_key.block_type,
usage_id=usage_id,
)
def for_branch(self, branch):
"""
Compatibility helper.
Some code calls .for_branch(None) on course keys. By implementing this,
it improves backwards compatibility between library keys and course
keys.
"""
if branch is not None:
raise ValueError("Cannot call for_branch on a content library key, except for_branch(None).")
return self
class LibraryUsageLocatorV2(BlockUsageKeyV2):
"""
An XBlock in a Blockstore-based content library.
When serialized, these keys look like:
lb:MITx:reallyhardproblems:problem:problem1
"""
CANONICAL_NAMESPACE = 'lb' # "Library Block"
KEY_FIELDS = ('library_org', 'library_slug', 'block_type', 'usage_id')
__slots__ = KEY_FIELDS
CHECKED_INIT = False
def __init__(self, library_org, library_slug, block_type, usage_id):
"""
Construct a LibraryUsageLocatorV2
"""
check_key_string_field(library_org)
check_key_string_field(library_slug)
check_key_string_field(block_type)
check_key_string_field(usage_id)
super(LibraryUsageLocatorV2, self).__init__(
library_org=library_org,
library_slug=library_slug,
block_type=block_type,
usage_id=usage_id,
)
@property
def context_key(self):
return LibraryLocatorV2(org=self.library_org, slug=self.library_slug)
@property
def block_id(self):
"""
Get the 'block ID' which is another name for the usage ID.
"""
return self.usage_id
def _to_string(self):
"""
Serialize this key as a string
"""
return ":".join((self.library_org, self.library_slug, self.block_type, self.usage_id))
@classmethod
def _from_string(cls, serialized):
"""
Instantiate this key from a serialized string
"""
try:
(library_org, library_slug, block_type, usage_id) = serialized.split(':')
except ValueError:
raise InvalidKeyError(cls, serialized)
return cls(library_org=library_org, library_slug=library_slug, block_type=block_type, usage_id=usage_id)

View File

@@ -5,12 +5,11 @@ from __future__ import absolute_import, division, print_function, unicode_litera
import logging
from django.utils.lru_cache import lru_cache
from opaque_keys.edx.locator import BundleDefinitionLocator, LibraryUsageLocatorV2
from xblock.core import XBlock
from xblock.plugin import PluginMissingError
from openedx.core.djangoapps.content_libraries.keys import LibraryUsageLocatorV2
from openedx.core.djangoapps.content_libraries.models import ContentLibrary
from openedx.core.djangoapps.xblock.learning_context.keys import BundleDefinitionLocator
from openedx.core.djangoapps.xblock.runtime.blockstore_runtime import xml_for_definition
from openedx.core.djangoapps.xblock.runtime.olx_parsing import (
BundleFormatException,
@@ -85,8 +84,7 @@ def usage_for_child_include(parent_usage, parent_definition, parsed_include):
# <xblock-include> but that requires much more complex logic.)
usage_id = parent_usage.usage_id + "-" + usage_id
return LibraryUsageLocatorV2(
library_org=parent_usage.library_org,
library_slug=parent_usage.library_slug,
lib_key=parent_usage.lib_key,
block_type=parsed_include.block_type,
usage_id=usage_id,
)
@@ -169,7 +167,7 @@ class LibraryBundle(object):
own_usage_keys = []
for olx_file_path in self.get_olx_files():
block_type, usage_id, _unused = olx_file_path.split('/')
usage_key = LibraryUsageLocatorV2(self.library_key.org, self.library_key.slug, block_type, usage_id)
usage_key = LibraryUsageLocatorV2(self.library_key, block_type, usage_id)
own_usage_keys.append(usage_key)
usage_keys_with_parents = self.get_bundle_includes().keys()
@@ -234,7 +232,7 @@ class LibraryBundle(object):
olx_path=bfile.path,
**version_arg
)
usage_key = LibraryUsageLocatorV2(self.library_key.org, self.library_key.slug, block_type, usage_id)
usage_key = LibraryUsageLocatorV2(self.library_key, block_type, usage_id)
add_definitions_children(usage_key, def_key)
self.cache.set(cache_key, usages_found)

View File

@@ -21,7 +21,7 @@ class Migration(migrations.Migration):
name='ContentLibrary',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('slug', models.SlugField()),
('slug', models.SlugField(allow_unicode=True)),
('bundle_uuid', models.UUIDField(unique=True)),
('allow_public_learning', models.BooleanField(default=False, help_text='\n Allow any user (even unregistered users) to view and interact with\n content in this library (in the LMS; not in Studio). If this is not\n enabled, then the content in this library is not directly accessible\n in the LMS, and learners will only ever see this content if it is\n explicitly added to a course. If in doubt, leave this unchecked.\n ')),
('allow_public_read', models.BooleanField(default=False, help_text="\n Allow any user with Studio access to view this library's content in\n Studio, use it in their courses, and copy content out of this\n library. If in doubt, leave this unchecked.\n ")),

View File

@@ -6,11 +6,10 @@ from __future__ import absolute_import, division, print_function, unicode_litera
from django.contrib.auth import get_user_model
from django.db import models
from django.utils.translation import ugettext_lazy as _
from opaque_keys.edx.locator import LibraryLocatorV2
from organizations.models import Organization
import six
from openedx.core.djangoapps.content_libraries.keys import LibraryLocatorV2
User = get_user_model()
@@ -45,7 +44,7 @@ class ContentLibrary(models.Model):
# library's opaque key:
# e.g. "lib:org:slug" is the opaque key for a library.
org = models.ForeignKey(Organization, on_delete=models.PROTECT, null=False)
slug = models.SlugField()
slug = models.SlugField(allow_unicode=True)
bundle_uuid = models.UUIDField(unique=True, null=False)
# How is this library going to be used?

View File

@@ -4,6 +4,7 @@ Serializers for the content libraries REST API
# pylint: disable=abstract-method
from __future__ import absolute_import, division, print_function, unicode_literals
from django.core.validators import validate_unicode_slug
from rest_framework import serializers
@@ -16,7 +17,7 @@ class ContentLibraryMetadataSerializer(serializers.Serializer):
# is a reserved prop name in React
id = serializers.CharField(source="key", read_only=True)
org = serializers.SlugField(source="key.org")
slug = serializers.SlugField(source="key.slug")
slug = serializers.CharField(source="key.slug", validators=(validate_unicode_slug, ))
bundle_uuid = serializers.UUIDField(format='hex_verbose', read_only=True)
collection_uuid = serializers.UUIDField(format='hex_verbose', write_only=True)
title = serializers.CharField()

View File

@@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function, unicode_litera
from functools import wraps
import logging
from opaque_keys.edx.locator import LibraryLocatorV2, LibraryUsageLocatorV2
from organizations.models import Organization
from rest_framework.exceptions import NotFound, ValidationError
from rest_framework.views import APIView
@@ -13,7 +14,6 @@ from rest_framework.response import Response
from openedx.core.lib.api.view_utils import view_auth_classes
from . import api
from .keys import LibraryLocatorV2, LibraryUsageLocatorV2
from .serializers import (
ContentLibraryMetadataSerializer,
ContentLibraryUpdateSerializer,
@@ -155,7 +155,7 @@ class LibraryCommitView(APIView):
@convert_exceptions
def delete(self, request, lib_key_str): # pylint: disable=unused-argument
"""
Revent the draft changes made to the specified block and its
Revert the draft changes made to the specified block and its
descendants. Restore it to the last published version
"""
key = LibraryLocatorV2.from_string(lib_key_str)

View File

@@ -12,13 +12,14 @@ import logging
from django.urls import reverse
from django.utils.translation import ugettext as _
from opaque_keys.edx.keys import UsageKeyV2
from opaque_keys.edx.locator import BundleDefinitionLocator
from rest_framework.exceptions import NotFound
import six
from xblock.core import XBlock
from xblock.exceptions import NoSuchViewError
from openedx.core.djangoapps.xblock.apps import get_xblock_app_config
from openedx.core.djangoapps.xblock.learning_context.keys import BundleDefinitionLocator, BlockUsageKeyV2
from openedx.core.djangoapps.xblock.learning_context.manager import get_learning_context_impl
from openedx.core.djangoapps.xblock.runtime.blockstore_runtime import BlockstoreXBlockRuntime, xml_for_definition
from openedx.core.djangoapps.xblock.runtime.runtime import XBlockRuntimeSystem
@@ -100,7 +101,7 @@ def resolve_definition(block_or_key):
"""
if isinstance(block_or_key, BundleDefinitionLocator):
return block_or_key
elif isinstance(block_or_key, BlockUsageKeyV2):
elif isinstance(block_or_key, UsageKeyV2):
context_impl = get_learning_context_impl(block_or_key)
return context_impl.definition_for_usage(block_or_key)
elif isinstance(block_or_key, XBlock):

View File

@@ -1,226 +0,0 @@
"""
New key/locator types that work with Blockstore and the new "Learning Context"
concept.
We will probably move these key types into the "opaque-keys" repository once
they are stable.
"""
# Disable warnings about _to_deprecated_string etc. which we don't want to implement.
# And fix warnings about key fields, which pylint doesn't see as member variables.
# pylint: disable=abstract-method, no-member
from __future__ import absolute_import, division, print_function, unicode_literals
import re
from uuid import UUID
import warnings
from opaque_keys import InvalidKeyError, OpaqueKey
from opaque_keys.edx.keys import DefinitionKey, UsageKey
import six
def check_key_string_field(value, regexp=r'^[\w\-.]+$'):
"""
Helper method to verify that a key's string field(s) meet certain
requirements:
Are a non-empty string
Match the specified regular expression
"""
if not isinstance(value, six.string_types):
raise TypeError("Expected a string")
if not value or not re.match(regexp, value):
raise ValueError("'{}' is not a valid field value for this key type.".format(value))
def check_draft_name(value):
"""
Check that the draft name is valid (unambiguously not a bundle version
nubmer).
Valid: studio_draft, foo-bar, import348975938
Invalid: 1, 15, 873452847357834
"""
if not isinstance(value, six.string_types) or not value:
raise TypeError("Expected a non-empty string")
if value.isdigit():
raise ValueError("Cannot use an integer draft name as it conflicts with bundle version nubmers")
class BundleDefinitionLocator(DefinitionKey):
"""
Implementation of the DefinitionKey type, for XBlock content stored in
Blockstore bundles. This is a low-level identifier used within the Open edX
system for identifying and retrieving OLX.
A "Definition" is a specific OLX file in a specific BundleVersion
(or sometimes rather than a BundleVersion, it may point to a named draft.)
The OLX file, and thus the definition key, defines Scope.content fields as
well as defaults for Scope.settings and Scope.children fields. However the
definition has no parent and no position in any particular course or other
context - both of which require a *usage key* and not just a definition key.
The same block definition (.olx file) can be used in multiple places in a
course, each with a different usage key.
Example serialized definition keys follow.
The 'html' type OLX file "html/introduction/definition.xml" in bundle
11111111-1111-1111-1111-111111111111, bundle version 5:
bundle-olx:11111111-1111-1111-1111-111111111111:5:html:html/introduction/definition.xml
The 'problem' type OLX file "problem324234.xml" in bundle
22222222-2222-2222-2222-222222222222, draft 'studio-draft':
bundle-olx:22222222-2222-2222-2222-222222222222:studio-draft:problem:problem/324234.xml
(The serialized version is somewhat long and verbose because it should
rarely be used except for debugging - the in-memory python key instance will
be used most of the time, and users will rarely/never see definition keys.)
User state should never be stored using a BundleDefinitionLocator as the
key. State should always be stored against a usage locator, which refers to
a particular definition being used in a particular context.
Each BundleDefinitionLocator holds the following data
1. Bundle UUID and [bundle version OR draft name]
2. Block type (e.g. 'html', 'problem', etc.)
3. Path to OLX file
Note that since the data in an .olx file can only ever change in a bundle
draft (not in a specific bundle version), an XBlock that is actively making
changes to its Scope.content/Scope.settings field values must have a
BundleDefinitionLocator with a draft name (not a bundle version).
"""
CANONICAL_NAMESPACE = 'bundle-olx'
KEY_FIELDS = ('bundle_uuid', 'block_type', 'olx_path', '_version_or_draft')
__slots__ = KEY_FIELDS
CHECKED_INIT = False
def __init__(self, bundle_uuid, block_type, olx_path, bundle_version=None, draft_name=None, _version_or_draft=None):
"""
Instantiate a new BundleDefinitionLocator
"""
if not isinstance(bundle_uuid, UUID):
bundle_uuid = UUID(bundle_uuid)
check_key_string_field(block_type)
check_key_string_field(olx_path, regexp=r'^[\w\-./]+$')
# For now the following is a convention; we could remove this restriction in the future given new use cases.
assert block_type + '/' in olx_path, 'path should contain block type, e.g. html/id/definition.xml for html'
if (bundle_version is not None) + (draft_name is not None) + (_version_or_draft is not None) != 1:
raise ValueError("Exactly one of [bundle_version, draft_name, _version_or_draft] must be specified")
if _version_or_draft is not None:
if isinstance(_version_or_draft, int):
pass # This is a bundle version number.
else:
# This is a draft name, not a bundle version:
check_draft_name(_version_or_draft)
elif draft_name is not None:
check_draft_name(draft_name)
_version_or_draft = draft_name
else:
assert isinstance(bundle_version, int)
_version_or_draft = bundle_version
super(BundleDefinitionLocator, self).__init__(
bundle_uuid=bundle_uuid,
block_type=block_type,
olx_path=olx_path,
_version_or_draft=_version_or_draft,
)
@property
def bundle_version(self):
return self._version_or_draft if isinstance(self._version_or_draft, int) else None
@property
def draft_name(self):
return self._version_or_draft if not isinstance(self._version_or_draft, int) else None
def _to_string(self):
"""
Return a string representing this BundleDefinitionLocator
"""
return ":".join((
six.text_type(self.bundle_uuid), six.text_type(self._version_or_draft), self.block_type, self.olx_path,
))
@classmethod
def _from_string(cls, serialized):
"""
Return a BundleDefinitionLocator by parsing the given serialized string
"""
try:
(bundle_uuid_str, _version_or_draft, block_type, olx_path) = serialized.split(':', 3)
except ValueError:
raise InvalidKeyError(cls, serialized)
bundle_uuid = UUID(bundle_uuid_str)
if not block_type or not olx_path:
raise InvalidKeyError(cls, serialized)
if _version_or_draft.isdigit():
_version_or_draft = int(_version_or_draft)
return cls(
bundle_uuid=bundle_uuid,
block_type=block_type,
olx_path=olx_path,
_version_or_draft=_version_or_draft,
)
class LearningContextKey(OpaqueKey):
"""
A key that idenitifies a course, a library, a program,
or some other collection of content where learning happens.
"""
KEY_TYPE = 'context_key'
__slots__ = ()
def make_definition_usage(self, definition_key, usage_id=None):
"""
Return a usage key, given the given the specified definition key and
usage_id.
"""
raise NotImplementedError()
class BlockUsageKeyV2(UsageKey):
"""
Abstract base class that encodes an XBlock used in a specific learning
context (e.g. a course).
Definition + Learning Context = Usage
"""
@property
def context_key(self):
raise NotImplementedError()
@property
def definition_key(self):
"""
Returns the definition key for this usage.
"""
# Because this key definition is likely going to be moved into the
# opaque-keys package, we cannot put the logic here for getting the
# definition.
raise NotImplementedError(
"To get the definition key, use: "
"get_learning_context_impl(usage_key).definition_for_usage(usage_key)"
)
@property
def course_key(self):
warnings.warn("Use .context_key instead of .course_key", DeprecationWarning, stacklevel=2)
return self.context_key
def html_id(self):
"""
Return an id which can be used on an html page as an id attr of an html
element. This is only in here for backwards-compatibility with XModules;
don't use in new code.
"""
warnings.warn(".html_id is deprecated", DeprecationWarning, stacklevel=2)
# HTML5 allows ID values to contain any characters at all other than spaces.
# These key types don't allow spaces either, so no transform is needed.
return six.text_type(self)

View File

@@ -31,7 +31,7 @@ class LearningContext(object):
user: a Django User object (may be an AnonymousUser)
usage_key: the BlockUsageKeyV2 subclass used for this learning context
usage_key: the UsageKeyV2 subclass used for this learning context
Must return a boolean.
"""
@@ -45,7 +45,7 @@ class LearningContext(object):
user: a Django User object (may be an AnonymousUser)
usage_key: the BlockUsageKeyV2 subclass used for this learning context
usage_key: the UsageKeyV2 subclass used for this learning context
Must return a boolean.
"""
@@ -57,7 +57,7 @@ class LearningContext(object):
BundleDefinitionLocator which specifies the actual XBlock definition
(as a path to an OLX in a specific blockstore bundle).
usage_key: the BlockUsageKeyV2 subclass used for this learning context
usage_key: the UsageKeyV2 subclass used for this learning context
Must return a BundleDefinitionLocator if the XBlock exists in this
context, or None otherwise.
@@ -71,7 +71,7 @@ class LearningContext(object):
The child is always from an <xblock-include /> element.
parent_usage: the BlockUsageKeyV2 subclass key of the parent
parent_usage: the UsageKeyV2 subclass key of the parent
parent_definition: the BundleDefinitionLocator key of the parent (same
as returned by definition_for_usage(parent_usage) but included here
@@ -80,7 +80,7 @@ class LearningContext(object):
parsed_include: the XBlockInclude tuple containing the data from the
parsed <xblock-include /> element. See xblock.runtime.olx_parsing.
Must return a BlockUsageKeyV2 subclass
Must return a UsageKeyV2 subclass
"""
raise NotImplementedError

View File

@@ -3,9 +3,10 @@ Helper methods for working with learning contexts
"""
from __future__ import absolute_import, division, print_function, unicode_literals
from opaque_keys.edx.keys import LearningContextKey, UsageKeyV2
from openedx.core.djangoapps.xblock.apps import get_xblock_app_config
from openedx.core.lib.plugins import PluginManager
from .keys import LearningContextKey, BlockUsageKeyV2
class LearningContextPluginManager(PluginManager):
@@ -35,7 +36,7 @@ def get_learning_context_impl(key):
"""
if isinstance(key, LearningContextKey):
context_type = key.CANONICAL_NAMESPACE # e.g. 'lib'
elif isinstance(key, BlockUsageKeyV2):
elif isinstance(key, UsageKeyV2):
context_type = key.context_key.CANONICAL_NAMESPACE
else:
# Maybe this is an older modulestore key etc.

View File

@@ -6,10 +6,10 @@ from __future__ import absolute_import, division, print_function, unicode_litera
import logging
from lxml import etree
from opaque_keys.edx.locator import BundleDefinitionLocator
from xblock.exceptions import NoSuchDefinition, NoSuchUsage
from xblock.fields import ScopeIds
from openedx.core.djangoapps.xblock.learning_context.keys import BundleDefinitionLocator
from openedx.core.djangoapps.xblock.learning_context.manager import get_learning_context_impl
from openedx.core.djangoapps.xblock.runtime.runtime import XBlockRuntime
from openedx.core.djangoapps.xblock.runtime.olx_parsing import parse_xblock_include

View File

@@ -4,9 +4,9 @@ our newer Open edX-specific opaque key formats.
"""
from __future__ import absolute_import, division, print_function, unicode_literals
from opaque_keys.edx.keys import UsageKeyV2
from xblock.runtime import IdReader
from openedx.core.djangoapps.xblock.learning_context.keys import BlockUsageKeyV2
from openedx.core.djangoapps.xblock.learning_context.manager import get_learning_context_impl
@@ -23,7 +23,7 @@ class OpaqueKeyReader(IdReader):
Returns:
The `definition_id` the usage is derived from
"""
if isinstance(usage_id, BlockUsageKeyV2):
if isinstance(usage_id, UsageKeyV2):
return get_learning_context_impl(usage_id).definition_for_usage(usage_id)
raise TypeError("This version of get_definition_id doesn't support the given key type.")

View File

@@ -4,14 +4,15 @@ Helpful methods to use when parsing OLX (XBlock XML)
from __future__ import absolute_import, division, print_function, unicode_literals
from collections import namedtuple
from openedx.core.djangoapps.xblock.learning_context.keys import BundleDefinitionLocator
from opaque_keys.edx.locator import BundleDefinitionLocator
from openedx.core.djangolib.blockstore_cache import get_bundle_direct_links_with_cache
class BundleFormatException(Exception):
"""
Raised when certain errors are found when parsing the OLX in a content
libary bundle.
library bundle.
"""

View File

@@ -98,7 +98,7 @@ drf-yasg==1.16
edx-ace==0.1.10
edx-analytics-data-api-client==0.15.3
edx-bulk-grades==0.6.0
edx-ccx-keys==0.2.2
edx-ccx-keys==1.0.0
edx-celeryutils==0.3.0
edx-completion==2.0.0
edx-django-oauth2-provider==1.3.5
@@ -110,7 +110,7 @@ edx-enterprise==1.9.12
edx-i18n-tools==0.4.8
edx-milestones==0.2.3
edx-oauth2-provider==1.3.0
edx-opaque-keys[django]==1.0.1
edx-opaque-keys[django]==2.0.0
edx-organizations==2.1.0
edx-proctoring-proctortrack==1.0.5
edx-proctoring==2.0.8

View File

@@ -121,7 +121,7 @@ drf-yasg==1.16
edx-ace==0.1.10
edx-analytics-data-api-client==0.15.3
edx-bulk-grades==0.6.0
edx-ccx-keys==0.2.2
edx-ccx-keys==1.0.0
edx-celeryutils==0.3.0
edx-completion==2.0.0
edx-django-oauth2-provider==1.3.5
@@ -134,7 +134,7 @@ edx-i18n-tools==0.4.8
edx-lint==1.3.0
edx-milestones==0.2.3
edx-oauth2-provider==1.3.0
edx-opaque-keys[django]==1.0.1
edx-opaque-keys[django]==2.0.0
edx-organizations==2.1.0
edx-proctoring-proctortrack==1.0.5
edx-proctoring==2.0.8

View File

@@ -7,7 +7,7 @@
argh==0.26.2 # via watchdog
certifi==2019.9.11 # via requests
chardet==3.0.4 # via requests
edx-opaque-keys==1.0.1
edx-opaque-keys==2.0.0
idna==2.8 # via requests
lazy==1.1
libsass==0.10.0

View File

@@ -118,7 +118,7 @@ drf-yasg==1.16
edx-ace==0.1.10
edx-analytics-data-api-client==0.15.3
edx-bulk-grades==0.6.0
edx-ccx-keys==0.2.2
edx-ccx-keys==1.0.0
edx-celeryutils==0.3.0
edx-completion==2.0.0
edx-django-oauth2-provider==1.3.5
@@ -131,7 +131,7 @@ edx-i18n-tools==0.4.8
edx-lint==1.3.0
edx-milestones==0.2.3
edx-oauth2-provider==1.3.0
edx-opaque-keys[django]==1.0.1
edx-opaque-keys[django]==2.0.0
edx-organizations==2.1.0
edx-proctoring-proctortrack==1.0.5
edx-proctoring==2.0.8

View File

@@ -103,15 +103,6 @@ setup(
"user_authn = openedx.core.djangoapps.user_authn.apps:UserAuthnConfig",
"instructor = lms.djangoapps.instructor.apps:InstructorConfig",
],
'definition_key': [
'bundle-olx = openedx.core.djangoapps.xblock.learning_context.keys:BundleDefinitionLocator',
],
'context_key': [
'lib = openedx.core.djangoapps.content_libraries.keys:LibraryLocatorV2',
],
'usage_key': [
'lb = openedx.core.djangoapps.content_libraries.keys:LibraryUsageLocatorV2',
],
'openedx.learning_context': [
'lib = openedx.core.djangoapps.content_libraries.library_context:LibraryContextImpl',
],