From 5972f335bd0ffc85d106b305d682556df46ed7cc Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 15 Jun 2023 17:21:18 -0400 Subject: [PATCH] feat: add Library Authoring MFE plugin Adds experimental plugin for the Library Authoring MFE --- README.rst | 1 + .../.gitignore | 7 ++ .../MANIFEST.in | 2 + .../README.rst | 46 ++++++++ .../setup.py | 59 ++++++++++ .../tutor_library_authoring_mfe/__about__.py | 1 + .../tutor_library_authoring_mfe/__init__.py | 0 .../patches/openedx-cms-development-settings | 1 + .../patches/openedx-cms-production-settings | 1 + .../patches/openedx-common-settings | 1 + .../patches/openedx-lms-production-settings | 2 + .../tutor_library_authoring_mfe/plugin.py | 102 ++++++++++++++++++ .../library_authoring_mfe/jobs/init/cms.sh | 6 ++ 13 files changed, 229 insertions(+) create mode 100644 plugins/tutor-contrib-library-authoring-mfe/.gitignore create mode 100644 plugins/tutor-contrib-library-authoring-mfe/MANIFEST.in create mode 100644 plugins/tutor-contrib-library-authoring-mfe/README.rst create mode 100644 plugins/tutor-contrib-library-authoring-mfe/setup.py create mode 100644 plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/__about__.py create mode 100644 plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/__init__.py create mode 100644 plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-cms-development-settings create mode 100644 plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-cms-production-settings create mode 100644 plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-common-settings create mode 100644 plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-lms-production-settings create mode 100644 plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/plugin.py create mode 100644 plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/templates/library_authoring_mfe/jobs/init/cms.sh diff --git a/README.rst b/README.rst index d25990a..945ae9f 100644 --- a/README.rst +++ b/README.rst @@ -19,6 +19,7 @@ community: Plugin Status (*Experimental*, *Production*, or *Deprecated*) =================================== ====================================================== tutor-contrib-learner-dashboard-mfe Experimental +tutor-contrib-library-authoring-mfe Experimental tutor-contrib-blockstore-filesystem Experimental tutor-contrib-blockstore-minio Experimental =================================== ====================================================== diff --git a/plugins/tutor-contrib-library-authoring-mfe/.gitignore b/plugins/tutor-contrib-library-authoring-mfe/.gitignore new file mode 100644 index 0000000..f6a874f --- /dev/null +++ b/plugins/tutor-contrib-library-authoring-mfe/.gitignore @@ -0,0 +1,7 @@ +.*.swp +!.gitignore +TODO +__pycache__ +*.egg-info/ +/build/ +/dist/ diff --git a/plugins/tutor-contrib-library-authoring-mfe/MANIFEST.in b/plugins/tutor-contrib-library-authoring-mfe/MANIFEST.in new file mode 100644 index 0000000..280b3f7 --- /dev/null +++ b/plugins/tutor-contrib-library-authoring-mfe/MANIFEST.in @@ -0,0 +1,2 @@ +recursive-include tutor_library_authoring_mfe/patches * +recursive-include tutor_library_authoring_mfe/templates * diff --git a/plugins/tutor-contrib-library-authoring-mfe/README.rst b/plugins/tutor-contrib-library-authoring-mfe/README.rst new file mode 100644 index 0000000..c95d413 --- /dev/null +++ b/plugins/tutor-contrib-library-authoring-mfe/README.rst @@ -0,0 +1,46 @@ +library_authoring_mfe plugin for `Tutor `_ +=================================================================================== + +Installation +------------ + +Follow these instructions to enable this microfrontend: + +* Install `tutor `_ and `tutor-mfe `_: ``pip install tutor tutor-mfe`` +* To use blockstore with `minio `_ + + * Install `tutor-minio `_ ``pip install tutor-minio`` + * Enable minio plugin: ``tutor plugins enable minio`` + * Enable the blockstore-minio plugin: ``tutor plugins enable blockstore-minio`` + +* To use blockstore with django :code:`FileSystemStorage` + + * Enable the blockstore-filesystem plugin: ``tutor plugins enable blockstore-filesystem`` + +* Enable this plugin: ``tutor plugins enable library-authoring-mfe`` +* Save the tutor config: ``tutor config save`` +* Build mfe image: ``tutor images build mfe`` (if you have trouble here you may need to run it with ``--no-cache``) +* Launch tutor: ``tutor local launch`` + +If you want to run this MFE in +`development mode `_ +(to make changes to the code), instead of step 9 above, do this:: + + tutor config save --append MOUNTS=./frontend-app-library-authoring + cd frontend-app-library-authoring + nvm use && npm install + tutor dev launch + +Setup +----- +* Ensure you have created a user: https://docs.tutor.overhang.io/local.html#creating-a-new-user-with-staff-and-admin-rights +* Ensure you have created an organization: http://studio.local.overhang.io/admin/organizations/organization/ +* If you're using minio + + * Log in to the `minio Web UI `_ (`instructions to find credentials `_) + * Create a **public** bucket for blockstore (the default configuration expects the bucket to be named :code:`blockstore`) + +Usage +----- +* Log in to studio: http://studio.local.overhang.io/home/ +* Click on the libraries tab diff --git a/plugins/tutor-contrib-library-authoring-mfe/setup.py b/plugins/tutor-contrib-library-authoring-mfe/setup.py new file mode 100644 index 0000000..696fdf3 --- /dev/null +++ b/plugins/tutor-contrib-library-authoring-mfe/setup.py @@ -0,0 +1,59 @@ +import io +import os +from setuptools import setup, find_packages + +HERE = os.path.abspath(os.path.dirname(__file__)) + + +def load_readme(): + with io.open(os.path.join(HERE, "README.rst"), "rt", encoding="utf8") as f: + return f.read() + + +def load_about(): + about = {} + with io.open( + os.path.join(HERE, "tutor_library_authoring_mfe", "__about__.py"), + "rt", + encoding="utf-8", + ) as f: + exec(f.read(), about) # pylint: disable=exec-used + return about + + +ABOUT = load_about() + + +setup( + name="tutor-contrib-library-authoring-mfe", + version=ABOUT["__version__"], + url="https://github.com/openedx/openedx-tutor-plugins", + project_urls={ + "Code": "https://github.com/openedx/openedx-tutor-plugins", + "Issue tracker": "https://github.com/openedx/openedx-tutor-plugins/issues", + }, + license="AGPLv3", + author="Braden MacDonald", + description="Library Authoring MFE plugin for Tutor", + long_description=load_readme(), + packages=find_packages(exclude=["tests*"]), + include_package_data=True, + python_requires=">=3.7", + install_requires=["tutor"], + entry_points={ + "tutor.plugin.v1": [ + "library-authoring-mfe = tutor_library_authoring_mfe.plugin" + ] + }, + classifiers=[ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: GNU Affero General Public License v3", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + ], +) diff --git a/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/__about__.py b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/__about__.py new file mode 100644 index 0000000..3dc1f76 --- /dev/null +++ b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/__about__.py @@ -0,0 +1 @@ +__version__ = "0.1.0" diff --git a/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/__init__.py b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-cms-development-settings b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-cms-development-settings new file mode 100644 index 0000000..8f2c8f6 --- /dev/null +++ b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-cms-development-settings @@ -0,0 +1 @@ +LIBRARY_AUTHORING_MICROFRONTEND_URL = "http://{{ MFE_HOST }}:{{ LIBRARY_AUTHORING_MFE_APP["port"] }}/library-authoring" diff --git a/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-cms-production-settings b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-cms-production-settings new file mode 100644 index 0000000..d324ff2 --- /dev/null +++ b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-cms-production-settings @@ -0,0 +1 @@ +LIBRARY_AUTHORING_MICROFRONTEND_URL = "{% if ENABLE_HTTPS %}https://{% else %}http://{% endif %}{{ MFE_HOST }}/library-authoring" diff --git a/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-common-settings b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-common-settings new file mode 100644 index 0000000..cdfdda6 --- /dev/null +++ b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-common-settings @@ -0,0 +1 @@ +FEATURES["ENABLE_LIBRARY_AUTHORING_MICROFRONTEND"] = True diff --git a/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-lms-production-settings b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-lms-production-settings new file mode 100644 index 0000000..1cc1f1b --- /dev/null +++ b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/patches/openedx-lms-production-settings @@ -0,0 +1,2 @@ +MFE_CONFIG_OVERRIDES.setdefault("library-authoring", {})["BLOCKSTORE_COLLECTION_UUID"] = "{{BLOCKSTORE_COLLECTION_UUID}}" +MFE_CONFIG_OVERRIDES["library-authoring"]["SECURE_ORIGIN_XBLOCK_BOOTSTRAP_HTML_URL"] = "/library-authoring/xblock-bootstrap.html" diff --git a/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/plugin.py b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/plugin.py new file mode 100644 index 0000000..7a69066 --- /dev/null +++ b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/plugin.py @@ -0,0 +1,102 @@ +from glob import glob +import os +import pkg_resources +import uuid + +from tutor import hooks as tutor_hooks +from tutormfe.plugin import MFE_APPS + +from .__about__ import __version__ + +######################################## +# CONFIGURATION +######################################## + +port = 3001 + +@MFE_APPS.add() +def _add_my_mfe(mfes): + mfes["library-authoring"] = { + "repository": "https://github.com/openedx/frontend-app-library-authoring", + "port": port, + } + return mfes + +tutor_hooks.Filters.ENV_TEMPLATE_VARIABLES.add_items( + [("library_authoring_port", port)] +) + +tutor_hooks.Filters.CONFIG_UNIQUE.add_items( + [ + ("BLOCKSTORE_COLLECTION_UUID", str(uuid.uuid4())) + ] +) + + +######################################## +# INITIALIZATION TASKS +######################################## + +MY_INIT_TASKS: list[tuple[str, tuple[str, ...]]] = [ + ("cms", ("library_authoring_mfe", "jobs", "init", "cms.sh")), +] + +# For each task added to MY_INIT_TASKS, we load the task template +# and add it to the CLI_DO_INIT_TASKS filter, which tells Tutor to +# run it as part of the `init` job. +for service, template_path in MY_INIT_TASKS: + full_path: str = pkg_resources.resource_filename( + "tutor_library_authoring_mfe", os.path.join("templates", *template_path) + ) + with open(full_path, encoding="utf-8") as init_task_file: + init_task: str = init_task_file.read() + tutor_hooks.Filters.CLI_DO_INIT_TASKS.add_item((service, init_task)) + +######################################## +# TEMPLATE RENDERING +######################################## + +tutor_hooks.Filters.ENV_TEMPLATE_ROOTS.add_items( + # Root paths for template files, relative to the project root. + [ + pkg_resources.resource_filename("tutor_library_authoring_mfe", "templates"), + ] +) + +######################################## +# PATCH LOADING +######################################## + +# For each file in tutor_library_authoring_mfe/patches, +# apply a patch based on the file's name and contents. +for path in glob( + os.path.join( + pkg_resources.resource_filename("tutor_library_authoring_mfe", "patches"), + "*", + ) +): + with open(path, encoding="utf-8") as patch_file: + tutor_hooks.Filters.ENV_PATCHES.add_item((os.path.basename(path), patch_file.read())) + +# Tutor overwrites webpack.dev.config.js, but this MFE depends on some code +# in that file to work correctly so we have to restore it here manually. +# https://github.com/openedx/frontend-app-library-authoring/blob/b95c198b/webpack.dev.config.js +tutor_hooks.Filters.ENV_PATCHES.add_item(("mfe-webpack-dev-config",""" +const fs = require('fs'); + +// If this is the Library Authoring MFE, apply this fix: +if (fs.existsSync("src/library-authoring/edit-block/LibraryBlock/xblock-bootstrap.html")) { + const path = require('path'); + const CopyWebpackPlugin = require('copy-webpack-plugin'); + module.exports = merge(module.exports, { + plugins: [ + new CopyWebpackPlugin({ + patterns: [{ + context: path.resolve(__dirname, 'src/library-authoring/edit-block/LibraryBlock'), + from: 'xblock-bootstrap.html', + }], + }), + ], + }); +} +""")) diff --git a/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/templates/library_authoring_mfe/jobs/init/cms.sh b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/templates/library_authoring_mfe/jobs/init/cms.sh new file mode 100644 index 0000000..228d9aa --- /dev/null +++ b/plugins/tutor-contrib-library-authoring-mfe/tutor_library_authoring_mfe/templates/library_authoring_mfe/jobs/init/cms.sh @@ -0,0 +1,6 @@ +# Enable the waffle flag to use this MFE +(./manage.py cms waffle_flag --list | grep studio.library_authoring_mfe) || ./manage.py lms waffle_flag studio.library_authoring_mfe --create --everyone + +# Make sure a Blockstore "Collection" exists to hold the library content. +# the UUID is created in CONFIG_UNIQUE in plugin.py +echo "from blockstore.apps.bundles.models import Collection; coll, _ = Collection.objects.get_or_create(title='Libraries Content Collection', uuid='{{BLOCKSTORE_COLLECTION_UUID}}')" | ./manage.py cms shell