Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab18396e89 | ||
|
|
ae4e3f20ac | ||
|
|
4fde7e355b | ||
|
|
1ff9c0bd77 | ||
|
|
3fe46bc278 | ||
|
|
cde10c2f97 | ||
|
|
97aed60b38 | ||
|
|
1465402bfa | ||
|
|
8540aef9b8 | ||
|
|
9d91f7499d | ||
|
|
3f0ff01105 | ||
|
|
e61f3cea5f | ||
|
|
0267ffde12 | ||
|
|
6e8bc34475 | ||
|
|
a61e09c11e | ||
|
|
e5fedc2d83 | ||
|
|
e52064fe64 | ||
|
|
75e64f5065 | ||
|
|
7d16414908 | ||
|
|
5515eda18b | ||
|
|
fdf73b62e3 | ||
|
|
f9fcbf26f4 | ||
|
|
dbf48674f9 | ||
|
|
28113792f3 | ||
|
|
7801778112 | ||
|
|
9671824e1f | ||
|
|
06fd645d44 | ||
|
|
6d3685a573 | ||
|
|
20ec2c8b99 | ||
|
|
f68719de86 | ||
|
|
8b1c93d900 | ||
|
|
c5bd0acab1 | ||
|
|
795ea5966e | ||
|
|
0d0128210c | ||
|
|
0751918e6a | ||
|
|
74c85b1edd | ||
|
|
58f8abc339 | ||
|
|
2d32da1245 | ||
|
|
1c349e00c2 | ||
|
|
305e008ea0 | ||
|
|
98a00ecb58 | ||
|
|
727d500bf5 | ||
|
|
f88afe05c3 | ||
|
|
d4a4274bc4 | ||
|
|
cb08b63217 | ||
|
|
16012432a1 | ||
|
|
0768eafd7e | ||
|
|
8c4f872756 | ||
|
|
3ca1417597 | ||
|
|
2b78e58e8a | ||
|
|
f8c28346a5 | ||
|
|
0093976541 | ||
|
|
581f986729 | ||
|
|
a7ad3758b5 | ||
|
|
5d6580c82b |
20
.github/workflows/auto-add-to-project.yml
vendored
Normal file
20
.github/workflows/auto-add-to-project.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
name: Auto Add Issues and Pull Requests to Project
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
|
||||
jobs:
|
||||
# https://github.com/actions/add-to-project
|
||||
add-to-project:
|
||||
name: Add issue and bugs to project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/add-to-project@v1.0.2
|
||||
with:
|
||||
project-url: https://github.com/orgs/overhangio/projects/4
|
||||
github-token: ${{ secrets.GH_PROJECT_PERSONAL_ACCESS_TOKEN }}
|
||||
4
.github/workflows/sync.yml
vendored
4
.github/workflows/sync.yml
vendored
@ -2,13 +2,13 @@ name: Sync with private repo
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, main, nightly ]
|
||||
branches: [ release, main ]
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Add remote
|
||||
|
||||
25
.github/workflows/test.yml
vendored
Normal file
25
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: Run tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ release, main ]
|
||||
push:
|
||||
branches: [ release, main ]
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.9', '3.12']
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip install .[dev]
|
||||
- name: Test lint, types, and format
|
||||
run: make test
|
||||
@ -2,7 +2,6 @@ variables:
|
||||
TUTOR_PLUGIN: notes
|
||||
TUTOR_IMAGES: notes
|
||||
TUTOR_PYPI_PACKAGE: tutor-notes
|
||||
OPENEDX_RELEASE: palm
|
||||
GITHUB_REPO: overhangio/tutor-notes
|
||||
|
||||
include:
|
||||
|
||||
21
.hatch_build.py
Normal file
21
.hatch_build.py
Normal file
@ -0,0 +1,21 @@
|
||||
# https://hatch.pypa.io/latest/how-to/config/dynamic-metadata/
|
||||
|
||||
import os
|
||||
import typing as t
|
||||
|
||||
from hatchling.metadata.plugin.interface import MetadataHookInterface
|
||||
|
||||
HERE = os.path.dirname(__file__)
|
||||
|
||||
|
||||
class MetaDataHook(MetadataHookInterface):
|
||||
def update(self, metadata: dict[str, t.Any]) -> None:
|
||||
about = load_about()
|
||||
metadata["version"] = about["__version__"]
|
||||
|
||||
|
||||
def load_about() -> dict[str, str]:
|
||||
about: dict[str, str] = {}
|
||||
with open(os.path.join(HERE, "tutornotes", "__about__.py"), "rt", encoding="utf-8") as f:
|
||||
exec(f.read(), about)
|
||||
return about
|
||||
52
CHANGELOG.md
52
CHANGELOG.md
@ -19,3 +19,55 @@ instructions, because git commits are used to generate release notes:
|
||||
|
||||
<!-- scriv-insert-here -->
|
||||
|
||||
<a id='changelog-20.0.0'></a>
|
||||
## v20.0.0 (2025-06-05)
|
||||
|
||||
- 💥[Feature] Upgrade to Teak. (by @jfavellar90)
|
||||
|
||||
<a id='changelog-19.0.2'></a>
|
||||
## v19.0.2 (2025-03-12)
|
||||
|
||||
- [Improvement] Add hatch_build.py in sdist target to fix the installation issues (by @dawoudsheraz)
|
||||
|
||||
<a id='changelog-19.0.1'></a>
|
||||
## v19.0.1 (2025-03-11)
|
||||
|
||||
- [Bugfix] Fix broken feature in `dev` mode, where the frontend is reporting a CORS error on loading the notes. (by @regisb)
|
||||
|
||||
- [Improvement] Migrate from `setup.py` (setuptools) to `pyproject.toml` (hatch). (by @jfavellar90)
|
||||
|
||||
<a id='changelog-19.0.0'></a>
|
||||
## v19.0.0 (2024-10-24)
|
||||
|
||||
- [Bugfix] Fix legacy warnings during Docker build. (by @regisb)
|
||||
|
||||
- 💥[Feature] Update Notes Image to use Ubuntu 24.04 as base OS. (by @jfavellar90)
|
||||
|
||||
- [Bugfix] Actually mount edx-notes-api repositories from host on `tutor mounts add /path/to/edx-notes-api`. (by @regisb)
|
||||
- 💥[Feature] Replace Elasticsearch by Meilisearch. The implementation is much more compact and readable. All content will be automatically re-indexed during init. (by @regisb)
|
||||
|
||||
- 💥 [Deprecation] Drop support for python 3.8 and set Python 3.9 as the minimum supported python version. (by @DawoudSheraz)
|
||||
|
||||
- 💥[Improvement] Rename Tutor's two branches (by @DawoudSheraz):
|
||||
* Rename **master** to **release**, as this branch runs the latest official Open edX release tag.
|
||||
* Rename **nightly** to **main**, as this branch runs the Open edX master branches, which are the basis for the next Open edX release.
|
||||
|
||||
- 💥[Feature] Upgrade to Sumac. (by @jfavellar90)
|
||||
|
||||
<a id='changelog-18.0.0'></a>
|
||||
## v18.0.0 (2024-05-09)
|
||||
|
||||
- [Bugfix] Make plugin compatible with Python 3.12 by removing dependency on `pkg_resources`. (by @regisb)
|
||||
|
||||
- 💥[Feature] Upgrade Python version to 3.12.3. (by @jfavellar90)
|
||||
- 💥[Feature] Upgrade to Redwood. (by @jfavellar90)
|
||||
|
||||
<a id='changelog-17.0.0'></a>
|
||||
## v17.0.0 (2023-12-09)
|
||||
|
||||
- 💥 [Feature] Upgrade to Quince.
|
||||
- [Improvement] Add a scriv-compliant changelog. (by @regisb)
|
||||
- [Improvement] Removing the notes permissions container in favor of a global single permissions container. (by @jfavellar90)
|
||||
- [Improvement] Added Makefile and test action to repository and formatted code with Black and isort. (by @CodeWithEmad)
|
||||
|
||||
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
recursive-include tutornotes/patches *
|
||||
recursive-include tutornotes/templates *
|
||||
46
Makefile
Normal file
46
Makefile
Normal file
@ -0,0 +1,46 @@
|
||||
.DEFAULT_GOAL := help
|
||||
.PHONY: docs
|
||||
SRC_DIRS = ./tutornotes
|
||||
RUFF_OPTS = --exclude templates ${SRC_DIRS}
|
||||
|
||||
# Warning: These checks are run on every PR.
|
||||
test: test-lint test-types test-format test-pythonpackage
|
||||
|
||||
test-format: ## Run code formatting tests.
|
||||
ruff format --check --diff $(RUFF_OPTS)
|
||||
|
||||
test-lint:
|
||||
ruff check ${SRC_DIRS}
|
||||
|
||||
test-types: ## Run type checks.
|
||||
mypy --exclude=templates --ignore-missing-imports --implicit-reexport --strict ${SRC_DIRS}
|
||||
|
||||
build-pythonpackage:
|
||||
python -m build --sdist
|
||||
|
||||
test-pythonpackage: build-pythonpackage
|
||||
twine check dist/tutor_notes-$(shell make version).tar.gz
|
||||
|
||||
format: ## Format code automatically.
|
||||
ruff format $(RUFF_OPTS)
|
||||
|
||||
fix-lint: ## Fix linting issues automatically.
|
||||
ruff check --fix $(RUFF_OPTS)
|
||||
|
||||
isort: ## Sort imports. This target is not mandatory because the output may be incompatible with black formatting. Provided for convenience purposes.
|
||||
isort --skip=templates ${SRC_DIRS}
|
||||
|
||||
changelog-entry: ## Create a new changelog entry.
|
||||
scriv create
|
||||
|
||||
changelog: ## Collect changelog entries in the CHANGELOG.md file.
|
||||
scriv collect
|
||||
|
||||
version: ## Print the current tutor-notes version
|
||||
@python -c 'import io, os; about = {}; exec(io.open(os.path.join("tutornotes", "__about__.py"), "rt", encoding="utf-8").read(), about); print(about["__version__"])'
|
||||
|
||||
ESCAPE =
|
||||
help: ## Print this help.
|
||||
@grep -E '^([a-zA-Z_-]+:.*?## .*|######* .+)$$' Makefile \
|
||||
| sed 's/######* \(.*\)/@ $(ESCAPE)[1;31m\1$(ESCAPE)[0m/g' | tr '@' '\n' \
|
||||
| awk 'BEGIN {FS = ":.*?## "}; {printf "\033[33m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
12
README.rst
12
README.rst
@ -1,9 +1,9 @@
|
||||
Students notes plugin for `Tutor <https://docs.tutor.overhang.io>`_
|
||||
Students notes plugin for `Tutor <https://docs.tutor.edly.io>`_
|
||||
===================================================================
|
||||
|
||||
This is a plugin for `Tutor <https://docs.tutor.overhang.io>`_ to easily add the `Open edX note-taking app <https://github.com/openedx/edx-notes-api>`_ to an Open edX platform. This app allows students to annotate portions of the courseware (see `the official documentation <https://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/open-release-palm.master/exercises_tools/notes.html>`_).
|
||||
This is a plugin for `Tutor <https://docs.tutor.edly.io>`_ to easily add the `Open edX note-taking app <https://github.com/openedx/edx-notes-api>`_ to an Open edX platform. This app allows students to annotate portions of the courseware (see `the official documentation <https://docs.openedx.org/en/latest/educators/how-tos/course_development/exercise_tools/enable_notes.html>`_).
|
||||
|
||||
.. image:: https://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/open-release-palm.master/_images/SFD_SN_bodyexample.png
|
||||
.. image:: https://docs.openedx.org/en/latest/_images/SFD_SN_bodyexample.png
|
||||
:alt: Notes in action
|
||||
|
||||
Installation
|
||||
@ -23,7 +23,7 @@ Then, to make migrations & tasks::
|
||||
|
||||
You should beware that the ``notes.<LMS_HOST>`` domain name should exist and point to your server. For instance, if your LMS is hosted at http://myopenedx.com, the notes service should be found at http://notes.myopenedx.com.
|
||||
|
||||
If you would like to host the notes service at a different domain name, you can set the ``NOTES_HOST`` configuration variable (see below). When testing Tutor on a local computer, this will be automatically set to notes.local.overhang.io.
|
||||
If you would like to host the notes service at a different domain name, you can set the ``NOTES_HOST`` configuration variable (see below). When testing Tutor on a local computer, this will be automatically set to notes.local.openedx.io.
|
||||
|
||||
To enable student notes for a specific course, you should go to the course advanced settings in the studio, and set "Enable Student Notes" to "true". Then, hit "save changes".
|
||||
|
||||
@ -54,9 +54,9 @@ Feel free to add breakpoints (``breakpoint()``) anywhere in your source code to
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
This Tutor plugin is maintained by Jhony Avella from `eduNEXT <https://www.edunext.co/>`__. Community support is available from the official `Open edX forum <https://discuss.openedx.org>`__. Do you need help with this plugin? See the `troubleshooting <https://docs.tutor.overhang.io/troubleshooting.html>`__ section from the Tutor documentation.
|
||||
This Tutor plugin is maintained by Jhony Avella from `eduNEXT <https://www.edunext.co/>`__. Community support is available from the official `Open edX forum <https://discuss.openedx.org>`__. Do you need help with this plugin? See the `troubleshooting <https://docs.tutor.edly.io/troubleshooting.html>`__ section from the Tutor documentation.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
This software is licensed under the terms of the `GNU Affero General Public License (AGPL) <https://github.com/overhangio/tutor-notes/blob/master/LICENSE.txt>`_.
|
||||
This software is licensed under the terms of the `GNU Affero General Public License (AGPL) <https://github.com/overhangio/tutor-notes/blob/release/LICENSE.txt>`_.
|
||||
|
||||
@ -1 +0,0 @@
|
||||
- [Improvement] Add a scriv-compliant changelog. (by @regisb)
|
||||
@ -1 +0,0 @@
|
||||
- [Improvement] Removing the notes permissions container in favor of a global single permissions container. (by @jfavellar90)
|
||||
@ -0,0 +1,2 @@
|
||||
- [Improvement] Migrate from pylint and black to ruff. (by @dawoudsheraz)
|
||||
- [Improvement] Test python package distribution build when running make-test. (by @dawoudsheraz)
|
||||
@ -1,2 +1,87 @@
|
||||
# https://packaging.python.org/en/latest/tutorials/packaging-projects/
|
||||
# https://hatch.pypa.io/latest/config/build/
|
||||
|
||||
[project]
|
||||
name = "tutor-notes"
|
||||
description = "A Tutor plugin for student notes"
|
||||
authors = [
|
||||
{ name = "Edly" },
|
||||
{ email = "hello@edly.io"},
|
||||
]
|
||||
maintainers = [
|
||||
{ name = "Jhony Avella" },
|
||||
{ email = "jhony.avella@edunext.co" },
|
||||
]
|
||||
license = {text = "AGPL-3.0-only"}
|
||||
readme = {file = "README.rst", content-type = "text/x-rst"}
|
||||
requires-python = ">=3.9"
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: GNU Affero General Public License v3",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
]
|
||||
dependencies = [
|
||||
"tutor>=20.0.0,<21.0.0",
|
||||
]
|
||||
|
||||
# These fields will be set by hatch_build.py
|
||||
dynamic = ["version"]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"tutor[dev]>=20.0.0,<21.0.0",
|
||||
"ruff"
|
||||
]
|
||||
|
||||
|
||||
# https://packaging.python.org/en/latest/specifications/well-known-project-urls/#well-known-labels
|
||||
[project.urls]
|
||||
Homepage = "https://docs.tutor.edly.io/"
|
||||
Documentation = "https://github.com/overhangio/tutor-notes#readme"
|
||||
Issues = "https://github.com/overhangio/tutor-notes/issues"
|
||||
Source = "https://github.com/overhangio/tutor-notes"
|
||||
Changelog = "https://github.com/overhangio/tutor-notes/blob/release/CHANGELOG.md"
|
||||
Community = "https://discuss.openedx.org/tag/tutor"
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools", "wheel"]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
# hatch-specific configuration
|
||||
[tool.hatch.metadata.hooks.custom]
|
||||
path = ".hatch_build.py"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["tutornotes"]
|
||||
|
||||
[tool.hatch.build.targets.sdist]
|
||||
# Disable strict naming, otherwise twine is not able to detect name/version
|
||||
strict-naming = false
|
||||
include = [ "/tutornotes", ".hatch_build.py"]
|
||||
exclude = ["tests*"]
|
||||
|
||||
[project.entry-points."tutor.plugin.v1"]
|
||||
notes = "tutornotes.plugin"
|
||||
|
||||
[tool.ruff]
|
||||
exclude = ["templates", "docs/_ext"]
|
||||
|
||||
[tool.ruff.lint]
|
||||
# E: pycodestyle errors
|
||||
# I: isort
|
||||
# N: pep8-naming
|
||||
select = ["E", "I", "N"]
|
||||
|
||||
# F401: unused-import
|
||||
# F841: unused-variable
|
||||
# W292: missing-newline-at-end-of-file
|
||||
extend-select = ["F401", "F841", "W292"]
|
||||
|
||||
[tool.ruff.format]
|
||||
# Default config is automatically taken from https://docs.astral.sh/ruff/configuration/
|
||||
|
||||
49
setup.py
49
setup.py
@ -1,49 +0,0 @@
|
||||
import io
|
||||
import os
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
with io.open(os.path.join(here, "README.rst"), "rt", encoding="utf8") as f:
|
||||
readme = f.read()
|
||||
|
||||
about = {}
|
||||
with io.open(
|
||||
os.path.join(here, "tutornotes", "__about__.py"), "rt", encoding="utf-8"
|
||||
) as f:
|
||||
exec(f.read(), about)
|
||||
|
||||
setup(
|
||||
name="tutor-notes",
|
||||
version=about["__package_version__"],
|
||||
url="https://docs.tutor.overhang.io/",
|
||||
project_urls={
|
||||
"Documentation": "https://docs.tutor.overhang.io/",
|
||||
"Code": "https://github.com/overhangio/tutor-notes",
|
||||
"Issue tracker": "https://github.com/overhangio/tutor-notes/issues",
|
||||
"Community": "https://discuss.openedx.org",
|
||||
},
|
||||
license="AGPLv3",
|
||||
author="Overhang.IO",
|
||||
author_email="contact@overhang.io",
|
||||
maintainer="eduNEXT",
|
||||
description="A Tutor plugin for student notes",
|
||||
long_description=readme,
|
||||
packages=find_packages(exclude=["tests*"]),
|
||||
include_package_data=True,
|
||||
python_requires=">=3.8",
|
||||
install_requires=["tutor>=16.0.0,<17.0.0"],
|
||||
entry_points={"tutor.plugin.v1": ["notes = tutornotes.plugin"]},
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: GNU Affero General Public License v3",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
],
|
||||
)
|
||||
@ -1,8 +1 @@
|
||||
__version__ = "16.0.2"
|
||||
__package_version__ = __version__
|
||||
|
||||
# Handle version suffix for nightly, just like tutor core.
|
||||
__version_suffix__ = ""
|
||||
|
||||
if __version_suffix__:
|
||||
__version__ += "-" + __version_suffix__
|
||||
__version__ = "20.0.0"
|
||||
|
||||
@ -15,8 +15,8 @@ spec:
|
||||
app.kubernetes.io/name: notes
|
||||
spec:
|
||||
securityContext:
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
runAsUser: {{ APP_USER_ID }}
|
||||
runAsGroup: {{ APP_USER_ID }}
|
||||
containers:
|
||||
- name: notes
|
||||
image: {{ NOTES_DOCKER_IMAGE }}
|
||||
|
||||
@ -4,4 +4,7 @@ notes-job:
|
||||
DJANGO_SETTINGS_MODULE: notesserver.settings.tutor
|
||||
volumes:
|
||||
- ../plugins/notes/apps/settings/tutor.py:/app/edx-notes-api/notesserver/settings/tutor.py:ro
|
||||
{%- for mount in iter_mounts(MOUNTS, "notes") %}
|
||||
- {{ mount }}
|
||||
{%- endfor %}
|
||||
depends_on: {{ [("mysql", RUN_MYSQL)]|list_if }}
|
||||
|
||||
@ -1 +1 @@
|
||||
setowner 1000 /mounts/notes
|
||||
setowner {{ APP_USER_ID }} /mounts/notes
|
||||
|
||||
@ -6,5 +6,8 @@ notes:
|
||||
volumes:
|
||||
- ../plugins/notes/apps/settings/tutor.py:/app/edx-notes-api/notesserver/settings/tutor.py:ro
|
||||
- ../../data/notes:/app/data
|
||||
{%- for mount in iter_mounts(MOUNTS, "notes") %}
|
||||
- {{ mount }}
|
||||
{%- endfor %}
|
||||
restart: unless-stopped
|
||||
depends_on: {{ [("mysql", RUN_MYSQL)]|list_if }}
|
||||
|
||||
@ -1,73 +1,79 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from glob import glob
|
||||
import os
|
||||
import typing as t
|
||||
from glob import glob
|
||||
|
||||
import pkg_resources
|
||||
|
||||
import importlib_resources
|
||||
from tutor import hooks as tutor_hooks
|
||||
from tutor.__about__ import __version_suffix__
|
||||
|
||||
from .__about__ import __version__
|
||||
|
||||
# Handle version suffix in main mode, just like tutor core
|
||||
if __version_suffix__:
|
||||
__version__ += "-" + __version_suffix__
|
||||
|
||||
config = {
|
||||
"unique": {
|
||||
"MYSQL_PASSWORD": "{{ 8|random_string }}",
|
||||
"SECRET_KEY": "{{ 24|random_string }}",
|
||||
"OAUTH2_SECRET": "{{ 24|random_string }}",
|
||||
},
|
||||
"defaults": {
|
||||
"VERSION": __version__,
|
||||
"DOCKER_IMAGE": "{{ DOCKER_REGISTRY }}overhangio/openedx-notes:{{ NOTES_VERSION }}",
|
||||
"DOCKER_IMAGE": "{{ DOCKER_REGISTRY }}overhangio/openedx-notes:{{ NOTES_VERSION }}", # noqa: E501
|
||||
"HOST": "notes.{{ LMS_HOST }}",
|
||||
"MYSQL_DATABASE": "notes",
|
||||
"MYSQL_USERNAME": "notes",
|
||||
"REPOSITORY": "https://github.com/openedx/edx-notes-api",
|
||||
"REPOSITORY_VERSION": "{{ OPENEDX_COMMON_VERSION }}",
|
||||
},
|
||||
"unique": {
|
||||
"MYSQL_PASSWORD": "{{ 8|random_string }}",
|
||||
"SECRET_KEY": "{{ 24|random_string }}",
|
||||
"OAUTH2_SECRET": "{{ 24|random_string }}",
|
||||
},
|
||||
}
|
||||
|
||||
# Initialization hooks
|
||||
|
||||
# To add a custom initialization task, create a bash script template under:
|
||||
# tutorcodejail/templates/codejail/tasks/
|
||||
# and then add it to the MY_INIT_TASKS list. Each task is in the format:
|
||||
# ("<service>", ("<path>", "<to>", "<script>", "<template>"))
|
||||
MY_INIT_TASKS: list[tuple[str, tuple[str, ...]]] = [
|
||||
("mysql", ("notes", "tasks", "mysql", "init")),
|
||||
("lms", ("notes", "tasks", "lms", "init")),
|
||||
("notes", ("notes", "tasks", "notes", "init")),
|
||||
]
|
||||
|
||||
# For each task added to MY_INIT_TASKS, we load the task template
|
||||
# For each service, 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(
|
||||
"tutornotes", os.path.join("templates", *template_path)
|
||||
for service in ["mysql", "lms", "notes"]:
|
||||
full_path: str = str(
|
||||
importlib_resources.files("tutornotes")
|
||||
/ "templates"
|
||||
/ "notes"
|
||||
/ "tasks"
|
||||
/ service
|
||||
/ "init"
|
||||
)
|
||||
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))
|
||||
|
||||
# Image management
|
||||
tutor_hooks.Filters.IMAGES_BUILD.add_item((
|
||||
"notes",
|
||||
("plugins", "notes", "build", "notes"),
|
||||
"{{ NOTES_DOCKER_IMAGE }}",
|
||||
(),
|
||||
))
|
||||
tutor_hooks.Filters.IMAGES_PULL.add_item((
|
||||
"notes",
|
||||
"{{ NOTES_DOCKER_IMAGE }}",
|
||||
))
|
||||
tutor_hooks.Filters.IMAGES_PUSH.add_item((
|
||||
"notes",
|
||||
"{{ NOTES_DOCKER_IMAGE }}",
|
||||
))
|
||||
tutor_hooks.Filters.IMAGES_BUILD.add_item(
|
||||
(
|
||||
"notes",
|
||||
("plugins", "notes", "build", "notes"),
|
||||
"{{ NOTES_DOCKER_IMAGE }}",
|
||||
(),
|
||||
)
|
||||
)
|
||||
tutor_hooks.Filters.IMAGES_PULL.add_item(
|
||||
(
|
||||
"notes",
|
||||
"{{ NOTES_DOCKER_IMAGE }}",
|
||||
)
|
||||
)
|
||||
tutor_hooks.Filters.IMAGES_PUSH.add_item(
|
||||
(
|
||||
"notes",
|
||||
"{{ NOTES_DOCKER_IMAGE }}",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@tutor_hooks.Filters.COMPOSE_MOUNTS.add()
|
||||
def _mount_edx_notes_api(volumes, name):
|
||||
def _mount_edx_notes_api(
|
||||
volumes: list[tuple[str, str]], name: str
|
||||
) -> list[tuple[str, str]]:
|
||||
"""
|
||||
When mounting edx-notes-api with `--mount=/path/to/edx-notes-api`,
|
||||
bind-mount the host repo in the notes container.
|
||||
@ -80,10 +86,10 @@ def _mount_edx_notes_api(volumes, name):
|
||||
]
|
||||
return volumes
|
||||
|
||||
####### Boilerplate code
|
||||
|
||||
# Add the "templates" folder as a template root
|
||||
tutor_hooks.Filters.ENV_TEMPLATE_ROOTS.add_item(
|
||||
pkg_resources.resource_filename("tutornotes", "templates")
|
||||
str(importlib_resources.files("tutornotes") / "templates")
|
||||
)
|
||||
# Render the "build" and "apps" folders
|
||||
tutor_hooks.Filters.ENV_TEMPLATE_TARGETS.add_items(
|
||||
@ -93,36 +99,29 @@ tutor_hooks.Filters.ENV_TEMPLATE_TARGETS.add_items(
|
||||
],
|
||||
)
|
||||
# Load patches from files
|
||||
for path in glob(
|
||||
os.path.join(
|
||||
pkg_resources.resource_filename("tutornotes", "patches"),
|
||||
"*",
|
||||
)
|
||||
):
|
||||
for path in glob(str(importlib_resources.files("tutornotes") / "patches" / "*")):
|
||||
with open(path, encoding="utf-8") as patch_file:
|
||||
tutor_hooks.Filters.ENV_PATCHES.add_item(
|
||||
(os.path.basename(path), patch_file.read())
|
||||
)
|
||||
|
||||
# Add configuration entries
|
||||
tutor_hooks.Filters.CONFIG_DEFAULTS.add_items(
|
||||
[
|
||||
(f"NOTES_{key}", value)
|
||||
for key, value in config.get("defaults", {}).items()
|
||||
]
|
||||
[(f"NOTES_{key}", value) for key, value in config.get("defaults", {}).items()]
|
||||
)
|
||||
tutor_hooks.Filters.CONFIG_UNIQUE.add_items(
|
||||
[
|
||||
(f"NOTES_{key}", value)
|
||||
for key, value in config.get("unique", {}).items()
|
||||
]
|
||||
[(f"NOTES_{key}", value) for key, value in config.get("unique", {}).items()]
|
||||
)
|
||||
tutor_hooks.Filters.CONFIG_OVERRIDES.add_items(
|
||||
list(config.get("overrides", {}).items())
|
||||
)
|
||||
|
||||
|
||||
# Notes public hosts
|
||||
@tutor_hooks.Filters.APP_PUBLIC_HOSTS.add()
|
||||
def _notes_public_hosts(hosts: list[str], context_name: t.Literal["local", "dev"]) -> list[str]:
|
||||
def _notes_public_hosts(
|
||||
hosts: list[str], context_name: t.Literal["local", "dev"]
|
||||
) -> list[str]:
|
||||
if context_name == "dev":
|
||||
hosts += ["{{ NOTES_HOST }}:8120"]
|
||||
else:
|
||||
|
||||
@ -4,13 +4,14 @@ SECRET_KEY = "{{ NOTES_SECRET_KEY }}"
|
||||
ALLOWED_HOSTS = [
|
||||
"notes",
|
||||
"{{ NOTES_HOST }}",
|
||||
"{{ NOTES_HOST }}:8120",
|
||||
]
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.mysql",
|
||||
"HOST": "{{ MYSQL_HOST }}",
|
||||
"PORT": {{MYSQL_PORT}},
|
||||
"PORT": {{ MYSQL_PORT }},
|
||||
"NAME": "{{ NOTES_MYSQL_DATABASE }}",
|
||||
"USER": "{{ NOTES_MYSQL_USERNAME }}",
|
||||
"PASSWORD": "{{ NOTES_MYSQL_PASSWORD }}",
|
||||
@ -23,11 +24,12 @@ DATABASES = {
|
||||
CLIENT_ID = "notes"
|
||||
CLIENT_SECRET = "{{ NOTES_OAUTH2_SECRET }}"
|
||||
|
||||
ELASTICSEARCH_DSL = {
|
||||
'default': {
|
||||
'hosts': '{{ ELASTICSEARCH_SCHEME }}://{{ ELASTICSEARCH_HOST }}:{{ ELASTICSEARCH_PORT }}'
|
||||
}
|
||||
}
|
||||
# Meilisearch credentials
|
||||
ES_DISABLED = True
|
||||
MEILISEARCH_ENABLED = True
|
||||
MEILISEARCH_URL = "{{ MEILISEARCH_URL }}"
|
||||
MEILISEARCH_API_KEY = "{{ MEILISEARCH_API_KEY }}"
|
||||
MEILISEARCH_INDEX = "{{ MEILISEARCH_INDEX_PREFIX }}student_notes"
|
||||
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
|
||||
@ -1,16 +1,27 @@
|
||||
{% if is_buildkit_enabled() %}# syntax=docker/dockerfile:1.4{% endif %}
|
||||
FROM docker.io/ubuntu:20.04
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM docker.io/ubuntu:24.04
|
||||
|
||||
RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked{% endif %} \
|
||||
apt update && \
|
||||
apt upgrade -y && \
|
||||
# python 3.8
|
||||
apt install -y language-pack-en git python3 python3-pip python3-venv libmysqlclient-dev
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Delete default UID=1000 `ubuntu` user to ensure we can use id 1000 for app user
|
||||
RUN userdel -r ubuntu
|
||||
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt update && \
|
||||
apt upgrade -y && \
|
||||
apt install -y \
|
||||
language-pack-en \
|
||||
git \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-venv \
|
||||
libmysqlclient-dev \
|
||||
pkg-config
|
||||
RUN ln -s /usr/bin/python3 /usr/bin/python
|
||||
|
||||
###### Git-clone Notes repo ######
|
||||
ARG APP_USER_ID=1000
|
||||
ARG APP_USER_ID={{ HOST_USER_ID }}
|
||||
RUN useradd --home-dir /app --create-home --shell /bin/bash --uid ${APP_USER_ID} app
|
||||
USER ${APP_USER_ID}
|
||||
|
||||
@ -19,12 +30,17 @@ WORKDIR /app/edx-notes-api
|
||||
|
||||
###### Install python venv ######
|
||||
RUN python -m venv /app/venv
|
||||
ENV PATH /app/venv/bin:${PATH}
|
||||
ENV PATH=/app/venv/bin:${PATH}
|
||||
# https://pypi.org/project/setuptools/
|
||||
# https://pypi.org/project/pip/
|
||||
# https://pypi.org/project/wheel/
|
||||
RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/app/.cache/pip,sharing=shared {% endif %}pip install setuptools==67.8.0 pip==23.1.2 wheel==0.40.0
|
||||
RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/app/.cache/pip,sharing=shared {% endif %}pip install -r requirements/base.txt
|
||||
RUN --mount=type=cache,target=/app/.cache/pip,sharing=shared pip install setuptools==78.1.0 pip==25.0.1 wheel==0.46.0
|
||||
RUN --mount=type=cache,target=/app/.cache/pip,sharing=shared pip install -r requirements/base.txt
|
||||
|
||||
EXPOSE 8000
|
||||
CMD gunicorn --workers=2 --name notes --bind=0.0.0.0:8000 --max-requests=1000 notesserver.wsgi:application
|
||||
CMD ["gunicorn", \
|
||||
"--workers=2", \
|
||||
"--name", "notes", \
|
||||
"--bind=0.0.0.0:8000", \
|
||||
"--max-requests=1000", \
|
||||
"notesserver.wsgi:application"]
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
./manage.py migrate
|
||||
./manage.py search_index --rebuild -f
|
||||
|
||||
# Re-index with meilisearch
|
||||
./manage.py shell -c "from notesapi.v1.views.meilisearch import reindex; reindex()"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user