Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit da80f04

Browse files
committed
Added deeplinking flow
1 parent 993011d commit da80f04

File tree

6 files changed

+329
-3
lines changed

6 files changed

+329
-3
lines changed

activities/activity4/app.py

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import datetime
22
import os
33
import pprint
4+
import json
45

56
from tempfile import mkdtemp
6-
from flask import Flask, jsonify, request, render_template, url_for, session, send_from_directory
7+
from flask import Flask, jsonify, request, render_template, url_for, session, abort, send_from_directory
78

89
from flask_caching import Cache
910
from werkzeug.exceptions import Forbidden
@@ -96,6 +97,43 @@ def home():
9697
}
9798
return render_template("home.html", **tpl_kwargs)
9899

100+
# Load the courses from the JSON file
101+
def load_courses():
102+
courses_path = os.path.join(app.root_path, '..', 'configs', 'resources.json')
103+
with open(courses_path) as f:
104+
courses = json.load(f)
105+
return courses
106+
107+
108+
def deeplink():
109+
# Get launch data from session
110+
launch_data = session.get('launch_data', {})
111+
launch_id = session.get('launch_id', '')
112+
113+
courses = load_courses()
114+
115+
tpl_kwargs = {
116+
'page_title': "Deeplinking",
117+
"courses": courses,
118+
'launch_id': launch_id,
119+
'target_link_uri': launch_data.get('https://purl.imsglobal.org/spec/lti/claim/target_link_uri', ''),
120+
'user_data': {
121+
'sub': launch_data.get('sub', ''),
122+
'name': launch_data.get('name', ''),
123+
'family_name': launch_data.get('family_name', ''),
124+
'given_name': launch_data.get('given_name', ''),
125+
'email': launch_data.get('email', ''),
126+
'sourced_id': launch_data.get('https://purl.imsglobal.org/spec/lti/claim/lis', '{}').get('person_sourcedid', ''),
127+
},
128+
'context_data': {
129+
**launch_data.get('https://purl.imsglobal.org/spec/lti/claim/context', {}),
130+
'sourced_id': launch_data.get('https://purl.imsglobal.org/spec/lti/claim/lis', {}).get('course_section_sourcedid', '')
131+
},
132+
'user_roles': launch_data.get('https://purl.imsglobal.org/spec/lti/claim/roles', []),
133+
'resource_link': launch_data.get('https://purl.imsglobal.org/spec/lti/claim/resource_link', {})
134+
}
135+
return render_template("deeplink.html", **tpl_kwargs)
136+
99137
@app.route("/")
100138
def basic():
101139
return render_template("basic.html")
@@ -204,12 +242,14 @@ def launch():
204242
launch_data_storage = get_launch_data_storage()
205243
message_launch = FlaskMessageLaunch(flask_request, tool_conf, launch_data_storage=launch_data_storage)
206244
message_launch_data = message_launch.get_launch_data()
207-
pprint.pprint(message_launch_data)
245+
# pprint.pprint(message_launch_data)
208246

209247
# Store the launch data in the session
210248
session['launch_data'] = message_launch_data
211249
session['launch_id'] = message_launch.get_launch_id()
212250

251+
if message_launch.is_deep_link_launch():
252+
return deeplink()
213253
return home()
214254

215255

@@ -229,6 +269,44 @@ def get_nrps_members():
229269
members = message_launch.get_nrps().get_members()
230270
return members
231271

272+
@app.route('/dl/<resource_id>/', methods=['GET', 'POST'])
273+
def deeplink_response(resource_id):
274+
275+
276+
launch_id = session.get('launch_id', '')
277+
tool_conf = ToolConfJsonFile(get_lti_config_path())
278+
flask_request = FlaskRequest()
279+
launch_data_storage = get_launch_data_storage()
280+
message_launch = FlaskMessageLaunch.from_cache(launch_id, flask_request, tool_conf,
281+
launch_data_storage=launch_data_storage)
282+
283+
if not message_launch.is_deep_link_launch():
284+
raise Forbidden('Must be a deep link!')
285+
286+
courses = load_courses()
287+
course = next((course for course in courses if course['id'] == int(resource_id)), None)
288+
289+
if not course:
290+
abort(404, description=f"Course with ID {resource_id} not found")
291+
292+
293+
launch_url = url_for('home', _external=True) + '/resource/' + resource_id + '/'
294+
295+
resource = DeepLinkResource()
296+
resource.set_url(launch_url) \
297+
.set_title(course.get("title", "Resource " + resource_id))
298+
299+
# Get the optional 'model_id' from query parameters
300+
model_id = request.args.get('model_id', 'default')
301+
302+
if model_id:
303+
resource.set_custom_params({'model_id': model_id})
304+
305+
306+
html = message_launch.get_deep_link().output_response_form([resource])
307+
return html
308+
309+
232310
# @app.route('/api/ags/gradebook', methods=['GET'])
233311
# def get_gradebook():
234312
# launch_id = session.get('launch_id', '')

activities/activity4/static/css/output.css

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,73 @@ html {
758758
--bc: 74.6477% 0.0216 264.435964;
759759
}
760760

761+
[data-theme=corporate] {
762+
color-scheme: light;
763+
--b2: 93% 0 0;
764+
--b3: 86% 0 0;
765+
--in: 72.06% 0.191 231.6;
766+
--su: 64.8% 0.150 160;
767+
--wa: 84.71% 0.199 83.87;
768+
--er: 71.76% 0.221 22.18;
769+
--pc: 12.078% 0.0456 269.1;
770+
--sc: 13.0739% 0.010951 256.688055;
771+
--ac: 15.3934% 0.022799 163.57888;
772+
--inc: 0% 0 0;
773+
--suc: 0% 0 0;
774+
--wac: 0% 0 0;
775+
--erc: 0% 0 0;
776+
--border-btn: 1px;
777+
--tab-border: 1px;
778+
--p: 60.39% 0.228 269.1;
779+
--s: 65.3694% 0.054756 256.688055;
780+
--a: 76.9669% 0.113994 163.57888;
781+
--n: 22.3899% 0.031305 278.07229;
782+
--nc: 95.8796% 0.008588 247.915135;
783+
--b1: 100% 0 0;
784+
--bc: 22.3899% 0.031305 278.07229;
785+
--rounded-box: 0.25rem;
786+
--rounded-btn: .125rem;
787+
--rounded-badge: .125rem;
788+
--tab-radius: 0.25rem;
789+
--animation-btn: 0;
790+
--animation-input: 0;
791+
--btn-focus-scale: 1;
792+
}
793+
794+
.container {
795+
width: 100%;
796+
}
797+
798+
@media (min-width: 640px) {
799+
.container {
800+
max-width: 640px;
801+
}
802+
}
803+
804+
@media (min-width: 768px) {
805+
.container {
806+
max-width: 768px;
807+
}
808+
}
809+
810+
@media (min-width: 1024px) {
811+
.container {
812+
max-width: 1024px;
813+
}
814+
}
815+
816+
@media (min-width: 1280px) {
817+
.container {
818+
max-width: 1280px;
819+
}
820+
}
821+
822+
@media (min-width: 1536px) {
823+
.container {
824+
max-width: 1536px;
825+
}
826+
}
827+
761828
@media (hover:hover) {
762829
.label a:hover {
763830
--tw-text-opacity: 1;
@@ -1071,6 +1138,40 @@ html {
10711138
justify-self: end;
10721139
}
10731140

1141+
.select {
1142+
display: inline-flex;
1143+
cursor: pointer;
1144+
-webkit-user-select: none;
1145+
-moz-user-select: none;
1146+
user-select: none;
1147+
-webkit-appearance: none;
1148+
-moz-appearance: none;
1149+
appearance: none;
1150+
height: 3rem;
1151+
min-height: 3rem;
1152+
padding-inline-start: 1rem;
1153+
padding-inline-end: 2.5rem;
1154+
font-size: 0.875rem;
1155+
line-height: 1.25rem;
1156+
line-height: 2;
1157+
border-radius: var(--rounded-btn, 0.5rem);
1158+
border-width: 1px;
1159+
border-color: transparent;
1160+
--tw-bg-opacity: 1;
1161+
background-color: var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity)));
1162+
background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
1163+
linear-gradient(135deg, currentColor 50%, transparent 50%);
1164+
background-position: calc(100% - 20px) calc(1px + 50%),
1165+
calc(100% - 16.1px) calc(1px + 50%);
1166+
background-size: 4px 4px,
1167+
4px 4px;
1168+
background-repeat: no-repeat;
1169+
}
1170+
1171+
.select[multiple] {
1172+
height: auto;
1173+
}
1174+
10741175
.table {
10751176
position: relative;
10761177
width: 100%;
@@ -1445,6 +1546,50 @@ html {
14451546
}
14461547
}
14471548

1549+
.select:focus {
1550+
box-shadow: none;
1551+
border-color: var(--fallback-bc,oklch(var(--bc)/0.2));
1552+
outline-style: solid;
1553+
outline-width: 2px;
1554+
outline-offset: 2px;
1555+
outline-color: var(--fallback-bc,oklch(var(--bc)/0.2));
1556+
}
1557+
1558+
.select-disabled,
1559+
.select:disabled,
1560+
.select[disabled] {
1561+
cursor: not-allowed;
1562+
--tw-border-opacity: 1;
1563+
border-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity)));
1564+
--tw-bg-opacity: 1;
1565+
background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));
1566+
color: var(--fallback-bc,oklch(var(--bc)/0.4));
1567+
}
1568+
1569+
.select-disabled::-moz-placeholder, .select:disabled::-moz-placeholder, .select[disabled]::-moz-placeholder {
1570+
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)));
1571+
--tw-placeholder-opacity: 0.2;
1572+
}
1573+
1574+
.select-disabled::placeholder,
1575+
.select:disabled::placeholder,
1576+
.select[disabled]::placeholder {
1577+
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)));
1578+
--tw-placeholder-opacity: 0.2;
1579+
}
1580+
1581+
.select-multiple,
1582+
.select[multiple],
1583+
.select[size].select:not([size="1"]) {
1584+
background-image: none;
1585+
padding-right: 1rem;
1586+
}
1587+
1588+
[dir="rtl"] .select {
1589+
background-position: calc(0% + 12px) calc(1px + 50%),
1590+
calc(0% + 16px) calc(1px + 50%);
1591+
}
1592+
14481593
@keyframes skeleton {
14491594
from {
14501595
background-position: 150%;
@@ -1646,6 +1791,11 @@ html {
16461791
top: 0.25rem;
16471792
}
16481793

1794+
.mx-auto {
1795+
margin-left: auto;
1796+
margin-right: auto;
1797+
}
1798+
16491799
.mb-5 {
16501800
margin-bottom: 1.25rem;
16511801
}
@@ -1658,6 +1808,10 @@ html {
16581808
margin-top: 0.5rem;
16591809
}
16601810

1811+
.mt-3 {
1812+
margin-top: 0.75rem;
1813+
}
1814+
16611815
.mt-4 {
16621816
margin-top: 1rem;
16631817
}
@@ -1831,6 +1985,11 @@ html {
18311985
padding-bottom: 0.25rem;
18321986
}
18331987

1988+
.py-10 {
1989+
padding-top: 2.5rem;
1990+
padding-bottom: 2.5rem;
1991+
}
1992+
18341993
.py-2 {
18351994
padding-top: 0.5rem;
18361995
padding-bottom: 0.5rem;
@@ -1850,6 +2009,11 @@ html {
18502009
line-height: 2rem;
18512010
}
18522011

2012+
.text-4xl {
2013+
font-size: 2.25rem;
2014+
line-height: 2.5rem;
2015+
}
2016+
18532017
.text-lg {
18542018
font-size: 1.125rem;
18552019
line-height: 1.75rem;
@@ -1879,6 +2043,11 @@ html {
18792043
color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)));
18802044
}
18812045

2046+
.text-white {
2047+
--tw-text-opacity: 1;
2048+
color: rgb(255 255 255 / var(--tw-text-opacity));
2049+
}
2050+
18822051
.shadow-md {
18832052
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
18842053
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);

activities/activity4/tailwind.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,8 @@ module.exports = {
1010
plugins: [
1111
require('daisyui')
1212
],
13+
daisyui: {
14+
themes: ["light", "dark", "corporate"],
15+
},
1316
}
1417

activities/activity4/templates/base.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html lang="en">
2+
<html data-theme="corporate" lang="en">
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">

0 commit comments

Comments
 (0)