diff --git a/.gitignore b/.gitignore index 6123dd4cf..faa881b9a 100644 --- a/.gitignore +++ b/.gitignore @@ -75,7 +75,12 @@ venv/ !.vscode/settings.json.example # Media files (for uploads) -media/ +/media/ # Media files generated during test runs -test_media/ +/test_media/ + +# uv stuff +.lock +CACHEDIR.TAG +pyvenv.cfg diff --git a/.importlinter b/.importlinter index 6c278d0dd..6b14b4a31 100644 --- a/.importlinter +++ b/.importlinter @@ -36,24 +36,24 @@ layers= openedx_learning.api.authoring # The "backup_restore" app handle the new export and import mechanism. - openedx_learning.apps.authoring.backup_restore + openedx_learning.apps.authoring.applets.backup_restore # The "components" app is responsible for storing versioned Components, # which is Open edX Studio terminology maps to things like individual # Problems, Videos, and blocks of HTML text. This is also the type we would # associate with a single "leaf" XBlock–one that is not a container type and # has no child elements. - openedx_learning.apps.authoring.components + openedx_learning.apps.authoring.applets.components # The "contents" app stores the simplest pieces of binary and text data, # without versioning information. These belong to a single Learning Package. - openedx_learning.apps.authoring.contents + openedx_learning.apps.authoring.applets.contents # The "collections" app stores arbitrary groupings of PublishableEntities. # Its only dependency should be the publishing app. - openedx_learning.apps.authoring.collections + openedx_learning.apps.authoring.applets.collections # The lowest layer is "publishing", which holds the basic primitives needed # to create Learning Packages and manage the draft and publish states for # various types of content. - openedx_learning.apps.authoring.publishing + openedx_learning.apps.authoring.applets.publishing diff --git a/docs/decisions/0016-python-public-api-conventions.rst b/docs/decisions/0016-python-public-api-conventions.rst index 20bb1f766..23644a47d 100644 --- a/docs/decisions/0016-python-public-api-conventions.rst +++ b/docs/decisions/0016-python-public-api-conventions.rst @@ -20,7 +20,7 @@ Learning Core Django apps will be grouped into packages. Apps in ``openedx_learning`` will be grouped into broadly related packages under ``openedx_learning.apps``. The first of these groups will be "authoring" (``openedx_learning.apps.authoring``). Future packages may include "learner", "personalization", "activity", "grading", etc. Learning Core Django apps will continue to have their own ``api`` modules. - So for example, ``openedx_learning.apps.authoring.components.api`` will continue to exist. + So for example, ``openedx_learning.apps.authoring.applets.components.api`` will continue to exist. Learning Core will have a top level package for its public API. All public APIs intended for use by consumers of Learning Core will be represented as modules in the ``openedx_learning.api`` package that corresponds to the app groupings (e.g. ``openedx_learning.api.authoring``). @@ -35,14 +35,14 @@ App ``api`` modules will define their public functions using ``__all__``. This relies on the individual apps to properly set ``__all__`` to the list of functions that they are willing to publicly support. App ``api`` modules within a package of apps still import from each other. - So for example, ``openedx_learning.apps.authoring.components.api`` will continue to import APIs that it needs from ``..publishing.api``, instead of using the public API at ``openedx_learning.api.authoring``. These imports should not use wildcards. + So for example, ``openedx_learning.apps.authoring.applets.components.api`` will continue to import APIs that it needs from ``..publishing.api``, instead of using the public API at ``openedx_learning.api.authoring``. These imports should not use wildcards. Functions and constants that are not listed as part of a module's ``__all__`` may still be imported by other app APIs in the same package grouping. This should allow a package more flexibility to create provisional APIs that we may not want to support publicly. If a function or attribute is intended to be completely private to an app's ``api`` module (i.e. not used even by other apps in its package), it should be prefixed with an underscore. App ``api`` modules should not import directly from apps outside their package. - For example, ``openedx_learning.apps.personalization.api`` should import authoring API functions from ``openedx_learning.api.authoring``, **not** directly from something like ``openedx_learning.apps.authoring.components.api``. This will help to limit the impact of refactoring app package internal changes, as well as exposing shortcomings in the existing public APIs. + For example, ``openedx_learning.apps.personalization.api`` should import authoring API functions from ``openedx_learning.api.authoring``, **not** directly from something like ``openedx_learning.apps.authoring.applets.components.api``. This will help to limit the impact of refactoring app package internal changes, as well as exposing shortcomings in the existing public APIs. Public API modules may implement their own functions. In addition to aggregating app ``api`` modules via wildcard imports, public API modules like ``openedx_learning.api.authoring`` may implement their own functionality. This will be useful for convenience functions that invoke multiple app APIs, and for backwards compatibility shims. When possible, the bulk of the logic for these should continue to live in app-defined APIs, with the public API module acting more as a glue layer. diff --git a/olx_importer/management/commands/load_components.py b/olx_importer/management/commands/load_components.py index 55cd268c8..a52ce72db 100644 --- a/olx_importer/management/commands/load_components.py +++ b/olx_importer/management/commands/load_components.py @@ -28,9 +28,9 @@ from django.db import transaction # Model references to remove -from openedx_learning.apps.authoring.components import api as components_api -from openedx_learning.apps.authoring.contents import api as contents_api -from openedx_learning.apps.authoring.publishing import api as publishing_api +from openedx_learning.apps.authoring.applets.components import api as components_api +from openedx_learning.apps.authoring.applets.contents import api as contents_api +from openedx_learning.apps.authoring.applets.publishing import api as publishing_api SUPPORTED_TYPES = ["problem", "video", "html"] logger = logging.getLogger(__name__) diff --git a/openedx_learning/api/authoring.py b/openedx_learning/api/authoring.py index 9082b33fb..36343f279 100644 --- a/openedx_learning/api/authoring.py +++ b/openedx_learning/api/authoring.py @@ -9,14 +9,14 @@ """ # These wildcard imports are okay because these api modules declare __all__. # pylint: disable=wildcard-import -from ..apps.authoring.backup_restore.api import * -from ..apps.authoring.collections.api import * -from ..apps.authoring.components.api import * -from ..apps.authoring.contents.api import * -from ..apps.authoring.publishing.api import * -from ..apps.authoring.sections.api import * -from ..apps.authoring.subsections.api import * -from ..apps.authoring.units.api import * +from ..apps.authoring.applets.backup_restore.api import * +from ..apps.authoring.applets.collections.api import * +from ..apps.authoring.applets.components.api import * +from ..apps.authoring.applets.contents.api import * +from ..apps.authoring.applets.publishing.api import * +from ..apps.authoring.applets.sections.api import * +from ..apps.authoring.applets.subsections.api import * +from ..apps.authoring.applets.units.api import * # This was renamed after the authoring API refactoring pushed this and other # app APIs into the openedx_learning.api.authoring module. Here I'm aliasing to diff --git a/openedx_learning/api/authoring_models.py b/openedx_learning/api/authoring_models.py index 617d85dc4..cb7d3bd82 100644 --- a/openedx_learning/api/authoring_models.py +++ b/openedx_learning/api/authoring_models.py @@ -7,10 +7,10 @@ """ # These wildcard imports are okay because these modules declare __all__. # pylint: disable=wildcard-import -from ..apps.authoring.collections.models import * -from ..apps.authoring.components.models import * -from ..apps.authoring.contents.models import * -from ..apps.authoring.publishing.models import * -from ..apps.authoring.sections.models import * -from ..apps.authoring.subsections.models import * -from ..apps.authoring.units.models import * +from ..apps.authoring.applets.collections.models import * +from ..apps.authoring.applets.components.models import * +from ..apps.authoring.applets.contents.models import * +from ..apps.authoring.applets.publishing.models import * +from ..apps.authoring.applets.sections.models import * +from ..apps.authoring.applets.subsections.models import * +from ..apps.authoring.applets.units.models import * diff --git a/openedx_learning/apps/authoring/admin.py b/openedx_learning/apps/authoring/admin.py new file mode 100644 index 000000000..2c946cfb3 --- /dev/null +++ b/openedx_learning/apps/authoring/admin.py @@ -0,0 +1,12 @@ +from .applets.backup_restore.admin import * +from .applets.collections.admin import * +from .applets.components.admin import * +from .applets.contents.admin import * +from .applets.publishing.admin import * +from .applets.sections.admin import * +from .applets.subsections.admin import * +from .applets.units.admin import * + +#from openedx_learning.lib import appletslib + +#globals().update(appletslib.auto_import_admin()) diff --git a/openedx_learning/apps/authoring/api.py b/openedx_learning/apps/authoring/api.py new file mode 100644 index 000000000..5159b2bed --- /dev/null +++ b/openedx_learning/apps/authoring/api.py @@ -0,0 +1,12 @@ +from .applets.backup_restore.api import * +from .applets.collections.api import * +from .applets.components.api import * +from .applets.contents.api import * +from .applets.publishing.api import * +from .applets.sections.api import * +from .applets.subsections.api import * +from .applets.units.api import * + +#from openedx_learning.lib import appletslib + +#globals().update(appletslib.auto_import_api()) diff --git a/openedx_learning/apps/authoring/backup_restore/__init__.py b/openedx_learning/apps/authoring/applets/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/backup_restore/__init__.py rename to openedx_learning/apps/authoring/applets/__init__.py diff --git a/openedx_learning/apps/authoring/backup_restore/management/__init__.py b/openedx_learning/apps/authoring/applets/backup_restore/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/backup_restore/management/__init__.py rename to openedx_learning/apps/authoring/applets/backup_restore/__init__.py diff --git a/openedx_learning/apps/authoring/backup_restore/admin.py b/openedx_learning/apps/authoring/applets/backup_restore/admin.py similarity index 100% rename from openedx_learning/apps/authoring/backup_restore/admin.py rename to openedx_learning/apps/authoring/applets/backup_restore/admin.py diff --git a/openedx_learning/apps/authoring/backup_restore/api.py b/openedx_learning/apps/authoring/applets/backup_restore/api.py similarity index 84% rename from openedx_learning/apps/authoring/backup_restore/api.py rename to openedx_learning/apps/authoring/applets/backup_restore/api.py index 802bf6ff3..097d86f89 100644 --- a/openedx_learning/apps/authoring/backup_restore/api.py +++ b/openedx_learning/apps/authoring/applets/backup_restore/api.py @@ -5,8 +5,8 @@ from django.contrib.auth.models import User as UserType # pylint: disable=imported-auth-user -from openedx_learning.apps.authoring.backup_restore.zipper import LearningPackageUnzipper, LearningPackageZipper -from openedx_learning.apps.authoring.publishing.api import get_learning_package_by_key +from .zipper import LearningPackageUnzipper, LearningPackageZipper +from ..publishing.api import get_learning_package_by_key def create_zip_file(lp_key: str, path: str, user: UserType | None = None, origin_server: str | None = None) -> None: diff --git a/openedx_learning/apps/authoring/backup_restore/models.py b/openedx_learning/apps/authoring/applets/backup_restore/models.py similarity index 100% rename from openedx_learning/apps/authoring/backup_restore/models.py rename to openedx_learning/apps/authoring/applets/backup_restore/models.py diff --git a/openedx_learning/apps/authoring/backup_restore/serializers.py b/openedx_learning/apps/authoring/applets/backup_restore/serializers.py similarity index 98% rename from openedx_learning/apps/authoring/backup_restore/serializers.py rename to openedx_learning/apps/authoring/applets/backup_restore/serializers.py index c34e81059..d8f7a5c15 100644 --- a/openedx_learning/apps/authoring/backup_restore/serializers.py +++ b/openedx_learning/apps/authoring/applets/backup_restore/serializers.py @@ -5,7 +5,7 @@ from rest_framework import serializers -from openedx_learning.apps.authoring.components import api as components_api +from ..components import api as components_api class LearningPackageSerializer(serializers.Serializer): # pylint: disable=abstract-method diff --git a/openedx_learning/apps/authoring/backup_restore/toml.py b/openedx_learning/apps/authoring/applets/backup_restore/toml.py similarity index 95% rename from openedx_learning/apps/authoring/backup_restore/toml.py rename to openedx_learning/apps/authoring/applets/backup_restore/toml.py index a3ab9a03d..a75e7a0ad 100644 --- a/openedx_learning/apps/authoring/backup_restore/toml.py +++ b/openedx_learning/apps/authoring/applets/backup_restore/toml.py @@ -8,10 +8,10 @@ import tomlkit from django.contrib.auth.models import User as UserType # pylint: disable=imported-auth-user -from openedx_learning.apps.authoring.collections.models import Collection -from openedx_learning.apps.authoring.publishing import api as publishing_api -from openedx_learning.apps.authoring.publishing.models import PublishableEntity, PublishableEntityVersion -from openedx_learning.apps.authoring.publishing.models.learning_package import LearningPackage +from ..collections.models import Collection +from ..publishing import api as publishing_api +from ..publishing.models import PublishableEntity, PublishableEntityVersion +from ..publishing.models.learning_package import LearningPackage def toml_learning_package( diff --git a/openedx_learning/apps/authoring/backup_restore/zipper.py b/openedx_learning/apps/authoring/applets/backup_restore/zipper.py similarity index 98% rename from openedx_learning/apps/authoring/backup_restore/zipper.py rename to openedx_learning/apps/authoring/applets/backup_restore/zipper.py index 27ddcacc3..4040983ae 100644 --- a/openedx_learning/apps/authoring/backup_restore/zipper.py +++ b/openedx_learning/apps/authoring/applets/backup_restore/zipper.py @@ -28,7 +28,7 @@ PublishableEntity, PublishableEntityVersion, ) -from openedx_learning.apps.authoring.backup_restore.serializers import ( +from .serializers import ( CollectionSerializer, ComponentSerializer, ComponentVersionSerializer, @@ -37,7 +37,7 @@ LearningPackageMetadataSerializer, LearningPackageSerializer, ) -from openedx_learning.apps.authoring.backup_restore.toml import ( +from .toml import ( parse_collection_toml, parse_learning_package_toml, parse_publishable_entity_toml, @@ -45,13 +45,13 @@ toml_learning_package, toml_publishable_entity, ) -from openedx_learning.apps.authoring.collections import api as collections_api -from openedx_learning.apps.authoring.components import api as components_api -from openedx_learning.apps.authoring.contents import api as contents_api -from openedx_learning.apps.authoring.publishing import api as publishing_api -from openedx_learning.apps.authoring.sections import api as sections_api -from openedx_learning.apps.authoring.subsections import api as subsections_api -from openedx_learning.apps.authoring.units import api as units_api +from ..collections import api as collections_api +from ..components import api as components_api +from ..contents import api as contents_api +from ..publishing import api as publishing_api +from ..sections import api as sections_api +from ..subsections import api as subsections_api +from ..units import api as units_api TOML_PACKAGE_NAME = "package.toml" DEFAULT_USERNAME = "command" diff --git a/openedx_learning/apps/authoring/backup_restore/management/commands/__init__.py b/openedx_learning/apps/authoring/applets/collections/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/backup_restore/management/commands/__init__.py rename to openedx_learning/apps/authoring/applets/collections/__init__.py diff --git a/openedx_learning/apps/authoring/collections/admin.py b/openedx_learning/apps/authoring/applets/collections/admin.py similarity index 100% rename from openedx_learning/apps/authoring/collections/admin.py rename to openedx_learning/apps/authoring/applets/collections/admin.py diff --git a/openedx_learning/apps/authoring/collections/api.py b/openedx_learning/apps/authoring/applets/collections/api.py similarity index 100% rename from openedx_learning/apps/authoring/collections/api.py rename to openedx_learning/apps/authoring/applets/collections/api.py diff --git a/openedx_learning/apps/authoring/collections/models.py b/openedx_learning/apps/authoring/applets/collections/models.py similarity index 98% rename from openedx_learning/apps/authoring/collections/models.py rename to openedx_learning/apps/authoring/applets/collections/models.py index 731f2cb73..225f2fc20 100644 --- a/openedx_learning/apps/authoring/collections/models.py +++ b/openedx_learning/apps/authoring/applets/collections/models.py @@ -180,7 +180,10 @@ class Meta: ), ] indexes = [ - models.Index(fields=["learning_package", "title"]), + models.Index( + fields=["learning_package", "title"], + name="oel_authoring_coll_lp_title", + ), ] def __repr__(self) -> str: diff --git a/openedx_learning/apps/authoring/collections/readme.rst b/openedx_learning/apps/authoring/applets/collections/readme.rst similarity index 100% rename from openedx_learning/apps/authoring/collections/readme.rst rename to openedx_learning/apps/authoring/applets/collections/readme.rst diff --git a/openedx_learning/apps/authoring/backup_restore/migrations/__init__.py b/openedx_learning/apps/authoring/applets/components/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/backup_restore/migrations/__init__.py rename to openedx_learning/apps/authoring/applets/components/__init__.py diff --git a/openedx_learning/apps/authoring/components/admin.py b/openedx_learning/apps/authoring/applets/components/admin.py similarity index 100% rename from openedx_learning/apps/authoring/components/admin.py rename to openedx_learning/apps/authoring/applets/components/admin.py diff --git a/openedx_learning/apps/authoring/components/api.py b/openedx_learning/apps/authoring/applets/components/api.py similarity index 100% rename from openedx_learning/apps/authoring/components/api.py rename to openedx_learning/apps/authoring/applets/components/api.py diff --git a/openedx_learning/apps/authoring/components/models.py b/openedx_learning/apps/authoring/applets/components/models.py similarity index 98% rename from openedx_learning/apps/authoring/components/models.py rename to openedx_learning/apps/authoring/applets/components/models.py index b53077637..340aa2505 100644 --- a/openedx_learning/apps/authoring/components/models.py +++ b/openedx_learning/apps/authoring/applets/components/models.py @@ -21,8 +21,8 @@ from django.db import models -from ....lib.fields import case_sensitive_char_field, key_field -from ....lib.managers import WithRelationsManager +from openedx_learning.lib.fields import case_sensitive_char_field, key_field +from openedx_learning.lib.managers import WithRelationsManager from ..contents.models import Content from ..publishing.models import LearningPackage, PublishableEntityMixin, PublishableEntityVersionMixin @@ -63,6 +63,7 @@ class ComponentType(models.Model): # the UsageKey. name = case_sensitive_char_field(max_length=100, blank=True) + # TODO: this needs to go into a class Meta constraints = [ models.UniqueConstraint( fields=[ diff --git a/openedx_learning/apps/authoring/components/readme.rst b/openedx_learning/apps/authoring/applets/components/readme.rst similarity index 100% rename from openedx_learning/apps/authoring/components/readme.rst rename to openedx_learning/apps/authoring/applets/components/readme.rst diff --git a/openedx_learning/apps/authoring/collections/__init__.py b/openedx_learning/apps/authoring/applets/contents/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/collections/__init__.py rename to openedx_learning/apps/authoring/applets/contents/__init__.py diff --git a/openedx_learning/apps/authoring/contents/admin.py b/openedx_learning/apps/authoring/applets/contents/admin.py similarity index 100% rename from openedx_learning/apps/authoring/contents/admin.py rename to openedx_learning/apps/authoring/applets/contents/admin.py diff --git a/openedx_learning/apps/authoring/contents/api.py b/openedx_learning/apps/authoring/applets/contents/api.py similarity index 99% rename from openedx_learning/apps/authoring/contents/api.py rename to openedx_learning/apps/authoring/applets/contents/api.py index 319935882..ed8251e53 100644 --- a/openedx_learning/apps/authoring/contents/api.py +++ b/openedx_learning/apps/authoring/applets/contents/api.py @@ -12,7 +12,7 @@ from django.core.files.base import ContentFile from django.db.transaction import atomic -from ....lib.fields import create_hash_digest +from openedx_learning.lib.fields import create_hash_digest from .models import Content, MediaType # The public API that will be re-exported by openedx_learning.apps.authoring.api diff --git a/openedx_learning/apps/authoring/contents/models.py b/openedx_learning/apps/authoring/applets/contents/models.py similarity index 98% rename from openedx_learning/apps/authoring/contents/models.py rename to openedx_learning/apps/authoring/applets/contents/models.py index c087c122f..dc2dd1829 100644 --- a/openedx_learning/apps/authoring/contents/models.py +++ b/openedx_learning/apps/authoring/applets/contents/models.py @@ -16,8 +16,8 @@ from django.db import models from django.utils.module_loading import import_string -from ....lib.fields import MultiCollationTextField, case_insensitive_char_field, hash_field, manual_date_time_field -from ....lib.managers import WithRelationsManager +from openedx_learning.lib.fields import MultiCollationTextField, case_insensitive_char_field, hash_field, manual_date_time_field +from openedx_learning.lib.managers import WithRelationsManager from ..publishing.models import LearningPackage logger = getLogger() diff --git a/openedx_learning/apps/authoring/collections/migrations/__init__.py b/openedx_learning/apps/authoring/applets/publishing/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/collections/migrations/__init__.py rename to openedx_learning/apps/authoring/applets/publishing/__init__.py diff --git a/openedx_learning/apps/authoring/publishing/admin.py b/openedx_learning/apps/authoring/applets/publishing/admin.py similarity index 100% rename from openedx_learning/apps/authoring/publishing/admin.py rename to openedx_learning/apps/authoring/applets/publishing/admin.py diff --git a/openedx_learning/apps/authoring/publishing/api.py b/openedx_learning/apps/authoring/applets/publishing/api.py similarity index 100% rename from openedx_learning/apps/authoring/publishing/api.py rename to openedx_learning/apps/authoring/applets/publishing/api.py diff --git a/openedx_learning/apps/authoring/publishing/contextmanagers.py b/openedx_learning/apps/authoring/applets/publishing/contextmanagers.py similarity index 100% rename from openedx_learning/apps/authoring/publishing/contextmanagers.py rename to openedx_learning/apps/authoring/applets/publishing/contextmanagers.py diff --git a/openedx_learning/apps/authoring/publishing/models/__init__.py b/openedx_learning/apps/authoring/applets/publishing/models/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/publishing/models/__init__.py rename to openedx_learning/apps/authoring/applets/publishing/models/__init__.py diff --git a/openedx_learning/apps/authoring/publishing/models/container.py b/openedx_learning/apps/authoring/applets/publishing/models/container.py similarity index 100% rename from openedx_learning/apps/authoring/publishing/models/container.py rename to openedx_learning/apps/authoring/applets/publishing/models/container.py diff --git a/openedx_learning/apps/authoring/publishing/models/draft_log.py b/openedx_learning/apps/authoring/applets/publishing/models/draft_log.py similarity index 100% rename from openedx_learning/apps/authoring/publishing/models/draft_log.py rename to openedx_learning/apps/authoring/applets/publishing/models/draft_log.py diff --git a/openedx_learning/apps/authoring/publishing/models/entity_list.py b/openedx_learning/apps/authoring/applets/publishing/models/entity_list.py similarity index 99% rename from openedx_learning/apps/authoring/publishing/models/entity_list.py rename to openedx_learning/apps/authoring/applets/publishing/models/entity_list.py index 252ea2e37..37874acee 100644 --- a/openedx_learning/apps/authoring/publishing/models/entity_list.py +++ b/openedx_learning/apps/authoring/applets/publishing/models/entity_list.py @@ -18,6 +18,7 @@ class EntityList(models.Model): anonymous in a sense–they're pointed to by ContainerVersions and other models, rather than being looked up by their own identifiers. """ + @cached_property def rows(self): """ diff --git a/openedx_learning/apps/authoring/publishing/models/learning_package.py b/openedx_learning/apps/authoring/applets/publishing/models/learning_package.py similarity index 100% rename from openedx_learning/apps/authoring/publishing/models/learning_package.py rename to openedx_learning/apps/authoring/applets/publishing/models/learning_package.py diff --git a/openedx_learning/apps/authoring/publishing/models/publish_log.py b/openedx_learning/apps/authoring/applets/publishing/models/publish_log.py similarity index 100% rename from openedx_learning/apps/authoring/publishing/models/publish_log.py rename to openedx_learning/apps/authoring/applets/publishing/models/publish_log.py diff --git a/openedx_learning/apps/authoring/publishing/models/publishable_entity.py b/openedx_learning/apps/authoring/applets/publishing/models/publishable_entity.py similarity index 100% rename from openedx_learning/apps/authoring/publishing/models/publishable_entity.py rename to openedx_learning/apps/authoring/applets/publishing/models/publishable_entity.py diff --git a/openedx_learning/apps/authoring/publishing/readme.rst b/openedx_learning/apps/authoring/applets/publishing/readme.rst similarity index 100% rename from openedx_learning/apps/authoring/publishing/readme.rst rename to openedx_learning/apps/authoring/applets/publishing/readme.rst diff --git a/openedx_learning/apps/authoring/components/__init__.py b/openedx_learning/apps/authoring/applets/sections/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/components/__init__.py rename to openedx_learning/apps/authoring/applets/sections/__init__.py diff --git a/openedx_learning/apps/authoring/sections/admin.py b/openedx_learning/apps/authoring/applets/sections/admin.py similarity index 100% rename from openedx_learning/apps/authoring/sections/admin.py rename to openedx_learning/apps/authoring/applets/sections/admin.py diff --git a/openedx_learning/apps/authoring/sections/api.py b/openedx_learning/apps/authoring/applets/sections/api.py similarity index 99% rename from openedx_learning/apps/authoring/sections/api.py rename to openedx_learning/apps/authoring/applets/sections/api.py index f6d58b858..589636075 100644 --- a/openedx_learning/apps/authoring/sections/api.py +++ b/openedx_learning/apps/authoring/applets/sections/api.py @@ -7,7 +7,7 @@ from django.db.transaction import atomic -from openedx_learning.apps.authoring.subsections.models import Subsection, SubsectionVersion +from ..subsections.models import Subsection, SubsectionVersion from ..publishing import api as publishing_api from .models import Section, SectionVersion diff --git a/openedx_learning/apps/authoring/sections/models.py b/openedx_learning/apps/authoring/applets/sections/models.py similarity index 100% rename from openedx_learning/apps/authoring/sections/models.py rename to openedx_learning/apps/authoring/applets/sections/models.py diff --git a/openedx_learning/apps/authoring/components/management/__init__.py b/openedx_learning/apps/authoring/applets/subsections/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/components/management/__init__.py rename to openedx_learning/apps/authoring/applets/subsections/__init__.py diff --git a/openedx_learning/apps/authoring/subsections/admin.py b/openedx_learning/apps/authoring/applets/subsections/admin.py similarity index 100% rename from openedx_learning/apps/authoring/subsections/admin.py rename to openedx_learning/apps/authoring/applets/subsections/admin.py diff --git a/openedx_learning/apps/authoring/subsections/api.py b/openedx_learning/apps/authoring/applets/subsections/api.py similarity index 99% rename from openedx_learning/apps/authoring/subsections/api.py rename to openedx_learning/apps/authoring/applets/subsections/api.py index 02c1edf93..97a9e3ff2 100644 --- a/openedx_learning/apps/authoring/subsections/api.py +++ b/openedx_learning/apps/authoring/applets/subsections/api.py @@ -7,7 +7,7 @@ from django.db.transaction import atomic -from openedx_learning.apps.authoring.units.models import Unit, UnitVersion +from ..units.models import Unit, UnitVersion from ..publishing import api as publishing_api from .models import Subsection, SubsectionVersion diff --git a/openedx_learning/apps/authoring/subsections/models.py b/openedx_learning/apps/authoring/applets/subsections/models.py similarity index 100% rename from openedx_learning/apps/authoring/subsections/models.py rename to openedx_learning/apps/authoring/applets/subsections/models.py diff --git a/openedx_learning/apps/authoring/components/management/commands/__init__.py b/openedx_learning/apps/authoring/applets/units/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/components/management/commands/__init__.py rename to openedx_learning/apps/authoring/applets/units/__init__.py diff --git a/openedx_learning/apps/authoring/units/admin.py b/openedx_learning/apps/authoring/applets/units/admin.py similarity index 100% rename from openedx_learning/apps/authoring/units/admin.py rename to openedx_learning/apps/authoring/applets/units/admin.py diff --git a/openedx_learning/apps/authoring/units/api.py b/openedx_learning/apps/authoring/applets/units/api.py similarity index 99% rename from openedx_learning/apps/authoring/units/api.py rename to openedx_learning/apps/authoring/applets/units/api.py index ca9a2468d..779b5b3d0 100644 --- a/openedx_learning/apps/authoring/units/api.py +++ b/openedx_learning/apps/authoring/applets/units/api.py @@ -7,8 +7,7 @@ from django.db.transaction import atomic -from openedx_learning.apps.authoring.components.models import Component, ComponentVersion - +from ..components.models import Component, ComponentVersion from ..publishing import api as publishing_api from .models import Unit, UnitVersion diff --git a/openedx_learning/apps/authoring/units/models.py b/openedx_learning/apps/authoring/applets/units/models.py similarity index 100% rename from openedx_learning/apps/authoring/units/models.py rename to openedx_learning/apps/authoring/applets/units/models.py diff --git a/openedx_learning/apps/authoring/apps.py b/openedx_learning/apps/authoring/apps.py new file mode 100644 index 000000000..911851a6e --- /dev/null +++ b/openedx_learning/apps/authoring/apps.py @@ -0,0 +1,22 @@ +from django.apps import AppConfig + +class AuthoringConfig(AppConfig): + name = "openedx_learning.apps.authoring" + verbose_name = "Learning Core > Authoring" + default_auto_field = "django.db.models.BigAutoField" + label = "oel_authoring" + + def ready(self): + from .api import register_publishable_models + from .models import ( + Component, ComponentVersion, + Container, ContainerVersion, + Section, SectionVersion, + Subsection, SubsectionVersion, + Unit, UnitVersion, + ) + register_publishable_models(Component, ComponentVersion) + register_publishable_models(Container, ContainerVersion) + register_publishable_models(Section, SectionVersion) + register_publishable_models(Subsection, SubsectionVersion) + register_publishable_models(Unit, UnitVersion) diff --git a/openedx_learning/apps/authoring/backup_restore/apps.py b/openedx_learning/apps/authoring/backup_restore/apps.py deleted file mode 100644 index 7aa3f022b..000000000 --- a/openedx_learning/apps/authoring/backup_restore/apps.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -Backup/Restore application initialization. -""" - -from django.apps import AppConfig - - -class BackupRestoreConfig(AppConfig): - name = 'openedx_learning.apps.authoring.backup_restore' - verbose_name = "Learning Core > Authoring > Backup Restore" - default_auto_field = 'django.db.models.BigAutoField' - label = "oel_backup_restore" diff --git a/openedx_learning/apps/authoring/collections/apps.py b/openedx_learning/apps/authoring/collections/apps.py deleted file mode 100644 index b1ca50c49..000000000 --- a/openedx_learning/apps/authoring/collections/apps.py +++ /dev/null @@ -1,15 +0,0 @@ -""" -Django metadata for the Collections Django application. -""" -from django.apps import AppConfig - - -class CollectionsConfig(AppConfig): - """ - Configuration for the Collections Django application. - """ - - name = "openedx_learning.apps.authoring.collections" - verbose_name = "Learning Core > Authoring > Collections" - default_auto_field = "django.db.models.BigAutoField" - label = "oel_collections" diff --git a/openedx_learning/apps/authoring/collections/migrations/0001_initial.py b/openedx_learning/apps/authoring/collections/migrations/0001_initial.py deleted file mode 100644 index 0fdee2734..000000000 --- a/openedx_learning/apps/authoring/collections/migrations/0001_initial.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 4.2.14 on 2024-08-05 20:42 - -import django.db.models.deletion -from django.db import migrations, models - -import openedx_learning.lib.fields - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('oel_publishing', '0002_alter_learningpackage_key_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='Collection', - fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('name', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, db_index=True, help_text='The name of the collection.', max_length=255)), - ('description', openedx_learning.lib.fields.MultiCollationCharField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, help_text='Provides extra information for the user about this collection.', max_length=10000)), - ('enabled', models.BooleanField(default=True, help_text='Whether the collection is enabled or not.')), - ('created', models.DateTimeField(auto_now_add=True)), - ('modified', models.DateTimeField(auto_now=True)), - ('learning_package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_publishing.learningpackage')), - ], - options={ - 'verbose_name_plural': 'Collections', - }, - ), - ] diff --git a/openedx_learning/apps/authoring/collections/migrations/0002_remove_collection_name_collection_created_by_and_more.py b/openedx_learning/apps/authoring/collections/migrations/0002_remove_collection_name_collection_created_by_and_more.py deleted file mode 100644 index eee95e509..000000000 --- a/openedx_learning/apps/authoring/collections/migrations/0002_remove_collection_name_collection_created_by_and_more.py +++ /dev/null @@ -1,53 +0,0 @@ -# Generated by Django 4.2.14 on 2024-08-14 14:20 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - -import openedx_learning.lib.fields -import openedx_learning.lib.validators - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('oel_collections', '0001_initial'), - ] - - operations = [ - migrations.RemoveField( - model_name='collection', - name='name', - ), - migrations.AddField( - model_name='collection', - name='created_by', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='collection', - name='title', - field=openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, default='Collection', help_text='The title of the collection.', max_length=500), - preserve_default=False, - ), - migrations.AlterField( - model_name='collection', - name='created', - field=models.DateTimeField(auto_now_add=True, validators=[openedx_learning.lib.validators.validate_utc_datetime]), - ), - migrations.AlterField( - model_name='collection', - name='description', - field=openedx_learning.lib.fields.MultiCollationTextField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, default='', help_text='Provides extra information for the user about this collection.', max_length=10000), - ), - migrations.AlterField( - model_name='collection', - name='modified', - field=models.DateTimeField(auto_now=True, validators=[openedx_learning.lib.validators.validate_utc_datetime]), - ), - migrations.AddIndex( - model_name='collection', - index=models.Index(fields=['learning_package', 'title'], name='oel_collect_learnin_dfaf89_idx'), - ), - ] diff --git a/openedx_learning/apps/authoring/collections/migrations/0003_collection_entities.py b/openedx_learning/apps/authoring/collections/migrations/0003_collection_entities.py deleted file mode 100644 index 1c5e84055..000000000 --- a/openedx_learning/apps/authoring/collections/migrations/0003_collection_entities.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 4.2.15 on 2024-08-29 00:05 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - -import openedx_learning.lib.validators - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('oel_publishing', '0002_alter_learningpackage_key_and_more'), - ('oel_collections', '0002_remove_collection_name_collection_created_by_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='CollectionPublishableEntity', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created', models.DateTimeField(auto_now_add=True, validators=[openedx_learning.lib.validators.validate_utc_datetime])), - ('collection', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_collections.collection')), - ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ('entity', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_publishing.publishableentity')), - ], - ), - migrations.AddField( - model_name='collection', - name='entities', - field=models.ManyToManyField(related_name='collections', through='oel_collections.CollectionPublishableEntity', to='oel_publishing.publishableentity'), - ), - migrations.AddConstraint( - model_name='collectionpublishableentity', - constraint=models.UniqueConstraint(fields=('collection', 'entity'), name='oel_collections_cpe_uniq_col_ent'), - ), - ] diff --git a/openedx_learning/apps/authoring/collections/migrations/0004_collection_key.py b/openedx_learning/apps/authoring/collections/migrations/0004_collection_key.py deleted file mode 100644 index 843419eec..000000000 --- a/openedx_learning/apps/authoring/collections/migrations/0004_collection_key.py +++ /dev/null @@ -1,57 +0,0 @@ -# Generated by Django 4.2.15 on 2024-09-04 23:15 - -from django.db import migrations, models -from django.utils.crypto import get_random_string - -import openedx_learning.lib.fields - - -def generate_keys(apps, schema_editor): - """ - Generates a random strings to initialize the key field where NULL. - """ - length = 50 - Collection = apps.get_model("oel_collections", "Collection") - for collection in Collection.objects.filter(key=None): - # Keep generating keys until we get a unique one - key = get_random_string(length) - while Collection.objects.filter(key=key).exists(): - key = get_random_string(length) - - collection.key = key - collection.save() - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_collections', '0003_collection_entities'), - ] - - operations = [ - # 1. Temporarily add this field with null=True, blank=True - migrations.AddField( - model_name='collection', - name='key', - field=openedx_learning.lib.fields.MultiCollationCharField( - db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, - db_column='_key', max_length=500, null=True, blank=True), - preserve_default=False, - ), - # 2. Populate the null keys - migrations.RunPython(generate_keys), - # 3. Add null=False, blank=False to disallow NULL values - migrations.AlterField( - model_name='collection', - name='key', - field=openedx_learning.lib.fields.MultiCollationCharField( - db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, - db_column='_key', max_length=500, null=False, blank=False), - preserve_default=False, - ), - # 4. Enforce unique constraint - migrations.AddConstraint( - model_name='collection', - constraint=models.UniqueConstraint(fields=('learning_package', 'key'), name='oel_coll_uniq_lp_key'), - ), - ] diff --git a/openedx_learning/apps/authoring/collections/migrations/0005_alter_collection_options_alter_collection_enabled.py b/openedx_learning/apps/authoring/collections/migrations/0005_alter_collection_options_alter_collection_enabled.py deleted file mode 100644 index 17405dac6..000000000 --- a/openedx_learning/apps/authoring/collections/migrations/0005_alter_collection_options_alter_collection_enabled.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.15 on 2024-09-24 07:31 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_collections', '0004_collection_key'), - ] - - operations = [ - migrations.AlterField( - model_name='collection', - name='enabled', - field=models.BooleanField(default=True, help_text='Disabled collections are "soft deleted", and should be re-enabled before use, or be deleted.'), - ), - ] diff --git a/openedx_learning/apps/authoring/components/apps.py b/openedx_learning/apps/authoring/components/apps.py deleted file mode 100644 index 591e60f6c..000000000 --- a/openedx_learning/apps/authoring/components/apps.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -Django metadata for the Components Django application. -""" -from django.apps import AppConfig - - -class ComponentsConfig(AppConfig): - """ - Configuration for the Components Django application. - """ - - name = "openedx_learning.apps.authoring.components" - verbose_name = "Learning Core > Authoring > Components" - default_auto_field = "django.db.models.BigAutoField" - label = "oel_components" - - def ready(self) -> None: - """ - Register Component and ComponentVersion. - """ - from ..publishing.api import register_publishable_models # pylint: disable=import-outside-toplevel - from .models import Component, ComponentVersion # pylint: disable=import-outside-toplevel - - register_publishable_models(Component, ComponentVersion) diff --git a/openedx_learning/apps/authoring/components/migrations/0001_initial.py b/openedx_learning/apps/authoring/components/migrations/0001_initial.py deleted file mode 100644 index ece93796e..000000000 --- a/openedx_learning/apps/authoring/components/migrations/0001_initial.py +++ /dev/null @@ -1,97 +0,0 @@ -# Generated by Django 3.2.23 on 2024-02-06 03:23 - -import uuid - -import django.db.models.deletion -from django.db import migrations, models - -import openedx_learning.lib.fields - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('oel_contents', '0001_initial'), - ('oel_publishing', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='Component', - fields=[ - ('publishable_entity', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='oel_publishing.publishableentity')), - ('local_key', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, max_length=500)), - ], - options={ - 'verbose_name': 'Component', - 'verbose_name_plural': 'Components', - }, - ), - migrations.CreateModel( - name='ComponentType', - fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('namespace', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, max_length=100)), - ('name', openedx_learning.lib.fields.MultiCollationCharField(blank=True, db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, max_length=100)), - ], - ), - migrations.CreateModel( - name='ComponentVersion', - fields=[ - ('publishable_entity_version', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='oel_publishing.publishableentityversion')), - ('component', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='versions', to='oel_components.component')), - ], - options={ - 'verbose_name': 'Component Version', - 'verbose_name_plural': 'Component Versions', - }, - ), - migrations.CreateModel( - name='ComponentVersionContent', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')), - ('key', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, max_length=500)), - ('learner_downloadable', models.BooleanField(default=False)), - ('component_version', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_components.componentversion')), - ('content', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_contents.content')), - ], - ), - migrations.AddField( - model_name='componentversion', - name='contents', - field=models.ManyToManyField(related_name='component_versions', through='oel_components.ComponentVersionContent', to='oel_contents.Content'), - ), - migrations.AddField( - model_name='component', - name='component_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='oel_components.componenttype'), - ), - migrations.AddField( - model_name='component', - name='learning_package', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_publishing.learningpackage'), - ), - migrations.AddIndex( - model_name='componentversioncontent', - index=models.Index(fields=['content', 'component_version'], name='oel_cvcontent_c_cv'), - ), - migrations.AddIndex( - model_name='componentversioncontent', - index=models.Index(fields=['component_version', 'content'], name='oel_cvcontent_cv_d'), - ), - migrations.AddConstraint( - model_name='componentversioncontent', - constraint=models.UniqueConstraint(fields=('component_version', 'key'), name='oel_cvcontent_uniq_cv_key'), - ), - migrations.AddIndex( - model_name='component', - index=models.Index(fields=['component_type', 'local_key'], name='oel_component_idx_ct_lk'), - ), - migrations.AddConstraint( - model_name='component', - constraint=models.UniqueConstraint(fields=('learning_package', 'component_type', 'local_key'), name='oel_component_uniq_lc_ct_lk'), - ), - ] diff --git a/openedx_learning/apps/authoring/components/migrations/0002_alter_componentversioncontent_key.py b/openedx_learning/apps/authoring/components/migrations/0002_alter_componentversioncontent_key.py deleted file mode 100644 index ee12970d2..000000000 --- a/openedx_learning/apps/authoring/components/migrations/0002_alter_componentversioncontent_key.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2.10 on 2024-02-14 22:02 - -from django.db import migrations - -import openedx_learning.lib.fields - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_components', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='componentversioncontent', - name='key', - field=openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, db_column='_key', max_length=500), - ), - ] diff --git a/openedx_learning/apps/authoring/components/migrations/0003_remove_componentversioncontent_learner_downloadable.py b/openedx_learning/apps/authoring/components/migrations/0003_remove_componentversioncontent_learner_downloadable.py deleted file mode 100644 index 4ae618b77..000000000 --- a/openedx_learning/apps/authoring/components/migrations/0003_remove_componentversioncontent_learner_downloadable.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.16 on 2024-11-06 17:14 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_components', '0002_alter_componentversioncontent_key'), - ] - - operations = [ - migrations.RemoveField( - model_name='componentversioncontent', - name='learner_downloadable', - ), - ] diff --git a/openedx_learning/apps/authoring/components/migrations/0004_remove_componentversioncontent_uuid.py b/openedx_learning/apps/authoring/components/migrations/0004_remove_componentversioncontent_uuid.py deleted file mode 100644 index 5005aa4ec..000000000 --- a/openedx_learning/apps/authoring/components/migrations/0004_remove_componentversioncontent_uuid.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.23 on 2025-10-02 14:00 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_components', '0003_remove_componentversioncontent_learner_downloadable'), - ] - - operations = [ - migrations.RemoveField( - model_name='componentversioncontent', - name='uuid', - ), - ] diff --git a/openedx_learning/apps/authoring/contents/apps.py b/openedx_learning/apps/authoring/contents/apps.py deleted file mode 100644 index 3c23bd4f5..000000000 --- a/openedx_learning/apps/authoring/contents/apps.py +++ /dev/null @@ -1,15 +0,0 @@ -""" -Django metadata for the Contents Django application. -""" -from django.apps import AppConfig - - -class ContentsConfig(AppConfig): - """ - Configuration for the Contents Django application. - """ - - name = "openedx_learning.apps.authoring.contents" - verbose_name = "Learning Core > Authoring > Contents" - default_auto_field = "django.db.models.BigAutoField" - label = "oel_contents" diff --git a/openedx_learning/apps/authoring/contents/migrations/0001_initial.py b/openedx_learning/apps/authoring/contents/migrations/0001_initial.py deleted file mode 100644 index 1abf65adf..000000000 --- a/openedx_learning/apps/authoring/contents/migrations/0001_initial.py +++ /dev/null @@ -1,66 +0,0 @@ -# Generated by Django 3.2.23 on 2024-02-06 03:23 - -import django.core.validators -import django.db.models.deletion -from django.db import migrations, models - -import openedx_learning.lib.fields -import openedx_learning.lib.validators - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('oel_publishing', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='Content', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('size', models.PositiveBigIntegerField(validators=[django.core.validators.MaxValueValidator(50000000)])), - ('hash_digest', models.CharField(editable=False, max_length=40)), - ('has_file', models.BooleanField()), - ('text', openedx_learning.lib.fields.MultiCollationTextField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, max_length=50000, null=True)), - ('created', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), - ], - options={ - 'verbose_name': 'Content', - 'verbose_name_plural': 'Contents', - }, - ), - migrations.CreateModel( - name='MediaType', - fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('type', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, max_length=127)), - ('sub_type', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, max_length=127)), - ('suffix', openedx_learning.lib.fields.MultiCollationCharField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, max_length=127)), - ], - ), - migrations.AddConstraint( - model_name='mediatype', - constraint=models.UniqueConstraint(fields=('type', 'sub_type', 'suffix'), name='oel_contents_uniq_t_st_sfx'), - ), - migrations.AddField( - model_name='content', - name='learning_package', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_publishing.learningpackage'), - ), - migrations.AddField( - model_name='content', - name='media_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='oel_contents.mediatype'), - ), - migrations.AddIndex( - model_name='content', - index=models.Index(fields=['learning_package', '-size'], name='oel_content_idx_lp_rsize'), - ), - migrations.AddConstraint( - model_name='content', - constraint=models.UniqueConstraint(fields=('learning_package', 'media_type', 'hash_digest'), name='oel_content_uniq_lc_media_type_hash_digest'), - ), - ] diff --git a/openedx_learning/apps/authoring/components/migrations/__init__.py b/openedx_learning/apps/authoring/management/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/components/migrations/__init__.py rename to openedx_learning/apps/authoring/management/__init__.py diff --git a/openedx_learning/apps/authoring/contents/__init__.py b/openedx_learning/apps/authoring/management/commands/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/contents/__init__.py rename to openedx_learning/apps/authoring/management/commands/__init__.py diff --git a/openedx_learning/apps/authoring/components/management/commands/add_assets_to_component.py b/openedx_learning/apps/authoring/management/commands/add_assets_to_component.py similarity index 100% rename from openedx_learning/apps/authoring/components/management/commands/add_assets_to_component.py rename to openedx_learning/apps/authoring/management/commands/add_assets_to_component.py diff --git a/openedx_learning/apps/authoring/backup_restore/management/commands/lp_dump.py b/openedx_learning/apps/authoring/management/commands/lp_dump.py similarity index 93% rename from openedx_learning/apps/authoring/backup_restore/management/commands/lp_dump.py rename to openedx_learning/apps/authoring/management/commands/lp_dump.py index b1fb52b4e..de6a158c9 100644 --- a/openedx_learning/apps/authoring/backup_restore/management/commands/lp_dump.py +++ b/openedx_learning/apps/authoring/management/commands/lp_dump.py @@ -8,8 +8,8 @@ from django.core.management import CommandError from django.core.management.base import BaseCommand -from openedx_learning.apps.authoring.backup_restore.api import create_zip_file -from openedx_learning.apps.authoring.publishing.api import LearningPackage +from openedx_learning.apps.authoring.applets.backup_restore.api import create_zip_file +from openedx_learning.apps.authoring.applets.publishing.api import LearningPackage logger = logging.getLogger(__name__) diff --git a/openedx_learning/apps/authoring/backup_restore/management/commands/lp_load.py b/openedx_learning/apps/authoring/management/commands/lp_load.py similarity index 95% rename from openedx_learning/apps/authoring/backup_restore/management/commands/lp_load.py rename to openedx_learning/apps/authoring/management/commands/lp_load.py index a326a0850..18084f73a 100644 --- a/openedx_learning/apps/authoring/backup_restore/management/commands/lp_load.py +++ b/openedx_learning/apps/authoring/management/commands/lp_load.py @@ -8,7 +8,7 @@ from django.core.management import CommandError from django.core.management.base import BaseCommand -from openedx_learning.apps.authoring.backup_restore.api import load_learning_package +from openedx_learning.apps.authoring.applets.backup_restore.api import load_learning_package logger = logging.getLogger(__name__) diff --git a/openedx_learning/apps/authoring/migrations/0001_initial.py b/openedx_learning/apps/authoring/migrations/0001_initial.py new file mode 100644 index 000000000..844908fd6 --- /dev/null +++ b/openedx_learning/apps/authoring/migrations/0001_initial.py @@ -0,0 +1,696 @@ +""" +This migration has two modes it needs to run in: + +1. Existing installs that have migration data that is current through 0.30.2 + (bundled with the Teak release). +2. New installs. +""" +import uuid + +import django.core.validators +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models +from django.db.migrations.operations.special import SeparateDatabaseAndState +from django.db.migrations.recorder import MigrationRecorder + +import openedx_learning.lib.fields +import openedx_learning.lib.validators + +class BootstrapMigrations(SeparateDatabaseAndState): + + def __init__(self, operations): + return super().__init__(database_operations=operations, state_operations=operations) + + def has_teak_release_tables(self): + """ + There are three possible outcomes: + + 1. The database we want to run this migration on already has migrations + for the smaller apps that the "authoring" is subsuming: Return True. + 2. The database has no migrations of those earlier apps: Return False. + 3. The database has *some* but not all of the migrations we expect: + Raise an error. This can happen if someone tries to upgrade and skips + the Teak release, e.g. Sumac -> Verawood directly. + """ + expected_migrations = { + "oel_collections": "0005_alter_collection_options_alter_collection_enabled", + "oel_components": "0004_remove_componentversioncontent_uuid", + "oel_contents": "0001_initial", + "oel_publishing": "0010_backfill_dependencies", + "oel_sections": "0001_initial", + "oel_subsections": "0001_initial", + "oel_units": "0001_initial", + } + if all( + MigrationRecorder.Migration.objects.filter(app=app, name=name).exists() + for app, name in expected_migrations.items() + ): + return True + + if MigrationRecorder.Migration.objects.filter(app="oel_publishing").exists(): + raise RuntimeError( + "Migration could not be run because database is in a pre-Teak " + "state. Please upgrade to Teak (openedx_learning==0.30.2) " + "before running this migration." + ) + + return False + + def database_forwards(self, app_label, schema_editor, from_state, to_state): + if self.has_teak_release_tables(): + return + return super().database_forwards(app_label, schema_editor, from_state, to_state) + + def database_backwards(self, app_label, schema_editor, from_state, to_state): + if self.has_teak_release_tables(): + return + return super().database_backwards(app_label, schema_editor, from_state, to_state) + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + BootstrapMigrations( + [ + migrations.CreateModel( + name='PublishableEntity', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')), + ('key', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, db_column='_key', max_length=500)), + ('created', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), + ('can_stand_alone', models.BooleanField(default=True, help_text='Set to True when created independently, False when created as part of a container.')), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Publishable Entity', + 'verbose_name_plural': 'Publishable Entities', + 'db_table': 'oel_publishing_publishableentity', + }, + ), + migrations.CreateModel( + name='ComponentType', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('namespace', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, max_length=100)), + ('name', openedx_learning.lib.fields.MultiCollationCharField(blank=True, db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, max_length=100)), + ], + options={ + 'db_table': 'oel_components_componenttype', + }, + ), + migrations.CreateModel( + name='PublishableEntityVersion', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')), + ('title', openedx_learning.lib.fields.MultiCollationCharField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, default='', max_length=500)), + ('version_num', models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1)])), + ('created', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ('entity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='versions', to='oel_authoring.publishableentity')), + ], + options={ + 'verbose_name': 'Publishable Entity Version', + 'verbose_name_plural': 'Publishable Entity Versions', + 'db_table': 'oel_publishing_publishableentityversion', + }, + ), + migrations.CreateModel( + name='Content', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('size', models.PositiveBigIntegerField(validators=[django.core.validators.MaxValueValidator(50000000)])), + ('hash_digest', models.CharField(editable=False, max_length=40)), + ('has_file', models.BooleanField()), + ('text', openedx_learning.lib.fields.MultiCollationTextField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, max_length=50000, null=True)), + ('created', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), + ], + options={ + 'verbose_name': 'Content', + 'verbose_name_plural': 'Contents', + 'db_table': 'oel_contents_content', + }, + ), + migrations.CreateModel( + name='EntityList', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + options={ + 'db_table': 'oel_publishing_entitylist', + }, + ), + migrations.CreateModel( + name='LearningPackage', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')), + ('key', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, db_column='_key', max_length=500)), + ('title', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, max_length=500)), + ('description', openedx_learning.lib.fields.MultiCollationTextField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, default='', max_length=10000)), + ('created', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), + ('updated', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), + ], + options={ + 'verbose_name': 'Learning Package', + 'verbose_name_plural': 'Learning Packages', + 'db_table': 'oel_publishing_learningpackage', + }, + ), + migrations.CreateModel( + name='MediaType', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('type', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, max_length=127)), + ('sub_type', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, max_length=127)), + ('suffix', openedx_learning.lib.fields.MultiCollationCharField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, max_length=127)), + ], + options={ + 'db_table': "oel_contents_mediatype", + }, + ), + migrations.CreateModel( + name='PublishableEntityVersionDependency', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + options={ + 'db_table': 'oel_publishing_publishableentityversiondependency', + }, + ), + migrations.CreateModel( + name='PublishLog', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')), + ('message', openedx_learning.lib.fields.MultiCollationCharField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, default='', max_length=500)), + ('published_at', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), + ], + options={ + 'verbose_name': 'Publish Log', + 'verbose_name_plural': 'Publish Logs', + 'db_table': 'oel_publishing_publishlog', + }, + ), + migrations.CreateModel( + name='PublishLogRecord', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('dependencies_hash_digest', models.CharField(blank=True, default='', editable=False, max_length=8)), + ], + options={ + 'verbose_name': 'Publish Log Record', + 'verbose_name_plural': 'Publish Log Records', + 'db_table': 'oel_publishing_publishlogrecord', + }, + ), + migrations.CreateModel( + name='PublishSideEffect', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + options={ + 'verbose_name': 'Publish Side Effect', + 'verbose_name_plural': 'Publish Side Effects', + 'db_table': 'oel_publishing_publishsideeffect', + }, + ), + migrations.CreateModel( + name='Collection', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('key', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, db_column='_key', max_length=500)), + ('title', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, help_text='The title of the collection.', max_length=500)), + ('description', openedx_learning.lib.fields.MultiCollationTextField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, default='', help_text='Provides extra information for the user about this collection.', max_length=10000)), + ('enabled', models.BooleanField(default=True, help_text='Disabled collections are "soft deleted", and should be re-enabled before use, or be deleted.')), + ('created', models.DateTimeField(auto_now_add=True, validators=[openedx_learning.lib.validators.validate_utc_datetime])), + ('modified', models.DateTimeField(auto_now=True, validators=[openedx_learning.lib.validators.validate_utc_datetime])), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name_plural': 'Collections', + 'db_table': 'oel_collections_collection', + }, + ), + migrations.CreateModel( + name='Component', + fields=[ + ('publishable_entity', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='oel_authoring.publishableentity')), + ('local_key', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, max_length=500)), + ], + options={ + 'verbose_name': 'Component', + 'verbose_name_plural': 'Components', + 'db_table': 'oel_components_component', + }, + ), + migrations.CreateModel( + name='Container', + fields=[ + ('publishable_entity', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='oel_authoring.publishableentity')), + ], + options={ + 'db_table': 'oel_publishing_container', + }, + ), + migrations.CreateModel( + name='Draft', + fields=[ + ('entity', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='oel_authoring.publishableentity')), + ], + options={ + 'db_table': 'oel_publishing_draft', + }, + ), + migrations.CreateModel( + name='Published', + fields=[ + ('entity', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='oel_authoring.publishableentity')), + ], + options={ + 'verbose_name': 'Published Entity', + 'verbose_name_plural': 'Published Entities', + 'db_table': 'oel_publishing_published', + }, + ), + migrations.CreateModel( + name='CollectionPublishableEntity', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(auto_now_add=True, validators=[openedx_learning.lib.validators.validate_utc_datetime])), + ('collection', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_authoring.collection')), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ('entity', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_authoring.publishableentity')), + ], + options={ + 'db_table': 'oel_collections_collectionpublishableentity', + }, + ), + migrations.AddField( + model_name='collection', + name='entities', + field=models.ManyToManyField(related_name='collections', through='oel_authoring.CollectionPublishableEntity', to='oel_authoring.publishableentity'), + ), + migrations.CreateModel( + name='ComponentVersion', + fields=[ + ('publishable_entity_version', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='oel_authoring.publishableentityversion')), + ], + options={ + 'verbose_name': 'Component Version', + 'verbose_name_plural': 'Component Versions', + 'db_table': 'oel_components_componentversion', + }, + ), + migrations.CreateModel( + name='ContainerVersion', + fields=[ + ('publishable_entity_version', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='oel_authoring.publishableentityversion')), + ], + options={ + 'db_table': 'oel_publishing_containerversion', + }, + ), + migrations.CreateModel( + name='ComponentVersionContent', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('key', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, db_column='_key', max_length=500)), + ('content', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_authoring.content')), + ], + options={ + 'db_table': 'oel_components_componentversioncontent', + }, + ), + migrations.CreateModel( + name='DraftChangeLog', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')), + ('changed_at', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), + ('changed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Draft Change Log', + 'verbose_name_plural': 'Draft Change Logs', + 'db_table': 'oel_publishing_draftchangelog', + }, + ), + migrations.CreateModel( + name='DraftChangeLogRecord', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('dependencies_hash_digest', models.CharField(blank=True, default='', editable=False, max_length=8)), + ('draft_change_log', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='records', to='oel_authoring.draftchangelog')), + ('entity', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_authoring.publishableentity')), + ('new_version', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.RESTRICT, to='oel_authoring.publishableentityversion')), + ('old_version', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.RESTRICT, related_name='+', to='oel_authoring.publishableentityversion')), + ], + options={ + 'verbose_name': 'Draft Change Log Record', + 'verbose_name_plural': 'Draft Change Log Records', + 'db_table': 'oel_publishing_draftchangelogrecord', + }, + ), + migrations.CreateModel( + name='DraftSideEffect', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('cause', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='causes', to='oel_authoring.draftchangelogrecord')), + ('effect', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='affected_by', to='oel_authoring.draftchangelogrecord')), + ], + options={ + 'verbose_name': 'Draft Side Effect', + 'verbose_name_plural': 'Draft Side Effects', + 'db_table': 'oel_publishing_draftsideeffect', + }, + ), + migrations.CreateModel( + name='EntityListRow', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('order_num', models.PositiveIntegerField()), + ('entity', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_authoring.publishableentity')), + ('entity_list', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_authoring.entitylist')), + ('entity_version', models.ForeignKey(null=True, on_delete=django.db.models.deletion.RESTRICT, related_name='+', to='oel_authoring.publishableentityversion')), + ], + options={ + 'db_table': 'oel_publishing_entitylistrow', + 'ordering': ['order_num'], + }, + ), + migrations.AddField( + model_name='publishableentity', + name='learning_package', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='publishable_entities', to='oel_authoring.learningpackage'), + ), + migrations.AddConstraint( + model_name='learningpackage', + constraint=models.UniqueConstraint(fields=('key',), name='oel_publishing_lp_uniq_key'), + ), + migrations.AddField( + model_name='draftchangelog', + name='learning_package', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_authoring.learningpackage'), + ), + migrations.AddField( + model_name='content', + name='learning_package', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_authoring.learningpackage'), + ), + migrations.AddField( + model_name='collection', + name='learning_package', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_authoring.learningpackage'), + ), + migrations.AddConstraint( + model_name='mediatype', + constraint=models.UniqueConstraint(fields=('type', 'sub_type', 'suffix'), name='oel_contents_uniq_t_st_sfx'), + ), + migrations.AddField( + model_name='content', + name='media_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='oel_authoring.mediatype'), + ), + migrations.AddField( + model_name='publishableentityversiondependency', + name='referenced_entity', + field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_authoring.publishableentity'), + ), + migrations.AddField( + model_name='publishableentityversiondependency', + name='referring_version', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_authoring.publishableentityversion'), + ), + migrations.AddField( + model_name='publishableentityversion', + name='dependencies', + field=models.ManyToManyField(related_name='affects', through='oel_authoring.PublishableEntityVersionDependency', to='oel_authoring.publishableentity'), + ), + migrations.AddField( + model_name='publishlog', + name='learning_package', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_authoring.learningpackage'), + ), + migrations.AddField( + model_name='publishlog', + name='published_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='publishlogrecord', + name='entity', + field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_authoring.publishableentity'), + ), + migrations.AddField( + model_name='publishlogrecord', + name='new_version', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.RESTRICT, to='oel_authoring.publishableentityversion'), + ), + migrations.AddField( + model_name='publishlogrecord', + name='old_version', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.RESTRICT, related_name='+', to='oel_authoring.publishableentityversion'), + ), + migrations.AddField( + model_name='publishlogrecord', + name='publish_log', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='records', to='oel_authoring.publishlog'), + ), + migrations.AddField( + model_name='publishsideeffect', + name='cause', + field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='causes', to='oel_authoring.publishlogrecord'), + ), + migrations.AddField( + model_name='publishsideeffect', + name='effect', + field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='affected_by', to='oel_authoring.publishlogrecord'), + ), + migrations.AddField( + model_name='component', + name='component_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='oel_authoring.componenttype'), + ), + migrations.AddField( + model_name='component', + name='learning_package', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_authoring.learningpackage'), + ), + migrations.CreateModel( + name='Section', + fields=[ + ('container', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_authoring.container')), + ], + options={ + 'abstract': False, + 'db_table': "oel_sections_section", + }, + bases=('oel_authoring.container',), + ), + migrations.CreateModel( + name='Subsection', + fields=[ + ('container', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_authoring.container')), + ], + options={ + 'abstract': False, + 'db_table': "oel_subsections_subsection", + }, + bases=('oel_authoring.container',), + ), + migrations.CreateModel( + name='Unit', + fields=[ + ('container', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_authoring.container')), + ], + options={ + 'abstract': False, + 'db_table': "oel_units_unit", + }, + bases=('oel_authoring.container',), + ), + migrations.AddField( + model_name='draft', + name='draft_log_record', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='oel_authoring.draftchangelogrecord'), + ), + migrations.AddField( + model_name='draft', + name='version', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.RESTRICT, to='oel_authoring.publishableentityversion'), + ), + migrations.AddField( + model_name='published', + name='publish_log_record', + field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_authoring.publishlogrecord'), + ), + migrations.AddField( + model_name='published', + name='version', + field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.RESTRICT, to='oel_authoring.publishableentityversion'), + ), + migrations.AddConstraint( + model_name='collectionpublishableentity', + constraint=models.UniqueConstraint(fields=('collection', 'entity'), name='oel_collections_cpe_uniq_col_ent'), + ), + migrations.AddField( + model_name='componentversioncontent', + name='component_version', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_authoring.componentversion'), + ), + migrations.AddField( + model_name='componentversion', + name='component', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='versions', to='oel_authoring.component'), + ), + migrations.AddField( + model_name='componentversion', + name='contents', + field=models.ManyToManyField(related_name='component_versions', through='oel_authoring.ComponentVersionContent', to='oel_authoring.content'), + ), + migrations.CreateModel( + name='SectionVersion', + fields=[ + ('container_version', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_authoring.containerversion')), + ], + options={ + 'abstract': False, + 'db_table': 'oel_sections_sectionversion', + }, + bases=('oel_authoring.containerversion',), + ), + migrations.CreateModel( + name='SubsectionVersion', + fields=[ + ('container_version', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_authoring.containerversion')), + ], + options={ + 'abstract': False, + 'db_table': 'oel_subsections_subsectionversion', + }, + bases=('oel_authoring.containerversion',), + ), + migrations.CreateModel( + name='UnitVersion', + fields=[ + ('container_version', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_authoring.containerversion')), + ], + options={ + 'abstract': False, + 'db_table': 'oel_units_unitversion', + }, + bases=('oel_authoring.containerversion',), + ), + migrations.AddField( + model_name='containerversion', + name='container', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='versions', to='oel_authoring.container'), + ), + migrations.AddField( + model_name='containerversion', + name='entity_list', + field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='container_versions', to='oel_authoring.entitylist'), + ), + migrations.AddIndex( + model_name='draftchangelogrecord', + index=models.Index(fields=['entity', '-draft_change_log'], name='oel_dlr_idx_entity_rdcl'), + ), + migrations.AddConstraint( + model_name='draftchangelogrecord', + constraint=models.UniqueConstraint(fields=('draft_change_log', 'entity'), name='oel_dlr_uniq_dcl'), + ), + migrations.AddConstraint( + model_name='draftsideeffect', + constraint=models.UniqueConstraint(fields=('cause', 'effect'), name='oel_pub_dse_uniq_c_e'), + ), + migrations.AddConstraint( + model_name='entitylistrow', + constraint=models.UniqueConstraint(fields=('entity_list', 'order_num'), name='oel_publishing_elist_row_order'), + ), + migrations.AddIndex( + model_name='publishableentity', + index=models.Index(fields=['key'], name='oel_pub_ent_idx_key'), + ), + migrations.AddIndex( + model_name='publishableentity', + index=models.Index(fields=['learning_package', '-created'], name='oel_pub_ent_idx_lp_rcreated'), + ), + migrations.AddConstraint( + model_name='publishableentity', + constraint=models.UniqueConstraint(fields=('learning_package', 'key'), name='oel_pub_ent_uniq_lp_key'), + ), + migrations.AddIndex( + model_name='collection', + index=models.Index(fields=['learning_package', 'title'], name='oel_collect_learnin_dfaf89_idx'), + ), + migrations.AddConstraint( + model_name='collection', + constraint=models.UniqueConstraint(fields=('learning_package', 'key'), name='oel_coll_uniq_lp_key'), + ), + migrations.AddIndex( + model_name='content', + index=models.Index(fields=['learning_package', '-size'], name='oel_content_idx_lp_rsize'), + ), + migrations.AddConstraint( + model_name='content', + constraint=models.UniqueConstraint(fields=('learning_package', 'media_type', 'hash_digest'), name='oel_content_uniq_lc_media_type_hash_digest'), + ), + migrations.AddConstraint( + model_name='publishableentityversiondependency', + constraint=models.UniqueConstraint(fields=('referring_version', 'referenced_entity'), name='oel_pevd_uniq_rv_re'), + ), + migrations.AddIndex( + model_name='publishableentityversion', + index=models.Index(fields=['entity', '-created'], name='oel_pv_idx_entity_rcreated'), + ), + migrations.AddIndex( + model_name='publishableentityversion', + index=models.Index(fields=['title'], name='oel_pv_idx_title'), + ), + migrations.AddConstraint( + model_name='publishableentityversion', + constraint=models.UniqueConstraint(fields=('entity', 'version_num'), name='oel_pv_uniq_entity_version_num'), + ), + migrations.AddIndex( + model_name='publishlogrecord', + index=models.Index(fields=['entity', '-publish_log'], name='oel_plr_idx_entity_rplr'), + ), + migrations.AddConstraint( + model_name='publishlogrecord', + constraint=models.UniqueConstraint(fields=('publish_log', 'entity'), name='oel_plr_uniq_pl_publishable'), + ), + migrations.AddConstraint( + model_name='publishsideeffect', + constraint=models.UniqueConstraint(fields=('cause', 'effect'), name='oel_pub_pse_uniq_c_e'), + ), + migrations.AddIndex( + model_name='component', + index=models.Index(fields=['component_type', 'local_key'], name='oel_component_idx_ct_lk'), + ), + migrations.AddConstraint( + model_name='component', + constraint=models.UniqueConstraint(fields=('learning_package', 'component_type', 'local_key'), name='oel_component_uniq_lc_ct_lk'), + ), + migrations.AddIndex( + model_name='componentversioncontent', + index=models.Index(fields=['content', 'component_version'], name='oel_cvcontent_c_cv'), + ), + migrations.AddIndex( + model_name='componentversioncontent', + index=models.Index(fields=['component_version', 'content'], name='oel_cvcontent_cv_d'), + ), + migrations.AddConstraint( + model_name='componentversioncontent', + constraint=models.UniqueConstraint(fields=('component_version', 'key'), name='oel_cvcontent_uniq_cv_key'), + ), + ] + ) + ] diff --git a/openedx_learning/apps/authoring/migrations/0002_rename_tables_to_oel_authoring.py b/openedx_learning/apps/authoring/migrations/0002_rename_tables_to_oel_authoring.py new file mode 100644 index 000000000..17cee6d25 --- /dev/null +++ b/openedx_learning/apps/authoring/migrations/0002_rename_tables_to_oel_authoring.py @@ -0,0 +1,138 @@ +# Generated by Django 5.2.9 on 2025-12-29 07:07 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('oel_authoring', '0001_initial'), + ] + + operations = [ + migrations.RenameIndex( + model_name='collection', + new_name='oel_authoring_coll_lp_title', + old_name='oel_collect_learnin_dfaf89_idx', + ), + migrations.AlterModelTable( + name='collection', + table=None, + ), + migrations.AlterModelTable( + name='collectionpublishableentity', + table=None, + ), + migrations.AlterModelTable( + name='content', + table=None, + ), + migrations.AlterModelTable( + name='component', + table=None, + ), + migrations.AlterModelTable( + name='componenttype', + table=None, + ), + migrations.AlterModelTable( + name='componentversion', + table=None, + ), + migrations.AlterModelTable( + name='componentversioncontent', + table=None, + ), + migrations.AlterModelTable( + name='container', + table=None, + ), + migrations.AlterModelTable( + name='containerversion', + table=None, + ), + migrations.AlterModelTable( + name='draft', + table=None, + ), + migrations.AlterModelTable( + name='draftchangelog', + table=None, + ), + migrations.AlterModelTable( + name='draftchangelogrecord', + table=None, + ), + migrations.AlterModelTable( + name='draftsideeffect', + table=None, + ), + migrations.AlterModelTable( + name='entitylist', + table=None, + ), + migrations.AlterModelTable( + name='entitylistrow', + table=None, + ), + migrations.AlterModelTable( + name='learningpackage', + table=None, + ), + migrations.AlterModelTable( + name='mediatype', + table=None, + ), + migrations.AlterModelTable( + name='publishableentity', + table=None, + ), + migrations.AlterModelTable( + name='publishableentityversion', + table=None, + ), + migrations.AlterModelTable( + name='publishableentityversiondependency', + table=None, + ), + migrations.AlterModelTable( + name='published', + table=None, + ), + migrations.AlterModelTable( + name='publishlog', + table=None, + ), + migrations.AlterModelTable( + name='publishlogrecord', + table=None, + ), + migrations.AlterModelTable( + name='publishsideeffect', + table=None, + ), + migrations.AlterModelTable( + name='section', + table=None, + ), + migrations.AlterModelTable( + name='sectionversion', + table=None, + ), + migrations.AlterModelTable( + name='subsection', + table=None, + ), + migrations.AlterModelTable( + name='subsectionversion', + table=None, + ), + migrations.AlterModelTable( + name='unit', + table=None, + ), + migrations.AlterModelTable( + name='unitversion', + table=None, + ), + ] diff --git a/openedx_learning/apps/authoring/contents/migrations/__init__.py b/openedx_learning/apps/authoring/migrations/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/contents/migrations/__init__.py rename to openedx_learning/apps/authoring/migrations/__init__.py diff --git a/openedx_learning/apps/authoring/models.py b/openedx_learning/apps/authoring/models.py new file mode 100644 index 000000000..bffc8f87a --- /dev/null +++ b/openedx_learning/apps/authoring/models.py @@ -0,0 +1,12 @@ +from .applets.backup_restore.models import * +from .applets.collections.models import * +from .applets.components.models import * +from .applets.contents.models import * +from .applets.publishing.models import * +from .applets.sections.models import * +from .applets.subsections.models import * +from .applets.units.models import * + +# from openedx_learning.lib import appletslib + +# globals().update(appletslib.auto_import_models()) diff --git a/openedx_learning/apps/authoring/publishing/apps.py b/openedx_learning/apps/authoring/publishing/apps.py deleted file mode 100644 index d3aefd8a6..000000000 --- a/openedx_learning/apps/authoring/publishing/apps.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -publishing Django application initialization. -""" - -from django.apps import AppConfig - - -class PublishingConfig(AppConfig): - """ - Configuration for the publishing Django application. - """ - - name = "openedx_learning.apps.authoring.publishing" - verbose_name = "Learning Core > Authoring > Publishing" - default_auto_field = "django.db.models.BigAutoField" - label = "oel_publishing" - - def ready(self): - """ - Register Container and ContainerVersion. - """ - from .api import register_publishable_models # pylint: disable=import-outside-toplevel - from .models import Container, ContainerVersion # pylint: disable=import-outside-toplevel - - register_publishable_models(Container, ContainerVersion) diff --git a/openedx_learning/apps/authoring/publishing/migrations/0001_initial.py b/openedx_learning/apps/authoring/publishing/migrations/0001_initial.py deleted file mode 100644 index 6ffb8b857..000000000 --- a/openedx_learning/apps/authoring/publishing/migrations/0001_initial.py +++ /dev/null @@ -1,166 +0,0 @@ -# Generated by Django 3.2.23 on 2024-02-06 00:36 - -import uuid - -import django.core.validators -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - -import openedx_learning.lib.fields -import openedx_learning.lib.validators - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='LearningPackage', - fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')), - ('key', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, max_length=500)), - ('title', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, max_length=500)), - ('description', openedx_learning.lib.fields.MultiCollationTextField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, default='', max_length=10000)), - ('created', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), - ('updated', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), - ], - options={ - 'verbose_name': 'Learning Package', - 'verbose_name_plural': 'Learning Packages', - }, - ), - migrations.CreateModel( - name='PublishableEntity', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')), - ('key', openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, max_length=500)), - ('created', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), - ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ('learning_package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='publishable_entities', to='oel_publishing.learningpackage')), - ], - options={ - 'verbose_name': 'Publishable Entity', - 'verbose_name_plural': 'Publishable Entities', - }, - ), - migrations.CreateModel( - name='PublishableEntityVersion', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')), - ('title', openedx_learning.lib.fields.MultiCollationCharField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, default='', max_length=500)), - ('version_num', models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1)])), - ('created', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), - ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ('entity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='versions', to='oel_publishing.publishableentity')), - ], - options={ - 'verbose_name': 'Publishable Entity Version', - 'verbose_name_plural': 'Publishable Entity Versions', - }, - ), - migrations.CreateModel( - name='PublishLog', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')), - ('message', openedx_learning.lib.fields.MultiCollationCharField(blank=True, db_collations={'mysql': 'utf8mb4_unicode_ci', 'sqlite': 'NOCASE'}, default='', max_length=500)), - ('published_at', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), - ('learning_package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_publishing.learningpackage')), - ('published_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ], - options={ - 'verbose_name': 'Publish Log', - 'verbose_name_plural': 'Publish Logs', - }, - ), - migrations.CreateModel( - name='Draft', - fields=[ - ('entity', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='oel_publishing.publishableentity')), - ], - ), - migrations.CreateModel( - name='Published', - fields=[ - ('entity', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='oel_publishing.publishableentity')), - ], - options={ - 'verbose_name': 'Published Entity', - 'verbose_name_plural': 'Published Entities', - }, - ), - migrations.CreateModel( - name='PublishLogRecord', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('entity', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_publishing.publishableentity')), - ('new_version', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.RESTRICT, to='oel_publishing.publishableentityversion')), - ('old_version', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.RESTRICT, related_name='+', to='oel_publishing.publishableentityversion')), - ('publish_log', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='records', to='oel_publishing.publishlog')), - ], - options={ - 'verbose_name': 'Publish Log Record', - 'verbose_name_plural': 'Publish Log Records', - }, - ), - migrations.AddConstraint( - model_name='learningpackage', - constraint=models.UniqueConstraint(fields=('key',), name='oel_publishing_lp_uniq_key'), - ), - migrations.AddIndex( - model_name='publishlogrecord', - index=models.Index(fields=['entity', '-publish_log'], name='oel_plr_idx_entity_rplr'), - ), - migrations.AddConstraint( - model_name='publishlogrecord', - constraint=models.UniqueConstraint(fields=('publish_log', 'entity'), name='oel_plr_uniq_pl_publishable'), - ), - migrations.AddField( - model_name='published', - name='publish_log_record', - field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_publishing.publishlogrecord'), - ), - migrations.AddField( - model_name='published', - name='version', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.RESTRICT, to='oel_publishing.publishableentityversion'), - ), - migrations.AddIndex( - model_name='publishableentityversion', - index=models.Index(fields=['entity', '-created'], name='oel_pv_idx_entity_rcreated'), - ), - migrations.AddIndex( - model_name='publishableentityversion', - index=models.Index(fields=['title'], name='oel_pv_idx_title'), - ), - migrations.AddConstraint( - model_name='publishableentityversion', - constraint=models.UniqueConstraint(fields=('entity', 'version_num'), name='oel_pv_uniq_entity_version_num'), - ), - migrations.AddIndex( - model_name='publishableentity', - index=models.Index(fields=['key'], name='oel_pub_ent_idx_key'), - ), - migrations.AddIndex( - model_name='publishableentity', - index=models.Index(fields=['learning_package', '-created'], name='oel_pub_ent_idx_lp_rcreated'), - ), - migrations.AddConstraint( - model_name='publishableentity', - constraint=models.UniqueConstraint(fields=('learning_package', 'key'), name='oel_pub_ent_uniq_lp_key'), - ), - migrations.AddField( - model_name='draft', - name='version', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.RESTRICT, to='oel_publishing.publishableentityversion'), - ), - ] diff --git a/openedx_learning/apps/authoring/publishing/migrations/0002_alter_learningpackage_key_and_more.py b/openedx_learning/apps/authoring/publishing/migrations/0002_alter_learningpackage_key_and_more.py deleted file mode 100644 index 0a4c3b48f..000000000 --- a/openedx_learning/apps/authoring/publishing/migrations/0002_alter_learningpackage_key_and_more.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2.10 on 2024-02-14 22:02 - -from django.db import migrations - -import openedx_learning.lib.fields - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_publishing', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='learningpackage', - name='key', - field=openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, db_column='_key', max_length=500), - ), - migrations.AlterField( - model_name='publishableentity', - name='key', - field=openedx_learning.lib.fields.MultiCollationCharField(db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'}, db_column='_key', max_length=500), - ), - ] diff --git a/openedx_learning/apps/authoring/publishing/migrations/0003_containers.py b/openedx_learning/apps/authoring/publishing/migrations/0003_containers.py deleted file mode 100644 index 55e967771..000000000 --- a/openedx_learning/apps/authoring/publishing/migrations/0003_containers.py +++ /dev/null @@ -1,54 +0,0 @@ -# Generated by Django 4.2.19 on 2025-03-11 04:10 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_publishing', '0002_alter_learningpackage_key_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='Container', - fields=[ - ('publishable_entity', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='oel_publishing.publishableentity')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='EntityList', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ], - ), - migrations.CreateModel( - name='EntityListRow', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('order_num', models.PositiveIntegerField()), - ('entity', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_publishing.publishableentity')), - ('entity_list', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_publishing.entitylist')), - ('entity_version', models.ForeignKey(null=True, on_delete=django.db.models.deletion.RESTRICT, related_name='+', to='oel_publishing.publishableentityversion')), - ], - ), - migrations.CreateModel( - name='ContainerVersion', - fields=[ - ('publishable_entity_version', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='oel_publishing.publishableentityversion')), - ('container', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='versions', to='oel_publishing.container')), - ('entity_list', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='container_versions', to='oel_publishing.entitylist')), - ], - options={ - 'abstract': False, - }, - ), - migrations.AddConstraint( - model_name='entitylistrow', - constraint=models.UniqueConstraint(fields=('entity_list', 'order_num'), name='oel_publishing_elist_row_order'), - ), - ] diff --git a/openedx_learning/apps/authoring/publishing/migrations/0004_publishableentity_can_stand_alone.py b/openedx_learning/apps/authoring/publishing/migrations/0004_publishableentity_can_stand_alone.py deleted file mode 100644 index 9949d159b..000000000 --- a/openedx_learning/apps/authoring/publishing/migrations/0004_publishableentity_can_stand_alone.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2.19 on 2025-03-17 11:07 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_publishing', '0003_containers'), - ] - - operations = [ - migrations.AddField( - model_name='publishableentity', - name='can_stand_alone', - field=models.BooleanField( - default=True, - help_text="Set to True when created independently, False when created as part of a container.", - ), - ), - ] diff --git a/openedx_learning/apps/authoring/publishing/migrations/0005_alter_entitylistrow_options.py b/openedx_learning/apps/authoring/publishing/migrations/0005_alter_entitylistrow_options.py deleted file mode 100644 index 84d603d51..000000000 --- a/openedx_learning/apps/authoring/publishing/migrations/0005_alter_entitylistrow_options.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 5.2 on 2025-04-08 10:50 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_publishing', '0004_publishableentity_can_stand_alone'), - ] - - operations = [ - migrations.AlterModelOptions( - name='entitylistrow', - options={'ordering': ['order_num']}, - ), - ] diff --git a/openedx_learning/apps/authoring/publishing/migrations/0006_draftchangelog.py b/openedx_learning/apps/authoring/publishing/migrations/0006_draftchangelog.py deleted file mode 100644 index b72e16843..000000000 --- a/openedx_learning/apps/authoring/publishing/migrations/0006_draftchangelog.py +++ /dev/null @@ -1,68 +0,0 @@ -# Generated by Django 4.2.18 on 2025-03-28 02:21 - -import uuid - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - -import openedx_learning.lib.validators - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('oel_publishing', '0005_alter_entitylistrow_options'), - ] - - operations = [ - migrations.CreateModel( - name='DraftChangeLog', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')), - ('changed_at', models.DateTimeField(validators=[openedx_learning.lib.validators.validate_utc_datetime])), - ('changed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ('learning_package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_publishing.learningpackage')), - ], - options={ - 'verbose_name': 'Draft Change Log', - 'verbose_name_plural': 'Draft Change Logs', - }, - ), - migrations.CreateModel( - name='DraftChangeLogRecord', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('draft_change_log', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='changes', to='oel_publishing.draftchangelog')), - ('entity', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_publishing.publishableentity')), - ('new_version', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.RESTRICT, to='oel_publishing.publishableentityversion')), - ('old_version', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.RESTRICT, related_name='+', to='oel_publishing.publishableentityversion')), - ], - options={ - 'verbose_name': 'Draft Log', - 'verbose_name_plural': 'Draft Log', - }, - ), - migrations.CreateModel( - name='DraftSideEffect', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('cause', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='causes', to='oel_publishing.draftchangelogrecord')), - ('effect', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='caused_by', to='oel_publishing.draftchangelogrecord')), - ], - ), - migrations.AddConstraint( - model_name='draftsideeffect', - constraint=models.UniqueConstraint(fields=('cause', 'effect'), name='oel_pub_dse_uniq_c_e'), - ), - migrations.AddIndex( - model_name='draftchangelogrecord', - index=models.Index(fields=['entity', '-draft_change_log'], name='oel_dlr_idx_entity_rdcl'), - ), - migrations.AddConstraint( - model_name='draftchangelogrecord', - constraint=models.UniqueConstraint(fields=('draft_change_log', 'entity'), name='oel_dlr_uniq_dcl'), - ), - ] diff --git a/openedx_learning/apps/authoring/publishing/migrations/0007_bootstrap_draftchangelog.py b/openedx_learning/apps/authoring/publishing/migrations/0007_bootstrap_draftchangelog.py deleted file mode 100644 index 5c8ab3735..000000000 --- a/openedx_learning/apps/authoring/publishing/migrations/0007_bootstrap_draftchangelog.py +++ /dev/null @@ -1,94 +0,0 @@ -""" -Bootstrap DraftChangeLogs - -DraftChangeLog and DraftChangeLogRecord are being introduced after Drafts, so -we're going to retroactively make entries for all the changes that were in our -Learning Packages. - -This migration will try to reconstruct create, edit, reset-to-published, and -delete operations, but it won't be fully accurate because we only have the -create dates of the versions and the current state of active Drafts to go on. -This means we won't accurately capture when things were deleted and then reset, -or when reset and then later edited. We're also missing the user for a number of -these operations, so we'll add those with null created_by entries. Addressing -these gaps is a big part of why we created DraftChangeLogs in the first place. -""" -# Generated by Django 4.2.18 on 2025-03-13 10:29 -import logging -from datetime import datetime, timezone - -from django.db import migrations - -logger = logging.getLogger(__name__) - - -def bootstrap_draft_change_logs(apps, schema_editor): - """ - Create a fake DraftChangeSet that encompasses the state of current Drafts. - """ - LearningPackage = apps.get_model("oel_publishing", "LearningPackage") - PublishableEntityVersion = apps.get_model("oel_publishing", "PublishableEntityVersion") - - Draft = apps.get_model("oel_publishing", "Draft") - DraftChangeLogRecord = apps.get_model("oel_publishing", "DraftChangeLogRecord") - DraftChangeLog = apps.get_model("oel_publishing", "DraftChangeLog") - now = datetime.now(tz=timezone.utc) - - for learning_package in LearningPackage.objects.all().order_by("key"): - logger.info(f"Creating bootstrap DraftChangeLogs for {learning_package.key}") - pub_ent_versions = PublishableEntityVersion.objects.filter( - entity__learning_package=learning_package - ).select_related("entity") - - # First cycle though all the simple create/edit operations... - last_version_seen = {} # PublishableEntity.id -> PublishableEntityVersion.id - for pub_ent_version in pub_ent_versions.order_by("pk"): - draft_change_log = DraftChangeLog.objects.create( - learning_package=learning_package, - changed_at=pub_ent_version.created, - changed_by=pub_ent_version.created_by, - ) - DraftChangeLogRecord.objects.create( - draft_change_log=draft_change_log, - entity=pub_ent_version.entity, - old_version_id=last_version_seen.get(pub_ent_version.entity.id), - new_version_id=pub_ent_version.id, - ) - last_version_seen[pub_ent_version.entity.id] = pub_ent_version.id - - # Now that we've created change sets for create/edit operations, we look - # at the latest state of the Draft model in order to determine whether - # we need to apply deletes or resets. - for draft in Draft.objects.filter(entity__learning_package=learning_package).order_by("entity_id"): - last_version_id = last_version_seen.get(draft.entity_id) - if draft.version_id == last_version_id: - continue - # We don't really know who did this or when, so we use None and now. - draft_change_log = DraftChangeLog.objects.create( - learning_package=learning_package, - changed_at=now, - changed_by=None, - ) - DraftChangeLogRecord.objects.create( - draft_change_log=draft_change_log, - entity_id=draft.entity_id, - old_version_id=last_version_id, - new_version_id=draft.version_id, - ) - - -def delete_draft_change_logs(apps, schema_editor): - logger.info(f"Deleting all DraftChangeLogs (reverse migration)") - DraftChangeLog = apps.get_model("oel_publishing", "DraftChangeLog") - DraftChangeLog.objects.all().delete() - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_publishing', '0006_draftchangelog'), - ] - - operations = [ - migrations.RunPython(bootstrap_draft_change_logs, reverse_code=delete_draft_change_logs) - ] diff --git a/openedx_learning/apps/authoring/publishing/migrations/0008_alter_draftchangelogrecord_options_and_more.py b/openedx_learning/apps/authoring/publishing/migrations/0008_alter_draftchangelogrecord_options_and_more.py deleted file mode 100644 index e83bf7202..000000000 --- a/openedx_learning/apps/authoring/publishing/migrations/0008_alter_draftchangelogrecord_options_and_more.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-17 18:22 -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_publishing', '0007_bootstrap_draftchangelog'), - ] - - operations = [ - migrations.AlterModelOptions( - name='draftchangelogrecord', - options={'verbose_name': 'Draft Change Log Record', 'verbose_name_plural': 'Draft Change Log Records'}, - ), - migrations.AlterModelOptions( - name='draftsideeffect', - options={'verbose_name': 'Draft Side Effect', 'verbose_name_plural': 'Draft Side Effects'}, - ), - migrations.AlterField( - model_name='draftchangelogrecord', - name='draft_change_log', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='records', to='oel_publishing.draftchangelog'), - ), - migrations.AlterField( - model_name='draftsideeffect', - name='effect', - field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='affected_by', to='oel_publishing.draftchangelogrecord'), - ), - ] diff --git a/openedx_learning/apps/authoring/publishing/migrations/0009_dependencies_and_hashing.py b/openedx_learning/apps/authoring/publishing/migrations/0009_dependencies_and_hashing.py deleted file mode 100644 index bbed19bd5..000000000 --- a/openedx_learning/apps/authoring/publishing/migrations/0009_dependencies_and_hashing.py +++ /dev/null @@ -1,62 +0,0 @@ -# Generated by Django 5.2.7 on 2025-10-29 17:59 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_publishing', '0008_alter_draftchangelogrecord_options_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='draft', - name='draft_log_record', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='oel_publishing.draftchangelogrecord'), - ), - migrations.AddField( - model_name='draftchangelogrecord', - name='dependencies_hash_digest', - field=models.CharField(blank=True, default='', editable=False, max_length=8), - ), - migrations.AddField( - model_name='publishlogrecord', - name='dependencies_hash_digest', - field=models.CharField(blank=True, default='', editable=False, max_length=8), - ), - migrations.CreateModel( - name='PublishableEntityVersionDependency', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('referenced_entity', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='oel_publishing.publishableentity')), - ('referring_version', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oel_publishing.publishableentityversion')), - ], - ), - migrations.AddField( - model_name='publishableentityversion', - name='dependencies', - field=models.ManyToManyField(related_name='affects', through='oel_publishing.PublishableEntityVersionDependency', to='oel_publishing.publishableentity'), - ), - migrations.CreateModel( - name='PublishSideEffect', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('cause', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='causes', to='oel_publishing.publishlogrecord')), - ('effect', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='affected_by', to='oel_publishing.publishlogrecord')), - ], - options={ - 'verbose_name': 'Publish Side Effect', - 'verbose_name_plural': 'Publish Side Effects', - }, - ), - migrations.AddConstraint( - model_name='publishableentityversiondependency', - constraint=models.UniqueConstraint(fields=('referring_version', 'referenced_entity'), name='oel_pevd_uniq_rv_re'), - ), - migrations.AddConstraint( - model_name='publishsideeffect', - constraint=models.UniqueConstraint(fields=('cause', 'effect'), name='oel_pub_pse_uniq_c_e'), - ), - ] diff --git a/openedx_learning/apps/authoring/publishing/migrations/0010_backfill_dependencies.py b/openedx_learning/apps/authoring/publishing/migrations/0010_backfill_dependencies.py deleted file mode 100644 index c274a401b..000000000 --- a/openedx_learning/apps/authoring/publishing/migrations/0010_backfill_dependencies.py +++ /dev/null @@ -1,149 +0,0 @@ -""" -Backfill PublishableEntityVersionDependency entries based on ContainerVersions. - -We're introducing a lower-level publishing concept of a dependency that will be -used by Containers, but this means we have to backfill that dependency info for -existing Containers in the system. -""" -from django.db import migrations -from django.db.models import F - - -def create_backfill(apps, schema_editor): - """ - Create dependency entries and update dep hashes for Draft and Published. - """ - _create_dependencies(apps) - _update_drafts(apps) - _update_draft_dependencies_hashes(apps) - _update_published_dependencies_hashes(apps) - - -def _create_dependencies(apps): - """ - Populate the PublishableEntityVersion.dependencies relation. - - The only ones we should have in the system at this point are the ones from - containers, so we query ContainerVersion for that. - """ - PublishableEntityVersionDependency = apps.get_model( - "oel_publishing", "PublishableEntityVersionDependency" - ) - ContainerVersion = apps.get_model("oel_publishing", "ContainerVersion") - - for container_version in ContainerVersion.objects.all(): - # child_entity_ids is a set to de-dupe. This doesn't handle pinned - # child references yet, but you can't actually make those in a real - # library yet, so we shouldn't have that data lying around to migrate. - child_entity_ids = set( - container_version - .entity_list - .entitylistrow_set - .all() - .values_list("entity_id", flat=True) - ) - PublishableEntityVersionDependency.objects.bulk_create( - [ - PublishableEntityVersionDependency( - referring_version_id=container_version.pk, - referenced_entity_id=entity_id - ) - for entity_id in child_entity_ids - ], - ignore_conflicts=True, - ) - - -def _update_drafts(apps): - """ - Update Draft entries to point to their most recent DraftLogRecord. - - This is slow and expensive. - """ - Draft = apps.get_model("oel_publishing", "Draft") - DraftChangeLogRecord = apps.get_model("oel_publishing", "DraftChangeLogRecord") - for draft in Draft.objects.all(): - draft_log_record = ( - # Find the most recent DraftChangeLogRecord related to this Draft, - DraftChangeLogRecord.objects - .filter(entity_id=draft.pk) - .order_by('-pk') - .first() - ) - draft.draft_log_record = draft_log_record - draft.save() - - -def _update_draft_dependencies_hashes(apps): - """ - Update the dependency_hash_digest for all DraftChangeLogRecords. - - Backfill dependency state hashes. The important thing here is that things - without dependencies will have the default (blank) state hash, so we only - need to query for Draft entries for Containers. - - We are only backfilling the current DraftChangeLogRecords pointed to by the - Draft entries now. We are not backfilling all historical - DraftChangeLogRecords. Full historical reconstruction is probably possible, - but it's not really worth the cost and complexity. - """ - from ..api import update_dependencies_hash_digests_for_log - from ..models import DraftChangeLog - - # All DraftChangeLogs that have records that are pointed to by the current - # Draft and have a possibility of having dependencies. - change_logs = DraftChangeLog.objects.filter( - pk=F('records__entity__draft__draft_log_record__draft_change_log'), - records__entity__draft__version__isnull=False, - records__entity__container__isnull=False, - ).distinct() - for change_log in change_logs: - update_dependencies_hash_digests_for_log(change_log, backfill=True) - -def _update_published_dependencies_hashes(apps): - """ - Update all container Published.dependencies_hash_digest - - Backfill dependency state hashes. The important thing here is that things - without dependencies will have the default (blank) state hash, so we only - need to query for Published entries for Containers. - """ - from ..api import update_dependencies_hash_digests_for_log - from ..models import PublishLog - - # All PublishLogs that have records that are pointed to by the current - # Published and have a possibility of having dependencies. - change_logs = PublishLog.objects.filter( - pk=F('records__entity__published__publish_log_record__publish_log'), - records__entity__published__version__isnull=False, - records__entity__container__isnull=False, - ).distinct() - for change_log in change_logs: - update_dependencies_hash_digests_for_log(change_log, backfill=True) - -def remove_backfill(apps, schema_editor): - """ - Reset all dep hash values to default ('') and remove dependencies. - """ - Draft = apps.get_model("oel_publishing", "Draft") - DraftChangeLogRecord = apps.get_model("oel_publishing", "DraftChangeLogRecord") - PublishLogRecord = apps.get_model("oel_publishing", "PublishLogRecord") - PublishableEntityVersionDependency = apps.get_model( - "oel_publishing", "PublishableEntityVersionDependency" - ) - - PublishLogRecord.objects.all().update(dependencies_hash_digest='') - DraftChangeLogRecord.objects.all().update(dependencies_hash_digest='') - PublishableEntityVersionDependency.objects.all().delete() - Draft.objects.all().update(draft_log_record=None) - - -class Migration(migrations.Migration): - - dependencies = [ - ('oel_publishing', '0009_dependencies_and_hashing'), - ] - - operations = [ - migrations.RunPython(create_backfill, reverse_code=remove_backfill) - ] diff --git a/openedx_learning/apps/authoring/sections/apps.py b/openedx_learning/apps/authoring/sections/apps.py deleted file mode 100644 index f506229e2..000000000 --- a/openedx_learning/apps/authoring/sections/apps.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -Sections Django application initialization. -""" - -from django.apps import AppConfig - - -class SectionsConfig(AppConfig): - """ - Configuration for the Sections Django application. - """ - - name = "openedx_learning.apps.authoring.sections" - verbose_name = "Learning Core > Authoring > Sections" - default_auto_field = "django.db.models.BigAutoField" - label = "oel_sections" - - def ready(self): - """ - Register Section and SectionVersion. - """ - from ..publishing.api import register_publishable_models # pylint: disable=import-outside-toplevel - from .models import Section, SectionVersion # pylint: disable=import-outside-toplevel - - register_publishable_models(Section, SectionVersion) diff --git a/openedx_learning/apps/authoring/sections/migrations/0001_initial.py b/openedx_learning/apps/authoring/sections/migrations/0001_initial.py deleted file mode 100644 index 5083cda73..000000000 --- a/openedx_learning/apps/authoring/sections/migrations/0001_initial.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-11 12:53 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('oel_publishing', '0005_alter_entitylistrow_options'), - ] - - operations = [ - migrations.CreateModel( - name='Section', - fields=[ - ('container', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_publishing.container')), - ], - options={ - 'abstract': False, - }, - bases=('oel_publishing.container',), - ), - migrations.CreateModel( - name='SectionVersion', - fields=[ - ('container_version', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_publishing.containerversion')), - ], - options={ - 'abstract': False, - }, - bases=('oel_publishing.containerversion',), - ), - ] diff --git a/openedx_learning/apps/authoring/subsections/apps.py b/openedx_learning/apps/authoring/subsections/apps.py deleted file mode 100644 index 950e14143..000000000 --- a/openedx_learning/apps/authoring/subsections/apps.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -Subsection Django application initialization. -""" - -from django.apps import AppConfig - - -class SubsectionsConfig(AppConfig): - """ - Configuration for the subsections Django application. - """ - - name = "openedx_learning.apps.authoring.subsections" - verbose_name = "Learning Core > Authoring > Subsections" - default_auto_field = "django.db.models.BigAutoField" - label = "oel_subsections" - - def ready(self): - """ - Register Subsection and SubsectionVersion. - """ - from ..publishing.api import register_publishable_models # pylint: disable=import-outside-toplevel - from .models import Subsection, SubsectionVersion # pylint: disable=import-outside-toplevel - - register_publishable_models(Subsection, SubsectionVersion) diff --git a/openedx_learning/apps/authoring/subsections/migrations/0001_initial.py b/openedx_learning/apps/authoring/subsections/migrations/0001_initial.py deleted file mode 100644 index 710c5532b..000000000 --- a/openedx_learning/apps/authoring/subsections/migrations/0001_initial.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 4.2.19 on 2025-04-09 12:59 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('oel_publishing', '0005_alter_entitylistrow_options'), - ] - - operations = [ - migrations.CreateModel( - name='Subsection', - fields=[ - ('container', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_publishing.container')), - ], - options={ - 'abstract': False, - }, - bases=('oel_publishing.container',), - ), - migrations.CreateModel( - name='SubsectionVersion', - fields=[ - ('container_version', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_publishing.containerversion')), - ], - options={ - 'abstract': False, - }, - bases=('oel_publishing.containerversion',), - ), - ] diff --git a/openedx_learning/apps/authoring/units/apps.py b/openedx_learning/apps/authoring/units/apps.py deleted file mode 100644 index 17affcf25..000000000 --- a/openedx_learning/apps/authoring/units/apps.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -Unit Django application initialization. -""" - -from django.apps import AppConfig - - -class UnitsConfig(AppConfig): - """ - Configuration for the units Django application. - """ - - name = "openedx_learning.apps.authoring.units" - verbose_name = "Learning Core > Authoring > Units" - default_auto_field = "django.db.models.BigAutoField" - label = "oel_units" - - def ready(self): - """ - Register Unit and UnitVersion. - """ - from ..publishing.api import register_publishable_models # pylint: disable=import-outside-toplevel - from .models import Unit, UnitVersion # pylint: disable=import-outside-toplevel - - register_publishable_models(Unit, UnitVersion) diff --git a/openedx_learning/apps/authoring/units/migrations/0001_initial.py b/openedx_learning/apps/authoring/units/migrations/0001_initial.py deleted file mode 100644 index 52a5b4fb6..000000000 --- a/openedx_learning/apps/authoring/units/migrations/0001_initial.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 4.2.19 on 2025-03-11 04:31 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('oel_publishing', '0003_containers'), - ] - - operations = [ - migrations.CreateModel( - name='Unit', - fields=[ - ('container', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_publishing.container')), - ], - options={ - 'abstract': False, - }, - bases=('oel_publishing.container',), - ), - migrations.CreateModel( - name='UnitVersion', - fields=[ - ('container_version', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='oel_publishing.containerversion')), - ], - options={ - 'abstract': False, - }, - bases=('oel_publishing.containerversion',), - ), - ] diff --git a/openedx_learning/contrib/media_server/views.py b/openedx_learning/contrib/media_server/views.py index d7088879e..929867074 100644 --- a/openedx_learning/contrib/media_server/views.py +++ b/openedx_learning/contrib/media_server/views.py @@ -8,7 +8,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.http import FileResponse, Http404 -from openedx_learning.apps.authoring.components.api import look_up_component_version_content +from openedx_learning.apps.authoring.applets.components.api import look_up_component_version_content def component_asset( diff --git a/openedx_learning/lib/appletslib.py b/openedx_learning/lib/appletslib.py new file mode 100644 index 000000000..3cca4439f --- /dev/null +++ b/openedx_learning/lib/appletslib.py @@ -0,0 +1,54 @@ +""" +This was an attempt to make cute and clever code to dynamically discover and +import all applet modules of a certain type for aggregation purposes (e.g. the +authoring/models.py file importing from all applet models.py files). This code +actually does work, but I only realized after buildling it that it breaks +editor introspection/autocomplete, which makes the cost far too high for this +convenience. +""" + +import functools +import importlib +import inspect +import pathlib + + +def auto_import(module_name): + caller_frame_info = inspect.stack()[1] + caller_module = inspect.getmodule(caller_frame_info[0]) + caller_module_name = caller_module.__name__ + + # converts openedx_learning.authoring.models -> openedx_learning.authoring + import_base = ".".join(caller_module_name.split(".")[:-1]) + + caller_filepath = caller_frame_info.filename + caller_dir = pathlib.Path(caller_filepath).resolve().parent + applets_dir = caller_dir / "applets" + module_paths = applets_dir.rglob(f"{module_name}.py") + relative_paths = [ + module_path.relative_to(caller_dir) for module_path in module_paths + ] + all_modules_dict = {} + for relative_path in sorted(relative_paths): + module_import_name = f"{import_base}." + ".".join(relative_path.parts)[:-3] + module = importlib.import_module(module_import_name) + module_dict = vars(module) + if '__all__' in module_dict: + module_dict_to_add = { + key: module_dict[key] + for key in module_dict['__all__'] + } + else: + module_dict_to_add = { + key: val + for (key, val) in module_dict.items() + if not key.startswith('_') + } + all_modules_dict.update(module_dict_to_add) + + return all_modules_dict + + +auto_import_models = functools.partial(auto_import, "models") +auto_import_api = functools.partial(auto_import, "api") +auto_import_admin = functools.partial(auto_import, "admin") diff --git a/projects/dev.py b/projects/dev.py index 1b3b42f47..b735ab0f9 100644 --- a/projects/dev.py +++ b/projects/dev.py @@ -31,19 +31,23 @@ "django.contrib.admin", "django.contrib.admindocs", # Learning Core Apps - "openedx_learning.apps.authoring.collections.apps.CollectionsConfig", - "openedx_learning.apps.authoring.components.apps.ComponentsConfig", - "openedx_learning.apps.authoring.contents.apps.ContentsConfig", - "openedx_learning.apps.authoring.publishing.apps.PublishingConfig", - "openedx_learning.apps.authoring.sections.apps.SectionsConfig", - "openedx_learning.apps.authoring.subsections.apps.SubsectionsConfig", - "openedx_learning.apps.authoring.units.apps.UnitsConfig", - "openedx_learning.apps.authoring.backup_restore.apps.BackupRestoreConfig", + + "openedx_learning.apps.authoring", + + #"openedx_learning.apps.authoring.applets.collections", + #"openedx_learning.apps.authoring.applets.components", + #"openedx_learning.apps.authoring.applets.contents", + #"openedx_learning.apps.authoring.applets.publishing", + #"openedx_learning.apps.authoring.sections", + #"openedx_learning.apps.authoring.subsections", + #"openedx_learning.apps.authoring.units", + #"openedx_learning.apps.authoring.applets.backup_restore", + # Learning Contrib Apps - "openedx_learning.contrib.media_server.apps.MediaServerConfig", + # "openedx_learning.contrib.media_server.apps.MediaServerConfig", # Apps that don't belong in this repo in the long term, but are here to make # testing/iteration easier until the APIs stabilize. - "olx_importer.apps.OLXImporterConfig", + # "olx_importer.apps.OLXImporterConfig", # REST API "rest_framework", @@ -51,9 +55,6 @@ 'rules.apps.AutodiscoverRulesConfig', # Tagging Core Apps "openedx_tagging.core.tagging.apps.TaggingConfig", - - # Debugging - "debug_toolbar", ) AUTHENTICATION_BACKENDS = [ @@ -62,7 +63,7 @@ ] MIDDLEWARE = [ - "debug_toolbar.middleware.DebugToolbarMiddleware", +# "debug_toolbar.middleware.DebugToolbarMiddleware", "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", diff --git a/projects/urls.py b/projects/urls.py index 583b004b4..082ff2113 100644 --- a/projects/urls.py +++ b/projects/urls.py @@ -9,5 +9,5 @@ path("admin/", admin.site.urls), path("media_server/", include("openedx_learning.contrib.media_server.urls")), path("tagging/rest_api/", include("openedx_tagging.core.tagging.urls")), - path('__debug__/', include('debug_toolbar.urls')), + # path('__debug__/', include('debug_toolbar.urls')), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/test_settings.py b/test_settings.py index c4b22926d..72bdc84e8 100644 --- a/test_settings.py +++ b/test_settings.py @@ -18,18 +18,14 @@ def root(*args): DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", - "NAME": "default.db", - "USER": "", - "PASSWORD": "", - "HOST": "", - "PORT": "", + "NAME": ":memory:", } } # If you provision the 'oel'@'%' with broad permissions on your MySQL instance, # running the tests will auto-generate a database for running tests. This is # slower than the default sqlite3 setup above, but it's sometimes helpful for -# finding things that only break in CI. +# finding things that only break in CI. # # DATABASES = { # "default": { @@ -50,20 +46,11 @@ def root(*args): # Admin 'django.contrib.admin', 'django.contrib.admindocs', - # Debugging - "debug_toolbar", # django-rules based authorization 'rules.apps.AutodiscoverRulesConfig', # Our own apps - "openedx_learning.apps.authoring.collections.apps.CollectionsConfig", - "openedx_learning.apps.authoring.components.apps.ComponentsConfig", - "openedx_learning.apps.authoring.contents.apps.ContentsConfig", - "openedx_learning.apps.authoring.publishing.apps.PublishingConfig", - "openedx_tagging.core.tagging.apps.TaggingConfig", - "openedx_learning.apps.authoring.sections.apps.SectionsConfig", - "openedx_learning.apps.authoring.subsections.apps.SubsectionsConfig", - "openedx_learning.apps.authoring.units.apps.UnitsConfig", - "openedx_learning.apps.authoring.backup_restore.apps.BackupRestoreConfig", + "openedx_learning.apps.authoring", + "openedx_tagging.core.tagging", ] AUTHENTICATION_BACKENDS = [ diff --git a/openedx_learning/apps/authoring/publishing/__init__.py b/tests/openedx_learning/apps/authoring/applets/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/publishing/__init__.py rename to tests/openedx_learning/apps/authoring/applets/__init__.py diff --git a/openedx_learning/apps/authoring/publishing/migrations/__init__.py b/tests/openedx_learning/apps/authoring/applets/backup_restore/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/publishing/migrations/__init__.py rename to tests/openedx_learning/apps/authoring/applets/backup_restore/__init__.py diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/collections/collection-test.toml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/collections/collection-test.toml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/collections/collection-test.toml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/collections/collection-test.toml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/section1-8ca126.toml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/section1-8ca126.toml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/section1-8ca126.toml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/section1-8ca126.toml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/subsection1-48afa3.toml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/subsection1-48afa3.toml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/subsection1-48afa3.toml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/subsection1-48afa3.toml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/unit1-b7eafb.toml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/unit1-b7eafb.toml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/unit1-b7eafb.toml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/unit1-b7eafb.toml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/drag-and-drop-v2/4d1b2fac-8b30-42fb-872d-6b10ab580b27.toml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/drag-and-drop-v2/4d1b2fac-8b30-42fb-872d-6b10ab580b27.toml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/drag-and-drop-v2/4d1b2fac-8b30-42fb-872d-6b10ab580b27.toml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/drag-and-drop-v2/4d1b2fac-8b30-42fb-872d-6b10ab580b27.toml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/drag-and-drop-v2/4d1b2fac-8b30-42fb-872d-6b10ab580b27/component_versions/v2/block.xml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/drag-and-drop-v2/4d1b2fac-8b30-42fb-872d-6b10ab580b27/component_versions/v2/block.xml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/drag-and-drop-v2/4d1b2fac-8b30-42fb-872d-6b10ab580b27/component_versions/v2/block.xml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/drag-and-drop-v2/4d1b2fac-8b30-42fb-872d-6b10ab580b27/component_versions/v2/block.xml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/c22b9f97-f1e9-4e8f-87f0-d5a3c26083e2.toml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/c22b9f97-f1e9-4e8f-87f0-d5a3c26083e2.toml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/c22b9f97-f1e9-4e8f-87f0-d5a3c26083e2.toml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/c22b9f97-f1e9-4e8f-87f0-d5a3c26083e2.toml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/c22b9f97-f1e9-4e8f-87f0-d5a3c26083e2/component_versions/v2/block.xml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/c22b9f97-f1e9-4e8f-87f0-d5a3c26083e2/component_versions/v2/block.xml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/c22b9f97-f1e9-4e8f-87f0-d5a3c26083e2/component_versions/v2/block.xml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/c22b9f97-f1e9-4e8f-87f0-d5a3c26083e2/component_versions/v2/block.xml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37.toml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37.toml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37.toml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37.toml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v4/block.xml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v4/block.xml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v4/block.xml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v4/block.xml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v4/static/me.png b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v4/static/me.png similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v4/static/me.png rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v4/static/me.png diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v5/block.xml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v5/block.xml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v5/block.xml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v5/block.xml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v5/static/me.png b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v5/static/me.png similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v5/static/me.png rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/html/e32d5479-9492-41f6-9222-550a7346bc37/component_versions/v5/static/me.png diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/openassessment/1ee38208-a585-4455-a27e-4930aa541f53.toml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/openassessment/1ee38208-a585-4455-a27e-4930aa541f53.toml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/openassessment/1ee38208-a585-4455-a27e-4930aa541f53.toml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/openassessment/1ee38208-a585-4455-a27e-4930aa541f53.toml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/openassessment/1ee38208-a585-4455-a27e-4930aa541f53/component_versions/v2/block.xml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/openassessment/1ee38208-a585-4455-a27e-4930aa541f53/component_versions/v2/block.xml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/openassessment/1ee38208-a585-4455-a27e-4930aa541f53/component_versions/v2/block.xml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/openassessment/1ee38208-a585-4455-a27e-4930aa541f53/component_versions/v2/block.xml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/problem/256739e8-c2df-4ced-bd10-8156f6cfa90b.toml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/problem/256739e8-c2df-4ced-bd10-8156f6cfa90b.toml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/problem/256739e8-c2df-4ced-bd10-8156f6cfa90b.toml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/problem/256739e8-c2df-4ced-bd10-8156f6cfa90b.toml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/problem/256739e8-c2df-4ced-bd10-8156f6cfa90b/component_versions/v2/block.xml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/problem/256739e8-c2df-4ced-bd10-8156f6cfa90b/component_versions/v2/block.xml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/problem/256739e8-c2df-4ced-bd10-8156f6cfa90b/component_versions/v2/block.xml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/problem/256739e8-c2df-4ced-bd10-8156f6cfa90b/component_versions/v2/block.xml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/survey/6681da3f-b056-4c6e-a8f9-040967907471.toml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/survey/6681da3f-b056-4c6e-a8f9-040967907471.toml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/survey/6681da3f-b056-4c6e-a8f9-040967907471.toml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/survey/6681da3f-b056-4c6e-a8f9-040967907471.toml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/survey/6681da3f-b056-4c6e-a8f9-040967907471/component_versions/v1/block.xml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/survey/6681da3f-b056-4c6e-a8f9-040967907471/component_versions/v1/block.xml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/survey/6681da3f-b056-4c6e-a8f9-040967907471/component_versions/v1/block.xml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/survey/6681da3f-b056-4c6e-a8f9-040967907471/component_versions/v1/block.xml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/video/22601ebd-9da8-430b-9778-cfe059a98568.toml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/video/22601ebd-9da8-430b-9778-cfe059a98568.toml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/video/22601ebd-9da8-430b-9778-cfe059a98568.toml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/video/22601ebd-9da8-430b-9778-cfe059a98568.toml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/video/22601ebd-9da8-430b-9778-cfe059a98568/component_versions/v3/block.xml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/video/22601ebd-9da8-430b-9778-cfe059a98568/component_versions/v3/block.xml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/entities/xblock.v1/video/22601ebd-9da8-430b-9778-cfe059a98568/component_versions/v3/block.xml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/entities/xblock.v1/video/22601ebd-9da8-430b-9778-cfe059a98568/component_versions/v3/block.xml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/package.toml b/tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/package.toml similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/fixtures/library_backup/package.toml rename to tests/openedx_learning/apps/authoring/applets/backup_restore/fixtures/library_backup/package.toml diff --git a/tests/openedx_learning/apps/authoring/backup_restore/test_backup.py b/tests/openedx_learning/apps/authoring/applets/backup_restore/test_backup.py similarity index 99% rename from tests/openedx_learning/apps/authoring/backup_restore/test_backup.py rename to tests/openedx_learning/apps/authoring/applets/backup_restore/test_backup.py index 312f289f1..0a23bb4db 100644 --- a/tests/openedx_learning/apps/authoring/backup_restore/test_backup.py +++ b/tests/openedx_learning/apps/authoring/applets/backup_restore/test_backup.py @@ -12,7 +12,7 @@ from openedx_learning.api import authoring as api from openedx_learning.api.authoring_models import Collection, Component, Content, LearningPackage, PublishableEntity -from openedx_learning.apps.authoring.backup_restore.zipper import LearningPackageZipper +from openedx_learning.apps.authoring.applets.backup_restore.zipper import LearningPackageZipper from openedx_learning.lib.test_utils import TestCase User = get_user_model() diff --git a/tests/openedx_learning/apps/authoring/backup_restore/test_restore.py b/tests/openedx_learning/apps/authoring/applets/backup_restore/test_restore.py similarity index 96% rename from tests/openedx_learning/apps/authoring/backup_restore/test_restore.py rename to tests/openedx_learning/apps/authoring/applets/backup_restore/test_restore.py index e34a0b5f7..4fa1a35c7 100644 --- a/tests/openedx_learning/apps/authoring/backup_restore/test_restore.py +++ b/tests/openedx_learning/apps/authoring/applets/backup_restore/test_restore.py @@ -7,10 +7,10 @@ from django.contrib.auth import get_user_model from django.core.management import call_command -from openedx_learning.apps.authoring.backup_restore.zipper import LearningPackageUnzipper, generate_staged_lp_key -from openedx_learning.apps.authoring.collections import api as collections_api -from openedx_learning.apps.authoring.components import api as components_api -from openedx_learning.apps.authoring.publishing import api as publishing_api +from openedx_learning.apps.authoring.applets.backup_restore.zipper import LearningPackageUnzipper, generate_staged_lp_key +from openedx_learning.apps.authoring.applets.collections import api as collections_api +from openedx_learning.apps.authoring.applets.components import api as components_api +from openedx_learning.apps.authoring.applets.publishing import api as publishing_api from openedx_learning.lib.test_utils import TestCase from test_utils.zip_file_utils import folder_to_inmemory_zip @@ -31,7 +31,7 @@ def setUp(self): class RestoreLearningPackageCommandTest(RestoreTestCase): """Tests for the lp_load management command.""" - @patch("openedx_learning.apps.authoring.backup_restore.api.load_learning_package") + @patch("openedx_learning.apps.authoring.applets.backup_restore.api.load_learning_package") def test_restore_command(self, mock_load_learning_package): # Mock load_learning_package to return our in-memory zip file restore_result = LearningPackageUnzipper(self.zip_file, user=self.user).load() @@ -284,7 +284,7 @@ def test_error_learning_package_missing_key(self): # Mock parse_learning_package_toml to return a dict without 'key' with patch( - "openedx_learning.apps.authoring.backup_restore.zipper.parse_learning_package_toml", + "openedx_learning.apps.authoring.applets.backup_restore.zipper.parse_learning_package_toml", return_value={ "learning_package": { "title": "Library test", @@ -315,7 +315,7 @@ def test_error_no_metadata_section(self): # Mock parse_learning_package_toml to return a dict without 'meta' with patch( - "openedx_learning.apps.authoring.backup_restore.zipper.parse_learning_package_toml", + "openedx_learning.apps.authoring.applets.backup_restore.zipper.parse_learning_package_toml", return_value={ "learning_package": { "title": "Library test", diff --git a/tests/openedx_learning/apps/authoring/backup_restore/test_slug_hash.py b/tests/openedx_learning/apps/authoring/applets/backup_restore/test_slug_hash.py similarity index 97% rename from tests/openedx_learning/apps/authoring/backup_restore/test_slug_hash.py rename to tests/openedx_learning/apps/authoring/applets/backup_restore/test_slug_hash.py index 292d08af1..d1073dc81 100644 --- a/tests/openedx_learning/apps/authoring/backup_restore/test_slug_hash.py +++ b/tests/openedx_learning/apps/authoring/applets/backup_restore/test_slug_hash.py @@ -5,7 +5,7 @@ generating slugified, hash-based filenames. """ -from openedx_learning.apps.authoring.backup_restore.zipper import slugify_hashed_filename +from openedx_learning.apps.authoring.applets.backup_restore.zipper import slugify_hashed_filename from openedx_learning.lib.test_utils import TestCase diff --git a/openedx_learning/apps/authoring/sections/__init__.py b/tests/openedx_learning/apps/authoring/applets/collections/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/sections/__init__.py rename to tests/openedx_learning/apps/authoring/applets/collections/__init__.py diff --git a/tests/openedx_learning/apps/authoring/collections/test_api.py b/tests/openedx_learning/apps/authoring/applets/collections/test_api.py similarity index 99% rename from tests/openedx_learning/apps/authoring/collections/test_api.py rename to tests/openedx_learning/apps/authoring/applets/collections/test_api.py index b70a8abd3..97b2f2ba4 100644 --- a/tests/openedx_learning/apps/authoring/collections/test_api.py +++ b/tests/openedx_learning/apps/authoring/applets/collections/test_api.py @@ -17,8 +17,8 @@ ComponentType, LearningPackage, PublishableEntity, + Unit, ) -from openedx_learning.apps.authoring.units.models import Unit from openedx_learning.lib.test_utils import TestCase User = get_user_model() diff --git a/openedx_learning/apps/authoring/sections/migrations/__init__.py b/tests/openedx_learning/apps/authoring/applets/components/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/sections/migrations/__init__.py rename to tests/openedx_learning/apps/authoring/applets/components/__init__.py diff --git a/tests/openedx_learning/apps/authoring/components/test_api.py b/tests/openedx_learning/apps/authoring/applets/components/test_api.py similarity index 97% rename from tests/openedx_learning/apps/authoring/components/test_api.py rename to tests/openedx_learning/apps/authoring/applets/components/test_api.py index 8a4dd44c5..e28e34d0f 100644 --- a/tests/openedx_learning/apps/authoring/components/test_api.py +++ b/tests/openedx_learning/apps/authoring/applets/components/test_api.py @@ -7,14 +7,14 @@ from django.contrib.auth.models import User as UserType # pylint: disable=imported-auth-user from django.core.exceptions import ObjectDoesNotExist -from openedx_learning.apps.authoring.collections import api as collection_api -from openedx_learning.apps.authoring.collections.models import Collection -from openedx_learning.apps.authoring.components import api as components_api -from openedx_learning.apps.authoring.components.models import Component, ComponentType -from openedx_learning.apps.authoring.contents import api as contents_api -from openedx_learning.apps.authoring.contents.models import MediaType -from openedx_learning.apps.authoring.publishing import api as publishing_api -from openedx_learning.apps.authoring.publishing.models import LearningPackage +from openedx_learning.apps.authoring.applets.collections import api as collection_api +from openedx_learning.apps.authoring.applets.collections.models import Collection +from openedx_learning.apps.authoring.applets.components import api as components_api +from openedx_learning.apps.authoring.applets.components.models import Component, ComponentType +from openedx_learning.apps.authoring.applets.contents import api as contents_api +from openedx_learning.apps.authoring.applets.contents.models import MediaType +from openedx_learning.apps.authoring.applets.publishing import api as publishing_api +from openedx_learning.apps.authoring.applets.publishing.models import LearningPackage from openedx_learning.lib.test_utils import TestCase User = get_user_model() diff --git a/tests/openedx_learning/apps/authoring/components/test_assets.py b/tests/openedx_learning/apps/authoring/applets/components/test_assets.py similarity index 94% rename from tests/openedx_learning/apps/authoring/components/test_assets.py rename to tests/openedx_learning/apps/authoring/applets/components/test_assets.py index f9cbf0643..d9f841d0e 100644 --- a/tests/openedx_learning/apps/authoring/components/test_assets.py +++ b/tests/openedx_learning/apps/authoring/applets/components/test_assets.py @@ -5,11 +5,11 @@ from pathlib import Path from uuid import uuid4 -from openedx_learning.apps.authoring.components import api as components_api -from openedx_learning.apps.authoring.components.api import AssetError -from openedx_learning.apps.authoring.contents import api as contents_api -from openedx_learning.apps.authoring.publishing import api as publishing_api -from openedx_learning.apps.authoring.publishing.models import LearningPackage +from openedx_learning.apps.authoring.applets.components import api as components_api +from openedx_learning.apps.authoring.applets.components.api import AssetError +from openedx_learning.apps.authoring.applets.contents import api as contents_api +from openedx_learning.apps.authoring.applets.publishing import api as publishing_api +from openedx_learning.apps.authoring.applets.publishing.models import LearningPackage from openedx_learning.lib.test_utils import TestCase diff --git a/tests/openedx_learning/apps/authoring/components/test_models.py b/tests/openedx_learning/apps/authoring/applets/components/test_models.py similarity index 96% rename from tests/openedx_learning/apps/authoring/components/test_models.py rename to tests/openedx_learning/apps/authoring/applets/components/test_models.py index ca786d281..ca6edaaa9 100644 --- a/tests/openedx_learning/apps/authoring/components/test_models.py +++ b/tests/openedx_learning/apps/authoring/applets/components/test_models.py @@ -6,13 +6,13 @@ from freezegun import freeze_time -from openedx_learning.apps.authoring.components.api import ( +from openedx_learning.apps.authoring.applets.components.api import ( create_component_and_version, get_component, get_or_create_component_type, ) -from openedx_learning.apps.authoring.components.models import Component, ComponentType, ComponentVersion -from openedx_learning.apps.authoring.publishing.api import ( +from openedx_learning.apps.authoring.applets.components.models import Component, ComponentType, ComponentVersion +from openedx_learning.apps.authoring.applets.publishing.api import ( LearningPackage, create_learning_package, create_publishable_entity_version, diff --git a/openedx_learning/apps/authoring/subsections/__init__.py b/tests/openedx_learning/apps/authoring/applets/contents/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/subsections/__init__.py rename to tests/openedx_learning/apps/authoring/applets/contents/__init__.py diff --git a/tests/openedx_learning/apps/authoring/contents/test_file_storage.py b/tests/openedx_learning/apps/authoring/applets/contents/test_file_storage.py similarity index 92% rename from tests/openedx_learning/apps/authoring/contents/test_file_storage.py rename to tests/openedx_learning/apps/authoring/applets/contents/test_file_storage.py index a94b31571..47dc356da 100644 --- a/tests/openedx_learning/apps/authoring/contents/test_file_storage.py +++ b/tests/openedx_learning/apps/authoring/applets/contents/test_file_storage.py @@ -7,9 +7,9 @@ from django.core.exceptions import ImproperlyConfigured from django.test import override_settings -from openedx_learning.apps.authoring.contents import api as contents_api -from openedx_learning.apps.authoring.contents.models import get_storage -from openedx_learning.apps.authoring.publishing import api as publishing_api +from openedx_learning.apps.authoring.applets.contents import api as contents_api +from openedx_learning.apps.authoring.applets.contents.models import get_storage +from openedx_learning.apps.authoring.applets.publishing import api as publishing_api from openedx_learning.lib.test_utils import TestCase diff --git a/tests/openedx_learning/apps/authoring/contents/test_media_types.py b/tests/openedx_learning/apps/authoring/applets/contents/test_media_types.py similarity index 91% rename from tests/openedx_learning/apps/authoring/contents/test_media_types.py rename to tests/openedx_learning/apps/authoring/applets/contents/test_media_types.py index 6f9b16b30..0216ce7bc 100644 --- a/tests/openedx_learning/apps/authoring/contents/test_media_types.py +++ b/tests/openedx_learning/apps/authoring/applets/contents/test_media_types.py @@ -1,7 +1,7 @@ """ A few tests to make sure our MediaType lookups are working as expected. """ -from openedx_learning.apps.authoring.contents import api as contents_api +from openedx_learning.apps.authoring.applets.contents import api as contents_api from openedx_learning.lib.test_utils import TestCase diff --git a/openedx_learning/apps/authoring/subsections/migrations/__init__.py b/tests/openedx_learning/apps/authoring/applets/publishing/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/subsections/migrations/__init__.py rename to tests/openedx_learning/apps/authoring/applets/publishing/__init__.py diff --git a/tests/openedx_learning/apps/authoring/publishing/test_api.py b/tests/openedx_learning/apps/authoring/applets/publishing/test_api.py similarity index 99% rename from tests/openedx_learning/apps/authoring/publishing/test_api.py rename to tests/openedx_learning/apps/authoring/applets/publishing/test_api.py index f44667178..d204c244e 100644 --- a/tests/openedx_learning/apps/authoring/publishing/test_api.py +++ b/tests/openedx_learning/apps/authoring/applets/publishing/test_api.py @@ -10,8 +10,8 @@ from django.contrib.auth import get_user_model from django.core.exceptions import ValidationError -from openedx_learning.apps.authoring.publishing import api as publishing_api -from openedx_learning.apps.authoring.publishing.models import ( +from openedx_learning.apps.authoring.applets.publishing import api as publishing_api +from openedx_learning.apps.authoring.applets.publishing.models import ( Container, ContainerVersion, Draft, diff --git a/tests/openedx_learning/apps/authoring/publishing/test_models.py b/tests/openedx_learning/apps/authoring/applets/publishing/test_models.py similarity index 84% rename from tests/openedx_learning/apps/authoring/publishing/test_models.py rename to tests/openedx_learning/apps/authoring/applets/publishing/test_models.py index 60b2d0840..2c1f68098 100644 --- a/tests/openedx_learning/apps/authoring/publishing/test_models.py +++ b/tests/openedx_learning/apps/authoring/applets/publishing/test_models.py @@ -3,7 +3,7 @@ """ from typing import TYPE_CHECKING, assert_type -from openedx_learning.apps.authoring.publishing.models import PublishableEntityMixin, PublishableEntityVersionMixin +from openedx_learning.apps.authoring.applets.publishing.models import PublishableEntityMixin, PublishableEntityVersionMixin from openedx_learning.lib.managers import WithRelationsManager if TYPE_CHECKING: diff --git a/openedx_learning/apps/authoring/units/__init__.py b/tests/openedx_learning/apps/authoring/applets/sections/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/units/__init__.py rename to tests/openedx_learning/apps/authoring/applets/sections/__init__.py diff --git a/tests/openedx_learning/apps/authoring/sections/test_api.py b/tests/openedx_learning/apps/authoring/applets/sections/test_api.py similarity index 100% rename from tests/openedx_learning/apps/authoring/sections/test_api.py rename to tests/openedx_learning/apps/authoring/applets/sections/test_api.py diff --git a/openedx_learning/apps/authoring/units/migrations/__init__.py b/tests/openedx_learning/apps/authoring/applets/subsections/__init__.py similarity index 100% rename from openedx_learning/apps/authoring/units/migrations/__init__.py rename to tests/openedx_learning/apps/authoring/applets/subsections/__init__.py diff --git a/tests/openedx_learning/apps/authoring/subsections/test_api.py b/tests/openedx_learning/apps/authoring/applets/subsections/test_api.py similarity index 99% rename from tests/openedx_learning/apps/authoring/subsections/test_api.py rename to tests/openedx_learning/apps/authoring/applets/subsections/test_api.py index 577881a9a..6bf4fb5f9 100644 --- a/tests/openedx_learning/apps/authoring/subsections/test_api.py +++ b/tests/openedx_learning/apps/authoring/applets/subsections/test_api.py @@ -262,7 +262,7 @@ def test_adding_external_units(self): created_by=None, ) - @patch('openedx_learning.apps.authoring.subsections.api._pub_entities_for_units') + @patch('openedx_learning.apps.authoring.applets.subsections.api._pub_entities_for_units') def test_adding_mismatched_versions(self, mock_entities_for_units): # pylint: disable=arguments-renamed """ Test that versioned units must match their entities. diff --git a/tests/openedx_learning/apps/authoring/backup_restore/__init__.py b/tests/openedx_learning/apps/authoring/applets/units/__init__.py similarity index 100% rename from tests/openedx_learning/apps/authoring/backup_restore/__init__.py rename to tests/openedx_learning/apps/authoring/applets/units/__init__.py diff --git a/tests/openedx_learning/apps/authoring/units/test_api.py b/tests/openedx_learning/apps/authoring/applets/units/test_api.py similarity index 99% rename from tests/openedx_learning/apps/authoring/units/test_api.py rename to tests/openedx_learning/apps/authoring/applets/units/test_api.py index ebef4810a..f327e37f2 100644 --- a/tests/openedx_learning/apps/authoring/units/test_api.py +++ b/tests/openedx_learning/apps/authoring/applets/units/test_api.py @@ -250,7 +250,7 @@ def test_adding_external_components(self): created_by=None, ) - @patch('openedx_learning.apps.authoring.units.api._pub_entities_for_components') + @patch('openedx_learning.apps.authoring.applets.units.api._pub_entities_for_components') def test_adding_mismatched_versions(self, mock_entities_for_components): """ Test that versioned components must match their entities. diff --git a/tests/openedx_learning/apps/authoring/collections/__init__.py b/tests/openedx_learning/apps/authoring/collections/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/openedx_learning/apps/authoring/components/__init__.py b/tests/openedx_learning/apps/authoring/components/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/openedx_learning/apps/authoring/contents/__init__.py b/tests/openedx_learning/apps/authoring/contents/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/openedx_learning/apps/authoring/publishing/__init__.py b/tests/openedx_learning/apps/authoring/publishing/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/openedx_learning/apps/authoring/sections/__init__.py b/tests/openedx_learning/apps/authoring/sections/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/openedx_learning/apps/authoring/subsections/__init__.py b/tests/openedx_learning/apps/authoring/subsections/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/openedx_learning/apps/authoring/units/__init__.py b/tests/openedx_learning/apps/authoring/units/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/openedx_tagging/core/tagging/test_system_defined_models.py b/tests/openedx_tagging/core/tagging/test_system_defined_models.py index f771d82ee..ccd30b336 100644 --- a/tests/openedx_tagging/core/tagging/test_system_defined_models.py +++ b/tests/openedx_tagging/core/tagging/test_system_defined_models.py @@ -9,7 +9,7 @@ import pytest from django.test import TestCase, override_settings -from openedx_learning.apps.authoring.publishing.models import LearningPackage +from openedx_learning.apps.authoring.applets.publishing.models import LearningPackage from openedx_tagging.core.tagging import api from openedx_tagging.core.tagging.models import Taxonomy from openedx_tagging.core.tagging.models.system_defined import ModelSystemDefinedTaxonomy, UserSystemDefinedTaxonomy