Compare commits

...

11 Commits

Author SHA1 Message Date
Florian du Garage Num
fa053ac7ae remove hard-coded uid 1000
Some checks failed
Run tests / tests (3.9) (push) Has been cancelled
Sync with private repo / sync (push) Has been cancelled
Run tests / tests (3.12) (push) Has been cancelled
2025-09-30 21:46:06 +02:00
Muhammad Labeeb
18d1825de7
feat: migrate from pylint/black to ruff (#104)
* feat: migrate from pylint/black to ruff

* test: verify python package distribution build when running make test
2025-08-28 18:59:56 +05:00
Ahmed Khalid
c6a0d16a76
Merge pull request #102 from overhangio/teak 2025-06-27 15:57:02 +05:00
Muhammad Labeeb
944b432ca4 v20.0.0 2025-06-05 18:10:15 +05:00
Danyal Faheem
7a31ce81fd
chore: replace site-configuration script with management command (#101)
* chore: replace site-configuration script with management command
The site-configuration script was used to set the value of the COURSE_CATALOG_API_URL
However, this script is being removed in tutor core as it is no longer required
For this reason, we migrate to the provided create_or_update_site_configuration management command in edx-platform
2025-04-22 15:23:18 +05:00
Syed Muhammad Dawoud Sheraz Ali
b189574e03
build: Add hatch_build in sdist to fix installation issues (#100) 2025-03-12 16:14:02 +05:00
Muhammad Faraz Maqsood
5c4daa9318
feat: migrate from setup.py/setuptools to pyproject.toml/hatch (#99)
* feat: migrate to pyproject.toml and hatch

* migrate from setup.py/setuptools to pyproject.toml/hatch.

* add optional dependencies

* fix license and author

* update maintainer name

---------

Co-authored-by: Muhammad Faraz  Maqsood <faraz.maqsood@192.168.10.35>
Co-authored-by: Muhammad Labeeb <mlabeeb03@gmail.com>
2025-03-02 14:14:48 +05:00
Muhammad Labeeb
4386c85adf docs: readme update
- Explicitly state that in order to use SSO with existing LMS admin users, the newly created superuser in discovery must have the same username and email as the LMS user.
2025-01-22 14:44:52 +05:00
Muhammad Faraz Maqsood
d34cc5dc75 docs: add changelog entry 2025-01-22 13:05:26 +05:00
Muhammad Faraz Maqsood
796c0497ec feat: add env variable to enable/disable programs
This commit includes:
- This aligns with the frontend, which now also utilizes this environment variable. To view the frontend related changes, click here: https://github.com/openedx/frontend-app-learner-dashboard/pull/506/files.
- Additionally, it automates the enabling of programs in the "programapiconfig" model on the LMS admin panel through init tasks.
- Update the documentation accordingly.
2025-01-22 13:05:26 +05:00
Syed Muhammad Dawoud Sheraz Ali
6ca50caa5a
build: re-add auto-add for PRs with a different target (#96) 2025-01-21 16:45:48 +05:00
20 changed files with 201 additions and 94 deletions

View File

@ -4,6 +4,9 @@ on:
issues:
types:
- opened
pull_request_target:
types:
- opened
jobs:
# https://github.com/actions/add-to-project

View File

@ -18,8 +18,6 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Upgrade pip
run: python -m pip install --upgrade pip setuptools
- name: Install dependencies
run: |
pip install .[dev]

22
.hatch_build.py Normal file
View File

@ -0,0 +1,22 @@
# 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, "tutordiscovery", "__about__.py"), "rt", encoding="utf-8"
) as f:
exec(f.read(), about)
return about

View File

@ -19,6 +19,24 @@ 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)
- [Bugfix] Add support to consume events from event bus in discovery. Explanation can be viewed here: https://github.com/openedx/event-bus-redis/blob/main/docs/tutor_installation.rst. (by @Faraz32123)
- [Feature] Introduced a new environment variable to enable or disable programs. (by @Faraz32123)
- This aligns with the frontend, which now also utilizes this environment variable. To view the frontend related changes, click here: https://github.com/openedx/frontend-app-learner-dashboard/pull/506/files.
- Additionally, it automates the enabling of programs in the "programapiconfig" model on the LMS admin panel through init tasks.
- [Improvement] Migrate packaging from setup.py/setuptools to pyproject.toml/hatch. (by @Faraz32123)
- For more details view tutor core PR: https://github.com/overhangio/tutor/pull/1163
- [Improvement] Add hatch_build.py in sdist target to fix the installation issues (by @dawoudsheraz)
- [Improvement] Replace site-configuration script with create_or_update_site_configuration management command in the init task. (by @Danyal-Faheem)
- 💥[Feature] Upgrade to Teak. (by @mlabeeb03)
<a id='changelog-19.0.0'></a>
## v19.0.0 (2024-10-23)

View File

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

View File

@ -1,16 +1,15 @@
.DEFAULT_GOAL := help
.PHONY: docs
SRC_DIRS = ./tutordiscovery ./tests
BLACK_OPTS = --exclude templates ${SRC_DIRS}
# Warning: These checks are run on every PR.
test: test-lint test-types test-format test-unit # Run some static checks.
test: test-lint test-types test-format test-unit test-pythonpackage # Run some static checks.
test-format: ## Run code formatting tests.
black --check --diff $(BLACK_OPTS)
ruff format --check --diff ${SRC_DIRS}
test-lint: ## Run code linting tests
pylint --errors-only --enable=unused-import,unused-argument --ignore=templates --ignore=docs/_ext ${SRC_DIRS}
ruff check ${SRC_DIRS}
test-types: ## Run type checks.
mypy --exclude=templates --ignore-missing-imports --implicit-reexport --strict ${SRC_DIRS}
@ -18,11 +17,17 @@ test-types: ## Run type checks.
test-unit: ## Run unit tests
python -m unittest discover tests
format: ## Format code automatically.
black $(BLACK_OPTS)
build-pythonpackage: ## Build the "tutor-discovery" python package for upload to pypi
python -m build --sdist
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}
test-pythonpackage: build-pythonpackage ## Test that package can be uploaded to pypi
twine check dist/tutor_discovery-$(shell make version).tar.gz
format: ## Format code automatically.
ruff format ${SRC_DIRS}
fix-lint: ## Fix lint errors automatically
ruff check --fix ${SRC_DIRS}
changelog-entry: ## Create a new changelog entry.
scriv create
@ -30,6 +35,9 @@ changelog-entry: ## Create a new changelog entry.
changelog: ## Collect changelog entries in the CHANGELOG.md file.
scriv collect
version: ## Print the current tutor-discovery version
@python -c 'import io, os; about = {}; exec(io.open(os.path.join("tutordiscovery", "__about__.py"), "rt", encoding="utf-8").read(), about); print(about["__version__"])'
ESCAPE = 
help: ## Print this help.
@grep -E '^([a-zA-Z_-]+:.*?## .*|######* .+)$$' Makefile \

View File

@ -48,9 +48,13 @@ commands from the UI, a user must be created:
Then, you must log in with this user at http://discovery.local.openedx.io/admin.
Alternatively, you can log in with oauth2 using a pre-existing user created on the LMS/CMS by accessing
http(s)://discovery.<your lms host>/login. To do so, the proper domain names must exist and point to
the production server.
Using SSO with LMS
~~~~~~~~~~~~~~~~~~
If you want to log in using Single Sign-On (SSO) with the LMS, ensure that the superuser you created
above in discovery has the same username and email as an existing admin user in the LMS/CMS. You can
then access the discovery interface via `http(s)://discovery.<your lms host>/login`. Make sure that
the proper domain names are configured and point to the production server.
Index configuration
~~~~~~~~~~~~~~~~~~~
@ -121,19 +125,30 @@ This last step should be performed every time you create new or make changes to
Show Programs Tab
~~~~~~~~~~~~~~~~~
To make the ``Programs`` tab work in the LMS dashboard, users will need to manually create an entry
in the ``Programs api config`` model in the LMS Admin Panel. Go to http://local.openedx.io/admin/programs/programsapiconfig/.
Add ``Marketing path`` equal to ``/programs`` and enable it. Then Programs tab will be shown on the LMS
where users can view their registered programs. It will show like in the below picture.
By default, the **Programs** tab is available in the LMS dashboard. Users can enable or disable this tab as needed.
To Disable Programs, run the following command:
.. code-block:: bash
tutor config save --set ENABLE_PROGRAMS=False
To Enable Programs, run the following command:
.. code-block:: bash
tutor config save --set ENABLE_PROGRAMS=True
Only programs in which learners are registered will appear on this page. If a learner is enrolled in any course that is part of a program, that program will be displayed here.
.. image:: https://github.com/overhangio/tutor-discovery/assets/122095701/e0224011-adc0-41e4-a104-af4cb0c24b82
:alt: Programs Tab on LMS dashboard
In the above image, the user can see explore programs button which is pointing to ``http://localhost:8080/programs`` by default.
This link does not exist. So, users can change this link to their custom-built marketing site URL to show all programs there.
This can be done by modifying the ``Site Configurations`` model in the LMS Admin Panel. Go to
http://local.openedx.io/admin/site_configuration/siteconfiguration/. Open the respective LMS site configuration and add the below
dictionary in ``site values`` field like the below image:
In the image above, the **Explore Programs** button points to http://localhost:8080/programs by default. This link does not exist, so users can change it to their custom-built marketing site URL to display all programs.
To Modify the Link:
1. Go to the **Site Configurations** model in the LMS Admin Panel: `http://local.openedx.io/admin/site_configuration/siteconfiguration/`
2. Open the respective LMS site configuration.
3. Add the following dictionary in the **site values** field like in the below image:
.. code-block:: python
@ -144,6 +159,11 @@ dictionary in ``site values`` field like the below image:
.. image:: https://github.com/overhangio/tutor-discovery/assets/122095701/2d588ea9-a830-40b6-9845-8fab56d7cb5a
:alt: Add Custom Site for Explore Programs
By following above instructions, this link (https://custom-marketing-site-here.com) will be replaced by http://localhost:8080. Additionally, users can also replace "/programs" by following these below steps:
1. Go to: `http://local.openedx.io/admin/programs/programsapiconfig/`
2. Add **Marketing path** equal to "/programs" or your desired marketing site path and enable it.
Install extra requirements
~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -214,7 +234,7 @@ Although tutor-discovery does not start event bus consumption by default, it sup
Troubleshooting
---------------
This Tutor plugin is maintained by Muhammad Faraz Maqsood from `Edly`_.
This Tutor plugin is maintained by Muhammad Labeeb from `Edly`_.
Community support is available from the official `Open edX forum`_.
Do you need help with this plugin? See the `troubleshooting`_
section from the Tutor documentation.

View File

@ -1 +0,0 @@
- [Bugfix] Add support to consume events from event bus in discovery. Explanation can be viewed here: https://github.com/openedx/event-bus-redis/blob/main/docs/tutor_installation.rst. (by @Faraz32123)

View File

@ -0,0 +1,2 @@
- [Improvement] Migrate from pylint and black to ruff. (by @mlabeeb03)
- [Improvement] Test python package distribution build when running make test. (by @mlabeeb03)

View File

@ -1,2 +1,84 @@
# https://packaging.python.org/en/latest/tutorials/packaging-projects/
# https://hatch.pypa.io/latest/config/build/
[project]
name = "tutor-discovery"
license = { text = "AGPL-3.0-only" }
authors = [
{name = "Edly"},
{email = "hello@edly.io"},
]
maintainers = [
{name = "Muhammad Labeeb"},
{email = "muhammad.labeeb@arbisoft.com"},
]
description="A Tutor plugin for course discovery, the Open edX service for providing access to consolidated course and program metadata"
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://docs.tutor.edly.io/"
Source = "https://github.com/overhangio/tutor-discovery"
Issues = "https://github.com/overhangio/tutor-discovery/issues"
Changelog = "https://github.com/overhangio/tutor-discovery/blob/release/CHANGELOG.md"
Community = "https://discuss.openedx.org/tag/tutor"
# hatch-specific configuration
[tool.hatch.metadata.hooks.custom]
path = ".hatch_build.py"
[build-system]
requires = ["setuptools", "wheel"]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.sdist]
# Disable strict naming, otherwise twine is not able to detect name/version
strict-naming = false
include = [ "/tutordiscovery", ".hatch_build.py"]
exclude = ["tests*"]
[tool.hatch.build.targets.wheel]
packages = ["tutordiscovery"]
[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]
[project.entry-points."tutor.plugin.v1"]
discovery = "tutordiscovery.plugin"

View File

@ -1,52 +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, "tutordiscovery", "__about__.py"), "rt", encoding="utf-8"
) as f:
exec(f.read(), about)
setup(
name="tutor-discovery",
version=about["__version__"],
url="https://docs.tutor.edly.io/",
project_urls={
"Documentation": "https://docs.tutor.edly.io/",
"Code": "https://github.com/overhangio/tutor-discovery",
"Issue tracker": "https://github.com/overhangio/tutor-discovery/issues",
"Community": "https://discuss.openedx.org",
},
license="AGPLv3",
author="Edly",
author_email="hello@edly.io",
maintainer="Edly",
maintainer_email="faraz.maqsood@arbisoft.com",
description="A Tutor plugin for course discovery, the Open edX service for providing access to consolidated course and program metadata",
long_description=readme,
long_description_content_type="text/x-rst",
packages=find_packages(exclude=["tests*"]),
include_package_data=True,
install_requires=["tutor>=19.0.0,<20.0.0"],
extras_require={"dev": "tutor[dev]>=19.0.0,<20.0.0"},
python_requires=">=3.9",
entry_points={"tutor.plugin.v1": ["discovery = tutordiscovery.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.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
],
)

View File

@ -20,7 +20,7 @@ class UtilsTests(unittest.TestCase):
@patch("subprocess.run")
def test_is_docker_rootless_podman(self, mock_run: MagicMock) -> None:
"""Test the `is_docker_rootless` when podman is used or any other error with `docker info`"""
"""Test the `is_docker_rootless` when podman is used or any other error with `docker info`""" # noqa: E501
utils.is_docker_rootless.cache_clear()
mock_run.side_effect = subprocess.CalledProcessError(1, "docker info")
self.assertFalse(utils.is_docker_rootless())

View File

@ -1 +1 @@
__version__ = "19.0.0"
__version__ = "20.0.0"

View File

@ -15,8 +15,8 @@ spec:
app.kubernetes.io/name: discovery
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
runAsUser: {{ APP_USER_ID }}
runAsGroup: {{ APP_USER_ID }}
containers:
- name: discovery
image: {{ DISCOVERY_DOCKER_IMAGE }}
@ -53,9 +53,9 @@ spec:
app.kubernetes.io/name: elasticsearch
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
runAsUser: {{ APP_USER_ID }}
runAsGroup: {{ APP_USER_ID }}
fsGroup: {{ APP_USER_ID }}
fsGroupChangePolicy: "OnRootMismatch"
containers:
- name: elasticsearch

View File

@ -1 +1 @@
{% if DISCOVERY_RUN_ELASTICSEARCH %}setowner 1000 /mounts/elasticsearch{% endif %}
{% if DISCOVERY_RUN_ELASTICSEARCH %}setowner {{ APP_USER_ID }} /mounts/elasticsearch{% endif %}

View File

@ -25,7 +25,7 @@ discovery:
soft: -1
hard: -1
restart: unless-stopped
user: "1000:1000"
user: "{{ APP_USER_ID }}:{{ APP_USER_ID }}"
volumes:
- ../../data/elasticsearch:/usr/share/elasticsearch/data
depends_on:

View File

@ -0,0 +1 @@
MFE_CONFIG["ENABLE_PROGRAMS"] = {{ ENABLE_PROGRAMS }}

View File

@ -22,7 +22,7 @@ APP_NAME = "discovery"
config: t.Dict[str, t.Dict[str, t.Any]] = {
"defaults": {
"VERSION": __version__,
"DOCKER_IMAGE": "{{ DOCKER_REGISTRY}}overhangio/openedx-discovery:{{ DISCOVERY_VERSION }}",
"DOCKER_IMAGE": "{{ DOCKER_REGISTRY}}overhangio/openedx-discovery:{{ DISCOVERY_VERSION }}", # noqa: E501
"HOST": "discovery.{{ LMS_HOST }}",
"INDEX_OVERRIDES": {},
"MYSQL_DATABASE": "discovery",
@ -50,6 +50,9 @@ config: t.Dict[str, t.Dict[str, t.Any]] = {
"OAUTH2_SECRET": "{{ 8|random_string }}",
"OAUTH2_SECRET_SSO": "{{ 8|random_string }}",
},
"overrides": {
"ENABLE_PROGRAMS": True,
},
}
# Initialization tasks

View File

@ -11,7 +11,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
pkg-config libsqlite3-dev media-types mailcap libbz2-dev liblzma-dev
ENV LC_ALL=en_US.UTF-8
ARG APP_USER_ID=1000
ARG APP_USER_ID={{ HOST_USER_ID }}
RUN if [ "$APP_USER_ID" = 0 ]; then echo "app user may not be root" && false; fi
RUN useradd --home-dir /openedx --create-home --shell /bin/bash --uid ${APP_USER_ID} app
USER ${APP_USER_ID}
@ -47,7 +47,7 @@ RUN --mount=type=cache,target=/openedx/.cache/pip,sharing=shared pip install \
# https://pypi.org/project/setuptools/
# https://pypi.org/project/pip/
# https://pypi.org/project/wheel/
setuptools==75.2.0 pip==24.2 wheel==0.44.0
setuptools==77.0.3 pip==25.0.1 wheel==0.45.1
# Install a recent version of nodejs
RUN pip install nodeenv==1.9.1
@ -73,7 +73,7 @@ RUN --mount=type=cache,target=/openedx/.cache/pip,sharing=shared pip install \
# Use redis as a django cache https://pypi.org/project/django-redis/
django-redis==5.4.0 \
# uwsgi server https://pypi.org/project/uWSGI/
uwsgi==2.0.27
uwsgi==2.0.28
{% if DISCOVERY_ATLAS_PULL %}
# Pull translations. Support the OEP-58 proposal behind a feature flag until it's fully implemented.

View File

@ -6,6 +6,11 @@
"from django.contrib.auth import get_user_model;\
get_user_model().objects.filter(username='lms_catalog_service_user').exclude(email='lms_catalog_service_user@openedx').update(email='lms_catalog_service_user@openedx')"
./manage.py lms shell -c \
"from openedx.core.djangoapps.programs.models import ProgramsApiConfig;\
ProgramsApiConfig.current().enabled or \
ProgramsApiConfig.objects.create(marketing_path='/programs', enabled=True)"
./manage.py lms manage_user discovery discovery@openedx --staff --superuser --unusable-password
./manage.py lms manage_user lms_catalog_service_user lms_catalog_service_user@openedx --staff --unusable-password
@ -57,5 +62,5 @@
# configuration -- which means that it takes different values for different
# sites. This is important because the programs and courses returned for each
# site will differ.
site-configuration set -d {{ LMS_HOST }} COURSE_CATALOG_API_URL {% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ DISCOVERY_HOST }}/api/v1
site-configuration set -d {{ LMS_HOST }}:8000 COURSE_CATALOG_API_URL http://{{ DISCOVERY_HOST }}:8381/api/v1
./manage.py lms create_or_update_site_configuration {{ LMS_HOST }} --configuration '{"COURSE_CATALOG_API_URL": "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ DISCOVERY_HOST }}/api/v1"}' --enabled
./manage.py lms create_or_update_site_configuration {{ LMS_HOST }}:8000 --configuration '{"COURSE_CATALOG_API_URL": "http://{{ DISCOVERY_HOST }}:8381/api/v1"}' --enabled