openedx-plugin-sample 3.4.0__tar.gz → 3.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openedx_plugin_sample-3.6.0/PKG-INFO +65 -0
- openedx_plugin_sample-3.6.0/README.md +36 -0
- openedx_plugin_sample-3.6.0/src/openedx_plugin_sample.egg-info/PKG-INFO +65 -0
- openedx_plugin_sample-3.4.0/PKG-INFO +0 -606
- openedx_plugin_sample-3.4.0/README.md +0 -577
- openedx_plugin_sample-3.4.0/src/openedx_plugin_sample.egg-info/PKG-INFO +0 -606
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/.annotation_safe_list.yml +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/.coveragerc +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/.editorconfig +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/.gitignore +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/.pii_annotations.yml +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/.readthedocs.yaml +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/LICENSE.txt +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/Makefile +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/codecov.yml +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/Makefile +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/_static/theme_overrides.css +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/concepts/index.rst +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/conf.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/decisions/0001-purpose-of-this-repo.rst +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/decisions/README.rst +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/decisions.rst +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/getting_started.rst +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/how-tos/index.rst +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/index.rst +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/internationalization.rst +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/make.bat +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/openedx_plugin_sample.rst +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/quickstarts/index.rst +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/references/index.rst +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/docs/testing.rst +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/manage.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/pylintrc +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/pylintrc_tweaks +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/pyproject.toml +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/setup.cfg +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/__init__.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/admin.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/apps.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/conf/locale/config.yaml +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/migrations/0001_initial.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/migrations/__init__.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/models.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/pipeline.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/py.typed +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/serializers.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/settings/common.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/settings/production.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/settings/test.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/signals.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/templates/openedx_plugin_sample/base.html +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/urls.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample/views.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample.egg-info/SOURCES.txt +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample.egg-info/dependency_links.txt +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample.egg-info/entry_points.txt +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample.egg-info/requires.txt +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/src/openedx_plugin_sample.egg-info/top_level.txt +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/test_settings.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/test_utils/__init__.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/tests/test_api.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/tests/test_models.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/tests/test_pipeline.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/tests/test_plugin_integration.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/tests/test_signals.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/tests/urls.py +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/tox.ini +0 -0
- {openedx_plugin_sample-3.4.0 → openedx_plugin_sample-3.6.0}/uv.lock +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openedx-plugin-sample
|
|
3
|
+
Version: 3.6.0
|
|
4
|
+
Summary: A sample backend plugin for the Open edX Platform
|
|
5
|
+
Author-email: Open edX Project <oscm@openedx.org>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://openedx.org/openedx/sample-plugin
|
|
8
|
+
Project-URL: Repository, https://openedx.org/openedx/sample-plugin
|
|
9
|
+
Keywords: Python,edx
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Framework :: Django
|
|
12
|
+
Classifier: Framework :: Django :: 4.2
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Natural Language :: English
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE.txt
|
|
20
|
+
Requires-Dist: Django
|
|
21
|
+
Requires-Dist: djangorestframework
|
|
22
|
+
Requires-Dist: django-filter
|
|
23
|
+
Requires-Dist: edx-opaque-keys
|
|
24
|
+
Requires-Dist: openedx-core
|
|
25
|
+
Requires-Dist: openedx-events
|
|
26
|
+
Requires-Dist: openedx-filters
|
|
27
|
+
Requires-Dist: openedx-atlas
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# backend-plugin-sample
|
|
31
|
+
|
|
32
|
+
A Django app plugin for edx-platform that adds a small course-archiving feature: learners can mark courses as archived (hidden from their active list) and unarchive them later. It demonstrates three backend extension points working together:
|
|
33
|
+
|
|
34
|
+
- A model + REST API (`CourseArchiveStatus`), consumed by [`frontend-plugin-sample`](../frontend-plugin-sample/)
|
|
35
|
+
- An [Open edX Events](https://docs.openedx.org/projects/openedx-events/en/latest/) handler that auto-unarchives on verified upgrade
|
|
36
|
+
- An [Open edX Filters](https://docs.openedx.org/projects/openedx-filters/en/latest/) pipeline step that rewrites the course-about URL
|
|
37
|
+
|
|
38
|
+
## How to use it
|
|
39
|
+
|
|
40
|
+
See the root [README](../README.md) for setup instructions. With Tutor, [`tutor-contrib-sample`](../tutor-contrib-sample/) installs this plugin automatically (or bind-mounts your local checkout if you `tutor mounts add` it). Without Tutor, `pip install -e .` into your edx-platform environment and run migrations.
|
|
41
|
+
|
|
42
|
+
## How it works
|
|
43
|
+
|
|
44
|
+
**Plugin registration.** [`apps.py`](./src/openedx_plugin_sample/apps.py) declares the Django app to edx-platform via the `plugin_app` config (URL routing, settings, signal registration). The entry points in [`pyproject.toml`](./pyproject.toml) make the platform discover the app automatically — no `INSTALLED_APPS` edit needed. See [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).
|
|
45
|
+
|
|
46
|
+
**Model.** [`models.py`](./src/openedx_plugin_sample/models.py) defines `CourseArchiveStatus(user, course_id, is_archived, archive_date)`, indexed for the lookups the API performs. Registered in Django admin via [`admin.py`](./src/openedx_plugin_sample/admin.py).
|
|
47
|
+
|
|
48
|
+
**REST API.** [`views.py`](./src/openedx_plugin_sample/views.py) exposes the model as a DRF `ModelViewSet` at `/sample-plugin/api/v1/course-archive-status/`, with per-user permissions, throttling, and pagination. Serializer in [`serializers.py`](./src/openedx_plugin_sample/serializers.py); URLs in [`urls.py`](./src/openedx_plugin_sample/urls.py). Business logic (e.g. setting `archive_date` when `is_archived` becomes true) lives in `perform_create`/`perform_update` rather than in the serializer.
|
|
49
|
+
|
|
50
|
+
**Event handler.** [`signals.py`](./src/openedx_plugin_sample/signals.py) listens for `COURSE_ENROLLMENT_CHANGED` and unarchives a learner's course when they upgrade to the verified track. An event (not a filter) is the right shape here because we want a one-time nudge at the moment of upgrade — if the learner re-archives the course later, we respect that. A filter would re-impose the rule on every render.
|
|
51
|
+
|
|
52
|
+
**Filter.** [`pipeline.py`](./src/openedx_plugin_sample/pipeline.py) implements `ChangeCourseAboutPageUrl`, a `PipelineStep` for `org.openedx.learning.course.about.render.started.v1` that rewrites course-about URLs to an external host. Registered via `OPEN_EDX_FILTERS_CONFIG` in [`settings/common.py`](./src/openedx_plugin_sample/settings/common.py).
|
|
53
|
+
|
|
54
|
+
**Settings.** Per-environment settings live in [`settings/`](./src/openedx_plugin_sample/settings/) (`common.py`, `production.py`, `test.py`). The plugin app loads these via its `plugin_app` config in `apps.py`.
|
|
55
|
+
|
|
56
|
+
## Testing and quality
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
cd backend-plugin-sample
|
|
60
|
+
make requirements # install test deps
|
|
61
|
+
make test # pytest
|
|
62
|
+
make quality # lint
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Tests live in [`tests/`](./tests/).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# backend-plugin-sample
|
|
2
|
+
|
|
3
|
+
A Django app plugin for edx-platform that adds a small course-archiving feature: learners can mark courses as archived (hidden from their active list) and unarchive them later. It demonstrates three backend extension points working together:
|
|
4
|
+
|
|
5
|
+
- A model + REST API (`CourseArchiveStatus`), consumed by [`frontend-plugin-sample`](../frontend-plugin-sample/)
|
|
6
|
+
- An [Open edX Events](https://docs.openedx.org/projects/openedx-events/en/latest/) handler that auto-unarchives on verified upgrade
|
|
7
|
+
- An [Open edX Filters](https://docs.openedx.org/projects/openedx-filters/en/latest/) pipeline step that rewrites the course-about URL
|
|
8
|
+
|
|
9
|
+
## How to use it
|
|
10
|
+
|
|
11
|
+
See the root [README](../README.md) for setup instructions. With Tutor, [`tutor-contrib-sample`](../tutor-contrib-sample/) installs this plugin automatically (or bind-mounts your local checkout if you `tutor mounts add` it). Without Tutor, `pip install -e .` into your edx-platform environment and run migrations.
|
|
12
|
+
|
|
13
|
+
## How it works
|
|
14
|
+
|
|
15
|
+
**Plugin registration.** [`apps.py`](./src/openedx_plugin_sample/apps.py) declares the Django app to edx-platform via the `plugin_app` config (URL routing, settings, signal registration). The entry points in [`pyproject.toml`](./pyproject.toml) make the platform discover the app automatically — no `INSTALLED_APPS` edit needed. See [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).
|
|
16
|
+
|
|
17
|
+
**Model.** [`models.py`](./src/openedx_plugin_sample/models.py) defines `CourseArchiveStatus(user, course_id, is_archived, archive_date)`, indexed for the lookups the API performs. Registered in Django admin via [`admin.py`](./src/openedx_plugin_sample/admin.py).
|
|
18
|
+
|
|
19
|
+
**REST API.** [`views.py`](./src/openedx_plugin_sample/views.py) exposes the model as a DRF `ModelViewSet` at `/sample-plugin/api/v1/course-archive-status/`, with per-user permissions, throttling, and pagination. Serializer in [`serializers.py`](./src/openedx_plugin_sample/serializers.py); URLs in [`urls.py`](./src/openedx_plugin_sample/urls.py). Business logic (e.g. setting `archive_date` when `is_archived` becomes true) lives in `perform_create`/`perform_update` rather than in the serializer.
|
|
20
|
+
|
|
21
|
+
**Event handler.** [`signals.py`](./src/openedx_plugin_sample/signals.py) listens for `COURSE_ENROLLMENT_CHANGED` and unarchives a learner's course when they upgrade to the verified track. An event (not a filter) is the right shape here because we want a one-time nudge at the moment of upgrade — if the learner re-archives the course later, we respect that. A filter would re-impose the rule on every render.
|
|
22
|
+
|
|
23
|
+
**Filter.** [`pipeline.py`](./src/openedx_plugin_sample/pipeline.py) implements `ChangeCourseAboutPageUrl`, a `PipelineStep` for `org.openedx.learning.course.about.render.started.v1` that rewrites course-about URLs to an external host. Registered via `OPEN_EDX_FILTERS_CONFIG` in [`settings/common.py`](./src/openedx_plugin_sample/settings/common.py).
|
|
24
|
+
|
|
25
|
+
**Settings.** Per-environment settings live in [`settings/`](./src/openedx_plugin_sample/settings/) (`common.py`, `production.py`, `test.py`). The plugin app loads these via its `plugin_app` config in `apps.py`.
|
|
26
|
+
|
|
27
|
+
## Testing and quality
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
cd backend-plugin-sample
|
|
31
|
+
make requirements # install test deps
|
|
32
|
+
make test # pytest
|
|
33
|
+
make quality # lint
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Tests live in [`tests/`](./tests/).
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openedx-plugin-sample
|
|
3
|
+
Version: 3.6.0
|
|
4
|
+
Summary: A sample backend plugin for the Open edX Platform
|
|
5
|
+
Author-email: Open edX Project <oscm@openedx.org>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://openedx.org/openedx/sample-plugin
|
|
8
|
+
Project-URL: Repository, https://openedx.org/openedx/sample-plugin
|
|
9
|
+
Keywords: Python,edx
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Framework :: Django
|
|
12
|
+
Classifier: Framework :: Django :: 4.2
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Natural Language :: English
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE.txt
|
|
20
|
+
Requires-Dist: Django
|
|
21
|
+
Requires-Dist: djangorestframework
|
|
22
|
+
Requires-Dist: django-filter
|
|
23
|
+
Requires-Dist: edx-opaque-keys
|
|
24
|
+
Requires-Dist: openedx-core
|
|
25
|
+
Requires-Dist: openedx-events
|
|
26
|
+
Requires-Dist: openedx-filters
|
|
27
|
+
Requires-Dist: openedx-atlas
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# backend-plugin-sample
|
|
31
|
+
|
|
32
|
+
A Django app plugin for edx-platform that adds a small course-archiving feature: learners can mark courses as archived (hidden from their active list) and unarchive them later. It demonstrates three backend extension points working together:
|
|
33
|
+
|
|
34
|
+
- A model + REST API (`CourseArchiveStatus`), consumed by [`frontend-plugin-sample`](../frontend-plugin-sample/)
|
|
35
|
+
- An [Open edX Events](https://docs.openedx.org/projects/openedx-events/en/latest/) handler that auto-unarchives on verified upgrade
|
|
36
|
+
- An [Open edX Filters](https://docs.openedx.org/projects/openedx-filters/en/latest/) pipeline step that rewrites the course-about URL
|
|
37
|
+
|
|
38
|
+
## How to use it
|
|
39
|
+
|
|
40
|
+
See the root [README](../README.md) for setup instructions. With Tutor, [`tutor-contrib-sample`](../tutor-contrib-sample/) installs this plugin automatically (or bind-mounts your local checkout if you `tutor mounts add` it). Without Tutor, `pip install -e .` into your edx-platform environment and run migrations.
|
|
41
|
+
|
|
42
|
+
## How it works
|
|
43
|
+
|
|
44
|
+
**Plugin registration.** [`apps.py`](./src/openedx_plugin_sample/apps.py) declares the Django app to edx-platform via the `plugin_app` config (URL routing, settings, signal registration). The entry points in [`pyproject.toml`](./pyproject.toml) make the platform discover the app automatically — no `INSTALLED_APPS` edit needed. See [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).
|
|
45
|
+
|
|
46
|
+
**Model.** [`models.py`](./src/openedx_plugin_sample/models.py) defines `CourseArchiveStatus(user, course_id, is_archived, archive_date)`, indexed for the lookups the API performs. Registered in Django admin via [`admin.py`](./src/openedx_plugin_sample/admin.py).
|
|
47
|
+
|
|
48
|
+
**REST API.** [`views.py`](./src/openedx_plugin_sample/views.py) exposes the model as a DRF `ModelViewSet` at `/sample-plugin/api/v1/course-archive-status/`, with per-user permissions, throttling, and pagination. Serializer in [`serializers.py`](./src/openedx_plugin_sample/serializers.py); URLs in [`urls.py`](./src/openedx_plugin_sample/urls.py). Business logic (e.g. setting `archive_date` when `is_archived` becomes true) lives in `perform_create`/`perform_update` rather than in the serializer.
|
|
49
|
+
|
|
50
|
+
**Event handler.** [`signals.py`](./src/openedx_plugin_sample/signals.py) listens for `COURSE_ENROLLMENT_CHANGED` and unarchives a learner's course when they upgrade to the verified track. An event (not a filter) is the right shape here because we want a one-time nudge at the moment of upgrade — if the learner re-archives the course later, we respect that. A filter would re-impose the rule on every render.
|
|
51
|
+
|
|
52
|
+
**Filter.** [`pipeline.py`](./src/openedx_plugin_sample/pipeline.py) implements `ChangeCourseAboutPageUrl`, a `PipelineStep` for `org.openedx.learning.course.about.render.started.v1` that rewrites course-about URLs to an external host. Registered via `OPEN_EDX_FILTERS_CONFIG` in [`settings/common.py`](./src/openedx_plugin_sample/settings/common.py).
|
|
53
|
+
|
|
54
|
+
**Settings.** Per-environment settings live in [`settings/`](./src/openedx_plugin_sample/settings/) (`common.py`, `production.py`, `test.py`). The plugin app loads these via its `plugin_app` config in `apps.py`.
|
|
55
|
+
|
|
56
|
+
## Testing and quality
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
cd backend-plugin-sample
|
|
60
|
+
make requirements # install test deps
|
|
61
|
+
make test # pytest
|
|
62
|
+
make quality # lint
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Tests live in [`tests/`](./tests/).
|