Compare commits

..

55 Commits

Author SHA1 Message Date
Florian du Garage Num
ab18396e89 remove hard-coded uid 1000
Some checks failed
Sync with private repo / sync (push) Has been cancelled
Run tests / tests (3.12) (push) Has been cancelled
Run tests / tests (3.9) (push) Has been cancelled
2025-09-30 21:47:30 +02:00
Syed Muhammad Dawoud Sheraz Ali
ae4e3f20ac
feat: migrate to ruff for linting and formatting checks (#50) 2025-09-24 10:30:18 +05:00
Ahmed Khalid
4fde7e355b
Merge pull request #49 from overhangio/teak 2025-06-27 17:04:20 +05:00
Syed Muhammad Dawoud Sheraz Ali
1ff9c0bd77 chore: generate changelog for v20 2025-06-05 17:50:09 +05:00
jfavellar90
3fe46bc278 feat: upgrade to teak 2025-04-04 12:44:52 -05:00
Syed Muhammad Dawoud Sheraz Ali
cde10c2f97
v19.0.2 (#48) 2025-03-12 15:17:38 +05:00
Syed Muhammad Dawoud Sheraz Ali
97aed60b38
build: Add hatch_build in sdist to fix installation issues (#47)
* build: Add hatch_build in sdist to fix installation issues
2025-03-12 15:13:12 +05:00
jfavellar90
1465402bfa v19.0.1 2025-03-11 13:14:03 -05:00
Jhony Avella
8540aef9b8
feat: migrate from setup.py to pyproject.toml (#46)
* feat: migrate from setup.py to pyproject.toml

* chore: fixes

* chore: addressing PR comments

* chore: addressing more comments
2025-03-11 13:09:00 -05:00
Régis Behmo
9d91f7499d
fix: broken feature in dev mode (#43)
Student notes were simply not working in dev mode because the dev server
hostname was not whitelisted in ALLOWED_HOSTS.
2025-02-13 20:34:56 -05:00
Syed Muhammad Dawoud Sheraz Ali
3f0ff01105
build: re-add auto-add for PRs with a different target (#45) 2025-01-17 11:31:04 +05:00
Régis Behmo
e61f3cea5f
feat: Upgrade to Sumac 2024-12-16 21:58:16 +01:00
Syed Muhammad Dawoud Sheraz Ali
0267ffde12 chore: update changelog 2024-12-09 18:52:20 +05:00
Régis Behmo
6e8bc34475 feat: migrate to Meilisearch
We make use of a new search engine to search annotations. The index will
automatically be created and filled during init. This is considered a
breaking change if you have customised your notes index.
2024-11-29 22:28:03 +05:00
Régis Behmo
a61e09c11e fix: actually mount notes directory
Notes directory could be added via `tutor mounts add ./edx-notes-api`,
but it was not actually being mounted.
2024-11-29 22:28:03 +05:00
jfavellar90
e5fedc2d83 feat: upgrade to sumac 2024-11-29 22:28:01 +05:00
Régis Behmo
e52064fe64 Merge branch 'release' 2024-11-27 18:35:01 +01:00
Syed Muhammad Dawoud Sheraz Ali
75e64f5065 feat!: Rename branches master->release, nightly->main 2024-11-27 22:34:13 +05:00
Overhang.IO
7d16414908 Merge remote-tracking branch 'origin/master' into nightly 2024-11-14 16:25:16 +00:00
Syed Muhammad Dawoud Sheraz Ali
5515eda18b
chore: remove python 3.8 references and set py39 as minimum version (#42) 2024-11-14 21:19:20 +05:00
Jhony Avella
fdf73b62e3
Ubuntu 24.04 Upgrade (#39)
* chore: notes service now uses ubuntu 24.04 as base image

* chore: using 1000 UID. Updating setuptools

* chore: adding changelog entry
2024-10-22 16:07:32 -05:00
Régis Behmo
f9fcbf26f4 docs: *.local.edly.io -> *.local.openedx.io
The default URL to run a local platform switched from local.edly.io to
local.openedx.io. This changes makes it clearer for everyone that Tutor
is to run Open edX.

See: https://github.com/overhangio/tutor/issues/1120
2024-10-17 08:36:40 +02:00
Régis Behmo
dbf48674f9 ci: upgrade vendor actions 2024-10-03 11:16:24 +02:00
Régis Behmo
28113792f3 docs: fix author domain name 2024-10-01 09:08:48 +02:00
Régis Behmo
7801778112 build: fix readme content type warning 2024-07-23 10:37:35 +02:00
Régis Behmo
9671824e1f fix: docker build deprecation warnings
With the latest Docker upgrade, we got the following warnings during
build:

	FromAsCasing: 'as' and 'FROM' keywords' casing do not match
	LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format
2024-06-21 17:12:57 +02:00
Régis Behmo
06fd645d44
Merge pull request #37 from overhangio/redwood
* feat: adding python 3.12 support (#36)

* feat: adding first version of Dockerfile Python3.12 compatible

* ci: add python 3.12 checks

* feat: upgrade to redwood
2024-06-20 03:12:10 +02:00
jfavellar90
6d3685a573 feat: upgrade to redwood 2024-06-20 01:13:57 +02:00
Jhony Avella
20ec2c8b99
feat: adding python 3.12 support (#36)
* feat: adding first version of Dockerfile Python3.12 compatible

* ci: add python 3.12 checks
2024-04-29 11:28:19 -05:00
Régis Behmo
f68719de86 ci: don't even try to auto-add PRs to github project
Auto-adding PRs to the Github project is not working because the
github-token is not available there.
2024-03-05 12:03:03 +05:00
Régis Behmo
8b1c93d900 ci: remove now useless OPENEDX_RELEASE variable 2024-02-20 15:15:40 +01:00
Régis Behmo
c5bd0acab1 fix: remove pkg_resources for compatibility with python 3.12
pkg_resources is a package that is unavailable in python 3.12, unless
setuptools is explicitely installed. Turns out, there are replacement
functions coming from importlib_resources, which can be obtained from
the importlib-resources pypi package. This package will be installed
with tutor starting from 17.0.2.
2024-02-12 11:57:51 +01:00
Régis Behmo
795ea5966e ci: auto-add issues and items to github project 2024-01-12 12:33:35 +01:00
jfavellar90
0d0128210c feat: upgrade to Quince 2023-12-11 18:12:10 +01:00
Régis Behmo
0751918e6a local.overhang.io -> local.edly.io
This is related to https://github.com/overhangio/tutor/issues/945
2023-12-09 15:54:28 +01:00
Overhang.IO
74c85b1edd Merge remote-tracking branch 'origin/master' into nightly 2023-12-08 18:37:47 +00:00
Emad Rad
58f8abc339
fix: dev dependency 2023-12-08 19:32:56 +01:00
Overhang.IO
2d32da1245 Merge remote-tracking branch 'origin/master' into nightly 2023-12-06 15:17:43 +00:00
Régis Behmo
1c349e00c2 chore: format 2023-12-06 16:13:29 +01:00
Régis Behmo
305e008ea0 Merge branch 'master' into nightly 2023-12-05 12:10:56 +01:00
Régis Behmo
98a00ecb58 docs: docs.tutor.overhang.io -> docs.tutor.edly.io
See: https://github.com/overhangio/tutor/issues/945
2023-12-05 11:45:48 +01:00
Emad Rad
727d500bf5 Feat: Testing and Linting (#31)
* ci: test action added

* chore: changelog entry added

* feat: Makefile added

* fix: typing added

* chore: cleanup with isort and black
2023-11-24 08:25:04 +01:00
Régis Behmo
f88afe05c3 feat: simplify nightly version management
By pulling the version suffix from tutor, we avoid git conflicts when
merging the release branch in nightly.
2023-11-24 08:25:02 +01:00
Emad Rad
d4a4274bc4
Feat: Testing and Linting (#31)
* ci: test action added

* chore: changelog entry added

* feat: Makefile added

* fix: typing added

* chore: cleanup with isort and black
2023-11-23 18:05:41 -05:00
Régis Behmo
cb08b63217
fix: add missing pkg-config package (#30)
Build fails in nightly with the following error:

	#27 4.029   × Getting requirements to build wheel did not run
	    successfully.
	#27 4.029   │ exit code: 1
	#27 4.029   ╰─> [24 lines of output]
	#27 4.029       /bin/sh: 1: pkg-config: not found
	#27 4.029       /bin/sh: 1: pkg-config: not found
	#27 4.029       Trying pkg-config --exists mysqlclient
	#27 4.029       Command 'pkg-config --exists mysqlclient' returned
	    non-zero exit status 127.
	#27 4.029       Trying pkg-config --exists mariadb
	#27 4.029       Command 'pkg-config --exists mariadb' returned non-zero
	    exit status 127.
	#27 4.029       Traceback (most recent call last):
	#27 4.029         File
	    "/app/venv/lib/python3.8/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py",
	line 353, in <module>
	#27 4.029           main()
	#27 4.029         File
	    "/app/venv/lib/python3.8/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py",
	line 335, in main
	#27 4.029           json_out['return_val'] =
	    hook(**hook_input['kwargs'])
	#27 4.029         File
	    "/app/venv/lib/python3.8/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py",
	line 118, in get_requires_for_build_wheel
	#27 4.029           return hook(config_settings)
	#27 4.029         File
	    "/tmp/pip-build-env-td0z_pds/overlay/lib/python3.8/site-packages/setuptools/build_meta.py",
	line 355, in get_requires_for_build_wheel
	#27 4.029           return self._get_build_requires(config_settings,
	    requirements=['wheel'])
	#27 4.029         File
	    "/tmp/pip-build-env-td0z_pds/overlay/lib/python3.8/site-packages/setuptools/build_meta.py",
	line 325, in _get_build_requires
	#27 4.029           self.run_setup()
	#27 4.029         File
	    "/tmp/pip-build-env-td0z_pds/overlay/lib/python3.8/site-packages/setuptools/build_meta.py",
	line 341, in run_setup
	#27 4.029           exec(code, locals())
	#27 4.029         File "<string>", line 154, in <module>
	#27 4.029         File "<string>", line 48, in get_config_posix
	#27 4.029         File "<string>", line 27, in find_package_name
	#27 4.029       Exception: Can not find valid pkg-config name.
	#27 4.029       Specify MYSQLCLIENT_CFLAGS and MYSQLCLIENT_LDFLAGS env
	    vars manually
2023-11-21 06:40:11 -05:00
Régis Behmo
16012432a1 feat: simplify nightly version management
By pulling the version suffix from tutor, we avoid git conflicts when
merging the release branch in nightly.
2023-11-20 17:39:47 +01:00
Overhang.IO
0768eafd7e Merge remote-tracking branch 'origin/master' into nightly 2023-11-15 00:23:49 +00:00
Overhang.IO
8c4f872756 Merge remote-tracking branch 'origin/master' into nightly 2023-10-03 06:34:28 +00:00
Overhang.IO
3ca1417597 Merge remote-tracking branch 'origin/master' into nightly 2023-09-07 16:50:48 +00:00
Overhang.IO
2b78e58e8a Merge remote-tracking branch 'origin/master' into nightly 2023-08-28 09:52:26 +00:00
Régis Behmo
f8c28346a5 Merge branch 'master' into nightly 2023-08-09 10:35:26 +02:00
Overhang.IO
0093976541 Merge remote-tracking branch 'origin/master' into nightly 2023-07-31 13:39:25 +00:00
Régis Behmo
581f986729 Merge branch 'master' into nightly 2023-06-15 01:09:31 +02:00
Régis Behmo
a7ad3758b5 fix: nightly package version
The package version number may not include the "-nightly" suffix.
Otherwise, installation fails with:

   setuptools.extern.packaging.version.InvalidVersion: Invalid version: '15.0.7-nightly'
2023-05-26 18:47:48 +02:00
Régis Behmo
5d6580c82b feat: label nightly version
This is to address https://github.com/overhangio/tutor-mfe/issues/122
As a consequence of this change, images will be tagged with a "-nightly"
suffix. Next, we'll probably have to build them periodically in CI.
2023-05-26 18:26:28 +02:00
23 changed files with 366 additions and 151 deletions

View 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 }}

View File

@ -2,13 +2,13 @@ name: Sync with private repo
on: on:
push: push:
branches: [ master, main, nightly ] branches: [ release, main ]
jobs: jobs:
sync: sync:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Add remote - name: Add remote

25
.github/workflows/test.yml vendored Normal file
View 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

View File

@ -2,7 +2,6 @@ variables:
TUTOR_PLUGIN: notes TUTOR_PLUGIN: notes
TUTOR_IMAGES: notes TUTOR_IMAGES: notes
TUTOR_PYPI_PACKAGE: tutor-notes TUTOR_PYPI_PACKAGE: tutor-notes
OPENEDX_RELEASE: palm
GITHUB_REPO: overhangio/tutor-notes GITHUB_REPO: overhangio/tutor-notes
include: include:

21
.hatch_build.py Normal file
View 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

View File

@ -19,3 +19,55 @@ instructions, because git commits are used to generate release notes:
<!-- scriv-insert-here --> <!-- 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)

View File

@ -1,2 +0,0 @@
recursive-include tutornotes/patches *
recursive-include tutornotes/templates *

46
Makefile Normal file
View 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}'

View File

@ -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 :alt: Notes in action
Installation 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. 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". 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 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 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>`_.

View File

@ -1 +0,0 @@
- [Improvement] Add a scriv-compliant changelog. (by @regisb)

View File

@ -1 +0,0 @@
- [Improvement] Removing the notes permissions container in favor of a global single permissions container. (by @jfavellar90)

View File

@ -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)

View File

@ -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] [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/

View File

@ -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",
],
)

View File

@ -1,8 +1 @@
__version__ = "16.0.2" __version__ = "20.0.0"
__package_version__ = __version__
# Handle version suffix for nightly, just like tutor core.
__version_suffix__ = ""
if __version_suffix__:
__version__ += "-" + __version_suffix__

View File

@ -15,8 +15,8 @@ spec:
app.kubernetes.io/name: notes app.kubernetes.io/name: notes
spec: spec:
securityContext: securityContext:
runAsUser: 1000 runAsUser: {{ APP_USER_ID }}
runAsGroup: 1000 runAsGroup: {{ APP_USER_ID }}
containers: containers:
- name: notes - name: notes
image: {{ NOTES_DOCKER_IMAGE }} image: {{ NOTES_DOCKER_IMAGE }}

View File

@ -4,4 +4,7 @@ notes-job:
DJANGO_SETTINGS_MODULE: notesserver.settings.tutor DJANGO_SETTINGS_MODULE: notesserver.settings.tutor
volumes: volumes:
- ../plugins/notes/apps/settings/tutor.py:/app/edx-notes-api/notesserver/settings/tutor.py:ro - ../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 }} depends_on: {{ [("mysql", RUN_MYSQL)]|list_if }}

View File

@ -1 +1 @@
setowner 1000 /mounts/notes setowner {{ APP_USER_ID }} /mounts/notes

View File

@ -6,5 +6,8 @@ notes:
volumes: volumes:
- ../plugins/notes/apps/settings/tutor.py:/app/edx-notes-api/notesserver/settings/tutor.py:ro - ../plugins/notes/apps/settings/tutor.py:/app/edx-notes-api/notesserver/settings/tutor.py:ro
- ../../data/notes:/app/data - ../../data/notes:/app/data
{%- for mount in iter_mounts(MOUNTS, "notes") %}
- {{ mount }}
{%- endfor %}
restart: unless-stopped restart: unless-stopped
depends_on: {{ [("mysql", RUN_MYSQL)]|list_if }} depends_on: {{ [("mysql", RUN_MYSQL)]|list_if }}

View File

@ -1,73 +1,79 @@
from __future__ import annotations from __future__ import annotations
from glob import glob
import os import os
import typing as t import typing as t
from glob import glob
import pkg_resources import importlib_resources
from tutor import hooks as tutor_hooks from tutor import hooks as tutor_hooks
from tutor.__about__ import __version_suffix__
from .__about__ import __version__ from .__about__ import __version__
# Handle version suffix in main mode, just like tutor core
if __version_suffix__:
__version__ += "-" + __version_suffix__
config = { config = {
"unique": {
"MYSQL_PASSWORD": "{{ 8|random_string }}",
"SECRET_KEY": "{{ 24|random_string }}",
"OAUTH2_SECRET": "{{ 24|random_string }}",
},
"defaults": { "defaults": {
"VERSION": __version__, "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 }}", "HOST": "notes.{{ LMS_HOST }}",
"MYSQL_DATABASE": "notes", "MYSQL_DATABASE": "notes",
"MYSQL_USERNAME": "notes", "MYSQL_USERNAME": "notes",
"REPOSITORY": "https://github.com/openedx/edx-notes-api", "REPOSITORY": "https://github.com/openedx/edx-notes-api",
"REPOSITORY_VERSION": "{{ OPENEDX_COMMON_VERSION }}", "REPOSITORY_VERSION": "{{ OPENEDX_COMMON_VERSION }}",
}, },
"unique": {
"MYSQL_PASSWORD": "{{ 8|random_string }}",
"SECRET_KEY": "{{ 24|random_string }}",
"OAUTH2_SECRET": "{{ 24|random_string }}",
},
} }
# Initialization hooks # For each service, we load the task template
# 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
# and add it to the CLI_DO_INIT_TASKS filter, which tells Tutor to # and add it to the CLI_DO_INIT_TASKS filter, which tells Tutor to
# run it as part of the `init` job. # run it as part of the `init` job.
for service, template_path in MY_INIT_TASKS: for service in ["mysql", "lms", "notes"]:
full_path: str = pkg_resources.resource_filename( full_path: str = str(
"tutornotes", os.path.join("templates", *template_path) importlib_resources.files("tutornotes")
/ "templates"
/ "notes"
/ "tasks"
/ service
/ "init"
) )
with open(full_path, encoding="utf-8") as init_task_file: with open(full_path, encoding="utf-8") as init_task_file:
init_task: str = init_task_file.read() init_task: str = init_task_file.read()
tutor_hooks.Filters.CLI_DO_INIT_TASKS.add_item((service, init_task)) tutor_hooks.Filters.CLI_DO_INIT_TASKS.add_item((service, init_task))
# Image management # Image management
tutor_hooks.Filters.IMAGES_BUILD.add_item(( tutor_hooks.Filters.IMAGES_BUILD.add_item(
"notes", (
("plugins", "notes", "build", "notes"), "notes",
"{{ NOTES_DOCKER_IMAGE }}", ("plugins", "notes", "build", "notes"),
(), "{{ NOTES_DOCKER_IMAGE }}",
)) (),
tutor_hooks.Filters.IMAGES_PULL.add_item(( )
"notes", )
"{{ NOTES_DOCKER_IMAGE }}", tutor_hooks.Filters.IMAGES_PULL.add_item(
)) (
tutor_hooks.Filters.IMAGES_PUSH.add_item(( "notes",
"notes", "{{ NOTES_DOCKER_IMAGE }}",
"{{ NOTES_DOCKER_IMAGE }}", )
)) )
tutor_hooks.Filters.IMAGES_PUSH.add_item(
(
"notes",
"{{ NOTES_DOCKER_IMAGE }}",
)
)
@tutor_hooks.Filters.COMPOSE_MOUNTS.add() @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`, When mounting edx-notes-api with `--mount=/path/to/edx-notes-api`,
bind-mount the host repo in the notes container. bind-mount the host repo in the notes container.
@ -80,10 +86,10 @@ def _mount_edx_notes_api(volumes, name):
] ]
return volumes return volumes
####### Boilerplate code
# Add the "templates" folder as a template root # Add the "templates" folder as a template root
tutor_hooks.Filters.ENV_TEMPLATE_ROOTS.add_item( 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 # Render the "build" and "apps" folders
tutor_hooks.Filters.ENV_TEMPLATE_TARGETS.add_items( tutor_hooks.Filters.ENV_TEMPLATE_TARGETS.add_items(
@ -93,36 +99,29 @@ tutor_hooks.Filters.ENV_TEMPLATE_TARGETS.add_items(
], ],
) )
# Load patches from files # Load patches from files
for path in glob( for path in glob(str(importlib_resources.files("tutornotes") / "patches" / "*")):
os.path.join(
pkg_resources.resource_filename("tutornotes", "patches"),
"*",
)
):
with open(path, encoding="utf-8") as patch_file: with open(path, encoding="utf-8") as patch_file:
tutor_hooks.Filters.ENV_PATCHES.add_item( tutor_hooks.Filters.ENV_PATCHES.add_item(
(os.path.basename(path), patch_file.read()) (os.path.basename(path), patch_file.read())
) )
# Add configuration entries # Add configuration entries
tutor_hooks.Filters.CONFIG_DEFAULTS.add_items( 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( 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( tutor_hooks.Filters.CONFIG_OVERRIDES.add_items(
list(config.get("overrides", {}).items()) list(config.get("overrides", {}).items())
) )
# Notes public hosts # Notes public hosts
@tutor_hooks.Filters.APP_PUBLIC_HOSTS.add() @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": if context_name == "dev":
hosts += ["{{ NOTES_HOST }}:8120"] hosts += ["{{ NOTES_HOST }}:8120"]
else: else:

View File

@ -4,13 +4,14 @@ SECRET_KEY = "{{ NOTES_SECRET_KEY }}"
ALLOWED_HOSTS = [ ALLOWED_HOSTS = [
"notes", "notes",
"{{ NOTES_HOST }}", "{{ NOTES_HOST }}",
"{{ NOTES_HOST }}:8120",
] ]
DATABASES = { DATABASES = {
"default": { "default": {
"ENGINE": "django.db.backends.mysql", "ENGINE": "django.db.backends.mysql",
"HOST": "{{ MYSQL_HOST }}", "HOST": "{{ MYSQL_HOST }}",
"PORT": {{MYSQL_PORT}}, "PORT": {{ MYSQL_PORT }},
"NAME": "{{ NOTES_MYSQL_DATABASE }}", "NAME": "{{ NOTES_MYSQL_DATABASE }}",
"USER": "{{ NOTES_MYSQL_USERNAME }}", "USER": "{{ NOTES_MYSQL_USERNAME }}",
"PASSWORD": "{{ NOTES_MYSQL_PASSWORD }}", "PASSWORD": "{{ NOTES_MYSQL_PASSWORD }}",
@ -23,11 +24,12 @@ DATABASES = {
CLIENT_ID = "notes" CLIENT_ID = "notes"
CLIENT_SECRET = "{{ NOTES_OAUTH2_SECRET }}" CLIENT_SECRET = "{{ NOTES_OAUTH2_SECRET }}"
ELASTICSEARCH_DSL = { # Meilisearch credentials
'default': { ES_DISABLED = True
'hosts': '{{ ELASTICSEARCH_SCHEME }}://{{ ELASTICSEARCH_HOST }}:{{ ELASTICSEARCH_PORT }}' MEILISEARCH_ENABLED = True
} MEILISEARCH_URL = "{{ MEILISEARCH_URL }}"
} MEILISEARCH_API_KEY = "{{ MEILISEARCH_API_KEY }}"
MEILISEARCH_INDEX = "{{ MEILISEARCH_INDEX_PREFIX }}student_notes"
LOGGING = { LOGGING = {
"version": 1, "version": 1,

View File

@ -1,16 +1,27 @@
{% if is_buildkit_enabled() %}# syntax=docker/dockerfile:1.4{% endif %} # syntax=docker/dockerfile:1
FROM docker.io/ubuntu:20.04 FROM docker.io/ubuntu:24.04
RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/var/cache/apt,sharing=locked \ ENV DEBIAN_FRONTEND=noninteractive
--mount=type=cache,target=/var/lib/apt,sharing=locked{% endif %} \
apt update && \ # Delete default UID=1000 `ubuntu` user to ensure we can use id 1000 for app user
apt upgrade -y && \ RUN userdel -r ubuntu
# python 3.8
apt install -y language-pack-en git python3 python3-pip python3-venv libmysqlclient-dev 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 RUN ln -s /usr/bin/python3 /usr/bin/python
###### Git-clone Notes repo ###### ###### 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 RUN useradd --home-dir /app --create-home --shell /bin/bash --uid ${APP_USER_ID} app
USER ${APP_USER_ID} USER ${APP_USER_ID}
@ -19,12 +30,17 @@ WORKDIR /app/edx-notes-api
###### Install python venv ###### ###### Install python venv ######
RUN python -m venv /app/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/setuptools/
# https://pypi.org/project/pip/ # https://pypi.org/project/pip/
# https://pypi.org/project/wheel/ # 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 --mount=type=cache,target=/app/.cache/pip,sharing=shared pip install setuptools==78.1.0 pip==25.0.1 wheel==0.46.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 -r requirements/base.txt
EXPOSE 8000 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"]

View File

@ -1,2 +1,4 @@
./manage.py migrate ./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()"