- 
                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.