diff --git a/cms/djangoapps/contentstore/views/component.py b/cms/djangoapps/contentstore/views/component.py
index deef87a403..724dc439d9 100644
--- a/cms/djangoapps/contentstore/views/component.py
+++ b/cms/djangoapps/contentstore/views/component.py
@@ -52,8 +52,7 @@ NOTE_COMPONENT_TYPES = ['notes']
ADVANCED_COMPONENT_TYPES = [
'annotatable',
'word_cloud',
- 'graphical_slider_tool',
- 'lti',
+ 'graphical_slider_tool'
] + OPEN_ENDED_COMPONENT_TYPES + NOTE_COMPONENT_TYPES
ADVANCED_COMPONENT_CATEGORY = 'advanced'
ADVANCED_COMPONENT_POLICY_KEY = 'advanced_modules'
diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py
index 45ad7a7424..ccbb7fb5bb 100644
--- a/cms/djangoapps/contentstore/views/preview.py
+++ b/cms/djangoapps/contentstore/views/preview.py
@@ -81,6 +81,7 @@ def preview_component(request, location):
component,
'xmodule_edit.html'
)
+
return render_to_response('component.html', {
'preview': get_preview_html(request, component, 0),
'editor': component.runtime.render(component, None, 'studio_view').content,
@@ -103,6 +104,7 @@ def preview_module_system(request, preview_id, descriptor):
return lms_field_data(descriptor._field_data, student_data)
course_id = get_course_for_item(descriptor.location).location.course_id
+
return ModuleSystem(
ajax_url=reverse('preview_dispatch', args=[preview_id, descriptor.location.url(), '']).rstrip('/'),
# TODO (cpennington): Do we want to track how instructors are using the preview problems?
@@ -116,8 +118,6 @@ def preview_module_system(request, preview_id, descriptor):
xblock_field_data=preview_field_data,
can_execute_unsafe_code=(lambda: can_execute_unsafe_code(course_id)),
mixins=settings.XBLOCK_MIXINS,
- course_id=course_id,
- anonymous_student_id='student'
)
diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py
index 6a24bf8f27..704de15ea7 100644
--- a/common/lib/xmodule/setup.py
+++ b/common/lib/xmodule/setup.py
@@ -56,7 +56,6 @@ setup(
"hidden = xmodule.hidden_module:HiddenDescriptor",
"raw = xmodule.raw_module:RawDescriptor",
"crowdsource_hinter = xmodule.crowdsource_hinter:CrowdsourceHinterDescriptor",
- "lti = xmodule.lti_module:LTIModuleDescriptor"
],
'console_scripts': [
'xmodule_assets = xmodule.static_content:main',
diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py
index 658a095d14..aca804d5e2 100644
--- a/common/lib/xmodule/xmodule/course_module.py
+++ b/common/lib/xmodule/xmodule/course_module.py
@@ -153,7 +153,6 @@ class TextbookList(List):
class CourseFields(object):
- lti_passports = List(help="LTI tools passports as id:client_key:client_secret", scope=Scope.settings)
textbooks = TextbookList(help="List of pairs of (title, url) for textbooks used in this course",
default=[], scope=Scope.content)
wiki_slug = String(help="Slug that points to the wiki for this course", scope=Scope.content)
diff --git a/common/lib/xmodule/xmodule/css/lti/lti.scss b/common/lib/xmodule/xmodule/css/lti/lti.scss
deleted file mode 100644
index 97a8f62d54..0000000000
--- a/common/lib/xmodule/xmodule/css/lti/lti.scss
+++ /dev/null
@@ -1,30 +0,0 @@
-div.lti {
- // align center
- margin: 0 auto;
-
- h3.error_message {
- display: block;
- }
-
- form.ltiLaunchForm {
- display: none;
- }
-
- iframe.ltiLaunchFrame {
- width: 100%;
- height: 800px;
- display: none;
- border: 0px;
- overflow-x: hidden;
- }
-
- &.rendered {
- iframe.ltiLaunchFrame {
- display: block;
- }
-
- h3.error_message {
- display: none;
- }
- }
-}
diff --git a/common/lib/xmodule/xmodule/js/fixtures/lti.html b/common/lib/xmodule/xmodule/js/fixtures/lti.html
deleted file mode 100644
index e5e7ab3f3f..0000000000
--- a/common/lib/xmodule/xmodule/js/fixtures/lti.html
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
- Please provide launch_url. Click "Edit", and fill in the
- required fields.
-
-
-
-
-
diff --git a/common/lib/xmodule/xmodule/js/spec/lti/constructor.js b/common/lib/xmodule/xmodule/js/spec/lti/constructor.js
deleted file mode 100644
index 0a73496bed..0000000000
--- a/common/lib/xmodule/xmodule/js/spec/lti/constructor.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * File: constructor.js
- *
- * Purpose: Jasmine tests for LTI module (front-end part).
- *
- *
- * The front-end part of the LTI module is really simple. If an action
- * is set for the hidden LTI form, then it is submited, and the results are
- * redirected to an iframe.
- *
- * We will test that the form is only submited when the action is set (i.e.
- * not empty).
- *
- * Other aspects of LTI module will be covered by Python unit tests and
- * acceptance tests.
- *
- */
-
-/*
- * "Hence that general is skilful in attack whose opponent does not know what
- * to defend; and he is skilful in defense whose opponent does not know what
- * to attack."
- *
- * ~ Sun Tzu
- */
-
-(function () {
- describe('LTI', function () {
- describe('constructor', function () {
- describe('before settings were filled in', function () {
- var element, errorMessage, frame;
-
- // This function will be executed before each of the it() specs
- // in this suite.
- beforeEach(function () {
- loadFixtures('lti.html');
-
- element = $('#lti_id');
- errorMessage = element.find('.error_message');
- form = element.find('.ltiLaunchForm');
- frame = element.find('.ltiLaunchFrame');
-
- spyOnEvent(form, 'submit');
-
- LTI(element);
- });
-
- it(
- 'when URL setting is filled form is not submited',
- function () {
-
- expect('submit').not.toHaveBeenTriggeredOn(form);
- });
- });
-
- describe('After the settings were filled in', function () {
- var element, errorMessage, frame;
-
- // This function will be executed before each of the it() specs
- // in this suite.
- beforeEach(function () {
- loadFixtures('lti.html');
-
- element = $('#lti_id');
- errorMessage = element.find('.error_message');
- form = element.find('.ltiLaunchForm');
- frame = element.find('.ltiLaunchFrame');
-
- spyOnEvent(form, 'submit');
-
- // The user "fills in" the necessary settings, and the
- // form will get an action URL.
- form.attr('action', 'http://www.example.com/');
-
- LTI(element);
- });
-
- it('when URL setting is filled form is submited', function () {
- expect('submit').toHaveBeenTriggeredOn(form);
- });
- });
- });
- });
-}());
diff --git a/common/lib/xmodule/xmodule/js/src/lti/lti.js b/common/lib/xmodule/xmodule/js/src/lti/lti.js
deleted file mode 100644
index e5b6885e1b..0000000000
--- a/common/lib/xmodule/xmodule/js/src/lti/lti.js
+++ /dev/null
@@ -1,26 +0,0 @@
-window.LTI = (function () {
- // Function initialize(element)
- //
- // Initialize the LTI iframe.
- function initialize(element) {
- var form;
-
- // In cms (Studio) the element is already a jQuery object. In lms it is
- // a DOM object.
- //
- // To make sure that there is no error, we pass it through the $()
- // function. This will make it a jQuery object if it isn't already so.
- element = $(element);
-
- form = element.find('.ltiLaunchForm');
-
- // If the Form's action attribute is set (i.e. we can perform a normal
- // submit), then we submit the form and make the frame shown.
- if (form.attr('action')) {
- form.submit();
- element.find('.lti').addClass('rendered')
- }
- }
-
- return initialize;
-}());
diff --git a/common/lib/xmodule/xmodule/lti_module.py b/common/lib/xmodule/xmodule/lti_module.py
deleted file mode 100644
index bc07cea97e..0000000000
--- a/common/lib/xmodule/xmodule/lti_module.py
+++ /dev/null
@@ -1,249 +0,0 @@
-"""
-Module that allows to insert LTI tools to page.
-
-Module uses current edx-platform 0.14.2 version of requests (oauth part).
-Please update code when upgrading requests.
-
-Protocol is oauth1, LTI version is 1.1.1:
-http://www.imsglobal.org/LTI/v1p1p1/ltiIMGv1p1p1.html
-"""
-
-import logging
-import requests
-import urllib
-
-from xmodule.editing_module import MetadataOnlyEditingDescriptor
-from xmodule.x_module import XModule
-from xmodule.course_module import CourseDescriptor
-from pkg_resources import resource_string
-from xblock.core import String, Scope, List
-
-log = logging.getLogger(__name__)
-
-
-class LTIError(Exception):
- pass
-
-
-class LTIFields(object):
- """
- Fields to define and obtain LTI tool from provider are set here,
- except credentials, which should be set in course settings::
-
- `lti_id` is id to connect tool with credentials in course settings.
- `launch_url` is launch url of tool.
- `custom_parameters` are additional parameters to navigate to proper book and book page.
-
- For example, for Vitalsource provider, `launch_url` should be
- *https://bc-staging.vitalsource.com/books/book*,
- and to get to proper book and book page, you should set custom parameters as::
-
- vbid=put_book_id_here
- book_location=page/put_page_number_here
-
- """
- lti_id = String(help="Id of the tool", default='', scope=Scope.settings)
- launch_url = String(help="URL of the tool", default='', scope=Scope.settings)
- custom_parameters = List(help="Custom parameters (vbid, book_location, etc..)", scope=Scope.settings)
-
-
-class LTIModule(LTIFields, XModule):
- '''
- Module provides LTI integration to course.
-
- Except usual xmodule structure it proceeds with oauth signing.
- How it works::
-
- 1. Get credentials from course settings.
-
- 2. There is minimal set of parameters need to be signed (presented for Vitalsource)::
-
- user_id
- oauth_callback
- lis_outcome_service_url
- lis_result_sourcedid
- launch_presentation_return_url
- lti_message_type
- lti_version
- role
- *+ all custom parameters*
-
- These parameters should be encoded and signed by *oauth1* together with
- `launch_url` and *POST* request type.
-
- 3. Signing proceeds with client key/secret pair obtained from course settings.
- That pair should be obtained from LTI provider and set into course settings by course author.
- After that signature and other oauth data are generated.
-
- Oauth data which is generated after signing is usual::
-
- oauth_callback
- oauth_nonce
- oauth_consumer_key
- oauth_signature_method
- oauth_timestamp
- oauth_version
-
-
- 4. All that data is passed to form and sent to LTI provider server by browser via
- autosubmit via javascript.
-
- Form example::
-
-
-
- 5. LTI provider has same secret key and it signs data string via *oauth1* and compares signatures.
-
- If signatures are correct, LTI provider redirects iframe source to LTI tool web page,
- and LTI tool is rendered to iframe inside course.
-
- Otherwise error message from LTI provider is generated.
- '''
-
- js = {'js': [resource_string(__name__, 'js/src/lti/lti.js')]}
- css = {'scss': [resource_string(__name__, 'css/lti/lti.scss')]}
- js_module_name = "LTI"
-
- def get_html(self):
- """
- Renders parameters to template.
- """
-
- # Obtains client_key and client_secret credentials from current course:
- course_id = self.runtime.course_id
- course_location = CourseDescriptor.id_to_location(course_id)
- course = self.descriptor.runtime.modulestore.get_item(course_location)
- client_key = client_secret = ''
- for lti_passport in course.lti_passports:
- try:
- lti_id, key, secret = lti_passport.split(':')
- except ValueError:
- raise LTIError('Could not parse LTI passport: {0!r}. \
- Should be "id:key:secret" string.'.format(lti_passport))
- if lti_id == self.lti_id:
- client_key, client_secret = key, secret
- break
-
- # parsing custom parameters to dict
- custom_parameters = {}
- for custom_parameter in self.custom_parameters:
- try:
- param_name, param_value = custom_parameter.split('=', 1)
- except ValueError:
- raise LTIError('Could not parse custom parameter: {0!r}. \
- Should be "x=y" string.'.format(custom_parameter))
-
- # LTI specs: 'custom_' should be prepended before each custom parameter
- custom_parameters[u'custom_' + unicode(param_name)] = unicode(param_value)
-
- input_fields = self.oauth_params(
- custom_parameters,
- client_key,
- client_secret
- )
-
- context = {
- 'input_fields': input_fields,
-
- # these params do not participate in oauth signing
- 'launch_url': self.launch_url,
- 'element_id': self.location.html_id(),
- 'element_class': self.location.category,
- }
-
- return self.system.render_template('lti.html', context)
-
- def oauth_params(self, custom_parameters, client_key, client_secret):
- """
- Signs request and returns signature and oauth parameters.
-
- `custom_paramters` is dict of parsed `custom_parameter` field
-
- `client_key` and `client_secret` are LTI tool credentials.
-
- Also *anonymous student id* is passed to template and therefore to LTI provider.
- """
-
- client = requests.auth.Client(
- client_key=unicode(client_key),
- client_secret=unicode(client_secret)
- )
-
- user_id = self.runtime.anonymous_student_id
- assert user_id is not None
-
- # must have parameters for correct signing from LTI:
- body = {
- u'user_id': user_id,
- u'oauth_callback': u'about:blank',
- u'lis_outcome_service_url': '',
- u'lis_result_sourcedid': '',
- u'launch_presentation_return_url': '',
- u'lti_message_type': u'basic-lti-launch-request',
- u'lti_version': 'LTI-1p0',
- u'role': u'student'
- }
-
- # appending custom parameter for signing
- body.update(custom_parameters)
-
- # This is needed for body encoding:
- headers = {'Content-Type': 'application/x-www-form-urlencoded'}
-
- __, headers, __ = client.sign(
- unicode(self.launch_url),
- http_method=u'POST',
- body=body,
- headers=headers)
- params = headers['Authorization']
- # parse headers to pass to template as part of context:
- params = dict([param.strip().replace('"', '').split('=') for param in params.split(',')])
-
- params[u'oauth_nonce'] = params[u'OAuth oauth_nonce']
- del params[u'OAuth oauth_nonce']
-
- # 0.14.2 (current) version of requests oauth library encodes signature,
- # with 'Content-Type': 'application/x-www-form-urlencoded'
- # so '='' becomes '%3D'.
- # We send form via browser, so browser will encode it again,
- # So we need to decode signature back:
- params[u'oauth_signature'] = urllib.unquote(params[u'oauth_signature']).decode('utf8')
-
- # add lti parameters to oauth parameters for sending in form
- params.update(body)
- return params
-
-
-class LTIModuleDescriptor(LTIFields, MetadataOnlyEditingDescriptor):
- """
- LTIModuleDescriptor provides no export/import to xml.
- """
- module_class = LTIModule
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/factories.py b/common/lib/xmodule/xmodule/modulestore/tests/factories.py
index c8228c5e3e..4ad801aef8 100644
--- a/common/lib/xmodule/xmodule/modulestore/tests/factories.py
+++ b/common/lib/xmodule/xmodule/modulestore/tests/factories.py
@@ -27,7 +27,7 @@ class XModuleCourseFactory(Factory):
store = editable_modulestore('direct')
# Write the data to the mongo datastore
- new_course = store.create_xmodule(location, metadata=kwargs.get('metadata', None))
+ new_course = store.create_xmodule(location)
# This metadata code was copied from cms/djangoapps/contentstore/views.py
if display_name is not None:
diff --git a/common/lib/xmodule/xmodule/tests/__init__.py b/common/lib/xmodule/xmodule/tests/__init__.py
index b7e5ea8435..fefa668a56 100644
--- a/common/lib/xmodule/xmodule/tests/__init__.py
+++ b/common/lib/xmodule/xmodule/tests/__init__.py
@@ -40,7 +40,7 @@ open_ended_grading_interface = {
}
-def get_test_system(course_id=''):
+def get_test_system():
"""
Construct a test ModuleSystem instance.
@@ -66,8 +66,7 @@ def get_test_system(course_id=''):
node_path=os.environ.get("NODE_PATH", "/usr/local/lib/node_modules"),
xblock_field_data=lambda descriptor: descriptor._field_data,
anonymous_student_id='student',
- open_ended_grading_interface=open_ended_grading_interface,
- course_id=course_id,
+ open_ended_grading_interface=open_ended_grading_interface
)
diff --git a/docs/developers/source/xmodule.rst b/docs/developers/source/xmodule.rst
index 77ee2ea684..008a1303d2 100644
--- a/docs/developers/source/xmodule.rst
+++ b/docs/developers/source/xmodule.rst
@@ -95,14 +95,6 @@ Html
:members:
:show-inheritance:
-
-LTI
-===
-
-.. automodule:: xmodule.lti_module
- :members:
- :show-inheritance:
-
Mako
====
diff --git a/lms/djangoapps/courseware/features/lti.feature b/lms/djangoapps/courseware/features/lti.feature
deleted file mode 100644
index abdcfdb704..0000000000
--- a/lms/djangoapps/courseware/features/lti.feature
+++ /dev/null
@@ -1,17 +0,0 @@
-Feature: LTI component
- As a student, I want to view LTI component in LMS.
-
- Scenario: LTI component in LMS is not rendered
- Given the course has correct LTI credentials
- And the course has an LTI component with incorrect fields
- Then I view the LTI and it is not rendered
-
- Scenario: LTI component in LMS is rendered
- Given the course has correct LTI credentials
- And the course has an LTI component filled with correct fields
- Then I view the LTI and it is rendered
-
- Scenario: LTI component in LMS is rendered incorrectly
- Given the course has incorrect LTI credentials
- And the course has an LTI component filled with correct fields
- Then I view the LTI but incorrect_signature warning is rendered
\ No newline at end of file
diff --git a/lms/djangoapps/courseware/features/lti.py b/lms/djangoapps/courseware/features/lti.py
deleted file mode 100644
index 0e91d5ed02..0000000000
--- a/lms/djangoapps/courseware/features/lti.py
+++ /dev/null
@@ -1,188 +0,0 @@
-#pylint: disable=C0111
-
-from django.contrib.auth.models import User
-from lettuce import world, step
-from lettuce.django import django_url
-from common import course_id
-
-from student.models import CourseEnrollment
-
-
-@step('I view the LTI and it is not rendered$')
-def lti_is_not_rendered(_step):
- # lti div has no class rendered
- assert world.is_css_not_present('div.lti.rendered')
-
- # error is shown
- assert world.css_visible('.error_message')
-
- # iframe is not visible
- assert not world.css_visible('iframe')
-
- #inside iframe test content is not presented
- with world.browser.get_iframe('ltiLaunchFrame') as iframe:
- # iframe does not contain functions from terrain/ui_helpers.py
- assert iframe.is_element_not_present_by_css('.result', wait_time=5)
-
-
-@step('I view the LTI and it is rendered$')
-def lti_is_rendered(_step):
- # lti div has class rendered
- assert world.is_css_present('div.lti.rendered')
-
- # error is hidden
- assert not world.css_visible('.error_message')
-
- # iframe is visible
- assert world.css_visible('iframe')
-
- #inside iframe test content is presented
- with world.browser.get_iframe('ltiLaunchFrame') as iframe:
- # iframe does not contain functions from terrain/ui_helpers.py
- assert iframe.is_element_present_by_css('.result', wait_time=5)
- assert ("This is LTI tool. Success." == world.retry_on_exception(
- lambda: iframe.find_by_css('.result')[0].text,
- max_attempts=5
- ))
-
-
-@step('I view the LTI but incorrect_signature warning is rendered$')
-def incorrect_lti_is_rendered(_step):
- # lti div has class rendered
- assert world.is_css_present('div.lti.rendered')
-
- # error is hidden
- assert not world.css_visible('.error_message')
-
- # iframe is visible
- assert world.css_visible('iframe')
-
- #inside iframe test content is presented
- with world.browser.get_iframe('ltiLaunchFrame') as iframe:
- # iframe does not contain functions from terrain/ui_helpers.py
- assert iframe.is_element_present_by_css('.result', wait_time=5)
- assert ("Wrong LTI signature" == world.retry_on_exception(
- lambda: iframe.find_by_css('.result')[0].text,
- max_attempts=5
- ))
-
-
-@step('the course has correct LTI credentials$')
-def set_correct_lti_passport(_step):
- coursenum = 'test_course'
- metadata = {
- 'lti_passports': ["correct_lti_id:{}:{}".format(
- world.lti_server.oauth_settings['client_key'],
- world.lti_server.oauth_settings['client_secret']
- )]
- }
- i_am_registered_for_the_course(coursenum, metadata)
-
-
-@step('the course has incorrect LTI credentials$')
-def set_incorrect_lti_passport(_step):
- coursenum = 'test_course'
- metadata = {
- 'lti_passports': ["test_lti_id:{}:{}".format(
- world.lti_server.oauth_settings['client_key'],
- "incorrect_lti_secret_key"
- )]
- }
- i_am_registered_for_the_course(coursenum, metadata)
-
-
-@step('the course has an LTI component filled with correct fields$')
-def add_correct_lti_to_course(_step):
- category = 'lti'
- world.ItemFactory.create(
- # parent_location=section_location(course),
- parent_location=world.scenario_dict['SEQUENTIAL'].location,
- category=category,
- display_name='LTI',
- metadata={
- 'lti_id': 'correct_lti_id',
- 'launch_url': world.lti_server.oauth_settings['lti_base'] + world.lti_server.oauth_settings['lti_endpoint']
- }
- )
- course = world.scenario_dict["COURSE"]
- chapter_name = world.scenario_dict['SECTION'].display_name.replace(
- " ", "_")
- section_name = chapter_name
- path = "/courses/{org}/{num}/{name}/courseware/{chapter}/{section}".format(
- org=course.org,
- num=course.number,
- name=course.display_name.replace(' ', '_'),
- chapter=chapter_name,
- section=section_name)
- url = django_url(path)
-
- world.browser.visit(url)
-
-
-@step('the course has an LTI component with incorrect fields$')
-def add_incorrect_lti_to_course(_step):
- category = 'lti'
- world.ItemFactory.create(
- parent_location=world.scenario_dict['SEQUENTIAL'].location,
- category=category,
- display_name='LTI',
- metadata={
- 'lti_id': 'incorrect_lti_id',
- 'lti_url': world.lti_server.oauth_settings['lti_base'] + world.lti_server.oauth_settings['lti_endpoint']
- }
- )
- course = world.scenario_dict["COURSE"]
- chapter_name = world.scenario_dict['SECTION'].display_name.replace(
- " ", "_")
- section_name = chapter_name
- path = "/courses/{org}/{num}/{name}/courseware/{chapter}/{section}".format(
- org=course.org,
- num=course.number,
- name=course.display_name.replace(' ', '_'),
- chapter=chapter_name,
- section=section_name)
- url = django_url(path)
-
- world.browser.visit(url)
-
-
-def create_course(course, metadata):
-
- # First clear the modulestore so we don't try to recreate
- # the same course twice
- # This also ensures that the necessary templates are loaded
- world.clear_courses()
-
- # Create the course
- # We always use the same org and display name,
- # but vary the course identifier (e.g. 600x or 191x)
- world.scenario_dict['COURSE'] = world.CourseFactory.create(
- org='edx',
- number=course,
- display_name='Test Course',
- metadata=metadata
- )
-
- # Add a section to the course to contain problems
- world.scenario_dict['SECTION'] = world.ItemFactory.create(
- parent_location=world.scenario_dict['COURSE'].location,
- display_name='Test Section'
- )
- world.scenario_dict['SEQUENTIAL'] = world.ItemFactory.create(
- parent_location=world.scenario_dict['SECTION'].location,
- category='sequential',
- display_name='Test Section')
-
-
-def i_am_registered_for_the_course(course, metadata):
- # Create the course
- create_course(course, metadata)
-
- # Create the user
- world.create_user('robot', 'test')
- usr = User.objects.get(username='robot')
-
- # If the user is not already enrolled, enroll the user.
- CourseEnrollment.enroll(usr, course_id(course))
-
- world.log_in(username='robot', password='test')
diff --git a/lms/djangoapps/courseware/features/lti_setup.py b/lms/djangoapps/courseware/features/lti_setup.py
deleted file mode 100644
index 0a6c4590dd..0000000000
--- a/lms/djangoapps/courseware/features/lti_setup.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#pylint: disable=C0111
-#pylint: disable=W0621
-
-from courseware.mock_lti_server.mock_lti_server import MockLTIServer
-from lettuce import before, after, world
-from django.conf import settings
-import threading
-
-from logging import getLogger
-logger = getLogger(__name__)
-
-
-@before.all
-def setup_mock_lti_server():
-
- server_host = '127.0.0.1'
-
- # Add +1 to XQUEUE random port number
- server_port = settings.XQUEUE_PORT + 1
-
- address = (server_host, server_port)
-
- # Create the mock server instance
- server = MockLTIServer(address)
- logger.debug("LTI server started at {} port".format(str(server_port)))
- # Start the server running in a separate daemon thread
- # Because the thread is a daemon, it will terminate
- # when the main thread terminates.
- server_thread = threading.Thread(target=server.serve_forever)
- server_thread.daemon = True
- server_thread.start()
-
- server.oauth_settings = {
- 'client_key': 'test_client_key',
- 'client_secret': 'test_client_secret',
- 'lti_base': 'http://{}:{}/'.format(server_host, server_port),
- 'lti_endpoint': 'correct_lti_endpoint'
- }
-
- # Store the server instance in lettuce's world
- # so that other steps can access it
- # (and we can shut it down later)
- world.lti_server = server
-
-
-@after.all
-def teardown_mock_lti_server(total):
-
- # Stop the LTI server and free up the port
- world.lti_server.shutdown()
diff --git a/lms/djangoapps/courseware/mock_lti_server/__init__.py b/lms/djangoapps/courseware/mock_lti_server/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/lms/djangoapps/courseware/mock_lti_server/mock_lti_server.py b/lms/djangoapps/courseware/mock_lti_server/mock_lti_server.py
deleted file mode 100644
index ba9cea84d6..0000000000
--- a/lms/djangoapps/courseware/mock_lti_server/mock_lti_server.py
+++ /dev/null
@@ -1,167 +0,0 @@
-from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
-import urlparse
-from requests.packages.oauthlib.oauth1.rfc5849 import signature
-import mock
-from logging import getLogger
-logger = getLogger(__name__)
-
-
-class MockLTIRequestHandler(BaseHTTPRequestHandler):
- '''
- A handler for LTI POST requests.
- '''
-
- protocol = "HTTP/1.0"
-
- def do_HEAD(self):
- self._send_head()
-
- def do_POST(self):
- '''
- Handle a POST request from the client and sends response back.
- '''
- self._send_head()
-
- post_dict = self._post_dict() # Retrieve the POST data
-
- logger.debug("LTI provider received POST request {} to path {}".format(
- str(post_dict),
- self.path)
- ) # Log the request
-
- # Respond only to requests with correct lti endpoint:
- if self._is_correct_lti_request():
- correct_keys = [
- 'user_id',
- 'role',
- 'oauth_nonce',
- 'oauth_timestamp',
- 'oauth_consumer_key',
- 'lti_version',
- 'oauth_signature_method',
- 'oauth_version',
- 'oauth_signature',
- 'lti_message_type',
- 'oauth_callback',
- 'lis_outcome_service_url',
- 'lis_result_sourcedid',
- 'launch_presentation_return_url'
- ]
-
- if sorted(correct_keys) != sorted(post_dict.keys()):
- status_message = "Incorrect LTI header"
- else:
- params = {k: v for k, v in post_dict.items() if k != 'oauth_signature'}
- if self.server.check_oauth_signature(params, post_dict['oauth_signature']):
- status_message = "This is LTI tool. Success."
- else:
- status_message = "Wrong LTI signature"
- else:
- status_message = "Invalid request URL"
-
- self._send_response(status_message)
-
- def _send_head(self):
- '''
- Send the response code and MIME headers
- '''
- if self._is_correct_lti_request():
- self.send_response(200)
- else:
- self.send_response(500)
-
- self.send_header('Content-type', 'text/html')
- self.end_headers()
-
- def _post_dict(self):
- '''
- Retrieve the POST parameters from the client as a dictionary
- '''
- try:
- length = int(self.headers.getheader('content-length'))
- post_dict = urlparse.parse_qs(self.rfile.read(length), keep_blank_values=True)
- # The POST dict will contain a list of values for each key.
- # None of our parameters are lists, however, so we map [val] --> val.
- # If the list contains multiple entries, we pick the first one
- post_dict = {key: val[0] for key, val in post_dict.items()}
- except:
- # We return an empty dict here, on the assumption
- # that when we later check that the request has
- # the correct fields, it won't find them,
- # and will therefore send an error response
- return {}
- return post_dict
-
- def _send_response(self, message):
- '''
- Send message back to the client
- '''
- response_str = """TEST TITLE
-
- IFrame loaded
\
- Server response is:
\
- {}
- """.format(message)
-
- # Log the response
- logger.debug("LTI: sent response {}".format(response_str))
-
- self.wfile.write(response_str)
-
- def _is_correct_lti_request(self):
- '''If url to LTI tool is correct.'''
- return self.server.oauth_settings['lti_endpoint'] in self.path
-
-
-class MockLTIServer(HTTPServer):
- '''
- A mock LTI provider server that responds
- to POST requests to localhost.
- '''
-
- def __init__(self, address):
- '''
- Initialize the mock XQueue server instance.
-
- *address* is the (host, host's port to listen to) tuple.
- '''
- handler = MockLTIRequestHandler
- HTTPServer.__init__(self, address, handler)
-
- def shutdown(self):
- '''
- Stop the server and free up the port
- '''
- # First call superclass shutdown()
- HTTPServer.shutdown(self)
- # We also need to manually close the socket
- self.socket.close()
-
- def check_oauth_signature(self, params, client_signature):
- '''
- Checks oauth signature from client.
-
- `params` are params from post request except signature,
- `client_signature` is signature from request.
-
- Builds mocked request and verifies hmac-sha1 signing::
- 1. builds string to sign from `params`, `url` and `http_method`.
- 2. signs it with `client_secret` which comes from server settings.
- 3. obtains signature after sign and then compares it with request.signature
- (request signature comes form client in request)
-
- Returns `True` if signatures are correct, otherwise `False`.
-
- '''
- client_secret = unicode(self.oauth_settings['client_secret'])
- url = self.oauth_settings['lti_base'] + self.oauth_settings['lti_endpoint']
-
- request = mock.Mock()
-
- request.params = [(unicode(k), unicode(v)) for k, v in params.items()]
- request.uri = unicode(url)
- request.http_method = u'POST'
- request.signature = unicode(client_signature)
-
- return signature.verify_hmac_sha1(request, client_secret)
-
diff --git a/lms/djangoapps/courseware/mock_lti_server/test_mock_lti_server.py b/lms/djangoapps/courseware/mock_lti_server/test_mock_lti_server.py
deleted file mode 100644
index 99650d5faa..0000000000
--- a/lms/djangoapps/courseware/mock_lti_server/test_mock_lti_server.py
+++ /dev/null
@@ -1,75 +0,0 @@
-"""
-Test for Mock_LTI_Server
-"""
-import unittest
-import threading
-import urllib
-from mock_lti_server import MockLTIServer
-
-from nose.plugins.skip import SkipTest
-
-
-class MockLTIServerTest(unittest.TestCase):
- '''
- A mock version of the LTI provider server that listens on a local
- port and responds with pre-defined grade messages.
-
- Used for lettuce BDD tests in lms/courseware/features/lti.feature
- '''
-
- def setUp(self):
-
- # This is a test of the test setup,
- # so it does not need to run as part of the unit test suite
- # You can re-enable it by commenting out the line below
- # raise SkipTest
-
- # Create the server
- server_port = 8034
- server_host = '127.0.0.1'
- address = (server_host, server_port)
- self.server = MockLTIServer(address)
- self.server.oauth_settings = {
- 'client_key': 'test_client_key',
- 'client_secret': 'test_client_secret',
- 'lti_base': 'http://{}:{}/'.format(server_host, server_port),
- 'lti_endpoint': 'correct_lti_endpoint'
- }
- # Start the server in a separate daemon thread
- server_thread = threading.Thread(target=self.server.serve_forever)
- server_thread.daemon = True
- server_thread.start()
-
- def tearDown(self):
-
- # Stop the server, freeing up the port
- self.server.shutdown()
-
- def test_request(self):
- """
- Tests that LTI server processes request with right program
- path, and responses with incorrect signature.
- """
- request = {
- 'user_id': 'default_user_id',
- 'role': 'student',
- 'oauth_nonce': '',
- 'oauth_timestamp': '',
- 'oauth_consumer_key': 'client_key',
- 'lti_version': 'LTI-1p0',
- 'oauth_signature_method': 'HMAC-SHA1',
- 'oauth_version': '1.0',
- 'oauth_signature': '',
- 'lti_message_type': 'basic-lti-launch-request',
- 'oauth_callback': 'about:blank',
- 'launch_presentation_return_url': '',
- 'lis_outcome_service_url': '',
- 'lis_result_sourcedid': ''
- }
-
- response_handle = urllib.urlopen(
- self.server.oauth_settings['lti_base'] + self.server.oauth_settings['lti_endpoint'],
- urllib.urlencode(request)
- )
- response = response_handle.read()
- self.assertTrue('Wrong LTI signature' in response)
diff --git a/lms/djangoapps/courseware/tests/__init__.py b/lms/djangoapps/courseware/tests/__init__.py
index 0a4d3508b8..88129cc8d1 100644
--- a/lms/djangoapps/courseware/tests/__init__.py
+++ b/lms/djangoapps/courseware/tests/__init__.py
@@ -86,7 +86,7 @@ class BaseTestXmodule(ModuleStoreTestCase):
data=self.DATA
)
- self.runtime = get_test_system(course_id=self.course.id)
+ self.runtime = get_test_system()
# Allow us to assert that the template was called in the same way from
# different code paths while maintaining the type returned by render_template
self.runtime.render_template = lambda template, context: u'{!r}, {!r}'.format(template, sorted(context.items()))
diff --git a/lms/djangoapps/courseware/tests/test_lti.py b/lms/djangoapps/courseware/tests/test_lti.py
deleted file mode 100644
index d2b4ea6867..0000000000
--- a/lms/djangoapps/courseware/tests/test_lti.py
+++ /dev/null
@@ -1,79 +0,0 @@
-"""LTI integration tests"""
-
-import requests
-from . import BaseTestXmodule
-from collections import OrderedDict
-import mock
-
-
-class TestLTI(BaseTestXmodule):
- """
- Integration test for lti xmodule.
-
- It checks overall code, by assuring that context that goes to template is correct.
- As part of that, checks oauth signature generation by mocking signing function of `requests` library.
- """
- CATEGORY = "lti"
-
- def setUp(self):
- """
- Mock oauth1 signing of requests library for testing.
- """
- super(TestLTI, self).setUp()
- mocked_nonce = u'135685044251684026041377608307'
- mocked_timestamp = u'1234567890'
- mocked_signature_after_sign = u'my_signature%3D'
- mocked_decoded_signature = u'my_signature='
-
- self.correct_headers = {
- u'oauth_callback': u'about:blank',
- u'lis_outcome_service_url': '',
- u'lis_result_sourcedid': '',
- u'launch_presentation_return_url': '',
- u'lti_message_type': u'basic-lti-launch-request',
- u'lti_version': 'LTI-1p0',
-
- u'oauth_nonce': mocked_nonce,
- u'oauth_timestamp': mocked_timestamp,
- u'oauth_consumer_key': u'',
- u'oauth_signature_method': u'HMAC-SHA1',
- u'oauth_version': u'1.0',
- u'user_id': self.runtime.anonymous_student_id,
- u'role': u'student',
- u'oauth_signature': mocked_decoded_signature
- }
-
- saved_sign = requests.auth.Client.sign
-
- def mocked_sign(self, *args, **kwargs):
- """
- Mocked oauth1 sign function.
- """
- # self is here:
- __, headers, __ = saved_sign(self, *args, **kwargs)
- # we should replace nonce, timestamp and signed_signature in headers:
- old = headers[u'Authorization']
- old_parsed = OrderedDict([param.strip().replace('"', '').split('=') for param in old.split(',')])
- old_parsed[u'OAuth oauth_nonce'] = mocked_nonce
- old_parsed[u'oauth_timestamp'] = mocked_timestamp
- old_parsed[u'oauth_signature'] = mocked_signature_after_sign
- headers[u'Authorization'] = ', '.join([k+'="'+v+'"' for k, v in old_parsed.items()])
- return None, headers, None
-
- patcher = mock.patch.object(requests.auth.Client, "sign", mocked_sign)
- patcher.start()
- self.addCleanup(patcher.stop)
-
- def test_lti_constructor(self):
- """
- Makes sure that all parameters extracted.
- """
- self.runtime.render_template = lambda template, context: context
- generated_context = self.item_module.get_html()
- expected_context = {
- 'input_fields': self.correct_headers,
- 'element_class': self.item_module.location.category,
- 'element_id': self.item_module.location.html_id(),
- 'launch_url': '', # default value
- }
- self.assertDictEqual(generated_context, expected_context)
diff --git a/lms/templates/lti.html b/lms/templates/lti.html
deleted file mode 100644
index 3d97c8d808..0000000000
--- a/lms/templates/lti.html
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
- ## This form will be hidden. Once available on the client, the LTI
- ## module JavaScript will trigget a "submit" on the form, and the
- ## result will be rendered to the below iFrame.
-
-
-
- Please provide launch_url. Click "Edit", and fill in the
- required fields.
-
-
- ## The result of the form submit will be rendered here.
-
-
-