44Some methods are meant to be used inside the XBlock, so they
55return plaintext to allow easy testing/mocking.
66"""
7+ from uuid import UUID
78
89import json
910
10- from opaque_keys .edx .keys import CourseKey
11+ from opaque_keys .edx .keys import CourseKey , UsageKey
1112
1213from lti_consumer .lti_1p3 .constants import LTI_1P3_ROLE_MAP
13- from .models import CourseAllowPIISharingInLTIFlag , LtiConfiguration , LtiDlContentItem
14+
15+ from .filters import get_external_config_from_filter
16+ from .models import CourseAllowPIISharingInLTIFlag , LtiConfiguration , LtiDlContentItem , LtiXBlockConfig
1417from .utils import (
1518 get_cache_key ,
1619 get_data_from_cache ,
17- get_lti_1p3_context_types_claim ,
18- get_lti_deeplinking_content_url ,
20+ get_lms_lti_access_token_link ,
1921 get_lms_lti_keyset_link ,
2022 get_lms_lti_launch_link ,
21- get_lms_lti_access_token_link ,
23+ get_lti_1p3_context_types_claim ,
24+ get_lti_deeplinking_content_url ,
2225)
23- from .filters import get_external_config_from_filter
2426
2527
26- def _get_or_create_local_lti_config (
27- lti_version ,
28- config_id ,
28+ def _get_or_create_local_lti_xblock_config (
29+ lti_version : str ,
30+ block_location : UsageKey | str ,
31+ config_id : str | None = None ,
2932 config_store = LtiConfiguration .CONFIG_ON_XBLOCK ,
3033 external_id = None ,
3134):
@@ -39,7 +42,14 @@ def _get_or_create_local_lti_config(
3942 This allows XBlock users to update the LTI version without needing to update the database.
4043 """
4144 # The create operation is only performed when there is no existing configuration for the block
42- lti_config , _ = LtiConfiguration .objects .get_or_create (config_id = config_id )
45+ lti_xblock_config , created = LtiXBlockConfig .objects .get_or_create (location = block_location )
46+ if created :
47+ if config_id :
48+ lti_config , _ = LtiConfiguration .objects .get_or_create (config_id = config_id )
49+ else :
50+ lti_config = LtiConfiguration .objects .create ()
51+ else :
52+ lti_config = lti_xblock_config .lti_configuration
4353
4454 lti_config .config_store = config_store
4555 lti_config .external_id = external_id
@@ -49,7 +59,7 @@ def _get_or_create_local_lti_config(
4959
5060 lti_config .save ()
5161
52- return lti_config
62+ return lti_xblock_config
5363
5464
5565def _get_config_by_config_id (config_id ):
@@ -59,16 +69,24 @@ def _get_config_by_config_id(config_id):
5969 return LtiConfiguration .objects .get (config_id = config_id )
6070
6171
72+ def _get_config_by_location (location : UsageKey | str ):
73+ """
74+ Gets the LTI xblock config by its UUID config ID
75+ """
76+ return LtiXBlockConfig .objects .get (location = location )
77+
78+
6279def _get_lti_config_for_block (block ):
6380 """
64- Retrieves or creates a LTI Configuration for a block.
81+ Retrieves or creates a LTI Xblock Configuration for a block.
6582
66- This wraps around `_get_or_create_local_lti_config ` and handles the block and modulestore
83+ This wraps around `_get_or_create_local_lti_xblock_config ` and handles the block and modulestore
6784 bits of configuration.
6885 """
6986 if block .config_type == 'database' :
70- lti_config = _get_or_create_local_lti_config (
87+ lti_xblock_config = _get_or_create_local_lti_xblock_config (
7188 block .lti_version ,
89+ block .scope_ids .usage_id ,
7290 block .config_id ,
7391 LtiConfiguration .CONFIG_ON_DB ,
7492 )
@@ -77,51 +95,54 @@ def _get_lti_config_for_block(block):
7795 {"course_key" : block .scope_ids .usage_id .context_key },
7896 block .external_config
7997 )
80- lti_config = _get_or_create_local_lti_config (
98+ lti_xblock_config = _get_or_create_local_lti_xblock_config (
8199 config .get ("version" ),
100+ block .scope_ids .usage_id ,
82101 block .config_id ,
83102 LtiConfiguration .CONFIG_EXTERNAL ,
84103 external_id = block .external_config ,
85104 )
86105 else :
87- lti_config = _get_or_create_local_lti_config (
106+ lti_xblock_config = _get_or_create_local_lti_xblock_config (
88107 block .lti_version ,
108+ block .scope_ids .usage_id ,
89109 block .config_id ,
90110 LtiConfiguration .CONFIG_ON_XBLOCK ,
91111 )
92- return lti_config
112+ return lti_xblock_config
93113
94114
95- def config_id_for_block (block ):
115+ def config_for_block (block ):
96116 """
97117 Returns the externally facing config_id of the LTI Configuration used by this block,
98118 creating one if required. That ID is suitable for use in launch data or get_consumer.
99119 """
100- config = _get_lti_config_for_block (block )
101- return config . config_id
120+ xblock_config = _get_lti_config_for_block (block )
121+ return xblock_config
102122
103123
104- def get_lti_consumer (config_id ):
124+ def get_lti_consumer (location : UsageKey ):
105125 """
106- Retrieves an LTI Consumer instance for a given configuration .
126+ Retrieves an LTI Consumer instance for a given location .
107127
108128 Returns an instance of LtiConsumer1p1 or LtiConsumer1p3 depending
109129 on the configuration.
110130 """
111131 # Return an instance of LTI 1.1 or 1.3 consumer, depending
112132 # on the configuration stored in the model.
113- return _get_config_by_config_id ( config_id ).get_lti_consumer ()
133+ return _get_config_by_location ( location ).get_lti_consumer ()
114134
115135
116136def get_lti_1p3_launch_info (
117137 launch_data ,
138+ location : UsageKey ,
118139):
119140 """
120141 Retrieves the Client ID, Keyset URL and other urls used to configure a LTI tool.
121142 """
122143 # Retrieve LTI Config and consumer
123- lti_config = _get_config_by_config_id ( launch_data . config_id )
124- lti_consumer = lti_config .get_lti_consumer ()
144+ lti_xblock_config = _get_config_by_location ( location )
145+ lti_consumer = lti_xblock_config .get_lti_consumer ()
125146
126147 # Check if deep Linking is available, if so, add some extra context:
127148 # Deep linking launch URL, and if deep linking is already configured
@@ -138,12 +159,13 @@ def get_lti_1p3_launch_info(
138159
139160 # Retrieve LTI Content Items (if any was set up)
140161 dl_content_items = LtiDlContentItem .objects .filter (
141- lti_configuration = lti_config
162+ lti_xblock_config = lti_xblock_config
142163 )
143164 # Add content item attributes to context
144165 if dl_content_items .exists ():
145166 deep_linking_content_items = [item .attributes for item in dl_content_items ]
146167
168+ lti_config = lti_xblock_config .lti_configuration
147169 config_id = lti_config .config_id
148170 client_id = lti_config .lti_1p3_client_id
149171
@@ -169,14 +191,15 @@ def get_lti_1p3_launch_info(
169191
170192def get_lti_1p3_launch_start_url (
171193 launch_data ,
194+ location : UsageKey ,
172195 deep_link_launch = False ,
173196 dl_content_id = None ,
174197):
175198 """
176199 Computes and retrieves the LTI URL that starts the OIDC flow.
177200 """
178201 # Retrieve LTI consumer
179- lti_consumer = get_lti_consumer (launch_data . config_id )
202+ lti_consumer = get_lti_consumer (location )
180203
181204 # Include a message hint in the launch_data depending on LTI launch type
182205 # Case 1: Performs Deep Linking configuration flow. Triggered by staff users to
@@ -194,6 +217,7 @@ def get_lti_1p3_launch_start_url(
194217
195218def get_lti_1p3_content_url (
196219 launch_data ,
220+ location : UsageKey ,
197221):
198222 """
199223 Computes and returns which URL the LTI consumer should launch to.
@@ -213,13 +237,14 @@ def get_lti_1p3_content_url(
213237
214238 # If there's no content items, return normal LTI launch URL
215239 if not content_items .count ():
216- return get_lti_1p3_launch_start_url (launch_data )
240+ return get_lti_1p3_launch_start_url (launch_data , location )
217241
218242 # If there's a single `ltiResourceLink` content, return the launch
219243 # url for that specific deep link
220244 if content_items .count () == 1 and content_items .get ().content_type == LtiDlContentItem .LTI_RESOURCE_LINK :
221245 return get_lti_1p3_launch_start_url (
222246 launch_data ,
247+ location ,
223248 dl_content_id = content_items .get ().id ,
224249 )
225250
0 commit comments