Skip to content

Commit

Permalink
#5 send the LTI simplied data to Maizey endpoint (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
pushyamig authored Jun 19, 2024
1 parent 742a026 commit cd8aae5
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 41 deletions.
8 changes: 5 additions & 3 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ MYSQL_PASSWORD=clrt_pwd
MYSQL_HOST=clrt_mysql_host
MYSQL_PORT=3306

# Django settings
# python manage.py shell -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
#Django settings
SECRET_KEY='you-django-key'
DJANGO_DEBUG=True
DJANGO_LOG_LEVEL=DEBUG
TZ=America/Detroit
CSRF_TRUSTED_ORIGINS=https://*.instructure.com,https://*.umich.edu
ALLOWED_HOSTS=.loophole.site,.ngrok-free.app, 127.0.0.1, localhost
ALLOWED_HOSTS=.loophole.site,.ngrok-free.app, 127.0.0.1, localhost

# grab from dropbox where all the secrets are stored
MAIZEY_JWT_SECRET=secret
66 changes: 66 additions & 0 deletions lti_redirect/maizey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import jwt, logging, requests
from decouple import config

logger = logging.getLogger(__name__)

class SendToMaizey():

def __init__(self, lti_launch_data) -> None:
self.lti_launch_data = lti_launch_data
self.maizey_jwt_secret = config('MAIZEY_JWT_SECRET', default=None)
self.lti_custom_data = self.lti_launch_data['https://purl.imsglobal.org/spec/lti/claim/custom']

def get_restructured_data(self):
course_title = self.lti_launch_data['https://purl.imsglobal.org/spec/lti/claim/context']['title']
lis = self.lti_launch_data['https://purl.imsglobal.org/spec/lti/claim/lis']

# Restructure the course info for Maizey needs
restructured_data = {
"canvas_url": self.lti_custom_data["canvas_url"],
"course": {
"id": self.lti_custom_data["course_id"],
"name": course_title,
"sis_id": lis["course_offering_sourcedid"],
"workflow_state": self.lti_custom_data["course_status"],
"enroll_status":self.lti_custom_data["course_enroll_status"]
},
"term": {
"id": self.lti_custom_data["term_id"],
"name": self.lti_custom_data["term_name"],
"term_start_date": self.lti_custom_data["term_start"],
"term_end_date": self.lti_custom_data["term_end"]
},
"user": {
"id": self.lti_custom_data["user_canvas_id"],
"login_id": self.lti_custom_data["login_id"],
"sis_id": lis["person_sourcedid"],
"roles": self.lti_custom_data["roles"].split(","),
"email_address": self.lti_launch_data["email"],
"name": self.lti_launch_data["name"],
} ,
"account": {
"id": self.lti_custom_data["course_canvas_account_id"],
"name": self.lti_custom_data["course_account_name"],
"sis_id": self.lti_custom_data["course_sis_account_id"]
}
}
logger.info(f"Course data sending to Maizey endpoint: {restructured_data}")
return restructured_data

def send_to_maizey(self):
if not self.maizey_jwt_secret:
logger.error("Maizey JWT secret is not configured")
return False
course_jwt = jwt.encode(self.get_restructured_data(), self.maizey_jwt_secret, algorithm='HS256')
maizey_url = f"{self.lti_custom_data['redirect_url']}t2/canvaslink?token={course_jwt}"
try:
response = requests.get(maizey_url)
response.raise_for_status()
# currently response from maizey endpoint upon success is retuning a HTML text
logger.info(f"Maizey response: {response.text}")
return True
except requests.exceptions.RequestException as e:
logger.error(f"Error sending course data to Maizey: {e}")
return False


2 changes: 1 addition & 1 deletion lti_redirect/templates/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
{% endblock %}
<hr/>
<footer>
<p>&copy; 2023</p>
<p>&copy; 2024 The Regents of the University of Michigan</p>
</footer>
</div>
</body>
Expand Down
60 changes: 23 additions & 37 deletions lti_redirect/views.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import random, logging
import string
import requests
import jwt
import django.contrib.auth
from django.conf import settings
from django.shortcuts import redirect, render
from lti_tool.views import LtiLaunchBaseView
from django.contrib.auth.models import User
from lti_redirect.maizey import SendToMaizey

logger = logging.getLogger(__name__)

Expand All @@ -17,41 +16,24 @@ def get_home_template(request):
def error(request):
return render(request, "error.html")

def get_restrucutured_data(launch_data):
custom = launch_data['https://purl.imsglobal.org/spec/lti/claim/custom']
course_title = launch_data['https://purl.imsglobal.org/spec/lti/claim/context']['title']
lis = launch_data['https://purl.imsglobal.org/spec/lti/claim/lis']
# Restructure the data as per the requirements
restructured_data = {
"canvas_url": custom["canvas_url"],
"course": {
"id": custom["course_id"],
"name": course_title,
"sis_id": lis["course_offering_sourcedid"],
"workflow_state": custom["course_status"],
"enroll_status":custom["course_enroll_status"]
},
"term": {
"id": custom["term_id"],
"name": custom["term_name"],
"term_start_date": custom["term_start"],
"term_end_date": custom["term_end"]
},
"user": {
"id": custom["user_canvas_id"],
"login_id": custom["login_id"],
"sis_id": lis["person_sourcedid"],
"roles": custom["roles"].split(","),
"email_address": launch_data["email"],
"name": launch_data["name"],
} ,
"account": {
"id": custom["course_canvas_account_id"],
"name": custom["course_account_name"],
"sis_id": custom["course_sis_account_id"]
}
}
return restructured_data
def validate_custom_lti_launch_data(lti_launch):
expected_keys = [
"roles", "term_id", "login_id", "term_end", "course_id", "term_name", "canvas_url",
"term_start", "redirect_url", "course_status", "user_canvas_id",
"course_account_name", "course_enroll_status", "course_sis_account_id",
"course_canvas_account_id"]
main_key = "https://purl.imsglobal.org/spec/lti/claim/custom"
if main_key not in lti_launch:
logger.error(f"LTI custom '{main_key}' variables are not configured")
return False

custom_data = lti_launch[main_key]
missing_keys = [key for key in expected_keys if key not in custom_data]
if missing_keys:
logger.error(f"LTI custom variables are missing in the '{main_key}' {', '.join(missing_keys)}")
return False
logger.debug("All keys are present.")
return True

def login_user_from_lti(request, launch_data):
try:
Expand Down Expand Up @@ -84,8 +66,12 @@ class ApplicationLaunchView(LtiLaunchBaseView):
def handle_resource_launch(self, request, lti_launch):
... # Required. Typically redirects the users to the appropriate page.
launch_data = lti_launch.get_launch_data()
if not validate_custom_lti_launch_data(launch_data):
return redirect("error")
if not login_user_from_lti(request, launch_data):
return redirect("error")
if not SendToMaizey(launch_data).send_to_maizey():
return redirect("error")
return redirect("home")

def handle_deep_linking_launch(self, request, lti_launch):
Expand Down

0 comments on commit cd8aae5

Please sign in to comment.