diff --git a/.github/workflows/backend-ci.yml b/.github/workflows/backend-ci.yml index c42f017..d1a944c 100644 --- a/.github/workflows/backend-ci.yml +++ b/.github/workflows/backend-ci.yml @@ -10,7 +10,7 @@ on: defaults: run: - working-directory: "./backend" + working-directory: "./platform-plugin-sample" jobs: run_tests: @@ -46,4 +46,4 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} flags: unittests fail_ci_if_error: true - working-directory: "./backend" + working-directory: "./platform-plugin-sample" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bbf5477..dd2272c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,7 +44,7 @@ jobs: git_committer_name: "github-actions" git_committer_email: "actions@users.noreply.github.com" changelog: "false" - directory: './backend' + directory: './platform-plugin-sample' - name: Publish | Upload to GitHub Release Assets uses: python-semantic-release/publish-action@v10.5.3 @@ -52,14 +52,14 @@ jobs: with: github_token: ${{ secrets.OPENEDX_SEMANTIC_RELEASE_GITHUB_TOKEN }} tag: ${{ steps.release.outputs.tag }} - directory: './backend' + directory: './platform-plugin-sample' - name: Upload | Backend Distribution Artifacts uses: actions/upload-artifact@v4 if: steps.release.outputs.released == 'true' with: name: backend-distribution-artifacts - path: backend/dist + path: platform-plugin-sample/dist if-no-files-found: error - name: Build | Tutor Plugin @@ -102,12 +102,12 @@ jobs: id: artifact-download with: name: backend-distribution-artifacts - path: backend/dist + path: platform-plugin-sample/dist - name: Publish to PyPi uses: pypa/gh-action-pypi-publish@release/v1 with: - packages-dir: backend/dist + packages-dir: platform-plugin-sample/dist user: __token__ password: ${{ secrets.PYPI_UPLOAD_TOKEN }} diff --git a/CLAUDE.md b/CLAUDE.md index 7519b28..d0e2f73 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ This is a **sample plugin repository** that demonstrates all major Open edX plug - **Target Audience**: Developers new to Open edX plugin development **Repository Structure:** -- `backend/` - Django app plugin with models, APIs, events, and filters +- `platform-plugin-sample/` - Django app plugin with models, APIs, events, and filters - `frontend/` - React component for MFE slot customization - `tutor/` - Tutor plugin for easy deployment - Each directory has comprehensive README.md files with TOCs @@ -25,21 +25,21 @@ This is a **sample plugin repository** that demonstrates all major Open edX plug - Keep examples realistic but not overly complex **Key Files and Their Relationships:** -- `backend/sample_plugin/apps.py` - Plugin registration and Django integration -- `backend/sample_plugin/signals.py` - Open edX Events handlers -- `backend/sample_plugin/pipeline.py` - Open edX Filters implementation -- `backend/sample_plugin/models.py` - CourseArchiveStatus model (business logic) -- `backend/sample_plugin/views.py` - REST API endpoints consumed by frontend +- `platform-plugin-sample/openedx_sample_plugin/apps.py` - Plugin registration and Django integration +- `platform-plugin-sample/openedx_sample_plugin/signals.py` - Open edX Events handlers +- `platform-plugin-sample/openedx_sample_plugin/pipeline.py` - Open edX Filters implementation +- `platform-plugin-sample/openedx_sample_plugin/models.py` - CourseArchiveStatus model (business logic) +- `platform-plugin-sample/openedx_sample_plugin/views.py` - REST API endpoints consumed by frontend - `frontend/src/plugin.jsx` - React component that replaces course list slot -- `tutor/sample_plugin.py` - Deployment configuration (currently basic template) +- `tutor/openedx_sample_plugin.py` - Deployment configuration (currently basic template) ## Build/Lint/Test Commands - Make sure to set the following so that test output is not too verbose: `export PYTEST_ADDOPTS="--disable-warnings --no-header --tb=short"` -- Backend testing: `cd backend && pytest` or `cd backend && make test` -- Run a single test: `cd backend && pytest tests/test_models.py::test_placeholder` -- Quality checks: `cd backend && make quality` -- Install requirements: `cd backend && make requirements` -- Compile requirements: `cd backend && make compile-requirements` +- Backend testing: `cd platform-plugin-sample && pytest` or `cd platform-plugin-sample && make test` +- Run a single test: `cd platform-plugin-sample && pytest tests/test_models.py::test_placeholder` +- Quality checks: `cd platform-plugin-sample && make quality` +- Install requirements: `cd platform-plugin-sample && make requirements` +- Compile requirements: `cd platform-plugin-sample && make compile-requirements` ## Code Style Guidelines - Python: Follow PEP 8 with max line length of 120 diff --git a/README.md b/README.md index 0a65bd1..a4ff30c 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,9 @@ This sample plugin showcases the **Open edX Hooks Extension Framework**, which a | Plugin Type | What It Does | Official Documentation | Sample Code | When To Use | |-------------|--------------|------------------------|-------------|-------------| -| **Django App Plugin** | Add models, APIs, views, and business logic | [How to create a plugin app](https://docs.openedx.org/projects/edx-django-utils/en/latest/plugins/how_tos/how_to_create_a_plugin_app.html) | [`backend/`](./backend/) | Adding new functionality, APIs, or data models | -| **Events (Signals)** | React to platform events | [Open edX Events Guide](https://docs.openedx.org/projects/openedx-events/en/latest/) | [`backend/sample_plugin/signals.py`](./backend/sample_plugin/signals.py) | Integrating with external systems, audit logging | -| **Filters** | Modify platform behavior | [Using Open edX Filters](https://docs.openedx.org/projects/openedx-filters/en/latest/how-tos/using-filters.html) | [`backend/sample_plugin/pipeline.py`](./backend/sample_plugin/pipeline.py) | Customizing business logic, URL redirects | +| **Django App Plugin** | Add models, APIs, views, and business logic | [How to create a plugin app](https://docs.openedx.org/projects/edx-django-utils/en/latest/plugins/how_tos/how_to_create_a_plugin_app.html) | [`platform-plugin-sample/`](./platform-plugin-sample/) | Adding new functionality, APIs, or data models | +| **Events (Signals)** | React to platform events | [Open edX Events Guide](https://docs.openedx.org/projects/openedx-events/en/latest/) | [`platform-plugin-sample/openedx_sample_plugin/signals.py`](./platform-plugin-sample/openedx_sample_plugin/signals.py) | Integrating with external systems, audit logging | +| **Filters** | Modify platform behavior | [Using Open edX Filters](https://docs.openedx.org/projects/openedx-filters/en/latest/how-tos/using-filters.html) | [`platform-plugin-sample/openedx_sample_plugin/pipeline.py`](./platform-plugin-sample/openedx_sample_plugin/pipeline.py) | Customizing business logic, URL redirects | | **Frontend Slots** | Customize MFE interfaces | [Frontend Plugin Slots](https://docs.openedx.org/en/latest/site_ops/how-tos/use-frontend-plugin-slots.html) | [`frontend/`](./frontend/) | UI customization, adding new components | | **Brand Packages** | Customize theming | [Open edX Brand Package Interface](https://github.com/openedx/brand-openedx) | [`brand/`](./brand/) | UI theming | | **Tutor Plugin** | Deploy plugins easily | [Tutor Plugin Development](https://docs.tutor.edly.io/) | [`tutor/`](./tutor/) | Simplified deployment and configuration | @@ -46,9 +46,13 @@ This sample plugin showcases the **Open edX Hooks Extension Framework**, which a ### Option 1: Development with Tutor (Recommended) ```bash -# Backend plugin setup -tutor mounts add "$PWD/backend" -tutor dev launch # Rebuilds image, runs migrations, reboots containers. +# Bind-mount backend source into Tutor image and containers. +# Tutor automatically recognizes the `platform-plugin-*` prefix and knows to +# treat it as an openedx-platform plugin. +tutor mounts add "$PWD/platform-plugin-sample" + +# Rebuild image, run migrations, reboot containers: +tutor dev launch # Frontend Plugin Setup (for learner-dashboard MFE development) npm install $PWD/frontend @@ -60,7 +64,7 @@ npm start ```bash # In your edx-platform directory -pip install -e /path/to/sample-plugin/backend +pip install -e /path/to/sample-plugin/platform-plugin-sample # Enable Learner Dashboard MFE # Go to http://localhost:18000/admin/waffle/flag/ @@ -87,9 +91,9 @@ python manage.py lms migrate Use the table above to identify which type of plugin matches your needs. You can combine multiple types in one plugin. ### 3. Study the Sample Code -- **Backend**: Start with [`backend/sample_plugin/apps.py`](./backend/sample_plugin/apps.py) to understand plugin registration -- **Events**: Examine [`backend/sample_plugin/signals.py`](./backend/sample_plugin/signals.py) for event handling patterns -- **Filters**: Review [`backend/sample_plugin/pipeline.py`](./backend/sample_plugin/pipeline.py) for behavior modification +- **Backend**: Start with [`platform-plugin-sample/openedx_sample_plugin/apps.py`](./platform-plugin-sample/openedx_sample_plugin/apps.py) to understand plugin registration +- **Events**: Examine [`platform-plugin-sample/openedx_sample_plugin/signals.py`](./platform-plugin-sample/openedx_sample_plugin/signals.py) for event handling patterns +- **Filters**: Review [`platform-plugin-sample/openedx_sample_plugin/pipeline.py`](./platform-plugin-sample/openedx_sample_plugin/pipeline.py) for behavior modification - **Frontend**: Explore [`frontend/src/plugin.jsx`](./frontend/src/plugin.jsx) for UI customization ### 4. Run This Sample @@ -103,9 +107,9 @@ Each directory contains detailed README.md files with adaptation guidance. ``` sample-plugin/ ├── README.md # This file - overview and quick start -├── backend/ +├── platform-plugin-sample/ │ ├── README.md # Backend plugin detailed guide -│ ├── sample_plugin/ +│ ├── openedx_sample_plugin/ │ │ ├── apps.py # Django plugin configuration │ │ ├── models.py # Database models example │ │ ├── views.py # REST API endpoints @@ -122,7 +126,7 @@ sample-plugin/ │ └── package.json # NPM package configuration └── tutor/ ├── README.md # Tutor deployment guide - └── sample_plugin.py # Tutor plugin configuration + └── openedx_sample_plugin.py # Tutor plugin configuration ``` ## Development Workflows @@ -135,10 +139,10 @@ sample-plugin/ - Add API endpoints in `views.py` - Implement event handlers in `signals.py` - Create filters in `pipeline.py` -3. **Testing**: `cd backend && make test` -4. **Quality**: `cd backend && make quality` +3. **Testing**: `cd platform-plugin-sample && make test` +4. **Quality**: `cd platform-plugin-sample && make quality` -**Detailed Guide**: See [`backend/README.md`](./backend/README.md) +**Detailed Guide**: See [`platform-plugin-sample/README.md`](./platform-plugin-sample/README.md) ### Frontend Plugin Development @@ -164,7 +168,7 @@ This sample shows how backend and frontend plugins work together: ### Backend + Frontend Integration ```python -# backend/sample_plugin/views.py - Provides API +# platform-plugin-sample/openedx_sample_plugin/views.py - Provides API class CourseArchiveStatusViewSet(viewsets.ModelViewSet): # API implementation ``` diff --git a/frontend/README.md b/frontend/README.md index 973714a..a0faaaf 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -305,7 +305,7 @@ if (response.data && Array.isArray(response.data)) { ### Prerequisites 1. **MFE Setup**: Have a learner dashboard MFE running locally -2. **Backend Plugin**: Install the backend plugin (see [`../backend/README.md`](../backend/README.md)) +2. **Backend Plugin**: Install the backend plugin (see [`../platform-plugin-sample/README.md`](../platform-plugin-sample/README.md)) 3. **Node.js**: Version 16+ with npm or yarn ### Local Development Setup diff --git a/backend/.annotation_safe_list.yml b/platform-plugin-sample/.annotation_safe_list.yml similarity index 100% rename from backend/.annotation_safe_list.yml rename to platform-plugin-sample/.annotation_safe_list.yml diff --git a/backend/.coveragerc b/platform-plugin-sample/.coveragerc similarity index 100% rename from backend/.coveragerc rename to platform-plugin-sample/.coveragerc diff --git a/backend/.editorconfig b/platform-plugin-sample/.editorconfig similarity index 100% rename from backend/.editorconfig rename to platform-plugin-sample/.editorconfig diff --git a/backend/.gitignore b/platform-plugin-sample/.gitignore similarity index 100% rename from backend/.gitignore rename to platform-plugin-sample/.gitignore diff --git a/backend/.pii_annotations.yml b/platform-plugin-sample/.pii_annotations.yml similarity index 100% rename from backend/.pii_annotations.yml rename to platform-plugin-sample/.pii_annotations.yml diff --git a/backend/.readthedocs.yaml b/platform-plugin-sample/.readthedocs.yaml similarity index 100% rename from backend/.readthedocs.yaml rename to platform-plugin-sample/.readthedocs.yaml diff --git a/backend/LICENSE.txt b/platform-plugin-sample/LICENSE.txt similarity index 100% rename from backend/LICENSE.txt rename to platform-plugin-sample/LICENSE.txt diff --git a/backend/Makefile b/platform-plugin-sample/Makefile similarity index 100% rename from backend/Makefile rename to platform-plugin-sample/Makefile diff --git a/backend/README.md b/platform-plugin-sample/README.md similarity index 89% rename from backend/README.md rename to platform-plugin-sample/README.md index c962695..1533d21 100644 --- a/backend/README.md +++ b/platform-plugin-sample/README.md @@ -34,7 +34,7 @@ This backend plugin demonstrates the **Open edX Django App Plugin** pattern, whi ## Django App Plugin Configuration -**File**: [`sample_plugin/apps.py`](./sample_plugin/apps.py) +**File**: [`openedx_sample_plugin/apps.py`](./openedx_sample_plugin/apps.py) ### Plugin Registration @@ -42,12 +42,12 @@ The `SamplePluginConfig` class configures this app as an edx-platform plugin: ```python class SamplePluginConfig(AppConfig): - name = "sample_plugin" + name = "openedx_sample_plugin" plugin_app = { "url_config": { # Register URLs for both LMS and CMS "lms.djangoapp": { - PluginURLs.NAMESPACE: "sample_plugin", + PluginURLs.NAMESPACE: "openedx_sample_plugin", PluginURLs.REGEX: r"^sample-plugin/", PluginURLs.RELATIVE_PATH: "urls", }, @@ -74,21 +74,21 @@ class SamplePluginConfig(AppConfig): ### Entry Points Configuration -In [`pyproject.toml`](./backend/pyproject.toml), the plugin registers itself with edx-platform: +In [`pyproject.toml`](./pyproject.toml), the plugin registers itself with edx-platform: ```python [project.entry-points."lms.djangoapp"] -sample_plugin = "sample_plugin.apps:SamplePluginConfig" +openedx_sample_plugin = "openedx_sample_plugin.apps:SamplePluginConfig" [project.entry-points."cms.djangoapp"] -sample_plugin = "sample_plugin.apps:SamplePluginConfig" +openedx_sample_plugin = "openedx_sample_plugin.apps:SamplePluginConfig" ``` **Why this works**: The platform automatically discovers and loads any Django app registered in these entry points. ## Models & Database -**File**: [`sample_plugin/models.py`](./sample_plugin/models.py) +**File**: [`openedx_sample_plugin/models.py`](./openedx_sample_plugin/models.py) **Official Docs**: [OEP-49: Django App Patterns](https://docs.openedx.org/projects/openedx-proposals/en/latest/best-practices/oep-0049-django-app-patterns.html) ### CourseArchiveStatus Model @@ -112,12 +112,12 @@ class CourseArchiveStatus(models.Model): ```bash # After modifying models.py -cd backend -python manage.py makemigrations sample_plugin +cd platform-plugin-sample +python manage.py makemigrations openedx_sample_plugin python manage.py migrate ``` -**Migration files**: Generated in [`sample_plugin/migrations/`](./sample_plugin/migrations/) +**Migration files**: Generated in [`openedx_sample_plugin/migrations/`](./openedx_sample_plugin/migrations/) ### PII Annotations @@ -130,8 +130,8 @@ The model includes PII documentation: ## API Endpoints -**File**: [`sample_plugin/views.py`](./sample_plugin/views.py) -**URLs**: [`sample_plugin/urls.py`](./sample_plugin/urls.py) +**File**: [`openedx_sample_plugin/views.py`](./openedx_sample_plugin/views.py) +**URLs**: [`openedx_sample_plugin/urls.py`](./openedx_sample_plugin/urls.py) ### REST API Implementation @@ -179,7 +179,7 @@ def perform_create(self, serializer): ## Events & Signals -**File**: [`sample_plugin/signals.py`](./sample_plugin/signals.py) +**File**: [`openedx_sample_plugin/signals.py`](./openedx_sample_plugin/signals.py) **Official Docs**: [Open edX Events Guide](https://docs.openedx.org/projects/openedx-events/en/latest/) ### Event Handler Example @@ -221,7 +221,7 @@ def log_course_info_changed(signal, sender, catalog_info: CourseCatalogData, **k ### Signal Handler Registration -Handlers are automatically registered via the `ready()` method in [`apps.py`](./sample_plugin/apps.py): +Handlers are automatically registered via the `ready()` method in [`apps.py`](./openedx_sample_plugin/apps.py): ```python def ready(self): @@ -238,7 +238,7 @@ def ready(self): ## Filters & Pipeline Steps -**File**: [`sample_plugin/pipeline.py`](./sample_plugin/pipeline.py) +**File**: [`openedx_sample_plugin/pipeline.py`](./openedx_sample_plugin/pipeline.py) **Official Docs**: [Using Open edX Filters](https://docs.openedx.org/projects/openedx-filters/en/latest/how-tos/using-filters.html) ### Filter Implementation @@ -292,7 +292,7 @@ Filters must be registered in Django settings. This happens automatically via th ## Settings Configuration -**Files**: [`sample_plugin/settings/`](./sample_plugin/settings/) +**Files**: [`openedx_sample_plugin/settings/`](./openedx_sample_plugin/settings/) ### Settings Structure @@ -321,7 +321,7 @@ def plugin_settings(settings): settings.OPEN_EDX_FILTERS_CONFIG = { "org.openedx.learning.course.about.render.started.v1": { "pipeline": [ - "sample_plugin.pipeline.ChangeCourseAboutPageUrl" + "openedx_sample_plugin.pipeline.ChangeCourseAboutPageUrl" ], "fail_silently": False, } @@ -368,7 +368,7 @@ tutor dev restart lms ```bash # In your edx-platform directory -pip install -e /path/to/sample-plugin/backend +pip install -e /path/to/sample-plugin/platform-plugin-sample # Run migrations python manage.py lms migrate @@ -380,7 +380,7 @@ python manage.py cms migrate 1. **Check Installation**: ```bash python manage.py lms shell - >>> from sample_plugin.models import CourseArchiveStatus + >>> from openedx_sample_plugin.models import CourseArchiveStatus >>> print("Plugin installed successfully!") ``` @@ -393,7 +393,7 @@ python manage.py cms migrate ### Running Tests ```bash -cd backend +cd platform-plugin-sample # Install test dependencies make requirements @@ -420,7 +420,7 @@ make test-coverage **Model Testing Pattern:** ```python from django.test import TestCase -from sample_plugin.models import CourseArchiveStatus +from openedx_sample_plugin.models import CourseArchiveStatus class TestCourseArchiveStatus(TestCase): def test_create_archive_status(self): @@ -449,9 +449,9 @@ class TestCourseArchiveStatusAPI(APITestCase): make quality # Individual tools -pylint sample_plugin/ -isort --check-only sample_plugin/ -black --check sample_plugin/ +pylint openedx_sample_plugin/ +isort --check-only openedx_sample_plugin/ +black --check openedx_sample_plugin/ ``` ## Integration Examples @@ -502,11 +502,11 @@ class ChangeCourseAboutPageUrl(PipelineStep): ### For Your Use Case -1. **Models**: Modify [`models.py`](./sample_plugin/models.py) for your data structure -2. **APIs**: Update [`views.py`](./sample_plugin/views.py) and [`serializers.py`](./sample_plugin/serializers.py) -3. **Events**: Change event handlers in [`signals.py`](./sample_plugin/signals.py) -4. **Filters**: Implement your business logic in [`pipeline.py`](./sample_plugin/pipeline.py) -5. **Settings**: Configure plugin behavior in [`settings/`](./sample_plugin/settings/) +1. **Models**: Modify [`models.py`](./openedx_sample_plugin/models.py) for your data structure +2. **APIs**: Update [`views.py`](./openedx_sample_plugin/views.py) and [`serializers.py`](./openedx_sample_plugin/serializers.py) +3. **Events**: Change event handlers in [`signals.py`](./openedx_sample_plugin/signals.py) +4. **Filters**: Implement your business logic in [`pipeline.py`](./openedx_sample_plugin/pipeline.py) +5. **Settings**: Configure plugin behavior in [`settings/`](./openedx_sample_plugin/settings/) ### Plugin Development Checklist diff --git a/backend/codecov.yml b/platform-plugin-sample/codecov.yml similarity index 100% rename from backend/codecov.yml rename to platform-plugin-sample/codecov.yml diff --git a/backend/docs/Makefile b/platform-plugin-sample/docs/Makefile similarity index 100% rename from backend/docs/Makefile rename to platform-plugin-sample/docs/Makefile diff --git a/backend/docs/_static/theme_overrides.css b/platform-plugin-sample/docs/_static/theme_overrides.css similarity index 100% rename from backend/docs/_static/theme_overrides.css rename to platform-plugin-sample/docs/_static/theme_overrides.css diff --git a/backend/docs/concepts/index.rst b/platform-plugin-sample/docs/concepts/index.rst similarity index 100% rename from backend/docs/concepts/index.rst rename to platform-plugin-sample/docs/concepts/index.rst diff --git a/backend/docs/conf.py b/platform-plugin-sample/docs/conf.py similarity index 98% rename from backend/docs/conf.py rename to platform-plugin-sample/docs/conf.py index 446cb06..ccdeb55 100644 --- a/backend/docs/conf.py +++ b/platform-plugin-sample/docs/conf.py @@ -1,6 +1,6 @@ # pylint: disable=invalid-name """ -sample_plugin documentation build configuration file. +openedx_sample_plugin documentation build configuration file. This file is execfile()d with the current directory set to its containing dir. @@ -76,10 +76,10 @@ top_level_doc = 'index' # General information about the project. -project = 'sample_plugin' +project = 'openedx_sample_plugin' copyright = f'{datetime.now().year}, Axim Collaborative, Inc.' # pylint: disable=redefined-builtin author = 'Axim Collaborative, Inc.' -project_title = 'sample_plugin' +project_title = 'openedx_sample_plugin' documentation_title = f"{project_title}" # Set display_github to False if you don't want "edit on Github" button @@ -208,7 +208,7 @@ # The name for this set of Sphinx documents. # " v documentation" by default. # -# html_title = 'sample_plugin v0.1.0' +# html_title = 'openedx_sample_plugin v0.1.0' # A shorter title for the navigation bar. Default is the same as html_title. # @@ -522,8 +522,8 @@ def on_init(app): # pylint: disable=unused-argument # If we are, assemble the path manually bin_path = os.path.abspath(os.path.join(sys.prefix, 'bin')) apidoc_path = os.path.join(bin_path, apidoc_path) - check_call([apidoc_path, '-o', docs_path, os.path.join(root_path, 'src/sample_plugin'), - os.path.join(root_path, 'src/sample_plugin/migrations')]) + check_call([apidoc_path, '-o', docs_path, os.path.join(root_path, 'src/openedx_sample_plugin'), + os.path.join(root_path, 'src/openedx_sample_plugin/migrations')]) def setup(app): diff --git a/backend/docs/decisions.rst b/platform-plugin-sample/docs/decisions.rst similarity index 100% rename from backend/docs/decisions.rst rename to platform-plugin-sample/docs/decisions.rst diff --git a/backend/docs/decisions/0001-purpose-of-this-repo.rst b/platform-plugin-sample/docs/decisions/0001-purpose-of-this-repo.rst similarity index 100% rename from backend/docs/decisions/0001-purpose-of-this-repo.rst rename to platform-plugin-sample/docs/decisions/0001-purpose-of-this-repo.rst diff --git a/backend/docs/decisions/README.rst b/platform-plugin-sample/docs/decisions/README.rst similarity index 100% rename from backend/docs/decisions/README.rst rename to platform-plugin-sample/docs/decisions/README.rst diff --git a/backend/docs/getting_started.rst b/platform-plugin-sample/docs/getting_started.rst similarity index 100% rename from backend/docs/getting_started.rst rename to platform-plugin-sample/docs/getting_started.rst diff --git a/backend/docs/how-tos/index.rst b/platform-plugin-sample/docs/how-tos/index.rst similarity index 100% rename from backend/docs/how-tos/index.rst rename to platform-plugin-sample/docs/how-tos/index.rst diff --git a/backend/docs/index.rst b/platform-plugin-sample/docs/index.rst similarity index 85% rename from backend/docs/index.rst rename to platform-plugin-sample/docs/index.rst index 08858a7..1f9c366 100644 --- a/backend/docs/index.rst +++ b/platform-plugin-sample/docs/index.rst @@ -1,9 +1,9 @@ -.. sample_plugin documentation top level file, created by +.. openedx_sample_plugin documentation top level file, created by sphinx-quickstart on Fri Apr 11 10:00:56 2025. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -sample_plugin +openedx_sample_plugin ============= A sample backend plugin for the Open edX Platform diff --git a/backend/docs/internationalization.rst b/platform-plugin-sample/docs/internationalization.rst similarity index 100% rename from backend/docs/internationalization.rst rename to platform-plugin-sample/docs/internationalization.rst diff --git a/backend/docs/make.bat b/platform-plugin-sample/docs/make.bat similarity index 100% rename from backend/docs/make.bat rename to platform-plugin-sample/docs/make.bat diff --git a/backend/docs/quickstarts/index.rst b/platform-plugin-sample/docs/quickstarts/index.rst similarity index 100% rename from backend/docs/quickstarts/index.rst rename to platform-plugin-sample/docs/quickstarts/index.rst diff --git a/backend/docs/references/index.rst b/platform-plugin-sample/docs/references/index.rst similarity index 100% rename from backend/docs/references/index.rst rename to platform-plugin-sample/docs/references/index.rst diff --git a/backend/docs/testing.rst b/platform-plugin-sample/docs/testing.rst similarity index 90% rename from backend/docs/testing.rst rename to platform-plugin-sample/docs/testing.rst index b3a9b21..74aea55 100644 --- a/backend/docs/testing.rst +++ b/platform-plugin-sample/docs/testing.rst @@ -3,7 +3,7 @@ Testing ####### -sample_plugin has an assortment of test cases and code quality +openedx_sample_plugin has an assortment of test cases and code quality checks to catch potential problems during development. To run them all in the version of Python you chose for your virtualenv: diff --git a/backend/manage.py b/platform-plugin-sample/manage.py similarity index 100% rename from backend/manage.py rename to platform-plugin-sample/manage.py diff --git a/backend/pylintrc b/platform-plugin-sample/pylintrc similarity index 100% rename from backend/pylintrc rename to platform-plugin-sample/pylintrc diff --git a/backend/pylintrc_tweaks b/platform-plugin-sample/pylintrc_tweaks similarity index 100% rename from backend/pylintrc_tweaks rename to platform-plugin-sample/pylintrc_tweaks diff --git a/backend/pyproject.toml b/platform-plugin-sample/pyproject.toml similarity index 96% rename from backend/pyproject.toml rename to platform-plugin-sample/pyproject.toml index 7b720df..fd095da 100644 --- a/backend/pyproject.toml +++ b/platform-plugin-sample/pyproject.toml @@ -38,10 +38,10 @@ dependencies = [ ] [project.entry-points."lms.djangoapp"] -sample_plugin = "sample_plugin.apps:SamplePluginConfig" +openedx_sample_plugin = "openedx_sample_plugin.apps:SamplePluginConfig" [project.entry-points."cms.djangoapp"] -sample_plugin = "sample_plugin.apps:SamplePluginConfig" +openedx_sample_plugin = "openedx_sample_plugin.apps:SamplePluginConfig" [project.urls] Homepage = "https://openedx.org/openedx/sample-plugin" diff --git a/backend/setup.cfg b/platform-plugin-sample/setup.cfg similarity index 100% rename from backend/setup.cfg rename to platform-plugin-sample/setup.cfg diff --git a/backend/src/sample_plugin/__init__.py b/platform-plugin-sample/src/openedx_sample_plugin/__init__.py similarity index 84% rename from backend/src/sample_plugin/__init__.py rename to platform-plugin-sample/src/openedx_sample_plugin/__init__.py index 000bb65..63e7562 100644 --- a/backend/src/sample_plugin/__init__.py +++ b/platform-plugin-sample/src/openedx_sample_plugin/__init__.py @@ -4,6 +4,6 @@ from importlib.metadata import version as get_version -# The name of the package is `openedx-sample-plugin` but __package__ is `sample_plugin` so we hardcode the name of the +# The name of the package is `openedx-sample-plugin` but __package__ is `openedx_sample_plugin` so we hardcode the name of the # package here so that the version fetching works correctly. A lot of examples will show using `__package__`. __version__ = get_version('openedx-sample-plugin') diff --git a/backend/src/sample_plugin/apps.py b/platform-plugin-sample/src/openedx_sample_plugin/apps.py similarity index 93% rename from backend/src/sample_plugin/apps.py rename to platform-plugin-sample/src/openedx_sample_plugin/apps.py index 0c4de1f..c701d8e 100644 --- a/backend/src/sample_plugin/apps.py +++ b/platform-plugin-sample/src/openedx_sample_plugin/apps.py @@ -1,5 +1,5 @@ """ -sample_plugin Django application initialization. +openedx_sample_plugin Django application initialization. """ from django.apps import AppConfig @@ -36,25 +36,25 @@ class SamplePluginConfig(AppConfig): This plugin is registered in pyproject.toml as:: [project.entry-points."lms.djangoapp"] - sample_plugin = "sample_plugin.apps:SamplePluginConfig" + openedx_sample_plugin = "openedx_sample_plugin.apps:SamplePluginConfig" [project.entry-points."cms.djangoapp"] - sample_plugin = "sample_plugin.apps:SamplePluginConfig" + openedx_sample_plugin = "openedx_sample_plugin.apps:SamplePluginConfig" The platform automatically discovers and loads plugins registered in these entry points. """ # pylint: disable=line-too-long # noqa: E501 default_auto_field = "django.db.models.BigAutoField" - name = "sample_plugin" + name = "openedx_sample_plugin" plugin_app = { "url_config": { "lms.djangoapp": { - PluginURLs.NAMESPACE: "sample_plugin", + PluginURLs.NAMESPACE: "openedx_sample_plugin", PluginURLs.REGEX: r"^sample-plugin/", PluginURLs.RELATIVE_PATH: "urls", }, "cms.djangoapp": { - PluginURLs.NAMESPACE: "sample_plugin", + PluginURLs.NAMESPACE: "openedx_sample_plugin", PluginURLs.REGEX: r"^sample-plugin/", PluginURLs.RELATIVE_PATH: "urls", }, diff --git a/backend/src/sample_plugin/conf/locale/config.yaml b/platform-plugin-sample/src/openedx_sample_plugin/conf/locale/config.yaml similarity index 100% rename from backend/src/sample_plugin/conf/locale/config.yaml rename to platform-plugin-sample/src/openedx_sample_plugin/conf/locale/config.yaml diff --git a/backend/src/sample_plugin/migrations/0001_initial.py b/platform-plugin-sample/src/openedx_sample_plugin/migrations/0001_initial.py similarity index 100% rename from backend/src/sample_plugin/migrations/0001_initial.py rename to platform-plugin-sample/src/openedx_sample_plugin/migrations/0001_initial.py diff --git a/backend/src/sample_plugin/migrations/__init__.py b/platform-plugin-sample/src/openedx_sample_plugin/migrations/__init__.py similarity index 100% rename from backend/src/sample_plugin/migrations/__init__.py rename to platform-plugin-sample/src/openedx_sample_plugin/migrations/__init__.py diff --git a/backend/src/sample_plugin/models.py b/platform-plugin-sample/src/openedx_sample_plugin/models.py similarity index 97% rename from backend/src/sample_plugin/models.py rename to platform-plugin-sample/src/openedx_sample_plugin/models.py index 240b1c4..123ed98 100644 --- a/backend/src/sample_plugin/models.py +++ b/platform-plugin-sample/src/openedx_sample_plugin/models.py @@ -1,5 +1,5 @@ """ -Database models for sample_plugin. +Database models for openedx_sample_plugin. """ from django.contrib.auth import get_user_model diff --git a/backend/src/sample_plugin/pipeline.py b/platform-plugin-sample/src/openedx_sample_plugin/pipeline.py similarity index 97% rename from backend/src/sample_plugin/pipeline.py rename to platform-plugin-sample/src/openedx_sample_plugin/pipeline.py index 8b5dc3d..41cc78c 100644 --- a/backend/src/sample_plugin/pipeline.py +++ b/platform-plugin-sample/src/openedx_sample_plugin/pipeline.py @@ -1,5 +1,5 @@ """ -Open edX Filters implementation for the sample_plugin application. +Open edX Filters implementation for the openedx_sample_plugin application. This module demonstrates how to use Open edX Filters to modify platform behavior without changing core code. Filters are part of the Hooks Extension Framework @@ -62,7 +62,7 @@ def plugin_settings(settings): settings.OPEN_EDX_FILTERS_CONFIG = { "org.openedx.learning.course.about.render.started.v1": { "pipeline": [ - "sample_plugin.pipeline.ChangeCourseAboutPageUrl" + "openedx_sample_plugin.pipeline.ChangeCourseAboutPageUrl" ], "fail_silently": False, } diff --git a/backend/src/sample_plugin/py.typed b/platform-plugin-sample/src/openedx_sample_plugin/py.typed similarity index 100% rename from backend/src/sample_plugin/py.typed rename to platform-plugin-sample/src/openedx_sample_plugin/py.typed diff --git a/backend/src/sample_plugin/serializers.py b/platform-plugin-sample/src/openedx_sample_plugin/serializers.py similarity index 88% rename from backend/src/sample_plugin/serializers.py rename to platform-plugin-sample/src/openedx_sample_plugin/serializers.py index b723acf..ca57ecd 100644 --- a/backend/src/sample_plugin/serializers.py +++ b/platform-plugin-sample/src/openedx_sample_plugin/serializers.py @@ -1,11 +1,11 @@ """ -Serializers for the sample_plugin app. +Serializers for the openedx_sample_plugin app. """ from django.contrib.auth import get_user_model from rest_framework import serializers -from sample_plugin.models import CourseArchiveStatus +from openedx_sample_plugin.models import CourseArchiveStatus User = get_user_model() diff --git a/backend/src/sample_plugin/settings/common.py b/platform-plugin-sample/src/openedx_sample_plugin/settings/common.py similarity index 97% rename from backend/src/sample_plugin/settings/common.py rename to platform-plugin-sample/src/openedx_sample_plugin/settings/common.py index a935984..37a54ce 100644 --- a/backend/src/sample_plugin/settings/common.py +++ b/platform-plugin-sample/src/openedx_sample_plugin/settings/common.py @@ -1,5 +1,5 @@ """ -Common settings for the sample_plugin application. +Common settings for the openedx_sample_plugin application. This module demonstrates how Django App Plugins integrate with the platform's settings system. Plugin settings are merged with the main settings during @@ -97,7 +97,7 @@ def _configure_openedx_filters(settings): # Filter we want to register filter_name = "org.openedx.learning.course_about.page.url.requested.v1" - our_pipeline_step = "sample_plugin.pipeline.ChangeCourseAboutPageUrl" + our_pipeline_step = "openedx_sample_plugin.pipeline.ChangeCourseAboutPageUrl" # Check if this filter already has configuration if filter_name in filters_config: diff --git a/backend/src/sample_plugin/settings/production.py b/platform-plugin-sample/src/openedx_sample_plugin/settings/production.py similarity index 59% rename from backend/src/sample_plugin/settings/production.py rename to platform-plugin-sample/src/openedx_sample_plugin/settings/production.py index 561bbe0..cec3378 100644 --- a/backend/src/sample_plugin/settings/production.py +++ b/platform-plugin-sample/src/openedx_sample_plugin/settings/production.py @@ -1,8 +1,8 @@ """ -Production settings for the sample_plugin application. +Production settings for the openedx_sample_plugin application. """ -from sample_plugin.settings.common import plugin_settings as common_settings +from openedx_sample_plugin.settings.common import plugin_settings as common_settings def plugin_settings(settings): diff --git a/backend/src/sample_plugin/settings/test.py b/platform-plugin-sample/src/openedx_sample_plugin/settings/test.py similarity index 59% rename from backend/src/sample_plugin/settings/test.py rename to platform-plugin-sample/src/openedx_sample_plugin/settings/test.py index bf28df3..821d1fe 100644 --- a/backend/src/sample_plugin/settings/test.py +++ b/platform-plugin-sample/src/openedx_sample_plugin/settings/test.py @@ -1,8 +1,8 @@ """ -Test settings for the sample_plugin application. +Test settings for the openedx_sample_plugin application. """ -from sample_plugin.settings.common import plugin_settings as common_settings +from openedx_sample_plugin.settings.common import plugin_settings as common_settings def plugin_settings(settings): diff --git a/backend/src/sample_plugin/signals.py b/platform-plugin-sample/src/openedx_sample_plugin/signals.py similarity index 98% rename from backend/src/sample_plugin/signals.py rename to platform-plugin-sample/src/openedx_sample_plugin/signals.py index 0e707e5..50b92de 100644 --- a/backend/src/sample_plugin/signals.py +++ b/platform-plugin-sample/src/openedx_sample_plugin/signals.py @@ -1,5 +1,5 @@ """ -Open edX Events signal handlers for the sample_plugin application. +Open edX Events signal handlers for the openedx_sample_plugin application. This module demonstrates how to consume Open edX Events (signals) to react to platform activities and integrate with external systems. Events are part of diff --git a/backend/src/sample_plugin/templates/sample_plugin/base.html b/platform-plugin-sample/src/openedx_sample_plugin/templates/openedx_sample_plugin/base.html similarity index 100% rename from backend/src/sample_plugin/templates/sample_plugin/base.html rename to platform-plugin-sample/src/openedx_sample_plugin/templates/openedx_sample_plugin/base.html diff --git a/backend/src/sample_plugin/urls.py b/platform-plugin-sample/src/openedx_sample_plugin/urls.py similarity index 80% rename from backend/src/sample_plugin/urls.py rename to platform-plugin-sample/src/openedx_sample_plugin/urls.py index 7f64ce0..077c293 100644 --- a/backend/src/sample_plugin/urls.py +++ b/platform-plugin-sample/src/openedx_sample_plugin/urls.py @@ -1,11 +1,11 @@ """ -URLs for sample_plugin. +URLs for openedx_sample_plugin. """ from django.urls import include, path from rest_framework.routers import DefaultRouter -from sample_plugin.views import CourseArchiveStatusViewSet +from openedx_sample_plugin.views import CourseArchiveStatusViewSet # Create a router and register our viewsets with it router = DefaultRouter() diff --git a/backend/src/sample_plugin/views.py b/platform-plugin-sample/src/openedx_sample_plugin/views.py similarity index 97% rename from backend/src/sample_plugin/views.py rename to platform-plugin-sample/src/openedx_sample_plugin/views.py index 855fb9f..6e0ba63 100644 --- a/backend/src/sample_plugin/views.py +++ b/platform-plugin-sample/src/openedx_sample_plugin/views.py @@ -1,5 +1,5 @@ """ -Views for the sample_plugin app. +Views for the openedx_sample_plugin app. """ import logging @@ -13,8 +13,8 @@ from rest_framework.pagination import PageNumberPagination from rest_framework.throttling import UserRateThrottle -from sample_plugin.models import CourseArchiveStatus -from sample_plugin.serializers import CourseArchiveStatusSerializer +from openedx_sample_plugin.models import CourseArchiveStatus +from openedx_sample_plugin.serializers import CourseArchiveStatusSerializer logger = logging.getLogger(__name__) diff --git a/backend/test_settings.py b/platform-plugin-sample/test_settings.py similarity index 98% rename from backend/test_settings.py rename to platform-plugin-sample/test_settings.py index 88894fc..0588447 100644 --- a/backend/test_settings.py +++ b/platform-plugin-sample/test_settings.py @@ -54,7 +54,7 @@ def root(*args): INSTALLED_APPS.extend(plugin_apps) LOCALE_PATHS = [ - root("sample_plugin", "conf", "locale"), + root("openedx_sample_plugin", "conf", "locale"), ] ROOT_URLCONF = "tests.urls" diff --git a/backend/test_utils/__init__.py b/platform-plugin-sample/test_utils/__init__.py similarity index 100% rename from backend/test_utils/__init__.py rename to platform-plugin-sample/test_utils/__init__.py diff --git a/backend/tests/test_api.py b/platform-plugin-sample/tests/test_api.py similarity index 90% rename from backend/tests/test_api.py rename to platform-plugin-sample/tests/test_api.py index 0dc1b56..71cabb1 100644 --- a/backend/tests/test_api.py +++ b/platform-plugin-sample/tests/test_api.py @@ -11,7 +11,7 @@ from rest_framework import status from rest_framework.test import APIClient -from sample_plugin.models import CourseArchiveStatus +from openedx_sample_plugin.models import CourseArchiveStatus User = get_user_model() @@ -87,7 +87,7 @@ def test_list_course_archive_status_authenticated( Test that an authenticated user can list their own course archive statuses. """ api_client.force_authenticate(user=user) - url = reverse("sample_plugin:course-archive-status-list") + url = reverse("openedx_sample_plugin:course-archive-status-list") response = api_client.get(url) assert response.status_code == status.HTTP_200_OK @@ -106,7 +106,7 @@ def test_list_course_archive_status_unauthenticated(api_client): """ Test that an unauthenticated user cannot list course archive statuses. """ - url = reverse("sample_plugin:course-archive-status-list") + url = reverse("openedx_sample_plugin:course-archive-status-list") response = api_client.get(url) assert response.status_code == status.HTTP_403_FORBIDDEN @@ -130,7 +130,7 @@ def test_list_course_archive_status_staff_can_see_all( ) api_client.force_authenticate(user=staff_user) - url = reverse("sample_plugin:course-archive-status-list") + url = reverse("openedx_sample_plugin:course-archive-status-list") response = api_client.get(url) assert response.status_code == status.HTTP_200_OK @@ -143,7 +143,7 @@ def test_create_course_archive_status(api_client, user, course_key): Test that a user can create a course archive status. """ api_client.force_authenticate(user=user) - url = reverse("sample_plugin:course-archive-status-list") + url = reverse("openedx_sample_plugin:course-archive-status-list") data = { "course_id": str(course_key), "user": user.id, @@ -173,7 +173,7 @@ def test_create_course_archive_status_for_another_user( Test that a regular user cannot create a course archive status for another user. """ api_client.force_authenticate(user=user) - url = reverse("sample_plugin:course-archive-status-list") + url = reverse("openedx_sample_plugin:course-archive-status-list") data = { "course_id": str(course_key), "user": another_user.id, @@ -192,7 +192,7 @@ def test_staff_create_course_archive_status_for_another_user( Test that a staff user can create a course archive status for another user. """ api_client.force_authenticate(user=staff_user) - url = reverse("sample_plugin:course-archive-status-list") + url = reverse("openedx_sample_plugin:course-archive-status-list") data = { "course_id": str(course_key), "user": user.id, @@ -214,7 +214,7 @@ def test_update_course_archive_status(api_client, user, course_archive_status): """ api_client.force_authenticate(user=user) url = reverse( - "sample_plugin:course-archive-status-detail", args=[course_archive_status.id] + "openedx_sample_plugin:course-archive-status-detail", args=[course_archive_status.id] ) data = {"is_archived": True} response = api_client.patch(url, data, format="json") @@ -236,7 +236,7 @@ def test_delete_course_archive_status(api_client, user, course_archive_status): """ api_client.force_authenticate(user=user) url = reverse( - "sample_plugin:course-archive-status-detail", args=[course_archive_status.id] + "openedx_sample_plugin:course-archive-status-detail", args=[course_archive_status.id] ) response = api_client.delete(url) @@ -253,7 +253,7 @@ def test_cannot_update_other_user_course_archive_status( """ api_client.force_authenticate(user=another_user) url = reverse( - "sample_plugin:course-archive-status-detail", args=[course_archive_status.id] + "openedx_sample_plugin:course-archive-status-detail", args=[course_archive_status.id] ) data = {"is_archived": True} response = api_client.patch(url, data, format="json") @@ -270,7 +270,7 @@ def test_staff_can_update_other_user_course_archive_status( """ api_client.force_authenticate(user=staff_user) url = reverse( - "sample_plugin:course-archive-status-detail", args=[course_archive_status.id] + "openedx_sample_plugin:course-archive-status-detail", args=[course_archive_status.id] ) data = {"is_archived": True} response = api_client.patch(url, data, format="json") @@ -287,7 +287,7 @@ def test_create_course_archive_status_without_user_field(api_client, user, cours The user field should default to the current user. """ api_client.force_authenticate(user=user) - url = reverse("sample_plugin:course-archive-status-list") + url = reverse("openedx_sample_plugin:course-archive-status-list") data = { "course_id": str(course_key), "is_archived": True, @@ -321,7 +321,7 @@ def test_update_course_archive_status_without_user_field(api_client, user, cours """ api_client.force_authenticate(user=user) url = reverse( - "sample_plugin:course-archive-status-detail", args=[course_archive_status.id] + "openedx_sample_plugin:course-archive-status-detail", args=[course_archive_status.id] ) data = {"is_archived": True} # Note: No "user" field in data @@ -346,7 +346,7 @@ def test_staff_create_with_explicit_user_override( Test that staff can explicitly set user field to override default behavior. """ api_client.force_authenticate(user=staff_user) - url = reverse("sample_plugin:course-archive-status-list") + url = reverse("openedx_sample_plugin:course-archive-status-list") data = { "course_id": str(course_key), "user": user.id, @@ -381,7 +381,7 @@ def test_staff_update_with_explicit_user_override( api_client.force_authenticate(user=staff_user) url = reverse( - "sample_plugin:course-archive-status-detail", args=[initial_status.id] + "openedx_sample_plugin:course-archive-status-detail", args=[initial_status.id] ) data = { "user": another_user.id, @@ -407,7 +407,7 @@ def test_regular_user_cannot_override_user_field_create( Test that regular users cannot override user field to create records for other users. """ api_client.force_authenticate(user=user) - url = reverse("sample_plugin:course-archive-status-list") + url = reverse("openedx_sample_plugin:course-archive-status-list") data = { "course_id": str(course_key), "user": another_user.id, # Try to create for another user @@ -426,7 +426,7 @@ def test_staff_create_without_user_field_defaults_to_current_user( Test that even staff users get records created for themselves when no user specified. """ api_client.force_authenticate(user=staff_user) - url = reverse("sample_plugin:course-archive-status-list") + url = reverse("openedx_sample_plugin:course-archive-status-list") data = { "course_id": str(course_key), "is_archived": True, diff --git a/backend/tests/test_models.py b/platform-plugin-sample/tests/test_models.py similarity index 97% rename from backend/tests/test_models.py rename to platform-plugin-sample/tests/test_models.py index 331598f..92d5324 100644 --- a/backend/tests/test_models.py +++ b/platform-plugin-sample/tests/test_models.py @@ -9,7 +9,7 @@ from django.db.utils import IntegrityError from opaque_keys.edx.keys import CourseKey -from sample_plugin.models import CourseArchiveStatus +from openedx_sample_plugin.models import CourseArchiveStatus User = get_user_model() diff --git a/backend/tests/test_plugin_integration.py b/platform-plugin-sample/tests/test_plugin_integration.py similarity index 77% rename from backend/tests/test_plugin_integration.py rename to platform-plugin-sample/tests/test_plugin_integration.py index 765b9d0..ed4f8ba 100644 --- a/backend/tests/test_plugin_integration.py +++ b/platform-plugin-sample/tests/test_plugin_integration.py @@ -15,8 +15,8 @@ def test_app_is_installed(): INSTALLED_APPS """ - assert "sample_plugin.apps.SamplePluginConfig" in settings.INSTALLED_APPS - assert apps.get_app_config("sample_plugin") is not None + assert "openedx_sample_plugin.apps.SamplePluginConfig" in settings.INSTALLED_APPS + assert apps.get_app_config("openedx_sample_plugin") is not None # We don't do a test for the URLs because the namespaced urls which should be auto registered are tested in the diff --git a/backend/tests/urls.py b/platform-plugin-sample/tests/urls.py similarity index 100% rename from backend/tests/urls.py rename to platform-plugin-sample/tests/urls.py diff --git a/backend/tox.ini b/platform-plugin-sample/tox.ini similarity index 86% rename from backend/tox.ini rename to platform-plugin-sample/tox.ini index 9523b16..2d72d3a 100644 --- a/backend/tox.ini +++ b/platform-plugin-sample/tox.ini @@ -33,7 +33,7 @@ match-dir = (?!migrations) [pytest] DJANGO_SETTINGS_MODULE = test_settings -addopts = --cov sample_plugin --cov tests --cov-report term-missing --cov-report xml +addopts = --cov openedx_sample_plugin --cov tests --cov-report term-missing --cov-report xml norecursedirs = .* docs requirements site-packages [testenv] @@ -59,7 +59,7 @@ allowlist_externals = rm commands = doc8 --ignore-path docs/_build docs - rm -f docs/sample_plugin.rst + rm -f docs/openedx_sample_plugin.rst rm -f docs/modules.rst make -e -C docs clean make -e -C docs html @@ -76,11 +76,11 @@ allowlist_externals = touch commands = touch tests/__init__.py - pylint src/sample_plugin tests test_utils manage.py + pylint src/openedx_sample_plugin tests test_utils manage.py rm tests/__init__.py - pycodestyle src/sample_plugin tests manage.py - pydocstyle src/sample_plugin tests manage.py - isort --check-only --diff tests test_utils src/sample_plugin manage.py test_settings.py + pycodestyle src/openedx_sample_plugin tests manage.py + pydocstyle src/openedx_sample_plugin tests manage.py + isort --check-only --diff tests test_utils src/openedx_sample_plugin manage.py test_settings.py make selfcheck [testenv:pii_check] diff --git a/backend/uv.lock b/platform-plugin-sample/uv.lock similarity index 100% rename from backend/uv.lock rename to platform-plugin-sample/uv.lock diff --git a/tutor/README.md b/tutor/README.md index 4116b58..518c8f8 100644 --- a/tutor/README.md +++ b/tutor/README.md @@ -29,7 +29,7 @@ This Tutor plugin simplifies the deployment of the sample plugin by: ## Plugin Configuration -**File**: [`sample_plugin.py`](./sample_plugin.py) +**File**: [`openedx_sample_plugin.py`](./openedx_sample_plugin.py) ### Current Configuration @@ -68,7 +68,7 @@ __version__ = "1.0.0" # Backend plugin installation @hooks.Filters.IMAGES_BUILD_MOUNTS.add() -def _mount_sample_plugin(mounts): +def _mount_openedx_sample_plugin(mounts): """Mount the sample plugin source code for development.""" mounts.append(("sample-plugin-backend", "/openedx/sample-plugin-backend")) return mounts @@ -126,14 +126,14 @@ pip install -e /path/to/sample-plugin/tutor/ # Method 2: Copy plugin file (simpler for development) mkdir -p "$(tutor plugins printroot)" -cp sample_plugin.py "$(tutor plugins printroot)/sample_plugin.py" +cp openedx_sample_plugin.py "$(tutor plugins printroot)/openedx_sample_plugin.py" ``` ### Step 2: Enable Plugin ```bash # Enable the plugin -tutor plugins enable sample_plugin +tutor plugins enable openedx_sample_plugin # Verify plugin is enabled tutor plugins list @@ -161,7 +161,7 @@ tutor local launch ```bash # Check backend plugin -tutor dev exec lms python manage.py shell -c "from sample_plugin.models import CourseArchiveStatus; print('Backend plugin loaded')" +tutor dev exec lms python manage.py shell -c "from openedx_sample_plugin.models import CourseArchiveStatus; print('Backend plugin loaded')" # Check frontend plugin (visit learner dashboard in browser) # Should see custom course list with archive functionality @@ -202,7 +202,7 @@ tutor dev restart lms **Setup Pattern:** ```bash # Enable plugin -tutor plugins enable sample_plugin +tutor plugins enable openedx_sample_plugin # Build and deploy tutor local launch @@ -236,7 +236,7 @@ def _add_backend_settings(env): "OPEN_EDX_FILTERS_CONFIG": { "org.openedx.learning.course.about.render.started.v1": { "pipeline": [ - "sample_plugin.pipeline.ChangeCourseAboutPageUrl" + "openedx_sample_plugin.pipeline.ChangeCourseAboutPageUrl" ], "fail_silently": False, } @@ -296,7 +296,7 @@ def _configure_by_environment(env): tutor plugins list # Check plugin syntax -python -m py_compile sample_plugin.py +python -m py_compile openedx_sample_plugin.py # Verify plugin location tutor plugins printroot @@ -310,10 +310,10 @@ tutor images build lms # Manual installation for debugging tutor dev exec lms pip install -e ../sample-plugin-backend -tutor dev exec lms python -c "import sample_plugin; print('Success')" +tutor dev exec lms python -c "import openedx_sample_plugin; print('Success')" # Check migrations -tutor dev exec lms python manage.py showmigrations sample_plugin +tutor dev exec lms python manage.py showmigrations openedx_sample_plugin ``` **Frontend Plugin Not Appearing:** @@ -340,7 +340,7 @@ tutor dev exec lms python manage.py shell -c "from django.conf import settings; ```bash # View plugin configuration -tutor plugins show sample_plugin +tutor plugins show openedx_sample_plugin # Check generated configuration tutor config printvalue PLUGINS @@ -418,7 +418,7 @@ def _build_custom_image(build_config): def _run_plugin_migrations(): """Run plugin migrations when platform is ready.""" from django.core.management import call_command - call_command("migrate", "sample_plugin") + call_command("migrate", "openedx_sample_plugin") ``` ### Plugin Dependencies diff --git a/tutor/pyproject.toml b/tutor/pyproject.toml index 2852ef6..1c36140 100644 --- a/tutor/pyproject.toml +++ b/tutor/pyproject.toml @@ -23,7 +23,7 @@ dependencies = ["tutor>=17.0.0"] dynamic = ["readme", "version"] [project.entry-points."tutor.plugin.v1"] -sample_plugin = "tutorsampleplugin.plugin" +openedx_sample_plugin = "tutorsampleplugin.plugin" [project.urls] Homepage = "https://github.com/openedx/sample-plugin" diff --git a/tutor/tutorsampleplugin/plugin.py b/tutor/tutorsampleplugin/plugin.py index 0c6e7e4..36fd6a6 100644 --- a/tutor/tutorsampleplugin/plugin.py +++ b/tutor/tutorsampleplugin/plugin.py @@ -22,13 +22,6 @@ # Backend: Install the Django app plugin into LMS and CMS images # --------------------------------------------------------------------------- -# If a directory named "backend" has been moutned with `tutor mount add`, then -# this line will ensure that the directory gets mapped into the openedx[-dev] -# image and into the container's virtualenv. When there is no such directory -# mounted, this line has no effect (thus it's safe for it to exist in the -# production version of the plugin). -hooks.Filters.MOUNTED_DIRECTORIES.add_item(("openedx", "backend")) - # The openedx-dockerfile-post-python-requirements patch runs after pip # installs the base Open edX requirements. Plugins installed here are # available in both LMS and CMS containers. @@ -39,12 +32,12 @@ )) # --------------------------------------------------------------------------- -# Migrations: Run sample_plugin migrations on init +# Migrations: Run openedx_sample_plugin migrations on init # --------------------------------------------------------------------------- hooks.Filters.CLI_DO_INIT_TASKS.add_item(( "lms", - "./manage.py lms migrate sample_plugin", + "./manage.py lms migrate openedx_sample_plugin", )) # --------------------------------------------------------------------------- @@ -93,7 +86,7 @@ { op: PLUGIN_OPERATIONS.Insert, widget: { - id: 'sample_plugin_course_list', + id: 'openedx_sample_plugin_course_list', type: DIRECT_PLUGIN, priority: 50, RenderWidget: CourseList,