openedx-learning 0.30.0__py2.py3-none-any.whl → 0.30.2__py2.py3-none-any.whl

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.
@@ -2,4 +2,4 @@
2
2
  Open edX Learning ("Learning Core").
3
3
  """
4
4
 
5
- __version__ = "0.30.0"
5
+ __version__ = "0.30.2"
@@ -9,7 +9,7 @@ from openedx_learning.apps.authoring.backup_restore.zipper import LearningPackag
9
9
  from openedx_learning.apps.authoring.publishing.api import get_learning_package_by_key
10
10
 
11
11
 
12
- def create_zip_file(lp_key: str, path: str, user: UserType | None = None) -> None:
12
+ def create_zip_file(lp_key: str, path: str, user: UserType | None = None, origin_server: str | None = None) -> None:
13
13
  """
14
14
  Creates a dump zip file for the given learning package key at the given path.
15
15
  The zip file contains a TOML representation of the learning package and its contents.
@@ -17,7 +17,7 @@ def create_zip_file(lp_key: str, path: str, user: UserType | None = None) -> Non
17
17
  Can throw a NotFoundError at get_learning_package_by_key
18
18
  """
19
19
  learning_package = get_learning_package_by_key(lp_key)
20
- LearningPackageZipper(learning_package, user).create_zip(path)
20
+ LearningPackageZipper(learning_package, user, origin_server).create_zip(path)
21
21
 
22
22
 
23
23
  def load_learning_package(path: str, key: str | None = None, user: UserType | None = None) -> dict:
@@ -32,11 +32,18 @@ class Command(BaseCommand):
32
32
  help='The username of the user performing the backup operation.',
33
33
  default=None
34
34
  )
35
+ parser.add_argument(
36
+ '--origin_server',
37
+ type=str,
38
+ help='The origin server for the backup operation.',
39
+ default=None
40
+ )
35
41
 
36
42
  def handle(self, *args, **options):
37
43
  lp_key = options['lp_key']
38
44
  file_name = options['file_name']
39
45
  username = options['username']
46
+ origin_server = options['origin_server']
40
47
  if not file_name.lower().endswith(".zip"):
41
48
  raise CommandError("Output file name must end with .zip")
42
49
  try:
@@ -45,7 +52,7 @@ class Command(BaseCommand):
45
52
  if username:
46
53
  user = User.objects.get(username=username)
47
54
  start_time = time.time()
48
- create_zip_file(lp_key, file_name, user=user)
55
+ create_zip_file(lp_key, file_name, user=user, origin_server=origin_server)
49
56
  elapsed = time.time() - start_time
50
57
  message = f'{lp_key} written to {file_name} (create_zip_file: {elapsed:.2f} seconds)'
51
58
  self.stdout.write(self.style.SUCCESS(message))
@@ -44,7 +44,6 @@ class EntitySerializer(serializers.Serializer): # pylint: disable=abstract-meth
44
44
  can_stand_alone = serializers.BooleanField(required=True)
45
45
  key = serializers.CharField(required=True)
46
46
  created = serializers.DateTimeField(required=True, default_timezone=timezone.utc)
47
- created_by = serializers.CharField(required=True, allow_null=True)
48
47
 
49
48
 
50
49
  class EntityVersionSerializer(serializers.Serializer): # pylint: disable=abstract-method
@@ -54,7 +53,6 @@ class EntityVersionSerializer(serializers.Serializer): # pylint: disable=abstra
54
53
  title = serializers.CharField(required=True)
55
54
  entity_key = serializers.CharField(required=True)
56
55
  created = serializers.DateTimeField(required=True, default_timezone=timezone.utc)
57
- created_by = serializers.CharField(required=True, allow_null=True)
58
56
  version_num = serializers.IntegerField(required=True)
59
57
 
60
58
 
@@ -160,7 +158,6 @@ class CollectionSerializer(serializers.Serializer): # pylint: disable=abstract-
160
158
  title = serializers.CharField(required=True)
161
159
  key = serializers.CharField(required=True)
162
160
  description = serializers.CharField(required=True, allow_blank=True)
163
- created_by = serializers.IntegerField(required=True, allow_null=True)
164
161
  entities = serializers.ListField(
165
162
  child=serializers.CharField(),
166
163
  required=True,
@@ -88,9 +88,22 @@ class LearningPackageZipper:
88
88
  A class to handle the zipping of learning content for backup and restore.
89
89
  """
90
90
 
91
- def __init__(self, learning_package: LearningPackage, user: UserType | None = None):
91
+ def __init__(
92
+ self,
93
+ learning_package: LearningPackage,
94
+ user: UserType | None = None,
95
+ origin_server: str | None = None):
96
+ """
97
+ Initialize the LearningPackageZipper.
98
+
99
+ Args:
100
+ learning_package (LearningPackage): The learning package to zip.
101
+ user (UserType | None): The user initiating the backup.
102
+ origin_server (str | None): The origin server for the backup.
103
+ """
92
104
  self.learning_package = learning_package
93
105
  self.user = user
106
+ self.origin_server = origin_server
94
107
  self.folders_already_created: set[Path] = set()
95
108
  self.entities_filenames_already_created: set[str] = set()
96
109
  self.utc_now = datetime.now(tz=timezone.utc)
@@ -269,7 +282,9 @@ class LearningPackageZipper:
269
282
 
270
283
  with zipfile.ZipFile(path, "w", compression=zipfile.ZIP_DEFLATED) as zipf:
271
284
  # Add the package.toml file
272
- package_toml_content: str = toml_learning_package(self.learning_package, self.utc_now, user=self.user)
285
+ package_toml_content: str = toml_learning_package(
286
+ self.learning_package, self.utc_now, user=self.user, origin_server=self.origin_server
287
+ )
273
288
  self.add_file_to_zip(zipf, Path(TOML_PACKAGE_NAME), package_toml_content, self.learning_package.updated)
274
289
 
275
290
  # Add the entities directory
@@ -493,6 +508,7 @@ class LearningPackageUnzipper:
493
508
  def __init__(self, zipf: zipfile.ZipFile, key: str | None = None, user: UserType | None = None):
494
509
  self.zipf = zipf
495
510
  self.user = user
511
+ self.user_id = getattr(self.user, "id", None)
496
512
  self.lp_key = key # If provided, use this key for the restored learning package
497
513
  self.learning_package_id: int | None = None # Will be set upon restoration
498
514
  self.utc_now: datetime = datetime.now(timezone.utc)
@@ -756,7 +772,9 @@ class LearningPackageUnzipper:
756
772
  """Save collections and their entities."""
757
773
  for valid_collection in collections.get("collections", []):
758
774
  entities = valid_collection.pop("entities", [])
759
- collection = collections_api.create_collection(learning_package.id, **valid_collection)
775
+ collection = collections_api.create_collection(
776
+ learning_package.id, created_by=self.user_id, **valid_collection
777
+ )
760
778
  collection = collections_api.add_to_collection(
761
779
  learning_package_id=learning_package.id,
762
780
  key=collection.key,
@@ -767,7 +785,7 @@ class LearningPackageUnzipper:
767
785
  """Save components and published component versions."""
768
786
  for valid_component in components.get("components", []):
769
787
  entity_key = valid_component.pop("key")
770
- component = components_api.create_component(learning_package.id, **valid_component)
788
+ component = components_api.create_component(learning_package.id, created_by=self.user_id, **valid_component)
771
789
  self.components_map_by_key[entity_key] = component
772
790
 
773
791
  for valid_published in components.get("components_published", []):
@@ -781,6 +799,7 @@ class LearningPackageUnzipper:
781
799
  self.components_map_by_key[entity_key].publishable_entity.id,
782
800
  content_to_replace=content_to_replace,
783
801
  force_version_num=valid_published.pop("version_num", None),
802
+ created_by=self.user_id,
784
803
  **valid_published
785
804
  )
786
805
 
@@ -788,7 +807,7 @@ class LearningPackageUnzipper:
788
807
  """Save units and published unit versions."""
789
808
  for valid_unit in containers.get("unit", []):
790
809
  entity_key = valid_unit.get("key")
791
- unit = units_api.create_unit(learning_package.id, **valid_unit)
810
+ unit = units_api.create_unit(learning_package.id, created_by=self.user_id, **valid_unit)
792
811
  self.units_map_by_key[entity_key] = unit
793
812
 
794
813
  for valid_published in containers.get("unit_published", []):
@@ -801,6 +820,7 @@ class LearningPackageUnzipper:
801
820
  self.units_map_by_key[entity_key],
802
821
  force_version_num=valid_published.pop("version_num", None),
803
822
  components=children,
823
+ created_by=self.user_id,
804
824
  **valid_published
805
825
  )
806
826
 
@@ -808,7 +828,9 @@ class LearningPackageUnzipper:
808
828
  """Save subsections and published subsection versions."""
809
829
  for valid_subsection in containers.get("subsection", []):
810
830
  entity_key = valid_subsection.get("key")
811
- subsection = subsections_api.create_subsection(learning_package.id, **valid_subsection)
831
+ subsection = subsections_api.create_subsection(
832
+ learning_package.id, created_by=self.user_id, **valid_subsection
833
+ )
812
834
  self.subsections_map_by_key[entity_key] = subsection
813
835
 
814
836
  for valid_published in containers.get("subsection_published", []):
@@ -821,6 +843,7 @@ class LearningPackageUnzipper:
821
843
  self.subsections_map_by_key[entity_key],
822
844
  units=children,
823
845
  force_version_num=valid_published.pop("version_num", None),
846
+ created_by=self.user_id,
824
847
  **valid_published
825
848
  )
826
849
 
@@ -828,7 +851,7 @@ class LearningPackageUnzipper:
828
851
  """Save sections and published section versions."""
829
852
  for valid_section in containers.get("section", []):
830
853
  entity_key = valid_section.get("key")
831
- section = sections_api.create_section(learning_package.id, **valid_section)
854
+ section = sections_api.create_section(learning_package.id, created_by=self.user_id, **valid_section)
832
855
  self.sections_map_by_key[entity_key] = section
833
856
 
834
857
  for valid_published in containers.get("section_published", []):
@@ -841,6 +864,7 @@ class LearningPackageUnzipper:
841
864
  self.sections_map_by_key[entity_key],
842
865
  subsections=children,
843
866
  force_version_num=valid_published.pop("version_num", None),
867
+ created_by=self.user_id,
844
868
  **valid_published
845
869
  )
846
870
 
@@ -859,6 +883,7 @@ class LearningPackageUnzipper:
859
883
  # Drafts can diverge from published, so we allow ignoring previous content
860
884
  # Use case: published v1 had files A, B; draft v2 only has file A
861
885
  ignore_previous_content=True,
886
+ created_by=self.user_id,
862
887
  **valid_draft
863
888
  )
864
889
 
@@ -872,6 +897,7 @@ class LearningPackageUnzipper:
872
897
  self.units_map_by_key[entity_key],
873
898
  components=children,
874
899
  force_version_num=valid_draft.pop("version_num", None),
900
+ created_by=self.user_id,
875
901
  **valid_draft
876
902
  )
877
903
 
@@ -885,6 +911,7 @@ class LearningPackageUnzipper:
885
911
  self.subsections_map_by_key[entity_key],
886
912
  units=children,
887
913
  force_version_num=valid_draft.pop("version_num", None),
914
+ created_by=self.user_id,
888
915
  **valid_draft
889
916
  )
890
917
 
@@ -898,6 +925,7 @@ class LearningPackageUnzipper:
898
925
  self.sections_map_by_key[entity_key],
899
926
  subsections=children,
900
927
  force_version_num=valid_draft.pop("version_num", None),
928
+ created_by=self.user_id,
901
929
  **valid_draft
902
930
  )
903
931
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openedx-learning
3
- Version: 0.30.0
3
+ Version: 0.30.2
4
4
  Summary: Open edX Learning Core and Tagging.
5
5
  Home-page: https://github.com/openedx/openedx-learning
6
6
  Author: David Ormsbee
@@ -19,12 +19,12 @@ Classifier: Programming Language :: Python :: 3.11
19
19
  Classifier: Programming Language :: Python :: 3.12
20
20
  Requires-Python: >=3.11
21
21
  License-File: LICENSE.txt
22
- Requires-Dist: tomlkit
23
- Requires-Dist: Django
24
- Requires-Dist: edx-drf-extensions
25
- Requires-Dist: celery
26
22
  Requires-Dist: attrs
27
23
  Requires-Dist: djangorestframework<4.0
24
+ Requires-Dist: edx-drf-extensions
25
+ Requires-Dist: tomlkit
26
+ Requires-Dist: celery
27
+ Requires-Dist: Django
28
28
  Requires-Dist: rules<4.0
29
29
  Dynamic: author
30
30
  Dynamic: author-email
@@ -1,4 +1,4 @@
1
- openedx_learning/__init__.py,sha256=o42mWx5Mabaa6g0sWTlTd70RT0dVUFS_P2zFpUePyl0,69
1
+ openedx_learning/__init__.py,sha256=rdJiRnpCQknZmQlA3HfubO2vRJ6C8CODfPZUw-rHtYM,69
2
2
  openedx_learning/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  openedx_learning/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  openedx_learning/api/authoring.py,sha256=EDWTY_JDKtjD9nFrrijzWuVccs3LZeDLEdzTUNanR4I,1111
@@ -7,15 +7,15 @@ openedx_learning/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
7
7
  openedx_learning/apps/authoring/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  openedx_learning/apps/authoring/backup_restore/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  openedx_learning/apps/authoring/backup_restore/admin.py,sha256=OnEixkOuysPRr-F6C_CMwPkiXawkqgSEF46n3yiUK0o,59
10
- openedx_learning/apps/authoring/backup_restore/api.py,sha256=TlQmb9VADDj8UlNjOczlwOfY8JVFfGyZ3UN5nluL9Tw,1243
10
+ openedx_learning/apps/authoring/backup_restore/api.py,sha256=jX6shgWLlPqBeHrhPq-r8IkN_0OizLXk0Pb0CxzNEPM,1292
11
11
  openedx_learning/apps/authoring/backup_restore/apps.py,sha256=UnExBA7jhd3qI30_87JMvzVhS_k82t89qDVKSMpvg_A,340
12
12
  openedx_learning/apps/authoring/backup_restore/models.py,sha256=jlr0ppxW0IOW3HPHoJNChHvDrYVnKMb5_3uC2itxqQk,45
13
- openedx_learning/apps/authoring/backup_restore/serializers.py,sha256=LBWrlWmA0Aok-XSfwiGBqNTU-1ig4hnEX_AxFaAjaoY,6487
13
+ openedx_learning/apps/authoring/backup_restore/serializers.py,sha256=T9MkYqq8kj6mQa5ZSwbyydl8AkAhE24ldB2wWe0_BsY,6271
14
14
  openedx_learning/apps/authoring/backup_restore/toml.py,sha256=4QFKDoFXsEF3xr1gvRXKQien-4_GezH6Gn1BdYQF8yU,8286
15
- openedx_learning/apps/authoring/backup_restore/zipper.py,sha256=S3pxdsKmt-KeTaJlJBzZg0qKOmUOvhkSKP12N6dGguU,47171
15
+ openedx_learning/apps/authoring/backup_restore/zipper.py,sha256=LGljsIB3nSJRN5QscHEg-URJ-ZwQtS0Wc-IcCXBcEcY,48232
16
16
  openedx_learning/apps/authoring/backup_restore/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  openedx_learning/apps/authoring/backup_restore/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- openedx_learning/apps/authoring/backup_restore/management/commands/lp_dump.py,sha256=6-8D1rnDajTAIJu1HZLayY87hTfMnkaumYgSmLWpiGE,2302
18
+ openedx_learning/apps/authoring/backup_restore/management/commands/lp_dump.py,sha256=kNr3luMjKrzxzGbJI7GiE9W0Wf_Kb8x6H71XsyGt6b4,2561
19
19
  openedx_learning/apps/authoring/backup_restore/management/commands/lp_load.py,sha256=z-glaYCulllcptqFbX5cb0UL_b9NslaaHK-0kOmPLa4,2205
20
20
  openedx_learning/apps/authoring/backup_restore/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  openedx_learning/apps/authoring/collections/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -106,7 +106,7 @@ openedx_learning/lib/fields.py,sha256=FwS2e5FYNGqbG9PJoDFvBsBlkfWCYbZ6G8BPAKbufL
106
106
  openedx_learning/lib/managers.py,sha256=-Q3gxalSqyPZ9Im4DTROW5tF8wVTZLlmfTe62_xmowY,1643
107
107
  openedx_learning/lib/test_utils.py,sha256=g3KLuepIZbaDBCsaj9711YuqyUx7LD4gXDcfNC-mWdc,527
108
108
  openedx_learning/lib/validators.py,sha256=iqEdEAvFV2tC7Ecssx69kjecpdU8nE87AlDJYrqrsnc,404
109
- openedx_learning-0.30.0.dist-info/licenses/LICENSE.txt,sha256=QTW2QN7q3XszgUAXm9Dzgtu5LXYKbR1SGnqMa7ufEuY,35139
109
+ openedx_learning-0.30.2.dist-info/licenses/LICENSE.txt,sha256=QTW2QN7q3XszgUAXm9Dzgtu5LXYKbR1SGnqMa7ufEuY,35139
110
110
  openedx_tagging/__init__.py,sha256=V9N8M7f9LYlAbA_DdPUsHzTnWjYRXKGa5qHw9P1JnNI,30
111
111
  openedx_tagging/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
112
112
  openedx_tagging/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -162,7 +162,7 @@ openedx_tagging/core/tagging/rest_api/v1/serializers.py,sha256=0HQD_Jrf6-YpocYfz
162
162
  openedx_tagging/core/tagging/rest_api/v1/urls.py,sha256=dNUKCtUCx_YzrwlbEbpDfjGVQbb2QdJ1VuJCkladj6E,752
163
163
  openedx_tagging/core/tagging/rest_api/v1/views.py,sha256=Hf92cy-tE767DE9FgsZcPKiCYrf5ihfETz8qGKBnuiU,36278
164
164
  openedx_tagging/core/tagging/rest_api/v1/views_import.py,sha256=kbHUPe5A6WaaJ3J1lFIcYCt876ecLNQfd19m7YYub6c,1470
165
- openedx_learning-0.30.0.dist-info/METADATA,sha256=UYSea814_Nu8TsAyHI-Gs2I-wT-zX6BWh1KHX0-3w-w,9372
166
- openedx_learning-0.30.0.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
167
- openedx_learning-0.30.0.dist-info/top_level.txt,sha256=IYFbr5mgiEHd-LOtZmXj3q3a0bkGK1M9LY7GXgnfi4M,33
168
- openedx_learning-0.30.0.dist-info/RECORD,,
165
+ openedx_learning-0.30.2.dist-info/METADATA,sha256=VeehzVrxbbru_Mr4RzrQsZEk7qHg2voITIqzQsmJnE8,9372
166
+ openedx_learning-0.30.2.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
167
+ openedx_learning-0.30.2.dist-info/top_level.txt,sha256=IYFbr5mgiEHd-LOtZmXj3q3a0bkGK1M9LY7GXgnfi4M,33
168
+ openedx_learning-0.30.2.dist-info/RECORD,,