Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: LTI 1.3 reusable configuration #390

24 changes: 24 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,30 @@ This XBlock supports `LTI 2.0 Result Service 2.0 <https://www.imsglobal.org/lti/
Please see the `LTI 2.0 Result Service 2.0 instructions <https://github.com/openedx/xblock-lti-consumer/tree/master/docs/result_service.rst>`_
for testing the LTI 2.0 Result Service 2.0 implementation.

LTI Reusable configuration
**************************

The LTI Consumer XBlock supports configuration reusability via plugins.
It is compatible with both LTI 1.1 and LTI 1.3.
All values (including the access token and keyset URL for LTI 1.3)
are shared across the XBlocks with the same external configuration ID.
This eliminates the need to have a tool deployment for each XBlock.

How to Setup
============

1. Install and setup the openedx-ltistore plugin on the LMS and studio
(https://github.com/open-craft/openedx-ltistore):
2. Go to LMS admin > WAFFLE_UTILS > Waffle flag course override
(http://localhost:18010/admin/waffle_utils/waffleflagcourseoverridemodel/).
3. Create a waffle flag course override with these values:
- Waffle flag: lti_consumer.enable_external_config_filter
- Course id: <your course id>
- Override choice: Force On
- Enabled: True
4. Create a new external LTI configuration and use it on the XBlock.
(This is explaioned on the README of the openedx-ltistore repository).
Agrendalath marked this conversation as resolved.
Show resolved Hide resolved

Getting Help
************

Expand Down
80 changes: 0 additions & 80 deletions docs/reusable_configuration.rst

This file was deleted.

2 changes: 1 addition & 1 deletion lti_consumer/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ def sync_configurations(self):
otherwise, it will try to query any children configuration and update their fields using
the current configuration values.
"""
EXCLUDED_FIELDS = ['id', 'config_id', 'location']
EXCLUDED_FIELDS = ['id', 'config_id', 'location', 'external_config']

if isinstance(self.location, CCXBlockUsageLocator):
# Query main configuration using main location.
Expand Down
10 changes: 8 additions & 2 deletions lti_consumer/tests/unit/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,10 @@ def test_sync_configurations_with_ccx_location(
call(location=self.lti_1p3_config.location.to_block_locator()),
call().first(),
])
model_to_dict_mock.assert_called_once_with(filter_mock.return_value.first(), ['id', 'config_id', 'location'])
model_to_dict_mock.assert_called_once_with(
filter_mock.return_value.first(),
['id', 'config_id', 'location', 'external_config'],
)
setattr_mock.assert_called_once_with(self.lti_1p3_config, 'test', 'test')

@patch('lti_consumer.models.isinstance', return_value=False)
Expand All @@ -508,7 +511,10 @@ def test_sync_configurations_with_location(
call().filter().exclude(id=self.lti_1p3_config.pk),
call().filter().exclude().update(**model_to_dict_mock),
])
model_to_dict_mock.assert_called_once_with(self.lti_1p3_config, ['id', 'config_id', 'location'])
model_to_dict_mock.assert_called_once_with(
self.lti_1p3_config,
['id', 'config_id', 'location', 'external_config'],
)

@patch('lti_consumer.models.isinstance', return_value=False)
@patch.object(LtiConfiguration.objects, 'filter', side_effect=IndexError())
Expand Down
Loading