-
Notifications
You must be signed in to change notification settings - Fork 17
Add PublishableEntities and PublishableEntityVersions to lp_dump file #340
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ormsbee
merged 8 commits into
openedx:main
from
WGU-Open-edX:dwong2708/lp_dump_publish_ent
Jul 31, 2025
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
209b8bd
feat: Add PublishableEntities to lp_dump file
dwong2708 3e8c352
test: add test to validate lp_dump output structure
dwong2708 53a27ba
feat: improve ZIP file generation and folder structure
dwong2708 ef85616
test: improve test to verify generated TOML files
dwong2708 5d5cb3b
feat: improve TOML files to meet requirements
dwong2708 f816acb
fix: improve typing in TOML module
dwong2708 c396fcb
refactor: use functions instead of classes for TOML file serialization
dwong2708 d4b31f0
fix: minor adjustments to TOML serialization
dwong2708 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,72 +1,73 @@ | ||
| """ | ||
| Utilities for backup and restore app | ||
| TOML serialization for learning packages and publishable entities. | ||
| """ | ||
|
|
||
| from datetime import datetime | ||
| from typing import Any, Dict | ||
|
|
||
| from tomlkit import comment, document, dumps, nl, table | ||
| from tomlkit.items import Table | ||
| import tomlkit | ||
|
|
||
| from openedx_learning.apps.authoring.publishing.models.learning_package import LearningPackage | ||
| from openedx_learning.apps.authoring.publishing.models.publishable_entity import ( | ||
| PublishableEntityMixin, | ||
| PublishableEntityVersionMixin, | ||
| ) | ||
|
|
||
|
|
||
| class TOMLLearningPackageFile(): | ||
| """ | ||
| Class to create a .toml representation of a LearningPackage instance. | ||
| def toml_learning_package(learning_package: LearningPackage) -> str: | ||
| """Create a TOML representation of the learning package.""" | ||
| doc = tomlkit.document() | ||
| doc.add(tomlkit.comment(f"Datetime of the export: {datetime.now()}")) | ||
| section = tomlkit.table() | ||
| section.add("title", learning_package.title) | ||
| section.add("key", learning_package.key) | ||
| section.add("description", learning_package.description) | ||
| section.add("created", learning_package.created) | ||
| section.add("updated", learning_package.updated) | ||
| doc.add("learning_package", section) | ||
| return tomlkit.dumps(doc) | ||
|
|
||
| This class builds a structured TOML document using `tomlkit` with metadata and fields | ||
| extracted from a `LearningPackage` object. The output can later be saved to a file or used elsewhere. | ||
| """ | ||
|
|
||
| def __init__(self, learning_package: LearningPackage): | ||
| self.doc = document() | ||
| self.learning_package = learning_package | ||
| def toml_publishable_entity(entity: PublishableEntityMixin) -> str: | ||
| """Create a TOML representation of a publishable entity.""" | ||
| doc = tomlkit.document() | ||
| entity_table = tomlkit.table() | ||
| entity_table.add("uuid", str(entity.uuid)) | ||
| entity_table.add("can_stand_alone", entity.can_stand_alone) | ||
|
|
||
| def _create_header(self) -> None: | ||
| """ | ||
| Adds a comment with the current datetime to indicate when the export occurred. | ||
| This helps with traceability and file versioning. | ||
| """ | ||
| self.doc.add(comment(f"Datetime of the export: {datetime.now()}")) | ||
| self.doc.add(nl()) | ||
| draft = tomlkit.table() | ||
| draft.add("version_num", entity.versioning.draft.version_num) | ||
| entity_table.add("draft", draft) | ||
|
|
||
| def _create_table(self, params: Dict[str, Any]) -> Table: | ||
| """ | ||
| Builds a TOML table section from a dictionary of key-value pairs. | ||
| published = tomlkit.table() | ||
| if entity.versioning.published: | ||
| published.add("version_num", entity.versioning.published.version_num) | ||
| else: | ||
| published.add(tomlkit.comment("unpublished: no published_version_num")) | ||
| entity_table.add("published", published) | ||
|
|
||
| Args: | ||
| params (Dict[str, Any]): A dictionary containing keys and values to include in the TOML table. | ||
| doc.add("entity", entity_table) | ||
| doc.add(tomlkit.nl()) | ||
| doc.add(tomlkit.comment("### Versions")) | ||
|
|
||
| Returns: | ||
| Table: A TOML table populated with the provided keys and values. | ||
| """ | ||
| section = table() | ||
| for key, value in params.items(): | ||
| section.add(key, value) | ||
| return section | ||
| for entity_version in entity.versioning.versions.all(): | ||
| version = tomlkit.aot() | ||
| version_table = toml_publishable_entity_version(entity_version) | ||
| version.append(version_table) | ||
| doc.add("version", version) | ||
|
|
||
| def create(self) -> None: | ||
| """ | ||
| Populates the TOML document with a header and a table containing | ||
| metadata from the LearningPackage instance. | ||
| return tomlkit.dumps(doc) | ||
|
|
||
| This method must be called before calling `get()`, otherwise the document will be empty. | ||
| """ | ||
| self._create_header() | ||
| section = self._create_table({ | ||
| "title": self.learning_package.title, | ||
| "key": self.learning_package.key, | ||
| "description": self.learning_package.description, | ||
| "created": self.learning_package.created, | ||
| "updated": self.learning_package.updated | ||
| }) | ||
| self.doc.add("learning_package", section) | ||
|
|
||
| def get(self) -> str: | ||
| """ | ||
| Returns: | ||
| str: The string representation of the generated TOML document. | ||
| Ensure `create()` has been called beforehand to get meaningful output. | ||
| """ | ||
| return dumps(self.doc) | ||
| def toml_publishable_entity_version(version: PublishableEntityVersionMixin) -> tomlkit.items.Table: | ||
| """Create a TOML representation of a publishable entity version.""" | ||
| version_table = tomlkit.table() | ||
| version_table.add("title", version.title) | ||
| version_table.add("uuid", str(version.uuid)) | ||
| version_table.add("version_num", version.version_num) | ||
| container_table = tomlkit.table() | ||
| container_table.add("children", []) | ||
| unit_table = tomlkit.table() | ||
| unit_table.add("graded", True) | ||
| container_table.add("unit", unit_table) | ||
| version_table.add("container", container_table) | ||
| return version_table # For use in AoT |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| """ | ||
| This module provides functionality to create a zip file containing the learning package data, | ||
| including a TOML representation of the learning package and its entities. | ||
| """ | ||
| import zipfile | ||
| from pathlib import Path | ||
|
|
||
| from openedx_learning.apps.authoring.backup_restore.toml import toml_learning_package, toml_publishable_entity | ||
| from openedx_learning.apps.authoring.components import api as components_api | ||
| from openedx_learning.apps.authoring.publishing.models.learning_package import LearningPackage | ||
|
|
||
| TOML_PACKAGE_NAME = "package.toml" | ||
|
|
||
|
|
||
| class LearningPackageZipper: | ||
| """ | ||
| A class to handle the zipping of learning content for backup and restore. | ||
| """ | ||
|
|
||
| def __init__(self, learning_package: LearningPackage): | ||
| self.learning_package = learning_package | ||
|
|
||
| def create_zip(self, path: str) -> None: | ||
| """ | ||
| Creates a zip file containing the learning package data. | ||
| Args: | ||
| path (str): The path where the zip file will be created. | ||
| Raises: | ||
| Exception: If the learning package cannot be found or if the zip creation fails. | ||
| """ | ||
| package_toml_content: str = toml_learning_package(self.learning_package) | ||
|
|
||
| with zipfile.ZipFile(path, "w", compression=zipfile.ZIP_DEFLATED) as zipf: | ||
| # Add the package.toml string | ||
| zipf.writestr(TOML_PACKAGE_NAME, package_toml_content) | ||
|
|
||
| # Add the entities directory | ||
| entities_folder = Path("entities") | ||
| zip_info = zipfile.ZipInfo(str(entities_folder) + "/") # Ensure trailing slash | ||
| zipf.writestr(zip_info, "") # Add explicit empty directory entry | ||
|
|
||
| # Add the collections directory | ||
| collections_folder = Path("collections") | ||
| collections_info = zipfile.ZipInfo(str(collections_folder) + "/") # Ensure trailing slash | ||
| zipf.writestr(collections_info, "") # Add explicit empty directory | ||
|
|
||
| # Add each entity's TOML file | ||
| for entity in components_api.get_components(self.learning_package.pk): | ||
| # Create a TOML representation of the entity | ||
| entity_toml_content: str = toml_publishable_entity(entity) | ||
| entity_toml_filename = f"{entity.key}.toml" | ||
| entity_toml_path = entities_folder / entity_toml_filename | ||
| zipf.writestr(str(entity_toml_path), entity_toml_content) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.