-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 0d65c57
Showing
48 changed files
with
784 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
name: Sync with private repo | ||
|
||
on: | ||
push: | ||
branches: [ master ] | ||
|
||
jobs: | ||
sync: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
with: | ||
fetch-depth: 0 | ||
- name: Add remote | ||
run: git remote add overhangio https://${{ secrets.GIT_USERNAME }}:${{ secrets.GIT_PASSWORD }}@git.overhang.io/core/tutor-richie.git | ||
- name: Push | ||
run: git push overhangio master |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.*.swp | ||
!.gitignore | ||
TODO | ||
__pycache__ | ||
*.egg-info/ | ||
/build/ | ||
/dist/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
variables: | ||
TUTOR_PLUGIN: richie | ||
TUTOR_IMAGES: richie | ||
TUTOR_PYPI_PACKAGE: tutor-richie | ||
OPENEDX_RELEASE: lilac | ||
GITHUB_REPO: overhangio/tutor-richie | ||
|
||
include: | ||
- project: 'community/tutor-ci' | ||
file: 'plugin-gitlab-ci.yml' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
recursive-include tutorrichie/patches * | ||
recursive-include tutorrichie/templates * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
Richie plugin for `Tutor <https://docs.tutor.overhang.io>`__ | ||
============================================================ | ||
|
||
This is a plugin to integrate `Richie <https://richie.education/>`__, the learning portal CMS, with `Open edX <https://open.edx.org>`__. The integration takes the form of a `Tutor <https://docs.tutor.overhang.io>`__ plugin. | ||
|
||
Installation | ||
------------ | ||
|
||
:: | ||
|
||
pip install tutor-richie | ||
tutor plugins enable richie | ||
|
||
Running the Richie plugin will require that you rebuild the "openedx" Docker image:: | ||
|
||
tutor config save | ||
tutor images build openedx | ||
|
||
This step is necessary to install the Richie connector app in edx-platform. | ||
|
||
Then, the platform can be launched as usual with:: | ||
|
||
tutor local quickstart | ||
|
||
You will be able to access your course catalog at http(s)://courses.LMS_HOST. In development, this url will be http://courses.local.overhang.io. | ||
|
||
Gettting started | ||
---------------- | ||
|
||
Once your Richie platform is up and running, you will quickly realize that your learning portal is empty. This is because you should first create the corresponding courses and organizations from inside Richie. To do so, start by creating a super user:: | ||
|
||
tutor local run richie ./sandbox/manage.py createsuperuser | ||
|
||
You can then use the credentials you just created at http(s)://yourrichiehost/admin. In development, this is http://courses.local.overhang.io/admin. | ||
|
||
Then, refer to the official `Richie documentation <https://richie.education/docs/quick-start>`__ to learn how to create courses and organizations. | ||
|
||
You may also want to fill your learning portal with a demo site -- but be careful not to run this command in production, as it will be difficult to get rid of the demo site afterwards:: | ||
|
||
# WARNING: do not attempt this in production! | ||
tutor local run richie ./sandbox/manage.py create_demo_site --force | ||
|
||
Configuration | ||
------------- | ||
|
||
This Tutor plugin comes with a few configuration settings: | ||
|
||
- ``RICHIE_RELEASE_VERSION`` (default: ``"v2.8.2"``) | ||
- ``RICHIE_HOST`` (default: ``"courses.{{ LMS_HOST }}"``) | ||
- ``RICHIE_MYSQL_DATABASE`` (default: ``"richie"``) | ||
- ``RICHIE_MYSQL_USERNAME`` (default: ``"richie"``) | ||
- ``RICHIE_ELASTICSEARCH_INDICES_PREFIX`` (default: ``"richie"``) | ||
|
||
These defaults should be enough for most users. To modify any one of them, run:: | ||
|
||
tutor config save --set RICHIE_SETTING_NAME=myvalue | ||
|
||
For instance, to customize the domain name at which Richie will run:: | ||
|
||
tutor config save --set "RICHIE_HOST=mysubdomain.{{ LMS_HOST }}" | ||
|
||
Development | ||
----------- | ||
|
||
Bind-mount volume:: | ||
|
||
tutor dev bindmount richie /app/richie | ||
|
||
Then, run a development server:: | ||
|
||
tutor dev runserver --volume=/app/richie richie | ||
|
||
The Richie development server will be available at http://courses.local.overhang.io:8003. | ||
|
||
License | ||
------- | ||
|
||
This software is licensed under the terms of the `AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.en.html>`__. It was developed and is being actively maintained thanks to the sponsorship of `France Université Numérique <https://github.com/openfun>`__. | ||
|
||
.. image:: https://www.fun-mooc.fr/static/richie/images/logo.png | ||
:alt: France Université Numérique | ||
:target: https://fun-mooc.fr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Richie connector plugin app for Open edX | ||
======================================== | ||
|
||
This is an `Open edX plugin <https://github.com/edx/edx-django-utils/blob/master/edx_django_utils/plugins/README.rst>`__ to facilitate the integration of a `Richie <https://richie.education>`__ learning portal. Its main feature is automatically syncing course properties when they are updated in the Open edX studio. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
from django.apps import AppConfig | ||
from edx_django_utils.plugins.constants import PluginSettings, PluginURLs | ||
from openedx.core.djangoapps.plugins.constants import ProjectType, SettingsType | ||
|
||
|
||
class RichieAppConfig(AppConfig): | ||
name = "richie" | ||
verbose_name = "Richie course catalog connector" | ||
|
||
# Open edX plugin docs: https://github.com/edx/edx-django-utils/blob/master/edx_django_utils/plugins/README.rst | ||
plugin_app = { | ||
PluginURLs.CONFIG: { | ||
ProjectType.LMS: { | ||
PluginURLs.NAMESPACE: "richie", | ||
PluginURLs.REGEX: r"^richie/", | ||
PluginURLs.RELATIVE_PATH: "urls", | ||
} | ||
}, | ||
PluginSettings.CONFIG: { | ||
ProjectType.LMS: { | ||
SettingsType.COMMON: { | ||
PluginSettings.RELATIVE_PATH: "settings.lms", | ||
}, | ||
}, | ||
ProjectType.CMS: { | ||
SettingsType.COMMON: { | ||
PluginSettings.RELATIVE_PATH: "settings.cms", | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
def ready(self): | ||
""" | ||
Connect signal handlers. | ||
""" | ||
# pylint: disable=unused-import | ||
from . import signals |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
def plugin_settings(settings): | ||
"""Common settings for Richie catalog connector""" | ||
settings.RICHIE_COURSE_HOOK = { | ||
"secret": "richiesecret", | ||
"url": "http://richie:8000/api/v1.0/course-runs-sync/", | ||
"timeout": 3, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
def plugin_settings(settings): | ||
"""Common settings for Richie catalog connector""" | ||
settings.RICHIE_ROOT_URL = "http://myrichie" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from django.dispatch import receiver | ||
from xmodule.modulestore.django import SignalHandler | ||
|
||
from .sync import sync_course_from_key | ||
|
||
|
||
@receiver(SignalHandler.course_published, dispatch_uid="update_course_on_publish") | ||
def update_course_on_publish(sender, course_key, **kwargs): | ||
""" | ||
Synchronize course properties with Richie catalog. | ||
""" | ||
sync_course_from_key(course_key) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import hashlib | ||
import hmac | ||
import json | ||
import logging | ||
|
||
|
||
from django.conf import settings | ||
import requests | ||
import requests.exceptions | ||
from xmodule.modulestore.django import modulestore | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def sync_all_courses(): | ||
""" | ||
Synchronize all courses with Richie. | ||
""" | ||
for course in modulestore().get_courses(): | ||
sync_course(course) | ||
|
||
|
||
def sync_course_from_key(course_key): | ||
return sync_course(modulestore().get_course(course_key)) | ||
|
||
|
||
def sync_course(course): | ||
""" | ||
Synchronize an Open edX course with a Richie instance. | ||
Note that only the course settings are synchronized, and not the actual | ||
course contents or description. This function always succeeds, even when the | ||
request fails. | ||
""" | ||
enrollment_start = course.enrollment_start and course.enrollment_start.isoformat() | ||
enrollment_end = course.enrollment_end and course.enrollment_end.isoformat() | ||
data = { | ||
"resource_link": "{}/courses/{}/course".format( | ||
settings.LMS_ROOT_URL, course.id | ||
), | ||
"start": course.start and course.start.isoformat(), | ||
"end": course.end and course.end.isoformat(), | ||
"enrollment_start": enrollment_start, | ||
"enrollment_end": enrollment_end, | ||
"languages": [course.language or settings.LANGUAGE_CODE], | ||
} | ||
|
||
signature = hmac.new( | ||
settings.RICHIE_COURSE_HOOK["secret"].encode("utf-8"), | ||
msg=json.dumps(data).encode("utf-8"), | ||
digestmod=hashlib.sha256, | ||
).hexdigest() | ||
|
||
try: | ||
response = requests.post( | ||
settings.RICHIE_COURSE_HOOK["url"], | ||
json=data, | ||
headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)}, | ||
timeout=settings.RICHIE_COURSE_HOOK["timeout"], | ||
) | ||
except requests.exceptions.Timeout: | ||
logger.error( | ||
f"Could not synchronize course {course.id} with Richie. Response timeout" | ||
) | ||
return | ||
if response.status_code >= 400: | ||
logger.error( | ||
f"Could not synchronize course {course.id} with Richie. Response: {response.content.decode()}" | ||
) | ||
else: | ||
logger.info(f"Successfuly synchronized course {course.id} with Richie") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from django.urls import path | ||
|
||
from . import views | ||
|
||
urlpatterns = [ | ||
path("<path:subpath>", views.redirect_to_richie, name="redirect_to_richie"), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from urllib.parse import urljoin | ||
|
||
|
||
from django.conf import settings | ||
from django.shortcuts import redirect | ||
|
||
|
||
def redirect_to_richie(request, subpath): | ||
""" | ||
Redirect to Richie catalog. | ||
This view is used after login from Richie, with a "?next=richie/en" | ||
parameter. | ||
""" | ||
return redirect(urljoin(settings.RICHIE_ROOT_URL, subpath)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import io | ||
import os | ||
from setuptools import setup, find_packages | ||
|
||
HERE = os.path.abspath(os.path.dirname(__file__)) | ||
|
||
|
||
def load_readme(): | ||
with io.open(os.path.join(HERE, "README.rst"), "rt", encoding="utf8") as f: | ||
return f.read() | ||
|
||
|
||
setup( | ||
name="richie-edx-platform", | ||
version="0.0.1", | ||
url="https://github.com/overhangio/tutor-richie/", | ||
project_urls={ | ||
"Code": "https://github.com/overhangio/tutor-richie/tree/master/contrib/edx-platform", | ||
"Issue tracker": "https://github.com/overhangio/tutor-richie/issues", | ||
}, | ||
license="AGPLv3", | ||
author="Overhang.IO", | ||
description="Open edX plugin app for integration with a Richie catalog", | ||
long_description=load_readme(), | ||
packages=find_packages(exclude=["tests*"]), | ||
include_package_data=True, | ||
entry_points={ | ||
"lms.djangoapp": [ | ||
"richie = richie.apps:RichieAppConfig", | ||
], | ||
"cms.djangoapp": [ | ||
"richie = richie.apps:RichieAppConfig", | ||
], | ||
}, | ||
python_requires=">=3.5", | ||
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.5", | ||
"Programming Language :: Python :: 3.6", | ||
"Programming Language :: Python :: 3.7", | ||
"Programming Language :: Python :: 3.8", | ||
"Programming Language :: Python :: 3.9", | ||
"Programming Language :: Python :: 3.10", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import io | ||
import os | ||
from setuptools import setup, find_packages | ||
|
||
HERE = os.path.abspath(os.path.dirname(__file__)) | ||
|
||
|
||
def load_readme(): | ||
with io.open(os.path.join(HERE, "README.rst"), "rt", encoding="utf8") as f: | ||
return f.read() | ||
|
||
|
||
def load_about(): | ||
about = {} | ||
with io.open( | ||
os.path.join(HERE, "tutorrichie", "__about__.py"), | ||
"rt", | ||
encoding="utf-8", | ||
) as f: | ||
exec(f.read(), about) # pylint: disable=exec-used | ||
return about | ||
|
||
|
||
ABOUT = load_about() | ||
|
||
|
||
setup( | ||
name="tutor-richie", | ||
version=ABOUT["__version__"], | ||
url="https://github.com/overhangio/tutor-richie", | ||
project_urls={ | ||
"Code": "https://github.com/overhangio/tutor-richie", | ||
"Issue tracker": "https://github.com/overhangio/tutor-richie/issues", | ||
}, | ||
license="AGPLv3", | ||
author="Overhang.IO", | ||
description="richie plugin for Tutor", | ||
long_description=load_readme(), | ||
packages=find_packages(exclude=["tests*", "contrib*"]), | ||
include_package_data=True, | ||
python_requires=">=3.5", | ||
install_requires=["tutor>=12.0.0,<13.0.0"], | ||
entry_points={ | ||
"tutor.plugin.v0": [ | ||
"richie = tutorrichie.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.5", | ||
"Programming Language :: Python :: 3.6", | ||
"Programming Language :: Python :: 3.7", | ||
"Programming Language :: Python :: 3.8", | ||
"Programming Language :: Python :: 3.9", | ||
"Programming Language :: Python :: 3.10", | ||
], | ||
) |
Oops, something went wrong.