Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions olx_importer/management/commands/load_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,33 +61,33 @@ def init_known_types(self):

def add_arguments(self, parser):
parser.add_argument("course_data_path", type=pathlib.Path)
parser.add_argument("learning_package_key", type=str)
parser.add_argument("learning_package_ref", type=str)

def handle(self, course_data_path, learning_package_key, **options):
def handle(self, course_data_path, learning_package_ref, **options):
self.course_data_path = course_data_path
self.learning_package_key = learning_package_key
self.load_course_data(learning_package_key)
self.learning_package_ref = learning_package_ref
self.load_course_data(learning_package_ref)

def get_course_title(self):
course_type_dir = self.course_data_path / "course"
course_xml_file = next(course_type_dir.glob("*.xml"))
course_root = ET.parse(course_xml_file).getroot()
return course_root.attrib.get("display_name", "Unknown Course")

def load_course_data(self, learning_package_key):
def load_course_data(self, learning_package_ref):
print(f"Importing course from: {self.course_data_path}")
now = datetime.now(timezone.utc)
title = self.get_course_title()

if content_api.learning_package_exists(learning_package_key):
if content_api.learning_package_exists(learning_package_ref):
raise CommandError(
f"{learning_package_key} already exists. "
f"{learning_package_ref} already exists. "
"This command currently only supports initial import."
)

with transaction.atomic():
self.learning_package = content_api.create_learning_package(
learning_package_key, title, created=now,
learning_package_ref, title, created=now,
)
for block_type in SUPPORTED_TYPES:
self.import_block_type(block_type, now) #, publish_log_entry)
Expand Down
14 changes: 8 additions & 6 deletions src/openedx_content/applets/backup_restore/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,28 @@

from django.contrib.auth.models import User as UserType # pylint: disable=imported-auth-user

from ..publishing.api import get_learning_package_by_key
from ..publishing.api import get_learning_package_by_ref
from .zipper import LearningPackageUnzipper, LearningPackageZipper


def create_zip_file(lp_key: str, path: str, user: UserType | None = None, origin_server: str | None = None) -> None:
def create_zip_file(
package_ref: str, path: str, user: UserType | None = None, origin_server: str | None = None
) -> None:
"""
Creates a dump zip file for the given learning package key at the given path.
The zip file contains a TOML representation of the learning package and its contents.

Can throw a NotFoundError at get_learning_package_by_key
Can throw a NotFoundError at get_learning_package_by_ref
"""
learning_package = get_learning_package_by_key(lp_key)
learning_package = get_learning_package_by_ref(package_ref)
LearningPackageZipper(learning_package, user, origin_server).create_zip(path)


def load_learning_package(path: str, key: str | None = None, user: UserType | None = None) -> dict:
def load_learning_package(path: str, package_ref: str | None = None, user: UserType | None = None) -> dict:
"""
Loads a learning package from a zip file at the given path.
Restores the learning package and its contents to the database.
Returns a dictionary with the status of the operation and any errors encountered.
"""
with zipfile.ZipFile(path, "r") as zipf:
return LearningPackageUnzipper(zipf, key, user).load()
return LearningPackageUnzipper(zipf, package_ref, user).load()
27 changes: 21 additions & 6 deletions src/openedx_content/applets/backup_restore/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
"""
The serializers module for restoration of authoring data.

Please note that the serializers are defined from the perspective of the
TOML format, with the models as the "source". That is, when the model fields
and TOML fields differ, we'll declare it like this:

my_toml_field = serializers.BlahField(source="my_model_field")
"""
from datetime import timezone

Expand All @@ -14,11 +20,14 @@ class LearningPackageSerializer(serializers.Serializer): # pylint: disable=abst
Serializer for learning packages.

Note:
The `key` field is serialized, but it is generally not trustworthy for restoration.
During restore, a new key may be generated or overridden.
The ref/key field is serialized but is generally not trustworthy for
restoration. During restore, a new ref may be generated or overridden.
"""

title = serializers.CharField(required=True)
key = serializers.CharField(required=True)
# The model field is now LearningPackage.package_ref, but the archive format
# still uses "key". A future v2 format may align the name.
key = serializers.CharField(required=True, source="package_ref")
description = serializers.CharField(required=True, allow_blank=True)
created = serializers.DateTimeField(required=True, default_timezone=timezone.utc)

Expand All @@ -42,8 +51,11 @@ class EntitySerializer(serializers.Serializer): # pylint: disable=abstract-meth
"""
Serializer for publishable entities.
"""

can_stand_alone = serializers.BooleanField(required=True)
key = serializers.CharField(required=True)
# The model field is now PublishableEntity.entity_ref, but the archive format
# still uses "key". A future v2 format may align the name.
key = serializers.CharField(required=True, source="entity_ref")
created = serializers.DateTimeField(required=True, default_timezone=timezone.utc)


Expand All @@ -52,10 +64,13 @@ class EntityVersionSerializer(serializers.Serializer): # pylint: disable=abstra
Serializer for publishable entity versions.
"""
title = serializers.CharField(required=True)
entity_key = serializers.CharField(required=True)
created = serializers.DateTimeField(required=True, default_timezone=timezone.utc)
version_num = serializers.IntegerField(required=True)

# Note: Unlike the fields above, `entity_ref` does not appear on the model
# nor in the TOML. This is just added by the validation pipeline for convenience.
entity_ref = serializers.CharField(required=True)


class ComponentSerializer(EntitySerializer): # pylint: disable=abstract-method
"""
Expand All @@ -68,7 +83,7 @@ def validate(self, attrs):
Custom validation logic:
parse the entity_key into (component_type, component_code).
"""
entity_key = attrs["key"]
entity_key = attrs["entity_ref"]
try:
component_type_obj, component_code = _get_or_create_component_type_by_entity_key(entity_key)
attrs["component_type"] = component_type_obj
Expand Down
15 changes: 9 additions & 6 deletions src/openedx_content/applets/backup_restore/toml.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ def toml_learning_package(
# Learning package main info
section = tomlkit.table()
section.add("title", learning_package.title)
section.add("key", learning_package.key)
# The model field is now LearningPackage.package_ref, but the archive format
# still uses "key". A future v2 format may align the name.
section.add("key", learning_package.package_ref)
section.add("description", learning_package.description)
section.add("created", learning_package.created)
section.add("updated", learning_package.updated)
Expand Down Expand Up @@ -89,8 +91,9 @@ def _get_toml_publishable_entity_table(
"""
entity_table = tomlkit.table()
entity_table.add("can_stand_alone", entity.can_stand_alone)
# Add key since the toml filename doesn't show the real key
entity_table.add("key", entity.key)
# The model field is now PublishableEntity.entity_ref, but the archive format
# still uses "key". A future v2 format may align the name.
entity_table.add("key", entity.entity_ref)
entity_table.add("created", entity.created)

if not include_versions:
Expand Down Expand Up @@ -191,13 +194,13 @@ def toml_publishable_entity_version(version: PublishableEntityVersion) -> tomlki
if hasattr(version, 'containerversion'):
# If the version has a container version, add its children
container_table = tomlkit.table()
children = containers_api.get_container_children_entities_keys(version.containerversion)
children = containers_api.get_container_children_entity_refs(version.containerversion)
container_table.add("children", children)
version_table.add("container", container_table)
return version_table


def toml_collection(collection: Collection, entity_keys: list[str]) -> str:
def toml_collection(collection: Collection, entity_refs: list[str]) -> str:
"""
Create a TOML representation of a collection.

Expand All @@ -215,7 +218,7 @@ def toml_collection(collection: Collection, entity_keys: list[str]) -> str:
doc = tomlkit.document()

entities_array = tomlkit.array()
entities_array.extend(entity_keys)
entities_array.extend(entity_refs)
entities_array.multiline(True)

collection_table = tomlkit.table()
Expand Down
Loading