Skip to content

Commit 6edb195

Browse files
authored
Merge pull request #94 from ccnmtl/generate-xml-response-ex
generate_xml_request: add LTI launch url parameter
2 parents 3f9ad88 + 238f549 commit 6edb195

File tree

2 files changed

+65
-11
lines changed

2 files changed

+65
-11
lines changed

lti_provider/lti.py

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from django.conf import settings
2+
3+
from lti_provider.models import LTICourseContext
24
from pylti.common import (
35
LTIException, LTINotInSessionException, LTI_SESSION_KEY,
46
verify_request_common, LTIRoleException, LTI_ROLES, LTI_PROPERTY_LIST)
5-
6-
from lti_provider.models import LTICourseContext
7+
from xml.etree import ElementTree as etree
78

89

910
LTI_PROPERTY_LIST_EX = [
@@ -208,3 +209,52 @@ def user_roles(self, request): # pylint: disable=no-self-use
208209

209210
def sis_course_id(self, request):
210211
return request.session.get('lis_course_offering_sourcedid', None)
212+
213+
def generate_request_xml(self, message_identifier_id, operation,
214+
lis_result_sourcedid, score, launch_url):
215+
# pylint: disable=too-many-locals
216+
"""
217+
Generates LTI 1.1 XML for posting result to LTI consumer.
218+
219+
:param message_identifier_id:
220+
:param operation:
221+
:param lis_result_sourcedid:
222+
:param score:
223+
:return: XML string
224+
"""
225+
root = etree.Element(u'imsx_POXEnvelopeRequest',
226+
xmlns=u'http://www.imsglobal.org/services/'
227+
u'ltiv1p1/xsd/imsoms_v1p0')
228+
229+
header = etree.SubElement(root, 'imsx_POXHeader')
230+
header_info = etree.SubElement(header, 'imsx_POXRequestHeaderInfo')
231+
version = etree.SubElement(header_info, 'imsx_version')
232+
version.text = 'V1.0'
233+
message_identifier = etree.SubElement(header_info,
234+
'imsx_messageIdentifier')
235+
message_identifier.text = message_identifier_id
236+
body = etree.SubElement(root, 'imsx_POXBody')
237+
xml_request = etree.SubElement(
238+
body, '%s%s' % (operation, 'Request'))
239+
record = etree.SubElement(xml_request, 'resultRecord')
240+
241+
guid = etree.SubElement(record, 'sourcedGUID')
242+
243+
sourcedid = etree.SubElement(guid, 'sourcedId')
244+
sourcedid.text = lis_result_sourcedid
245+
if score is not None:
246+
result = etree.SubElement(record, 'result')
247+
result_score = etree.SubElement(result, 'resultScore')
248+
language = etree.SubElement(result_score, 'language')
249+
language.text = 'en'
250+
text_string = etree.SubElement(result_score, 'textString')
251+
text_string.text = score.__str__()
252+
if launch_url:
253+
result_data = etree.SubElement(result, 'resultData')
254+
lti_launch_url = etree.SubElement(
255+
result_data, 'ltiLaunchUrl')
256+
lti_launch_url.text = launch_url
257+
ret = "<?xml version='1.0' encoding='utf-8'?>\n{}".format(
258+
etree.tostring(root, encoding='utf-8').decode('utf-8'))
259+
260+
return ret

lti_provider/views.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,21 @@
44
from django.contrib import messages
55
from django.contrib.auth.decorators import login_required
66
from django.contrib.auth.models import Group
7-
try:
8-
from django.urls import reverse
9-
except ImportError:
10-
from django.core.urlresolvers import reverse
117
from django.http.response import HttpResponseRedirect
128
from django.shortcuts import get_object_or_404
139
from django.utils.decorators import method_decorator
1410
from django.views.decorators.csrf import csrf_exempt
1511
from django.views.generic.base import View, TemplateView
12+
1613
from lti_provider.mixins import LTIAuthMixin
1714
from lti_provider.models import LTICourseContext
18-
from pylti.common import \
19-
generate_request_xml, LTIPostMessageException, post_message
15+
from pylti.common import LTIPostMessageException, post_message
16+
17+
18+
try:
19+
from django.urls import reverse
20+
except ImportError:
21+
from django.core.urlresolvers import reverse
2022

2123

2224
class LTIConfigView(TemplateView):
@@ -167,9 +169,12 @@ def post(self, request, *args, **kwargs):
167169
except ValueError:
168170
score = 0
169171

170-
xml = generate_request_xml(
172+
redirect_url = request.POST.get('next', '/')
173+
174+
xml = self.lti.generate_request_xml(
171175
self.message_identifier(), 'replaceResult',
172-
self.lti.lis_result_sourcedid(request), score)
176+
self.lti.lis_result_sourcedid(request), score,
177+
request.build_absolute_uri(redirect_url))
173178

174179
if not post_message(
175180
self.lti.consumers(), self.lti.oauth_consumer_key(request),
@@ -186,5 +191,4 @@ def post(self, request, *args, **kwargs):
186191
msg = ('Your score was submitted. Great job!')
187192
messages.add_message(request, messages.INFO, msg)
188193

189-
redirect_url = request.POST.get('next', '/')
190194
return HttpResponseRedirect(redirect_url)

0 commit comments

Comments
 (0)