Skip to content

Commit af68c7c

Browse files
authored
Merge pull request #38 from edx/aed/EDUCATOR-2516
Add context_title and context_label parameters
2 parents c1c7233 + 349b8df commit af68c7c

7 files changed

Lines changed: 91 additions & 29 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,6 @@ codekit-config.json
1515
### Testing artifacts
1616
.coverage
1717
var/
18+
19+
# virtualenvironment
20+
venv/

README.rst

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,31 @@ root folder:
1515
1616
$ pip install -r requirements.txt
1717
18+
Installing in Docker Devstack
19+
-----------------------------
20+
21+
Assuming that your ``devstack`` repo lives at ``~/code/devstack``
22+
and that ``edx-platform`` lives right alongside that directory, you'll want
23+
to checkout ``xblock-lti-consumer`` and have it live in ``~/code/src/xblock-lti-consumer``.
24+
This will make it so that you can access it inside an LMS container shell
25+
and easily make modifications for local testing.
26+
27+
Run ``make lms-shell`` from your ``devstack`` directory to enter a running LMS container.
28+
Once in there, you can do the following to have your devstack pointing at a local development
29+
version of ``xblock-lti-consumer``:
30+
31+
.. code:: bash
32+
33+
$ pushd /edx/src/xblock-lti-consumer
34+
$ virtualenv venv/
35+
$ source venv/bin/activate
36+
$ make install
37+
$ make test # optional, if you want to see that everything works
38+
$ deactivate
39+
$ pushd # should take you back to /edx/app/edxapp/edx-platform
40+
$ pip uninstall -y lti_consumer_xblock
41+
$ pip install -e /edx/src/xblock-lti-consumer
42+
1843
Enabling in Studio
1944
------------------
2045

@@ -27,6 +52,30 @@ advanced settings.
2752
``"lti_consumer"`` to the policy value list.
2853
3. Click the "Save changes" button.
2954

55+
Testing Against an LTI Provider
56+
-------------------------------
57+
58+
http://lti.tools/saltire/ provides a "Test Tool Provider" service that allows
59+
you to see messages sent by an LTI consumer.
60+
61+
We have some useful documentation on how to set this up here:
62+
http://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/latest/exercises_tools/lti_component.html#lti-authentication-information
63+
64+
1. In Studio Advanced settings, set the value of the "LTI Passports" field to "test:test:secret" -
65+
this will set the oauth client key and secret used to send a message to the test LTI provider.
66+
2. Create an LTI Consumer problem in a course in studio (after enabling it in "advanced_modules"
67+
as seen above). Make a unit, select "Advanced", then "LTI Consumer".
68+
3. Click edit and fill in the following fields:
69+
``LTI ID``: "test"
70+
``LTI URL``: "http://lti.tools/saltire/tp"
71+
4. Click save. The unit should refresh and you should see "Passed" in the "Verification" field of
72+
the message tab in the LTI Tool Provider emulator.
73+
5. Click the "Publish" button.
74+
6. View the unit in your local LMS. If you get an ``ImportError: No module named lti_consumer``, you
75+
should ``docker-compose restart lms`` (since we previously uninstalled the lti_consumer to get the
76+
tests for this repo running inside an LMS container). From here, you can see the contents of the
77+
messages that we are sending as an LTI Consumer in the "Message Parameters" part of the "Message" tab.
78+
3079
Workbench installation and settings
3180
-----------------------------------
3281

lti_consumer/lti.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import urllib
1010
import json
1111

12+
from six import text_type
13+
1214
from .exceptions import LtiError
1315
from .oauth import get_oauth_request_signature, verify_oauth_body_signature
1416

@@ -116,19 +118,22 @@ def get_signed_lti_parameters(self):
116118

117119
# Must have parameters for correct signing from LTI:
118120
lti_parameters = {
119-
u'user_id': self.xblock.user_id,
120-
u'oauth_callback': u'about:blank',
121-
u'launch_presentation_return_url': '',
122-
u'lti_message_type': u'basic-lti-launch-request',
123-
u'lti_version': 'LTI-1p0',
124-
u'roles': self.xblock.role,
121+
text_type('user_id'): self.xblock.user_id,
122+
text_type('oauth_callback'): text_type('about:blank'),
123+
text_type('launch_presentation_return_url'): '',
124+
text_type('lti_message_type'): text_type('basic-lti-launch-request'),
125+
text_type('lti_version'): text_type('LTI-1p0'),
126+
text_type('roles'): self.xblock.role,
125127

126128
# Parameters required for grading:
127-
u'resource_link_id': self.xblock.resource_link_id,
128-
u'lis_result_sourcedid': self.xblock.lis_result_sourcedid,
129+
text_type('resource_link_id'): self.xblock.resource_link_id,
130+
text_type('lis_result_sourcedid'): self.xblock.lis_result_sourcedid,
131+
132+
text_type('context_id'): self.xblock.context_id,
133+
text_type('custom_component_display_name'): self.xblock.display_name,
129134

130-
u'context_id': self.xblock.context_id,
131-
u'custom_component_display_name': self.xblock.display_name,
135+
text_type('context_title'): self.xblock.course.display_name_with_default,
136+
text_type('context_label'): self.xblock.course.display_org_with_default,
132137
}
133138

134139
if self.xblock.due:
@@ -138,7 +143,7 @@ def get_signed_lti_parameters(self):
138143

139144
if self.xblock.has_score:
140145
lti_parameters.update({
141-
u'lis_outcome_service_url': self.xblock.outcome_service_url
146+
text_type('lis_outcome_service_url'): self.xblock.outcome_service_url
142147
})
143148

144149
self.xblock.user_email = ""

lti_consumer/tests/unit/test_lti.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from datetime import timedelta
99
from mock import Mock, PropertyMock, patch
10+
from six import text_type
1011

1112
from django.utils import timezone
1213

@@ -153,30 +154,32 @@ def test_get_signed_lti_parameters(self):
153154
self.lti_consumer.xblock.graceperiod = timedelta(days=1)
154155

155156
expected_lti_parameters = {
156-
u'user_id': self.lti_consumer.xblock.user_id,
157-
u'oauth_callback': u'about:blank',
158-
u'launch_presentation_return_url': '',
159-
u'lti_message_type': u'basic-lti-launch-request',
160-
u'lti_version': 'LTI-1p0',
161-
u'roles': self.lti_consumer.xblock.role,
162-
u'resource_link_id': self.lti_consumer.xblock.resource_link_id,
163-
u'lis_result_sourcedid': self.lti_consumer.xblock.lis_result_sourcedid,
164-
u'context_id': self.lti_consumer.xblock.context_id,
165-
u'lis_outcome_service_url': self.lti_consumer.xblock.outcome_service_url,
166-
u'custom_component_display_name': self.lti_consumer.xblock.display_name,
167-
u'custom_component_due_date': self.lti_consumer.xblock.due.strftime('%Y-%m-%d %H:%M:%S'),
168-
u'custom_component_graceperiod': str(self.lti_consumer.xblock.graceperiod.total_seconds()),
157+
text_type('user_id'): self.lti_consumer.xblock.user_id,
158+
text_type('oauth_callback'): 'about:blank',
159+
text_type('launch_presentation_return_url'): '',
160+
text_type('lti_message_type'): 'basic-lti-launch-request',
161+
text_type('lti_version'): 'LTI-1p0',
162+
text_type('roles'): self.lti_consumer.xblock.role,
163+
text_type('resource_link_id'): self.lti_consumer.xblock.resource_link_id,
164+
text_type('lis_result_sourcedid'): self.lti_consumer.xblock.lis_result_sourcedid,
165+
text_type('context_id'): self.lti_consumer.xblock.context_id,
166+
text_type('lis_outcome_service_url'): self.lti_consumer.xblock.outcome_service_url,
167+
text_type('custom_component_display_name'): self.lti_consumer.xblock.display_name,
168+
text_type('custom_component_due_date'): self.lti_consumer.xblock.due.strftime('%Y-%m-%d %H:%M:%S'),
169+
text_type('custom_component_graceperiod'): str(self.lti_consumer.xblock.graceperiod.total_seconds()),
169170
'lis_person_sourcedid': 'edx',
170171
'lis_person_contact_email_primary': 'edx@example.com',
171172
'launch_presentation_locale': 'en',
172-
u'custom_param_1': 'custom1',
173-
u'custom_param_2': 'custom2',
174-
u'oauth_nonce': 'fake_nonce',
173+
text_type('custom_param_1'): 'custom1',
174+
text_type('custom_param_2'): 'custom2',
175+
text_type('oauth_nonce'): 'fake_nonce',
175176
'oauth_timestamp': 'fake_timestamp',
176177
'oauth_version': 'fake_version',
177178
'oauth_signature_method': 'fake_method',
178179
'oauth_consumer_key': 'fake_consumer_key',
179-
'oauth_signature': u'fake_signature'
180+
'oauth_signature': 'fake_signature',
181+
text_type('context_label'): self.lti_consumer.xblock.course.display_org_with_default,
182+
text_type('context_title'): self.lti_consumer.xblock.course.display_name_with_default,
180183
}
181184
self.lti_consumer.xblock.has_score = True
182185
self.lti_consumer.xblock.ask_to_send_username = True

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ lxml
22
bleach
33
oauthlib
44
mako
5+
lazy
56
git+https://github.com/edx/XBlock.git#egg=XBlock
67
git+https://github.com/edx/xblock-utils.git@v1.0.0#egg=xblock-utils==v1.0.0
78
-e .

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def package_data(pkg, roots):
2222

2323
setup(
2424
name='lti_consumer-xblock',
25-
version='1.1.7',
25+
version='1.1.8',
2626
description='This XBlock implements the consumer side of the LTI specification.',
2727
packages=[
2828
'lti_consumer',

test_requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
django-nose==1.4.4
44
astroid==1.3.8 # Pinning to avoid backwards incompatibility issue with pylint/pylint-django
55
coveralls
6+
mock
67
pep8
78
git+https://github.com/edx/django-pyfs.git@1.0.3#egg=django-pyfs==1.0.3
89
git+https://github.com/edx/edx-lint.git@v0.3.2#egg=edx_lint==0.3.2

0 commit comments

Comments
 (0)