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
3 changes: 3 additions & 0 deletions .importlinter
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ layers=
# Its only dependency should be the publishing app.
openedx_learning.apps.authoring.collections

# The "backup_restore" app handle the new export and import mechanism.
openedx_learning.apps.authoring.backup_restore

# The lowest layer is "publishing", which holds the basic primitives needed
# to create Learning Packages and manage the draft and publish states for
# various types of content.
Expand Down
Empty file.
3 changes: 3 additions & 0 deletions openedx_learning/apps/authoring/backup_restore/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
Django Admin pages for Backup Restore models (WIP)
"""
20 changes: 20 additions & 0 deletions openedx_learning/apps/authoring/backup_restore/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""
Backup Restore API
"""
import zipfile

from .toml import TOMLLearningPackageFile

TOML_PACKAGE_NAME = "package.toml"


def create_zip_file(lp_key: str, path: str) -> None:
"""
Creates a zip file with a toml file so far (WIP)
"""
toml_file = TOMLLearningPackageFile()
toml_file.create(lp_key)
toml_content: str = toml_file.get()
with zipfile.ZipFile(path, "w", compression=zipfile.ZIP_DEFLATED) as zipf:
# Add the TOML string as a file in the ZIP
zipf.writestr(TOML_PACKAGE_NAME, toml_content)
12 changes: 12 additions & 0 deletions openedx_learning/apps/authoring/backup_restore/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""
Backup/Restore application initialization.
"""

from django.apps import AppConfig


class BackupRestoreConfig(AppConfig):
name = 'openedx_learning.apps.authoring.backup_restore'
verbose_name = "Learning Core > Authoring > Backup Restore"
default_auto_field = 'django.db.models.BigAutoField'
label = "oel_backup_restore"
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
Django management commands to handle backup and restore learning packages (WIP)
"""
import logging

from django.core.management.base import BaseCommand

from openedx_learning.apps.authoring.backup_restore.api import create_zip_file

logger = logging.getLogger(__name__)


class Command(BaseCommand):
"""
Django management command to export a learning package to a zip file.
"""
help = 'Export a learning package to a zip file.'

def add_arguments(self, parser):
parser.add_argument('lp_key', type=str, help='The key of the LearningPackage to dump')
parser.add_argument('file_name', type=str, help='The name of the output zip file')

def handle(self, *args, **options):
lp_key = options['lp_key']
file_name = options['file_name']
try:
create_zip_file(lp_key, file_name)
message = f'{lp_key} written to {file_name}'
self.stdout.write(self.style.SUCCESS(message))
except Exception as e: # pylint: disable=broad-exception-caught
message = f"Error creating zip file: error {e}"
self.stderr.write(self.style.ERROR(message))
logger.exception(
"Failed to create zip file %s (learning‑package key %s)",
file_name,
lp_key,
)
Empty file.
3 changes: 3 additions & 0 deletions openedx_learning/apps/authoring/backup_restore/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
Core models for Backup Restore (WIP)
"""
45 changes: 45 additions & 0 deletions openedx_learning/apps/authoring/backup_restore/toml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""
Utilities for backup and restore app
"""

from datetime import datetime
from typing import Any, Dict

from tomlkit import comment, document, dumps, nl, table
from tomlkit.items import Table


class TOMLLearningPackageFile():
"""
Class to create a .toml file of a learning package (WIP)
"""

def __init__(self):
self.doc = document()

def _create_header(self) -> None:
self.doc.add(comment(f"Datetime of the export: {datetime.now()}"))
self.doc.add(nl())

def _create_table(self, params: Dict[str, Any]) -> Table:
section = table()
for key, value in params.items():
section.add(key, value)
return section

def create(self, lp_key: str) -> None:
"""
Process the toml file
"""
self._create_header()
section = self._create_table({
"title": "",
"key": lp_key,
"description": "",
"created": "",
"updated": ""
})
self.doc.add("learning_package", section)

def get(self) -> str:
return dumps(self.doc)
1 change: 1 addition & 0 deletions projects/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"openedx_learning.apps.authoring.sections.apps.SectionsConfig",
"openedx_learning.apps.authoring.subsections.apps.SubsectionsConfig",
"openedx_learning.apps.authoring.units.apps.UnitsConfig",
"openedx_learning.apps.authoring.backup_restore.apps.BackupRestoreConfig",
# Learning Contrib Apps
"openedx_learning.contrib.media_server.apps.MediaServerConfig",
# Apps that don't belong in this repo in the long term, but are here to make
Expand Down
2 changes: 2 additions & 0 deletions requirements/base.in
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ djangorestframework<4.0 # REST API
edx-drf-extensions # Extensions to the Django REST Framework used by Open edX

rules<4.0 # Django extension for rules-based authorization checks

tomlkit # Parses and writes TOML configuration files
2 changes: 2 additions & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ stevedore==5.4.1
# via
# edx-django-utils
# edx-opaque-keys
tomlkit==0.13.3
# via -r requirements/base.in
typing-extensions==4.14.1
# via edx-opaque-keys
tzdata==2025.2
Expand Down
10 changes: 0 additions & 10 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ cryptography==45.0.5
# via
# -r requirements/quality.txt
# pyjwt
# secretstorage
ddt==1.7.2
# via -r requirements/quality.txt
diff-cover==9.4.1
Expand Down Expand Up @@ -231,11 +230,6 @@ jaraco-functools==4.2.1
# via
# -r requirements/quality.txt
# keyring
jeepney==0.9.0
# via
# -r requirements/quality.txt
# keyring
# secretstorage
jinja2==3.1.6
# via
# -r requirements/quality.txt
Expand Down Expand Up @@ -449,10 +443,6 @@ rich==14.0.0
# twine
rules==3.5
# via -r requirements/quality.txt
secretstorage==3.3.3
# via
# -r requirements/quality.txt
# keyring
semantic-version==2.10.0
# via
# -r requirements/quality.txt
Expand Down
2 changes: 2 additions & 0 deletions requirements/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ text-unidecode==1.3
# via
# -r requirements/test.txt
# python-slugify
tomlkit==0.13.3
# via -r requirements/test.txt
types-pyyaml==6.0.12.20250516
# via
# -r requirements/test.txt
Expand Down
11 changes: 3 additions & 8 deletions requirements/quality.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ cryptography==45.0.5
# via
# -r requirements/test.txt
# pyjwt
# secretstorage
ddt==1.7.2
# via -r requirements/test.txt
dill==0.4.0
Expand Down Expand Up @@ -173,10 +172,6 @@ jaraco-context==6.0.1
# via keyring
jaraco-functools==4.2.1
# via keyring
jeepney==0.9.0
# via
# keyring
# secretstorage
jinja2==3.1.6
# via
# -r requirements/test.txt
Expand Down Expand Up @@ -327,8 +322,6 @@ rich==14.0.0
# via twine
rules==3.5
# via -r requirements/test.txt
secretstorage==3.3.3
# via keyring
semantic-version==2.10.0
# via
# -r requirements/test.txt
Expand Down Expand Up @@ -356,7 +349,9 @@ text-unidecode==1.3
# -r requirements/test.txt
# python-slugify
tomlkit==0.13.3
# via pylint
# via
# -r requirements/test.txt
# pylint
twine==6.1.0
# via -r requirements/quality.in
types-pyyaml==6.0.12.20250516
Expand Down
2 changes: 2 additions & 0 deletions requirements/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ stevedore==5.4.1
# edx-opaque-keys
text-unidecode==1.3
# via python-slugify
tomlkit==0.13.3
# via -r requirements/base.txt
types-pyyaml==6.0.12.20250516
# via
# django-stubs
Expand Down