-
Notifications
You must be signed in to change notification settings - Fork 0
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
Showing
8 changed files
with
700 additions
and
1 deletion.
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,67 @@ | ||
name: Publish Python 🐍 distribution 📦 to PyPI and TestPyPI | ||
|
||
on: push | ||
|
||
jobs: | ||
build: | ||
name: Build distribution 📦 | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Set up Python | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: "3.x" | ||
|
||
- name: Install pypa/build | ||
run: >- | ||
python3 -m | ||
pip install | ||
build | ||
--user | ||
- name: Build a binary wheel and a source tarball | ||
run: python3 -m build | ||
- name: Store the distribution packages | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: python-package-distributions | ||
path: dist/ | ||
|
||
publish-to-pypi: | ||
name: >- | ||
Publish Python 🐍 distribution 📦 to PyPI | ||
if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes | ||
needs: | ||
- build | ||
runs-on: ubuntu-latest | ||
environment: | ||
name: pypi | ||
url: https://pypi.org/p/django-lti-dynamic-registration | ||
permissions: | ||
id-token: write # IMPORTANT: mandatory for trusted publishing | ||
|
||
|
||
publish-to-testpypi: | ||
name: Publish Python 🐍 distribution 📦 to TestPyPI | ||
needs: | ||
- build | ||
runs-on: ubuntu-latest | ||
|
||
environment: | ||
name: testpypi | ||
url: https://test.pypi.org/p/django-lti-dynamic-registration | ||
|
||
permissions: | ||
id-token: write # IMPORTANT: mandatory for trusted publishing | ||
|
||
steps: | ||
- name: Download all the dists | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: python-package-distributions | ||
path: dist/ | ||
- name: Publish distribution 📦 to TestPyPI | ||
uses: pypa/gh-action-pypi-publish@release/v1 | ||
with: | ||
repository-url: https://test.pypi.org/legacy/ |
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,186 @@ | ||
# MacOS | ||
|
||
# General | ||
.DS_Store | ||
.AppleDouble | ||
.LSOverride | ||
|
||
# Icon must end with two \r | ||
Icon | ||
|
||
# Thumbnails | ||
._* | ||
|
||
# Files that might appear in the root of a volume | ||
.DocumentRevisions-V100 | ||
.fseventsd | ||
.Spotlight-V100 | ||
.TemporaryItems | ||
.Trashes | ||
.VolumeIcon.icns | ||
.com.apple.timemachine.donotpresent | ||
|
||
# Directories potentially created on remote AFP share | ||
.AppleDB | ||
.AppleDesktop | ||
Network Trash Folder | ||
Temporary Items | ||
.apdisk | ||
|
||
|
||
# VS Code | ||
|
||
.vscode/* | ||
!.vscode/settings.json | ||
!.vscode/tasks.json | ||
!.vscode/launch.json | ||
!.vscode/extensions.json | ||
*.code-workspace | ||
|
||
# Local History for Visual Studio Code | ||
.history/ | ||
|
||
|
||
# Python | ||
|
||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
wheels/ | ||
share/python-wheels/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
MANIFEST | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.nox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*.cover | ||
*.py,cover | ||
.hypothesis/ | ||
.pytest_cache/ | ||
cover/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
db.sqlite3 | ||
db.sqlite3-journal | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
.pybuilder/ | ||
target/ | ||
|
||
# Jupyter Notebook | ||
.ipynb_checkpoints | ||
|
||
# IPython | ||
profile_default/ | ||
ipython_config.py | ||
|
||
# pyenv | ||
# For a library or package, you might want to ignore these files since the code is | ||
# intended to run in multiple environments; otherwise, check them in: | ||
# .python-version | ||
|
||
# pipenv | ||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | ||
# However, in case of collaboration, if having platform-specific dependencies or dependencies | ||
# having no cross-platform support, pipenv may install dependencies that don't work, or not | ||
# install all needed dependencies. | ||
#Pipfile.lock | ||
|
||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow | ||
__pypackages__/ | ||
|
||
# Celery stuff | ||
celerybeat-schedule | ||
celerybeat.pid | ||
|
||
# SageMath parsed files | ||
*.sage.py | ||
|
||
# Environments | ||
.env | ||
.venv | ||
env/ | ||
venv/ | ||
ENV/ | ||
env.bak/ | ||
venv.bak/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
.spyproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
|
||
# mkdocs documentation | ||
/site | ||
|
||
# mypy | ||
.mypy_cache/ | ||
.dmypy.json | ||
dmypy.json | ||
|
||
# Pyre type checker | ||
.pyre/ | ||
|
||
# pytype static type analyzer | ||
.pytype/ | ||
|
||
# Cython debug symbols | ||
cython_debug/ | ||
|
||
# Local only files | ||
.local/ |
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 |
---|---|---|
@@ -1,2 +1,4 @@ | ||
# django-lti-dynamic-registration | ||
Add-on to django-lti to support dynamic registration. | ||
Add-on to django-lti to support dynamic registration. | ||
|
||
See: https://www.imsglobal.org/spec/lti-dr/v1p0 |
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,94 @@ | ||
import requests | ||
from django.http import HttpResponse | ||
from django.views import View | ||
from lti_tool.models import LtiRegistration | ||
from .types import LmsLtiRegistration | ||
|
||
|
||
class DynamicRegistrationBaseView(View): | ||
|
||
tool_friendly_name: str = "Override this in your subclass" | ||
|
||
def get(self, request, *args, **kwargs): | ||
# handle get requests here | ||
raise NotImplementedError( | ||
"Subclasses of DynamicRegistrationBaseView must implement get" | ||
) | ||
|
||
def post(self, request, *args, **kwargs): | ||
# handle post requests here | ||
raise NotImplementedError( | ||
"Subclasses of DynamicRegistrationBaseView must implement post" | ||
) | ||
|
||
def get_openid_config(self) -> dict: | ||
openid_configuration_url = self.request.GET.get("openid_configuration") | ||
registration_token = self.request.GET.get("registration_token") | ||
|
||
if not openid_configuration_url or not registration_token: | ||
raise ValueError( | ||
"openid_configuration_url and registration_token are required (this view must be accessed from within a dynamic registration flow)" | ||
) | ||
|
||
headers = {"Authorization": f"Bearer {registration_token}"} | ||
response = requests.get(openid_configuration_url, headers=headers) | ||
response.raise_for_status() | ||
openid_config = response.json() | ||
|
||
# make sure that the openid_configuration_url starts with the issuer from the openid_config | ||
if not openid_configuration_url.startswith(openid_config["issuer"]): | ||
raise ValueError( | ||
"invalid openid_configuration_url: does not match the issuer in the openid config" | ||
) | ||
return openid_config | ||
|
||
def register_tool_in_platform( | ||
self, | ||
openid_config: dict, | ||
tool_platform_registration: LmsLtiRegistration, | ||
) -> str: | ||
|
||
registration_token = self.request.GET.get("registration_token") | ||
|
||
response = requests.post( | ||
openid_config["registration_endpoint"], | ||
json=tool_platform_registration.to_dict(), | ||
headers={ | ||
"Authorization": f"Bearer {registration_token}", | ||
"Content-Type": "application/json", | ||
}, | ||
) | ||
response.raise_for_status() | ||
|
||
response_data = response.json() | ||
client_id = response_data["client_id"] | ||
return client_id | ||
|
||
def register_platform_in_tool( | ||
self, consumer_name: str, openid_config: dict | ||
) -> LtiRegistration: | ||
reg = LtiRegistration( | ||
name=consumer_name, | ||
issuer=openid_config["issuer"], | ||
auth_url=openid_config["authorization_endpoint"], | ||
token_url=openid_config["token_endpoint"], | ||
keyset_url=openid_config["jwks_uri"], | ||
) | ||
reg.save() | ||
return reg | ||
|
||
def success_response(self) -> HttpResponse: | ||
return HttpResponse( | ||
""" | ||
<html> | ||
<head> | ||
<title>Dynamic Registration Successful</title> | ||
</head> | ||
<body> | ||
<script> | ||
window.parent.postMessage({subject: 'org.imsglobal.lti.close'}, '*'); | ||
</script> | ||
</body> | ||
</html> | ||
""" | ||
) |
Oops, something went wrong.