Skip to content

Commit fea8dd8

Browse files
committed
feat: Allow adding custom LTI parameters via LTI_CUSTOM_PARAMS django setting
Adds a new Django setting called `LTI_CUSTOM_PARAMS` that allows extending the list of optional LTI parameters processed by the platform. These parameters can be used by plugins for deeper platform integration. (cherry picked from commit 0fde8c2)
1 parent a4df83a commit fea8dd8

3 files changed

Lines changed: 46 additions & 2 deletions

File tree

lms/djangoapps/lti_provider/tests/test_views.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
"""
22
Tests for the LTI provider views
33
"""
4-
5-
64
from unittest.mock import MagicMock, patch
75

86
from django.contrib.auth.models import AnonymousUser
97
from django.test import TestCase
108
from django.test.client import RequestFactory
9+
from django.test.utils import override_settings
1110
from django.urls import reverse
1211
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
1312

@@ -121,6 +120,23 @@ def test_valid_launch_with_optional_params(self, _authenticate, store_params, _r
121120
self.consumer
122121
)
123122

123+
@patch('lms.djangoapps.lti_provider.views.render_courseware')
124+
@patch('lms.djangoapps.lti_provider.views.store_outcome_parameters')
125+
@patch('lms.djangoapps.lti_provider.views.authenticate_lti_user')
126+
@override_settings(LTI_CUSTOM_PARAMS=["extra_param1", "extra_param2"])
127+
def test_valid_launch_with_extra_params(self, _authenticate, store_params, _render):
128+
"""
129+
Verifies that the LTI launch succeeds when passed a valid request.
130+
"""
131+
extra_params = {'extra_param1': 'extra_value1', 'extra_param2': "extra_value2"}
132+
request = build_launch_request(extra_post_data=LTI_OPTIONAL_PARAMS | extra_params)
133+
views.lti_launch(request, str(COURSE_KEY), str(USAGE_KEY))
134+
store_params.assert_called_with(
135+
dict(list(ALL_PARAMS.items()) + list(LTI_OPTIONAL_PARAMS.items()) + list(extra_params.items())),
136+
request.user,
137+
self.consumer
138+
)
139+
124140
@patch('lms.djangoapps.courseware.views.views.render_xblock')
125141
@patch('lms.djangoapps.lti_provider.views.authenticate_lti_user')
126142
def test_render_xblock_params(self, _authenticate, render):

lms/djangoapps/lti_provider/views.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from lms.djangoapps.lti_provider.outcomes import store_outcome_parameters
1919
from lms.djangoapps.lti_provider.signature_validator import SignatureValidator
2020
from lms.djangoapps.lti_provider.users import authenticate_lti_user
21+
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
2122
from openedx.core.lib.url_utils import unquote_slashes
2223

2324
log = logging.getLogger("edx.lti_provider")
@@ -59,6 +60,7 @@ def lti_launch(request, course_id, usage_id):
5960
if not params:
6061
return HttpResponseBadRequest()
6162
params.update(get_optional_parameters(request.POST))
63+
params.update(get_custom_parameters(request.POST))
6264

6365
# Get the consumer information from either the instance GUID or the consumer
6466
# key
@@ -145,6 +147,22 @@ def get_optional_parameters(dictionary):
145147
return {key: dictionary[key] for key in OPTIONAL_PARAMETERS if key in dictionary}
146148

147149

150+
def get_custom_parameters(params: dict[str]) -> dict[str]:
151+
"""
152+
Extract all optional LTI parameters from a dictionary. This method does not
153+
fail if any parameters are missing.
154+
155+
:param params: A dictionary containing zero or more parameters.
156+
:return: A new dictionary containing all optional parameters from the
157+
original dictionary, or an empty dictionary if no optional parameters
158+
were present.
159+
"""
160+
custom_params = configuration_helpers.get_value("LTI_CUSTOM_PARAMS", settings.LTI_CUSTOM_PARAMS)
161+
if not custom_params:
162+
return {}
163+
return {key: params[key] for key in custom_params if key in params}
164+
165+
148166
def render_courseware(request, usage_key):
149167
"""
150168
Render the content requested for the LTI launch.

lms/envs/common.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4450,6 +4450,16 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring
44504450
# The time value is in seconds.
44514451
LTI_AGGREGATE_SCORE_PASSBACK_DELAY = 15 * 60
44524452

4453+
4454+
# .. setting_name: LTI_CUSTOM_PARAMS
4455+
# .. setting_default: []
4456+
# .. setting_description: This expands the list of optional LTI parameters that the
4457+
# platform accepts. These parameters are not used by the platform, but can then
4458+
# be used by other plugins.
4459+
# .. setting_creation_date: 2025-08-22
4460+
# .. setting_tickets:
4461+
LTI_CUSTOM_PARAMS = []
4462+
44534463
# Credit notifications settings
44544464
NOTIFICATION_EMAIL_CSS = "templates/credit_notifications/credit_notification.css"
44554465
NOTIFICATION_EMAIL_EDX_LOGO = "templates/credit_notifications/edx-logo-header.png"

0 commit comments

Comments
 (0)