Skip to content
Snippets Groups Projects
Commit 349b8df8 authored by Alex Dusenbery's avatar Alex Dusenbery
Browse files

Add context_label and context_title to LTI POST parameters; Add required...

Add context_label and context_title to LTI POST parameters; Add required requirements; add some docker devstack instructions;
parent c1c7233b
No related branches found
No related tags found
No related merge requests found
...@@ -15,3 +15,6 @@ codekit-config.json ...@@ -15,3 +15,6 @@ codekit-config.json
### Testing artifacts ### Testing artifacts
.coverage .coverage
var/ var/
# virtualenvironment
venv/
\ No newline at end of file
...@@ -15,6 +15,31 @@ root folder: ...@@ -15,6 +15,31 @@ root folder:
$ pip install -r requirements.txt $ pip install -r requirements.txt
Installing in Docker Devstack
-----------------------------
Assuming that your ``devstack`` repo lives at ``~/code/devstack``
and that ``edx-platform`` lives right alongside that directory, you'll want
to checkout ``xblock-lti-consumer`` and have it live in ``~/code/src/xblock-lti-consumer``.
This will make it so that you can access it inside an LMS container shell
and easily make modifications for local testing.
Run ``make lms-shell`` from your ``devstack`` directory to enter a running LMS container.
Once in there, you can do the following to have your devstack pointing at a local development
version of ``xblock-lti-consumer``:
.. code:: bash
$ pushd /edx/src/xblock-lti-consumer
$ virtualenv venv/
$ source venv/bin/activate
$ make install
$ make test # optional, if you want to see that everything works
$ deactivate
$ pushd # should take you back to /edx/app/edxapp/edx-platform
$ pip uninstall -y lti_consumer_xblock
$ pip install -e /edx/src/xblock-lti-consumer
Enabling in Studio Enabling in Studio
------------------ ------------------
...@@ -27,6 +52,30 @@ advanced settings. ...@@ -27,6 +52,30 @@ advanced settings.
``"lti_consumer"`` to the policy value list. ``"lti_consumer"`` to the policy value list.
3. Click the "Save changes" button. 3. Click the "Save changes" button.
Testing Against an LTI Provider
-------------------------------
http://lti.tools/saltire/ provides a "Test Tool Provider" service that allows
you to see messages sent by an LTI consumer.
We have some useful documentation on how to set this up here:
http://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/latest/exercises_tools/lti_component.html#lti-authentication-information
1. In Studio Advanced settings, set the value of the "LTI Passports" field to "test:test:secret" -
this will set the oauth client key and secret used to send a message to the test LTI provider.
2. Create an LTI Consumer problem in a course in studio (after enabling it in "advanced_modules"
as seen above). Make a unit, select "Advanced", then "LTI Consumer".
3. Click edit and fill in the following fields:
``LTI ID``: "test"
``LTI URL``: "http://lti.tools/saltire/tp"
4. Click save. The unit should refresh and you should see "Passed" in the "Verification" field of
the message tab in the LTI Tool Provider emulator.
5. Click the "Publish" button.
6. View the unit in your local LMS. If you get an ``ImportError: No module named lti_consumer``, you
should ``docker-compose restart lms`` (since we previously uninstalled the lti_consumer to get the
tests for this repo running inside an LMS container). From here, you can see the contents of the
messages that we are sending as an LTI Consumer in the "Message Parameters" part of the "Message" tab.
Workbench installation and settings Workbench installation and settings
----------------------------------- -----------------------------------
......
...@@ -9,6 +9,8 @@ import logging ...@@ -9,6 +9,8 @@ import logging
import urllib import urllib
import json import json
from six import text_type
from .exceptions import LtiError from .exceptions import LtiError
from .oauth import get_oauth_request_signature, verify_oauth_body_signature from .oauth import get_oauth_request_signature, verify_oauth_body_signature
...@@ -116,19 +118,22 @@ class LtiConsumer(object): ...@@ -116,19 +118,22 @@ class LtiConsumer(object):
# Must have parameters for correct signing from LTI: # Must have parameters for correct signing from LTI:
lti_parameters = { lti_parameters = {
u'user_id': self.xblock.user_id, text_type('user_id'): self.xblock.user_id,
u'oauth_callback': u'about:blank', text_type('oauth_callback'): text_type('about:blank'),
u'launch_presentation_return_url': '', text_type('launch_presentation_return_url'): '',
u'lti_message_type': u'basic-lti-launch-request', text_type('lti_message_type'): text_type('basic-lti-launch-request'),
u'lti_version': 'LTI-1p0', text_type('lti_version'): text_type('LTI-1p0'),
u'roles': self.xblock.role, text_type('roles'): self.xblock.role,
# Parameters required for grading: # Parameters required for grading:
u'resource_link_id': self.xblock.resource_link_id, text_type('resource_link_id'): self.xblock.resource_link_id,
u'lis_result_sourcedid': self.xblock.lis_result_sourcedid, text_type('lis_result_sourcedid'): self.xblock.lis_result_sourcedid,
text_type('context_id'): self.xblock.context_id,
text_type('custom_component_display_name'): self.xblock.display_name,
u'context_id': self.xblock.context_id, text_type('context_title'): self.xblock.course.display_name_with_default,
u'custom_component_display_name': self.xblock.display_name, text_type('context_label'): self.xblock.course.display_org_with_default,
} }
if self.xblock.due: if self.xblock.due:
...@@ -138,7 +143,7 @@ class LtiConsumer(object): ...@@ -138,7 +143,7 @@ class LtiConsumer(object):
if self.xblock.has_score: if self.xblock.has_score:
lti_parameters.update({ lti_parameters.update({
u'lis_outcome_service_url': self.xblock.outcome_service_url text_type('lis_outcome_service_url'): self.xblock.outcome_service_url
}) })
self.xblock.user_email = "" self.xblock.user_email = ""
......
...@@ -7,6 +7,7 @@ import unittest ...@@ -7,6 +7,7 @@ import unittest
from datetime import timedelta from datetime import timedelta
from mock import Mock, PropertyMock, patch from mock import Mock, PropertyMock, patch
from six import text_type
from django.utils import timezone from django.utils import timezone
...@@ -153,30 +154,32 @@ class TestLtiConsumer(TestLtiConsumerXBlock): ...@@ -153,30 +154,32 @@ class TestLtiConsumer(TestLtiConsumerXBlock):
self.lti_consumer.xblock.graceperiod = timedelta(days=1) self.lti_consumer.xblock.graceperiod = timedelta(days=1)
expected_lti_parameters = { expected_lti_parameters = {
u'user_id': self.lti_consumer.xblock.user_id, text_type('user_id'): self.lti_consumer.xblock.user_id,
u'oauth_callback': u'about:blank', text_type('oauth_callback'): 'about:blank',
u'launch_presentation_return_url': '', text_type('launch_presentation_return_url'): '',
u'lti_message_type': u'basic-lti-launch-request', text_type('lti_message_type'): 'basic-lti-launch-request',
u'lti_version': 'LTI-1p0', text_type('lti_version'): 'LTI-1p0',
u'roles': self.lti_consumer.xblock.role, text_type('roles'): self.lti_consumer.xblock.role,
u'resource_link_id': self.lti_consumer.xblock.resource_link_id, text_type('resource_link_id'): self.lti_consumer.xblock.resource_link_id,
u'lis_result_sourcedid': self.lti_consumer.xblock.lis_result_sourcedid, text_type('lis_result_sourcedid'): self.lti_consumer.xblock.lis_result_sourcedid,
u'context_id': self.lti_consumer.xblock.context_id, text_type('context_id'): self.lti_consumer.xblock.context_id,
u'lis_outcome_service_url': self.lti_consumer.xblock.outcome_service_url, text_type('lis_outcome_service_url'): self.lti_consumer.xblock.outcome_service_url,
u'custom_component_display_name': self.lti_consumer.xblock.display_name, text_type('custom_component_display_name'): self.lti_consumer.xblock.display_name,
u'custom_component_due_date': self.lti_consumer.xblock.due.strftime('%Y-%m-%d %H:%M:%S'), text_type('custom_component_due_date'): self.lti_consumer.xblock.due.strftime('%Y-%m-%d %H:%M:%S'),
u'custom_component_graceperiod': str(self.lti_consumer.xblock.graceperiod.total_seconds()), text_type('custom_component_graceperiod'): str(self.lti_consumer.xblock.graceperiod.total_seconds()),
'lis_person_sourcedid': 'edx', 'lis_person_sourcedid': 'edx',
'lis_person_contact_email_primary': 'edx@example.com', 'lis_person_contact_email_primary': 'edx@example.com',
'launch_presentation_locale': 'en', 'launch_presentation_locale': 'en',
u'custom_param_1': 'custom1', text_type('custom_param_1'): 'custom1',
u'custom_param_2': 'custom2', text_type('custom_param_2'): 'custom2',
u'oauth_nonce': 'fake_nonce', text_type('oauth_nonce'): 'fake_nonce',
'oauth_timestamp': 'fake_timestamp', 'oauth_timestamp': 'fake_timestamp',
'oauth_version': 'fake_version', 'oauth_version': 'fake_version',
'oauth_signature_method': 'fake_method', 'oauth_signature_method': 'fake_method',
'oauth_consumer_key': 'fake_consumer_key', 'oauth_consumer_key': 'fake_consumer_key',
'oauth_signature': u'fake_signature' 'oauth_signature': 'fake_signature',
text_type('context_label'): self.lti_consumer.xblock.course.display_org_with_default,
text_type('context_title'): self.lti_consumer.xblock.course.display_name_with_default,
} }
self.lti_consumer.xblock.has_score = True self.lti_consumer.xblock.has_score = True
self.lti_consumer.xblock.ask_to_send_username = True self.lti_consumer.xblock.ask_to_send_username = True
......
...@@ -2,6 +2,7 @@ lxml ...@@ -2,6 +2,7 @@ lxml
bleach bleach
oauthlib oauthlib
mako mako
lazy
git+https://github.com/edx/XBlock.git#egg=XBlock git+https://github.com/edx/XBlock.git#egg=XBlock
git+https://github.com/edx/xblock-utils.git@v1.0.0#egg=xblock-utils==v1.0.0 git+https://github.com/edx/xblock-utils.git@v1.0.0#egg=xblock-utils==v1.0.0
-e . -e .
...@@ -22,7 +22,7 @@ def package_data(pkg, roots): ...@@ -22,7 +22,7 @@ def package_data(pkg, roots):
setup( setup(
name='lti_consumer-xblock', name='lti_consumer-xblock',
version='1.1.7', version='1.1.8',
description='This XBlock implements the consumer side of the LTI specification.', description='This XBlock implements the consumer side of the LTI specification.',
packages=[ packages=[
'lti_consumer', 'lti_consumer',
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
django-nose==1.4.4 django-nose==1.4.4
astroid==1.3.8 # Pinning to avoid backwards incompatibility issue with pylint/pylint-django astroid==1.3.8 # Pinning to avoid backwards incompatibility issue with pylint/pylint-django
coveralls coveralls
mock
pep8 pep8
git+https://github.com/edx/django-pyfs.git@1.0.3#egg=django-pyfs==1.0.3 git+https://github.com/edx/django-pyfs.git@1.0.3#egg=django-pyfs==1.0.3
git+https://github.com/edx/edx-lint.git@v0.3.2#egg=edx_lint==0.3.2 git+https://github.com/edx/edx-lint.git@v0.3.2#egg=edx_lint==0.3.2
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment