openedx-learning 0.11.3__tar.gz → 0.11.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openedx_learning-0.11.3/openedx_learning.egg-info → openedx_learning-0.11.5}/PKG-INFO +5 -5
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/__init__.py +1 -1
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/collections/api.py +17 -12
- openedx_learning-0.11.5/openedx_learning/apps/authoring/collections/migrations/0004_collection_key.py +57 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/collections/models.py +33 -3
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/publishing/model_mixins.py +4 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5/openedx_learning.egg-info}/PKG-INFO +5 -5
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning.egg-info/SOURCES.txt +1 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/setup.py +1 -1
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/CHANGELOG.rst +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/LICENSE.txt +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/MANIFEST.in +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/README.rst +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/api/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/api/authoring.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/api/authoring_models.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/collections/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/collections/apps.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/collections/migrations/0001_initial.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/collections/migrations/0002_remove_collection_name_collection_created_by_and_more.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/collections/migrations/0003_collection_entities.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/collections/migrations/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/components/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/components/admin.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/components/api.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/components/apps.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/components/migrations/0001_initial.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/components/migrations/0002_alter_componentversioncontent_key.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/components/migrations/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/components/models.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/contents/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/contents/admin.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/contents/api.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/contents/apps.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/contents/migrations/0001_initial.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/contents/migrations/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/contents/models.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/publishing/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/publishing/admin.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/publishing/api.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/publishing/apps.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/publishing/migrations/0001_initial.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/publishing/migrations/0002_alter_learningpackage_key_and_more.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/publishing/migrations/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/publishing/models.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/contrib/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/contrib/media_server/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/contrib/media_server/apps.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/contrib/media_server/urls.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/contrib/media_server/views.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/lib/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/lib/admin_utils.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/lib/cache.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/lib/collations.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/lib/fields.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/lib/managers.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/lib/test_utils.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/lib/validators.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/py.typed +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning.egg-info/dependency_links.txt +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning.egg-info/not-zip-safe +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning.egg-info/requires.txt +3 -3
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning.egg-info/top_level.txt +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/admin.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/api.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/apps.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/data.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/import_export/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/import_export/actions.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/import_export/api.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/import_export/exceptions.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/import_export/import_plan.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/import_export/parsers.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/import_export/tasks.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/import_export/template.csv +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/import_export/template.json +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0001_initial.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0001_squashed.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0002_auto_20230718_2026.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0003_auto_20230721_1238.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0004_auto_20230723_2001.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0005_language_taxonomy.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0006_alter_objecttag_unique_together.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0006_auto_20230802_1631.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0007_tag_import_task_log_null_fix.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0008_taxonomy_description_not_null.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0009_alter_objecttag_object_id.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0010_cleanups.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0011_remove_required.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0012_language_taxonomy.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0013_tag_parent_blank.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0014_minor_fixes.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0015_taxonomy_export_id.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0016_object_tag_export_id.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/0017_alter_tagimporttask_status.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/migrations/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/models/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/models/base.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/models/import_export.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/models/system_defined.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/models/utils.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/paginators.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/urls.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/utils.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/v1/__init__.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/v1/permissions.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/v1/serializers.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/v1/urls.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/v1/views.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/v1/views_import.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rules.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/urls.py +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/py.typed +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/requirements/base.in +0 -0
- {openedx_learning-0.11.3 → openedx_learning-0.11.5}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: openedx-learning
|
|
3
|
-
Version: 0.11.
|
|
3
|
+
Version: 0.11.5
|
|
4
4
|
Summary: Open edX Learning Core and Tagging.
|
|
5
5
|
Home-page: https://github.com/openedx/openedx-learning
|
|
6
6
|
Author: David Ormsbee
|
|
@@ -9,7 +9,7 @@ License: AGPL 3.0
|
|
|
9
9
|
Keywords: Python edx
|
|
10
10
|
Classifier: Development Status :: 3 - Alpha
|
|
11
11
|
Classifier: Framework :: Django
|
|
12
|
-
Classifier: Framework :: Django ::
|
|
12
|
+
Classifier: Framework :: Django :: 4.2
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
|
|
15
15
|
Classifier: Natural Language :: English
|
|
@@ -18,12 +18,12 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
19
|
Requires-Python: >=3.11
|
|
20
20
|
License-File: LICENSE.txt
|
|
21
|
+
Requires-Dist: celery
|
|
21
22
|
Requires-Dist: Django<5.0
|
|
22
|
-
Requires-Dist: djangorestframework<4.0
|
|
23
|
-
Requires-Dist: edx-drf-extensions
|
|
24
23
|
Requires-Dist: attrs
|
|
24
|
+
Requires-Dist: djangorestframework<4.0
|
|
25
25
|
Requires-Dist: rules<4.0
|
|
26
|
-
Requires-Dist:
|
|
26
|
+
Requires-Dist: edx-drf-extensions
|
|
27
27
|
|
|
28
28
|
Open edX Learning Core (and Tagging)
|
|
29
29
|
====================================
|
|
@@ -30,6 +30,8 @@ __all__ = [
|
|
|
30
30
|
|
|
31
31
|
def create_collection(
|
|
32
32
|
learning_package_id: int,
|
|
33
|
+
key: str,
|
|
34
|
+
*,
|
|
33
35
|
title: str,
|
|
34
36
|
created_by: int | None,
|
|
35
37
|
description: str = "",
|
|
@@ -40,6 +42,7 @@ def create_collection(
|
|
|
40
42
|
"""
|
|
41
43
|
collection = Collection.objects.create(
|
|
42
44
|
learning_package_id=learning_package_id,
|
|
45
|
+
key=key,
|
|
43
46
|
title=title,
|
|
44
47
|
created_by_id=created_by,
|
|
45
48
|
description=description,
|
|
@@ -48,22 +51,24 @@ def create_collection(
|
|
|
48
51
|
return collection
|
|
49
52
|
|
|
50
53
|
|
|
51
|
-
def get_collection(
|
|
54
|
+
def get_collection(learning_package_id: int, collection_key: str) -> Collection:
|
|
52
55
|
"""
|
|
53
56
|
Get a Collection by ID
|
|
54
57
|
"""
|
|
55
|
-
return Collection.objects.
|
|
58
|
+
return Collection.objects.get_by_key(learning_package_id, collection_key)
|
|
56
59
|
|
|
57
60
|
|
|
58
61
|
def update_collection(
|
|
59
|
-
|
|
62
|
+
learning_package_id: int,
|
|
63
|
+
key: str,
|
|
64
|
+
*,
|
|
60
65
|
title: str | None = None,
|
|
61
66
|
description: str | None = None,
|
|
62
67
|
) -> Collection:
|
|
63
68
|
"""
|
|
64
|
-
Update a Collection
|
|
69
|
+
Update a Collection identified by the learning_package_id + key.
|
|
65
70
|
"""
|
|
66
|
-
collection =
|
|
71
|
+
collection = get_collection(learning_package_id, key)
|
|
67
72
|
|
|
68
73
|
# If no changes were requested, there's nothing to update, so just return
|
|
69
74
|
# the Collection as-is
|
|
@@ -80,7 +85,8 @@ def update_collection(
|
|
|
80
85
|
|
|
81
86
|
|
|
82
87
|
def add_to_collection(
|
|
83
|
-
|
|
88
|
+
learning_package_id: int,
|
|
89
|
+
key: str,
|
|
84
90
|
entities_qset: QuerySet[PublishableEntity],
|
|
85
91
|
created_by: int | None = None,
|
|
86
92
|
) -> Collection:
|
|
@@ -95,17 +101,15 @@ def add_to_collection(
|
|
|
95
101
|
|
|
96
102
|
Returns the updated Collection object.
|
|
97
103
|
"""
|
|
98
|
-
collection = get_collection(collection_id)
|
|
99
|
-
learning_package_id = collection.learning_package_id
|
|
100
|
-
|
|
101
104
|
# Disallow adding entities outside the collection's learning package
|
|
102
105
|
invalid_entity = entities_qset.exclude(learning_package_id=learning_package_id).first()
|
|
103
106
|
if invalid_entity:
|
|
104
107
|
raise ValidationError(
|
|
105
108
|
f"Cannot add entity {invalid_entity.pk} in learning package {invalid_entity.learning_package_id} "
|
|
106
|
-
f"to collection {
|
|
109
|
+
f"to collection {key} in learning package {learning_package_id}."
|
|
107
110
|
)
|
|
108
111
|
|
|
112
|
+
collection = get_collection(learning_package_id, key)
|
|
109
113
|
collection.entities.add(
|
|
110
114
|
*entities_qset.all(),
|
|
111
115
|
through_defaults={"created_by_id": created_by},
|
|
@@ -117,7 +121,8 @@ def add_to_collection(
|
|
|
117
121
|
|
|
118
122
|
|
|
119
123
|
def remove_from_collection(
|
|
120
|
-
|
|
124
|
+
learning_package_id: int,
|
|
125
|
+
key: str,
|
|
121
126
|
entities_qset: QuerySet[PublishableEntity],
|
|
122
127
|
) -> Collection:
|
|
123
128
|
"""
|
|
@@ -129,7 +134,7 @@ def remove_from_collection(
|
|
|
129
134
|
|
|
130
135
|
Returns the updated Collection.
|
|
131
136
|
"""
|
|
132
|
-
collection = get_collection(
|
|
137
|
+
collection = get_collection(learning_package_id, key)
|
|
133
138
|
|
|
134
139
|
collection.entities.remove(*entities_qset.all())
|
|
135
140
|
collection.modified = datetime.now(tz=timezone.utc)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Generated by Django 4.2.15 on 2024-09-04 23:15
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
from django.utils.crypto import get_random_string
|
|
5
|
+
|
|
6
|
+
import openedx_learning.lib.fields
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def generate_keys(apps, schema_editor):
|
|
10
|
+
"""
|
|
11
|
+
Generates a random strings to initialize the key field where NULL.
|
|
12
|
+
"""
|
|
13
|
+
length = 50
|
|
14
|
+
Collection = apps.get_model("oel_collections", "Collection")
|
|
15
|
+
for collection in Collection.objects.filter(key=None):
|
|
16
|
+
# Keep generating keys until we get a unique one
|
|
17
|
+
key = get_random_string(length)
|
|
18
|
+
while Collection.objects.filter(key=key).exists():
|
|
19
|
+
key = get_random_string(length)
|
|
20
|
+
|
|
21
|
+
collection.key = key
|
|
22
|
+
collection.save()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Migration(migrations.Migration):
|
|
26
|
+
|
|
27
|
+
dependencies = [
|
|
28
|
+
('oel_collections', '0003_collection_entities'),
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
operations = [
|
|
32
|
+
# 1. Temporarily add this field with null=True, blank=True
|
|
33
|
+
migrations.AddField(
|
|
34
|
+
model_name='collection',
|
|
35
|
+
name='key',
|
|
36
|
+
field=openedx_learning.lib.fields.MultiCollationCharField(
|
|
37
|
+
db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'},
|
|
38
|
+
db_column='_key', max_length=500, null=True, blank=True),
|
|
39
|
+
preserve_default=False,
|
|
40
|
+
),
|
|
41
|
+
# 2. Populate the null keys
|
|
42
|
+
migrations.RunPython(generate_keys),
|
|
43
|
+
# 3. Add null=False, blank=False to disallow NULL values
|
|
44
|
+
migrations.AlterField(
|
|
45
|
+
model_name='collection',
|
|
46
|
+
name='key',
|
|
47
|
+
field=openedx_learning.lib.fields.MultiCollationCharField(
|
|
48
|
+
db_collations={'mysql': 'utf8mb4_bin', 'sqlite': 'BINARY'},
|
|
49
|
+
db_column='_key', max_length=500, null=False, blank=False),
|
|
50
|
+
preserve_default=False,
|
|
51
|
+
),
|
|
52
|
+
# 4. Enforce unique constraint
|
|
53
|
+
migrations.AddConstraint(
|
|
54
|
+
model_name='collection',
|
|
55
|
+
constraint=models.UniqueConstraint(fields=('learning_package', 'key'), name='oel_coll_uniq_lp_key'),
|
|
56
|
+
),
|
|
57
|
+
]
|
|
@@ -70,8 +70,9 @@ from django.conf import settings
|
|
|
70
70
|
from django.db import models
|
|
71
71
|
from django.utils.translation import gettext_lazy as _
|
|
72
72
|
|
|
73
|
-
from
|
|
74
|
-
from
|
|
73
|
+
from openedx_learning.lib.fields import MultiCollationTextField, case_insensitive_char_field, key_field
|
|
74
|
+
from openedx_learning.lib.validators import validate_utc_datetime
|
|
75
|
+
|
|
75
76
|
from ..publishing.models import LearningPackage, PublishableEntity
|
|
76
77
|
|
|
77
78
|
__all__ = [
|
|
@@ -80,16 +81,35 @@ __all__ = [
|
|
|
80
81
|
]
|
|
81
82
|
|
|
82
83
|
|
|
84
|
+
class CollectionManager(models.Manager):
|
|
85
|
+
"""
|
|
86
|
+
Custom manager for Collection class.
|
|
87
|
+
"""
|
|
88
|
+
def get_by_key(self, learning_package_id: int, key: str):
|
|
89
|
+
"""
|
|
90
|
+
Get the Collection for the given Learning Package + key.
|
|
91
|
+
"""
|
|
92
|
+
return self.select_related('learning_package') \
|
|
93
|
+
.get(learning_package_id=learning_package_id, key=key)
|
|
94
|
+
|
|
95
|
+
|
|
83
96
|
class Collection(models.Model):
|
|
84
97
|
"""
|
|
85
98
|
Represents a collection of library components
|
|
86
99
|
"""
|
|
100
|
+
objects: CollectionManager[Collection] = CollectionManager()
|
|
87
101
|
|
|
88
102
|
id = models.AutoField(primary_key=True)
|
|
89
103
|
|
|
90
104
|
# Each collection belongs to a learning package
|
|
91
105
|
learning_package = models.ForeignKey(LearningPackage, on_delete=models.CASCADE)
|
|
92
106
|
|
|
107
|
+
# Every collection is uniquely and permanently identified within its learning package
|
|
108
|
+
# by a 'key' that is set during creation. Both will appear in the
|
|
109
|
+
# collection's opaque key:
|
|
110
|
+
# e.g. "lib-collection:lib:key" is the opaque key for a library collection.
|
|
111
|
+
key = key_field(db_column='_key')
|
|
112
|
+
|
|
93
113
|
title = case_insensitive_char_field(
|
|
94
114
|
null=False,
|
|
95
115
|
blank=False,
|
|
@@ -151,6 +171,16 @@ class Collection(models.Model):
|
|
|
151
171
|
|
|
152
172
|
class Meta:
|
|
153
173
|
verbose_name_plural = "Collections"
|
|
174
|
+
constraints = [
|
|
175
|
+
# Keys are unique within a given LearningPackage.
|
|
176
|
+
models.UniqueConstraint(
|
|
177
|
+
fields=[
|
|
178
|
+
"learning_package",
|
|
179
|
+
"key",
|
|
180
|
+
],
|
|
181
|
+
name="oel_coll_uniq_lp_key",
|
|
182
|
+
),
|
|
183
|
+
]
|
|
154
184
|
indexes = [
|
|
155
185
|
models.Index(fields=["learning_package", "title"]),
|
|
156
186
|
]
|
|
@@ -165,7 +195,7 @@ class Collection(models.Model):
|
|
|
165
195
|
"""
|
|
166
196
|
User-facing string representation of a Collection.
|
|
167
197
|
"""
|
|
168
|
-
return f"<{self.__class__.__name__}> ({self.
|
|
198
|
+
return f"<{self.__class__.__name__}> (lp:{self.learning_package_id} {self.key}:{self.title})"
|
|
169
199
|
|
|
170
200
|
|
|
171
201
|
class CollectionPublishableEntity(models.Model):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: openedx-learning
|
|
3
|
-
Version: 0.11.
|
|
3
|
+
Version: 0.11.5
|
|
4
4
|
Summary: Open edX Learning Core and Tagging.
|
|
5
5
|
Home-page: https://github.com/openedx/openedx-learning
|
|
6
6
|
Author: David Ormsbee
|
|
@@ -9,7 +9,7 @@ License: AGPL 3.0
|
|
|
9
9
|
Keywords: Python edx
|
|
10
10
|
Classifier: Development Status :: 3 - Alpha
|
|
11
11
|
Classifier: Framework :: Django
|
|
12
|
-
Classifier: Framework :: Django ::
|
|
12
|
+
Classifier: Framework :: Django :: 4.2
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
|
|
15
15
|
Classifier: Natural Language :: English
|
|
@@ -18,12 +18,12 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
19
|
Requires-Python: >=3.11
|
|
20
20
|
License-File: LICENSE.txt
|
|
21
|
+
Requires-Dist: celery
|
|
21
22
|
Requires-Dist: Django<5.0
|
|
22
|
-
Requires-Dist: djangorestframework<4.0
|
|
23
|
-
Requires-Dist: edx-drf-extensions
|
|
24
23
|
Requires-Dist: attrs
|
|
24
|
+
Requires-Dist: djangorestframework<4.0
|
|
25
25
|
Requires-Dist: rules<4.0
|
|
26
|
-
Requires-Dist:
|
|
26
|
+
Requires-Dist: edx-drf-extensions
|
|
27
27
|
|
|
28
28
|
Open edX Learning Core (and Tagging)
|
|
29
29
|
====================================
|
|
@@ -24,6 +24,7 @@ openedx_learning/apps/authoring/collections/models.py
|
|
|
24
24
|
openedx_learning/apps/authoring/collections/migrations/0001_initial.py
|
|
25
25
|
openedx_learning/apps/authoring/collections/migrations/0002_remove_collection_name_collection_created_by_and_more.py
|
|
26
26
|
openedx_learning/apps/authoring/collections/migrations/0003_collection_entities.py
|
|
27
|
+
openedx_learning/apps/authoring/collections/migrations/0004_collection_key.py
|
|
27
28
|
openedx_learning/apps/authoring/collections/migrations/__init__.py
|
|
28
29
|
openedx_learning/apps/authoring/components/__init__.py
|
|
29
30
|
openedx_learning/apps/authoring/components/admin.py
|
|
@@ -85,7 +85,7 @@ setup(
|
|
|
85
85
|
classifiers=[
|
|
86
86
|
'Development Status :: 3 - Alpha',
|
|
87
87
|
'Framework :: Django',
|
|
88
|
-
'Framework :: Django ::
|
|
88
|
+
'Framework :: Django :: 4.2',
|
|
89
89
|
'Intended Audience :: Developers',
|
|
90
90
|
'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)',
|
|
91
91
|
'Natural Language :: English',
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/api/authoring_models.py
RENAMED
|
File without changes
|
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/contents/api.py
RENAMED
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/apps/authoring/contents/apps.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/contrib/media_server/apps.py
RENAMED
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/contrib/media_server/urls.py
RENAMED
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning/contrib/media_server/views.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_learning.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/models/__init__.py
RENAMED
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/models/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/models/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/urls.py
RENAMED
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openedx_learning-0.11.3 → openedx_learning-0.11.5}/openedx_tagging/core/tagging/rest_api/v1/urls.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|