openedx-learning 0.8.0__tar.gz → 0.9.1__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.
Files changed (114) hide show
  1. {openedx-learning-0.8.0/openedx_learning.egg-info → openedx_learning-0.9.1}/PKG-INFO +6 -5
  2. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/__init__.py +1 -1
  3. {openedx-learning-0.8.0 → openedx_learning-0.9.1/openedx_learning.egg-info}/PKG-INFO +6 -5
  4. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning.egg-info/SOURCES.txt +1 -0
  5. openedx_learning-0.9.1/openedx_tagging/core/tagging/migrations/0017_alter_tagimporttask_status.py +18 -0
  6. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/models/import_export.py +7 -8
  7. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/rest_api/v1/serializers.py +8 -9
  8. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/rest_api/v1/views.py +57 -36
  9. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/setup.py +1 -0
  10. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/CHANGELOG.rst +0 -0
  11. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/LICENSE.txt +0 -0
  12. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/MANIFEST.in +0 -0
  13. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/README.rst +0 -0
  14. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/contrib/__init__.py +0 -0
  15. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/contrib/media_server/__init__.py +0 -0
  16. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/contrib/media_server/apps.py +0 -0
  17. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/contrib/media_server/urls.py +0 -0
  18. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/contrib/media_server/views.py +0 -0
  19. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/__init__.py +0 -0
  20. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/components/__init__.py +0 -0
  21. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/components/admin.py +0 -0
  22. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/components/api.py +0 -0
  23. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/components/apps.py +0 -0
  24. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/components/migrations/0001_initial.py +0 -0
  25. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/components/migrations/0002_alter_componentversioncontent_key.py +0 -0
  26. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/components/migrations/__init__.py +0 -0
  27. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/components/models.py +0 -0
  28. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/contents/__init__.py +0 -0
  29. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/contents/admin.py +0 -0
  30. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/contents/api.py +0 -0
  31. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/contents/apps.py +0 -0
  32. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/contents/migrations/0001_initial.py +0 -0
  33. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/contents/migrations/__init__.py +0 -0
  34. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/contents/models.py +0 -0
  35. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/publishing/__init__.py +0 -0
  36. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/publishing/admin.py +0 -0
  37. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/publishing/api.py +0 -0
  38. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/publishing/apps.py +0 -0
  39. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/publishing/migrations/0001_initial.py +0 -0
  40. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/publishing/migrations/0002_alter_learningpackage_key_and_more.py +0 -0
  41. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/publishing/migrations/__init__.py +0 -0
  42. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/publishing/model_mixins.py +0 -0
  43. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/core/publishing/models.py +0 -0
  44. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/lib/__init__.py +0 -0
  45. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/lib/admin_utils.py +0 -0
  46. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/lib/cache.py +0 -0
  47. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/lib/collations.py +0 -0
  48. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/lib/fields.py +0 -0
  49. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/lib/managers.py +0 -0
  50. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/lib/test_utils.py +0 -0
  51. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/lib/validators.py +0 -0
  52. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/py.typed +0 -0
  53. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/rest_api/__init__.py +0 -0
  54. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/rest_api/apps.py +0 -0
  55. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/rest_api/urls.py +0 -0
  56. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/rest_api/v1/__init__.py +0 -0
  57. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/rest_api/v1/components.py +0 -0
  58. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning/rest_api/v1/urls.py +0 -0
  59. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning.egg-info/dependency_links.txt +0 -0
  60. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning.egg-info/not-zip-safe +0 -0
  61. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning.egg-info/requires.txt +4 -4
  62. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_learning.egg-info/top_level.txt +0 -0
  63. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/__init__.py +0 -0
  64. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/__init__.py +0 -0
  65. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/__init__.py +0 -0
  66. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/admin.py +0 -0
  67. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/api.py +0 -0
  68. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/apps.py +0 -0
  69. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/data.py +0 -0
  70. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/import_export/__init__.py +0 -0
  71. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/import_export/actions.py +0 -0
  72. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/import_export/api.py +0 -0
  73. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/import_export/exceptions.py +0 -0
  74. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/import_export/import_plan.py +0 -0
  75. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/import_export/parsers.py +0 -0
  76. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/import_export/tasks.py +0 -0
  77. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/import_export/template.csv +0 -0
  78. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/import_export/template.json +0 -0
  79. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0001_initial.py +0 -0
  80. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0001_squashed.py +0 -0
  81. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0002_auto_20230718_2026.py +0 -0
  82. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0003_auto_20230721_1238.py +0 -0
  83. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0004_auto_20230723_2001.py +0 -0
  84. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0005_language_taxonomy.py +0 -0
  85. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0006_alter_objecttag_unique_together.py +0 -0
  86. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0006_auto_20230802_1631.py +0 -0
  87. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0007_tag_import_task_log_null_fix.py +0 -0
  88. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0008_taxonomy_description_not_null.py +0 -0
  89. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0009_alter_objecttag_object_id.py +0 -0
  90. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0010_cleanups.py +0 -0
  91. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0011_remove_required.py +0 -0
  92. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0012_language_taxonomy.py +0 -0
  93. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0013_tag_parent_blank.py +0 -0
  94. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0014_minor_fixes.py +0 -0
  95. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0015_taxonomy_export_id.py +0 -0
  96. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/0016_object_tag_export_id.py +0 -0
  97. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/migrations/__init__.py +0 -0
  98. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/models/__init__.py +0 -0
  99. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/models/base.py +0 -0
  100. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/models/system_defined.py +0 -0
  101. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/models/utils.py +0 -0
  102. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/rest_api/__init__.py +0 -0
  103. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/rest_api/paginators.py +0 -0
  104. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/rest_api/urls.py +0 -0
  105. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/rest_api/utils.py +0 -0
  106. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/rest_api/v1/__init__.py +0 -0
  107. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/rest_api/v1/permissions.py +0 -0
  108. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/rest_api/v1/urls.py +0 -0
  109. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/rest_api/v1/views_import.py +0 -0
  110. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/rules.py +0 -0
  111. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/core/tagging/urls.py +0 -0
  112. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/openedx_tagging/py.typed +0 -0
  113. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/requirements/base.in +0 -0
  114. {openedx-learning-0.8.0 → openedx_learning-0.9.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openedx-learning
3
- Version: 0.8.0
3
+ Version: 0.9.1
4
4
  Summary: An experiment.
5
5
  Home-page: https://github.com/openedx/openedx-learning
6
6
  Author: David Ormsbee
@@ -15,15 +15,16 @@ Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or l
15
15
  Classifier: Natural Language :: English
16
16
  Classifier: Programming Language :: Python :: 3
17
17
  Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.11
18
19
  Classifier: Programming Language :: Python :: 3.12
19
20
  Requires-Python: >=3.8
20
21
  License-File: LICENSE.txt
21
- Requires-Dist: rules<4.0
22
- Requires-Dist: Django<5.0
23
- Requires-Dist: edx-drf-extensions
24
- Requires-Dist: attrs
25
22
  Requires-Dist: djangorestframework<4.0
23
+ Requires-Dist: attrs
24
+ Requires-Dist: edx-drf-extensions
25
+ Requires-Dist: Django<5.0
26
26
  Requires-Dist: celery
27
+ Requires-Dist: rules<4.0
27
28
 
28
29
  openedx-learning
29
30
  =============================
@@ -1,4 +1,4 @@
1
1
  """
2
2
  Open edX Learning ("Learning Core").
3
3
  """
4
- __version__ = "0.8.0"
4
+ __version__ = "0.9.1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openedx-learning
3
- Version: 0.8.0
3
+ Version: 0.9.1
4
4
  Summary: An experiment.
5
5
  Home-page: https://github.com/openedx/openedx-learning
6
6
  Author: David Ormsbee
@@ -15,15 +15,16 @@ Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or l
15
15
  Classifier: Natural Language :: English
16
16
  Classifier: Programming Language :: Python :: 3
17
17
  Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.11
18
19
  Classifier: Programming Language :: Python :: 3.12
19
20
  Requires-Python: >=3.8
20
21
  License-File: LICENSE.txt
21
- Requires-Dist: rules<4.0
22
- Requires-Dist: Django<5.0
23
- Requires-Dist: edx-drf-extensions
24
- Requires-Dist: attrs
25
22
  Requires-Dist: djangorestframework<4.0
23
+ Requires-Dist: attrs
24
+ Requires-Dist: edx-drf-extensions
25
+ Requires-Dist: Django<5.0
26
26
  Requires-Dist: celery
27
+ Requires-Dist: rules<4.0
27
28
 
28
29
  openedx-learning
29
30
  =============================
@@ -93,6 +93,7 @@ openedx_tagging/core/tagging/migrations/0013_tag_parent_blank.py
93
93
  openedx_tagging/core/tagging/migrations/0014_minor_fixes.py
94
94
  openedx_tagging/core/tagging/migrations/0015_taxonomy_export_id.py
95
95
  openedx_tagging/core/tagging/migrations/0016_object_tag_export_id.py
96
+ openedx_tagging/core/tagging/migrations/0017_alter_tagimporttask_status.py
96
97
  openedx_tagging/core/tagging/migrations/__init__.py
97
98
  openedx_tagging/core/tagging/models/__init__.py
98
99
  openedx_tagging/core/tagging/models/base.py
@@ -0,0 +1,18 @@
1
+ # Generated by Django 4.2.11 on 2024-04-05 06:58
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('oel_tagging', '0016_object_tag_export_id'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='tagimporttask',
15
+ name='status',
16
+ field=models.CharField(choices=[('loading_data', 'Loading Data'), ('planning', 'Planning'), ('executing', 'Executing'), ('success', 'Success'), ('error', 'Error')], help_text='Task status', max_length=20),
17
+ ),
18
+ ]
@@ -3,7 +3,6 @@ Models used by the Taxonomy import/export tasks.
3
3
  """
4
4
 
5
5
  from datetime import datetime
6
- from enum import Enum
7
6
 
8
7
  from django.db import models
9
8
  from django.utils.translation import gettext as _
@@ -12,15 +11,15 @@ from django.utils.translation import gettext_lazy
12
11
  from .base import Taxonomy
13
12
 
14
13
 
15
- class TagImportTaskState(Enum):
14
+ class TagImportTaskState(models.TextChoices):
16
15
  """
17
16
  Enumerates the states that a TagImportTask can be in.
18
17
  """
19
- LOADING_DATA = "loading_data"
20
- PLANNING = "planning"
21
- EXECUTING = "executing"
22
- SUCCESS = "success"
23
- ERROR = "error"
18
+ LOADING_DATA = "loading_data", gettext_lazy("Loading Data")
19
+ PLANNING = "planning", gettext_lazy("Planning")
20
+ EXECUTING = "executing", gettext_lazy("Executing")
21
+ SUCCESS = "success", gettext_lazy("Success")
22
+ ERROR = "error", gettext_lazy("Error")
24
23
 
25
24
 
26
25
  class TagImportTask(models.Model):
@@ -42,7 +41,7 @@ class TagImportTask(models.Model):
42
41
 
43
42
  status = models.CharField(
44
43
  max_length=20,
45
- choices=[(status, status.value) for status in TagImportTaskState],
44
+ choices=TagImportTaskState.choices,
46
45
  help_text=gettext_lazy("Task status"),
47
46
  )
48
47
 
@@ -191,22 +191,21 @@ class ObjectTagsByTaxonomySerializer(UserPermissionsSerializerMixin, serializers
191
191
  return by_object
192
192
 
193
193
 
194
- class ObjectTagUpdateBodySerializer(serializers.Serializer): # pylint: disable=abstract-method
194
+ class ObjectTagUpdateByTaxonomySerializer(serializers.Serializer): # pylint: disable=abstract-method
195
195
  """
196
- Serializer of the body for the ObjectTag UPDATE view
196
+ Serializer of a taxonomy item of ObjectTag UPDATE view.
197
197
  """
198
-
198
+ taxonomy = serializers.PrimaryKeyRelatedField(
199
+ queryset=Taxonomy.objects.all(), required=True
200
+ )
199
201
  tags = serializers.ListField(child=serializers.CharField(), required=True)
200
202
 
201
203
 
202
- class ObjectTagUpdateQueryParamsSerializer(serializers.Serializer): # pylint: disable=abstract-method
204
+ class ObjectTagUpdateBodySerializer(serializers.Serializer): # pylint: disable=abstract-method
203
205
  """
204
- Serializer of the query params for the ObjectTag UPDATE view
206
+ Serializer of the body for the ObjectTag UPDATE view
205
207
  """
206
-
207
- taxonomy = serializers.PrimaryKeyRelatedField(
208
- queryset=Taxonomy.objects.all(), required=True
209
- )
208
+ tagsData = serializers.ListField(child=ObjectTagUpdateByTaxonomySerializer(), required=True)
210
209
 
211
210
 
212
211
  class TagDataSerializer(UserPermissionsSerializerMixin, serializers.Serializer): # pylint: disable=abstract-method
@@ -40,7 +40,6 @@ from .serializers import (
40
40
  ObjectTagsByTaxonomySerializer,
41
41
  ObjectTagSerializer,
42
42
  ObjectTagUpdateBodySerializer,
43
- ObjectTagUpdateQueryParamsSerializer,
44
43
  TagDataSerializer,
45
44
  TaxonomyExportQueryParamsSerializer,
46
45
  TaxonomyImportBodySerializer,
@@ -501,8 +500,8 @@ class ObjectTagView(
501
500
  Update ObjectTags that belong to a given object_id
502
501
 
503
502
  Pass a list of Tag ids or Tag values to be applied to an object id in the
504
- body `tag` parameter. Passing an empty list will remove all tags from
505
- the object id.
503
+ body `tag` parameter, by each taxonomy. Passing an empty list will remove all tags from
504
+ the object id on an specific taxonomy.
506
505
 
507
506
  **Example Body Requests**
508
507
 
@@ -511,54 +510,76 @@ class ObjectTagView(
511
510
  **Example Body Requests**
512
511
  ```json
513
512
  {
514
- "tags": [1, 2, 3]
513
+ "tagsData": [
514
+ {
515
+ "taxonomy": 1,
516
+ "tags": [1, 2, 3]
517
+ },
518
+ {
519
+ "taxonomy": 1,
520
+ "tags": [1, 2, 3]
521
+ }
522
+ ],
515
523
  },
516
524
  {
517
- "tags": ["Tag 1", "Tag 2"]
525
+ "tagsData": [
526
+ {
527
+ "taxonomy": 1,
528
+ "tags": ["Tag 1", "Tag 2"]
529
+ },
530
+ ]
518
531
  },
519
532
  {
520
- "tags": []
533
+ "tagsData": [
534
+ {
535
+ "taxonomy": 1,
536
+ "tags": []
537
+ },
538
+ ]
521
539
  }
522
540
  """
523
-
524
541
  partial = kwargs.pop('partial', False)
525
542
  if partial:
526
543
  raise MethodNotAllowed("PATCH", detail="PATCH not allowed")
527
544
 
528
- query_params = ObjectTagUpdateQueryParamsSerializer(
529
- data=request.query_params.dict()
530
- )
531
- query_params.is_valid(raise_exception=True)
532
- taxonomy = query_params.validated_data.get("taxonomy", None)
533
- taxonomy = taxonomy.cast()
534
-
545
+ object_id = kwargs.pop('object_id')
535
546
  perm = "oel_tagging.can_tag_object"
547
+ body = ObjectTagUpdateBodySerializer(data=request.data)
548
+ body.is_valid(raise_exception=True)
536
549
 
537
- object_id = kwargs.pop('object_id')
538
- perm_obj = ObjectTagPermissionItem(
539
- taxonomy=taxonomy,
540
- object_id=object_id,
541
- )
550
+ data = body.validated_data.get("tagsData", [])
542
551
 
543
- if not request.user.has_perm(
544
- perm,
545
- # The obj arg expects a model, but we are passing an object
546
- perm_obj, # type: ignore[arg-type]
547
- ):
548
- raise PermissionDenied(
549
- "You do not have permission to change object tags for this taxonomy or object_id."
550
- )
552
+ if not data:
553
+ return self.retrieve(request, object_id)
551
554
 
552
- body = ObjectTagUpdateBodySerializer(data=request.data)
553
- body.is_valid(raise_exception=True)
555
+ # Check permissions
556
+ for tagsData in data:
557
+ taxonomy = tagsData.get("taxonomy")
554
558
 
555
- tags = body.data.get("tags", [])
556
- try:
557
- tag_object(object_id, taxonomy, tags)
558
- except TagDoesNotExist as e:
559
- raise ValidationError from e
560
- except ValueError as e:
561
- raise ValidationError from e
559
+ perm_obj = ObjectTagPermissionItem(
560
+ taxonomy=taxonomy,
561
+ object_id=object_id,
562
+ )
563
+ if not request.user.has_perm(
564
+ perm,
565
+ # The obj arg expects a model, but we are passing an object
566
+ perm_obj, # type: ignore[arg-type]
567
+ ):
568
+ raise PermissionDenied(f"""
569
+ You do not have permission to change object tags
570
+ for Taxonomy: {str(taxonomy)} or Object: {object_id}.
571
+ """)
572
+
573
+ # Tag object_id per taxonomy
574
+ for tagsData in data:
575
+ taxonomy = tagsData.get("taxonomy")
576
+ tags = tagsData.get("tags", [])
577
+ try:
578
+ tag_object(object_id, taxonomy, tags)
579
+ except TagDoesNotExist as e:
580
+ raise ValidationError from e
581
+ except ValueError as e:
582
+ raise ValidationError from e
562
583
 
563
584
  return self.retrieve(request, object_id)
564
585
 
@@ -91,6 +91,7 @@ setup(
91
91
  'Natural Language :: English',
92
92
  'Programming Language :: Python :: 3',
93
93
  'Programming Language :: Python :: 3.8',
94
+ 'Programming Language :: Python :: 3.11',
94
95
  'Programming Language :: Python :: 3.12',
95
96
  ],
96
97
  )
@@ -1,6 +1,6 @@
1
- rules<4.0
2
- Django<5.0
3
- edx-drf-extensions
4
- attrs
5
1
  djangorestframework<4.0
2
+ attrs
3
+ edx-drf-extensions
4
+ Django<5.0
6
5
  celery
6
+ rules<4.0