Skip to content

Commit

Permalink
🌅
Browse files Browse the repository at this point in the history
  • Loading branch information
regisb committed Aug 21, 2019
0 parents commit 15518f0
Show file tree
Hide file tree
Showing 26 changed files with 427 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.*.swp
!.gitignore
TODO
__pycache__
*.egg-info/
/build/
/dist/
40 changes: 40 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
build:image:
script:
- apk add --no-cache docker
- python setup.py install
- tutor plugins enable notes
- tutor config save
- tutor images build notes
only:
refs:
- master
tags:
- private
stage: build

deploy:image:
script:
- apk add --no-cache docker
- docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"
- python setup.py install
- tutor plugins enable notes
- tutor config save
- tutor images push notes
only:
refs:
- master
tags:
- private
stage: deploy

deploy:pypi:
script:
- pip3 install -U setuptools twine
- python3 setup.py sdist
- twine upload --skip-existing dist/tutor-notes*.tar.gz
only:
refs:
- master
tags:
- private
stage: deploy
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
recursive-include tutornotes/patches *
recursive-include tutornotes/templates *
37 changes: 37 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Students notes plugin for `Tutor <https://docs.tutor.overhang.io>`_
===================================================================

This is a plugin for `Tutor <https://docs.tutor.overhang.io>`_ to easily add the `Open edX note-taking app <https://github.com/edx/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-ironwood.master/exercises_tools/notes.html?highlight=notes>`_).

.. image:: https://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/open-release-ironwood.master/_images/SFD_SN_bodyexample.png
:alt: Notes in action

Installation
------------

The plugin is currently bundled with the `binary releases of Tutor <https://github.com/overhangio/tutor/releases>`_. If you have installed Tutor from source, you will have to install this plugin from source, too::
pip install tutor-notes

Then, to enable this plugin, run::
tutor plugins enable notes

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). In particular, in development you should set this configuration variable to ``notes.localhost`` in order to be able to access the notes service from the LMS. Otherwise you will get a "Sorry, we could not search the store for annotations" error.


Configuration
-------------

- ``NOTES_MYSQL_PASSWORD`` (default: ``"{{ 8|random_string }}"``)
- ``NOTES_SECRET_KEY`` (default: ``"{{ 24|random_string }}"``)
- ``NOTES_OAUTH2_SECRET`` (default: ``"{{ 24|random_string }}"``)
- ``NOTES_DOCKER_IMAGE`` (default: ``"overhangio/openedx-notes:{{ TUTOR_VERSION }}"``)
- ``NOTES_HOST`` (default: ``"notes.{{ LMS_HOST }}"``)
- ``NOTES_MYSQL_DATABASE`` (default: ``"notes"``)
- ``NOTES_MYSQL_USERNAME`` (default: ``"notes"``)

These values can be modified with ``tutor config save --set PARAM_NAME=VALUE`` commands.
46 changes: 46 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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["__version__"],
url="https://docs.tutor.overhang.io/",
project_urls={
"Documentation": "https://docs.tutor.overhang.io/",
"Code": "https://github.com/overhangio/tutor/tree/master/plugins/notes",
"Issue tracker": "https://github.com/overhangio/tutor/issues",
"Community": "https://discuss.overhang.io",
},
license="AGPLv3",
author="Overhang.io",
author_email="[email protected]",
description="A Tutor plugin for student notes",
long_description=readme,
packages=find_packages(exclude=["tests*"]),
include_package_data=True,
python_requires=">=3.5",
install_requires=["tutor-openedx"],
entry_points={"tutor.plugin.v0": ["notes = tutornotes.plugin"]},
classifiers=[
"Development Status :: 3 - Alpha",
"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",
],
)
1 change: 1 addition & 0 deletions tutornotes/__about__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "0.1.1"
Empty file added tutornotes/__init__.py
Empty file.
1 change: 1 addition & 0 deletions tutornotes/patches/common-env-features
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"ENABLE_EDXNOTES": true
1 change: 1 addition & 0 deletions tutornotes/patches/https-create
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
certbot certonly --standalone -n --agree-tos -m admin@{{ LMS_HOST }} -d {{ NOTES_HOST }}
32 changes: 32 additions & 0 deletions tutornotes/patches/k8s-deployments
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: notes
labels:
app.kubernetes.io/name: notes
spec:
selector:
matchLabels:
app.kubernetes.io/name: notes
template:
metadata:
labels:
app.kubernetes.io/name: notes
spec:
containers:
- name: notes
image: {{ DOCKER_REGISTRY }}{{ NOTES_DOCKER_IMAGE }}
ports:
- containerPort: 8000
env:
- name: DJANGO_SETTINGS_MODULE
value: notesserver.settings.tutor
volumeMounts:
- mountPath: /openedx/edx-notes-api/notesserver/settings/tutor.py
name: settings
subPath: tutor.py
volumes:
- name: settings
configMap:
name: notes-settings
18 changes: 18 additions & 0 deletions tutornotes/patches/k8s-ingress-certificates
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: {{ NOTES_HOST|replace(".", "-") }}
spec:
secretName: {{ NOTES_HOST }}-tls
issuerRef:
name: letsencrypt
commonName: {{ NOTES_HOST }}
dnsNames:
- {{ NOTES_HOST }}
acme:
config:
- http01:
ingress: web
domains:
- {{ NOTES_HOST }}
6 changes: 6 additions & 0 deletions tutornotes/patches/k8s-ingress-rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
- host: {{ NOTES_HOST }}
http:
paths:
- backend:
serviceName: nginx
servicePort: {% if ACTIVATE_HTTPS %}443{% else %}80{% endif %}
1 change: 1 addition & 0 deletions tutornotes/patches/k8s-ingress-tls-hosts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- {{ NOTES_HOST }}
12 changes: 12 additions & 0 deletions tutornotes/patches/k8s-services
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
apiVersion: v1
kind: Service
metadata:
name: notes
spec:
type: NodePort
ports:
- port: 8000
protocol: TCP
selector:
app.kubernetes.io/name: notes
3 changes: 3 additions & 0 deletions tutornotes/patches/kustomization-configmapgenerator
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- name: notes-settings
files:
- plugins/notes/apps/settings/tutor.py
2 changes: 2 additions & 0 deletions tutornotes/patches/lms-env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"EDXNOTES_PUBLIC_API": "{{ "https" if ACTIVATE_HTTPS else "http" }}://{{ NOTES_HOST }}/api/v1",
"EDXNOTES_INTERNAL_API": "http://notes:8000/api/v1"
11 changes: 11 additions & 0 deletions tutornotes/patches/local-docker-compose-services
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
############# Notes: backend store for edX Student Notes
notes:
image: {{ DOCKER_REGISTRY }}{{ NOTES_DOCKER_IMAGE }}
environment:
DJANGO_SETTINGS_MODULE: notesserver.settings.tutor
volumes:
- ../plugins/notes/apps/settings/tutor.py:/openedx/edx-notes-api/notesserver/settings/tutor.py
- ../../data/notes:/openedx/data
restart: unless-stopped
{% if ACTIVATE_MYSQL %}depends_on:
- mysql{% endif %}
37 changes: 37 additions & 0 deletions tutornotes/patches/nginx-extra
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
### Student notes service
upstream notes-backend {
server notes:8000 fail_timeout=0;
}

{% if ACTIVATE_HTTPS %}
server {
server_name {{ NOTES_HOST }};
listen 80;
return 301 https://$server_name$request_uri;
}
{% endif %}

server {
{% if ACTIVATE_HTTPS %}listen 443 {{ "" if WEB_PROXY else "ssl" }};{% else %}listen 80;{% endif %}
server_name notes.localhost {{ NOTES_HOST }};

{% if ACTIVATE_HTTPS and not WEB_PROXY %}
ssl_certificate /etc/letsencrypt/live/{{ NOTES_HOST }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ NOTES_HOST }}/privkey.pem;
{% endif %}

# Disables server version feedback on pages and in headers
server_tokens off;

location / {
{% if not WEB_PROXY %}
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $remote_addr;
{% endif %}
proxy_set_header Host $http_host;
proxy_redirect off;

proxy_pass http://notes-backend;
}
}
27 changes: 27 additions & 0 deletions tutornotes/patches/proxy-apache
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{% if ACTIVATE_HTTPS %}
<VirtualHost *:80>
ServerName {{ NOTES_HOST }}
Redirect / https://notes.{{ LMS_HOST }}/
</VirtualHost>

<VirtualHost *:443>
ServerName {{ NOTES_HOST }}
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/{{ NOTES_HOST }}/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/{{ NOTES_HOST }}/privkey.pem

ProxyPreserveHost On
ProxyRequests On
ProxyPass / http://localhost:{{ NGINX_HTTP_PORT }}/
ProxyPassReverse / http://localhost:{{ NGINX_HTTP_PORT }}/
</VirtualHost>
{% else %}
<VirtualHost *:80>
ServerName {{ NOTES_HOST }}

ProxyPreserveHost On
ProxyRequests On
ProxyPass / http://localhost:{{ NGINX_HTTP_PORT }}/
ProxyPassReverse / http://localhost:{{ NGINX_HTTP_PORT }}/
</VirtualHost>
{% endif %}
33 changes: 33 additions & 0 deletions tutornotes/patches/proxy-nginx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
server {
listen 80;
server_name {{ NOTES_HOST }};

server_tokens off;
location / {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://localhost:{{ NGINX_HTTP_PORT }};
}
}
{% if ACTIVATE_HTTPS %}
server {
listen 443 ssl;
server_name {{ NOTES_HOST }};

ssl_certificate /etc/letsencrypt/live/{{ NOTES_HOST }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ NOTES_HOST }}/privkey.pem;

server_tokens off;
location / {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://localhost:{{ NGINX_HTTPS_PORT }};
}
}
{% endif %}
41 changes: 41 additions & 0 deletions tutornotes/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from glob import glob
import os

import pkg_resources

from .__about__ import __version__


config = {
"add": {
"MYSQL_PASSWORD": "{{ 8|random_string }}",
"SECRET_KEY": "{{ 24|random_string }}",
"OAUTH2_SECRET": "{{ 24|random_string }}",
},
"defaults": {
"VERSION": __version__,
"DOCKER_IMAGE": "overhangio/openedx-notes:{{ NOTES_VERSION }}",
"HOST": "notes.{{ LMS_HOST }}",
"MYSQL_DATABASE": "notes",
"MYSQL_USERNAME": "notes",
},
}

templates = pkg_resources.resource_filename("tutornotes", "templates")
hooks = {
"init": ["mysql-client", "lms", "notes"],
"build-image": {"notes": "{{ NOTES_DOCKER_IMAGE }}"},
"remote-image": {"notes": "{{ NOTES_DOCKER_IMAGE }}"},
}


def patches():
all_patches = {}
for path in glob(
os.path.join(pkg_resources.resource_filename("tutornotes", "patches"), "*")
):
with open(path) as patch_file:
name = os.path.basename(path)
content = patch_file.read()
all_patches[name] = content
return all_patches
Loading

0 comments on commit 15518f0

Please sign in to comment.