74
74
from web_fragments .fragment import Fragment
75
75
from xblock .core import List , Scope , String , XBlock
76
76
from xblock .fields import Boolean , Float
77
- from xblock .utils .resources import ResourceLoader
77
+ try :
78
+ from xblock .utils .resources import ResourceLoader
79
+ from xblock .utils .studio_editable import StudioEditableXBlockMixin
80
+ except ModuleNotFoundError :
81
+ from xblockutils .resources import ResourceLoader
82
+ from xblockutils .studio_editable import StudioEditableXBlockMixin
78
83
79
84
from openedx .core .djangolib .markup import HTML , Text
80
85
from .lti_2_util import LTI20BlockMixin , LTIError
@@ -101,26 +106,116 @@ def noop(text):
101
106
102
107
_ = noop
103
108
104
- class LTIFields :
109
+ @XBlock .needs ("i18n" )
110
+ @XBlock .needs ("user" )
111
+ @XBlock .needs ("rebind_user" )
112
+ class LTIBlock (
113
+ LTI20BlockMixin ,
114
+ StudioEditableXBlockMixin ,
115
+ XBlock ,
116
+ ): # pylint: disable=abstract-method
105
117
"""
106
- Fields to define and obtain LTI tool from provider are set here,
107
- except credentials, which should be set in course settings::
118
+ THIS MODULE IS DEPRECATED IN FAVOR OF https://github.com/openedx/xblock-lti-consumer
119
+
120
+ Module provides LTI integration to course.
121
+
122
+ Except usual Xmodule structure it proceeds with OAuth signing.
123
+ How it works::
124
+
125
+ 1. Get credentials from course settings.
126
+
127
+ 2. There is minimal set of parameters need to be signed (presented for Vitalsource)::
128
+
129
+ user_id
130
+ oauth_callback
131
+ lis_outcome_service_url
132
+ lis_result_sourcedid
133
+ launch_presentation_return_url
134
+ lti_message_type
135
+ lti_version
136
+ roles
137
+ *+ all custom parameters*
138
+
139
+ These parameters should be encoded and signed by *OAuth1* together with
140
+ `launch_url` and *POST* request type.
141
+
142
+ 3. Signing proceeds with client key/secret pair obtained from course settings.
143
+ That pair should be obtained from LTI provider and set into course settings by course author.
144
+ After that signature and other OAuth data are generated.
145
+
146
+ OAuth data which is generated after signing is usual::
108
147
109
- `lti_id` is id to connect tool with credentials in course settings. It should not contain :: (double semicolon)
110
- `launch_url` is launch URL of tool.
111
- `custom_parameters` are additional parameters to navigate to proper book and book page.
148
+ oauth_callback
149
+ oauth_nonce
150
+ oauth_consumer_key
151
+ oauth_signature_method
152
+ oauth_timestamp
153
+ oauth_version
112
154
113
- For example, for Vitalsource provider, `launch_url` should be
114
- *https://bc-staging.vitalsource.com/books/book*,
115
- and to get to proper book and book page, you should set custom parameters as::
116
155
117
- vbid=put_book_id_here
118
- book_location=page/put_page_number_here
156
+ 4. All that data is passed to form and sent to LTI provider server by browser via
157
+ autosubmit via JavaScript.
119
158
120
- Default non-empty URL for `launch_url` is needed due to oauthlib demand (URL scheme should be presented) ::
159
+ Form example ::
121
160
122
- https://github.com/idan/oauthlib/blob/master/oauthlib/oauth1/rfc5849/signature.py#L136
161
+ <form
162
+ action="${launch_url}"
163
+ name="ltiLaunchForm-${element_id}"
164
+ class="ltiLaunchForm"
165
+ method="post"
166
+ target="ltiLaunchFrame-${element_id}"
167
+ encType="application/x-www-form-urlencoded"
168
+ >
169
+ <input name="launch_presentation_return_url" value="" />
170
+ <input name="lis_outcome_service_url" value="" />
171
+ <input name="lis_result_sourcedid" value="" />
172
+ <input name="lti_message_type" value="basic-lti-launch-request" />
173
+ <input name="lti_version" value="LTI-1p0" />
174
+ <input name="oauth_callback" value="about:blank" />
175
+ <input name="oauth_consumer_key" value="${oauth_consumer_key}" />
176
+ <input name="oauth_nonce" value="${oauth_nonce}" />
177
+ <input name="oauth_signature_method" value="HMAC-SHA1" />
178
+ <input name="oauth_timestamp" value="${oauth_timestamp}" />
179
+ <input name="oauth_version" value="1.0" />
180
+ <input name="user_id" value="${user_id}" />
181
+ <input name="role" value="student" />
182
+ <input name="oauth_signature" value="${oauth_signature}" />
183
+
184
+ <input name="custom_1" value="${custom_param_1_value}" />
185
+ <input name="custom_2" value="${custom_param_2_value}" />
186
+ <input name="custom_..." value="${custom_param_..._value}" />
187
+
188
+ <input type="submit" value="Press to Launch" />
189
+ </form>
190
+
191
+ 5. LTI provider has same secret key and it signs data string via *OAuth1* and compares signatures.
192
+
193
+ If signatures are correct, LTI provider redirects iframe source to LTI tool web page,
194
+ and LTI tool is rendered to iframe inside course.
195
+
196
+ Otherwise error message from LTI provider is generated.
123
197
"""
198
+
199
+ # Indicates that this XBlock has been extracted from edx-platform.
200
+ is_extracted = True
201
+
202
+ ######################################
203
+ # LTI FIELDS #
204
+ ######################################
205
+ # `lti_id` is id to connect tool with credentials in course settings. It should not contain :: (double semicolon)
206
+ # `launch_url` is launch URL of tool.
207
+ # `custom_parameters` are additional parameters to navigate to proper book and book page.
208
+
209
+ # For example, for Vitalsource provider, `launch_url` should be
210
+ # *https://bc-staging.vitalsource.com/books/book*,
211
+ # and to get to proper book and book page, you should set custom parameters as::
212
+
213
+ # vbid=put_book_id_here
214
+ # book_location=page/put_page_number_here
215
+
216
+ # Default non-empty URL for `launch_url` is needed due to oauthlib demand (URL scheme should be presented)::
217
+
218
+ # https://github.com/idan/oauthlib/blob/master/oauthlib/oauth1/rfc5849/signature.py#L136
124
219
display_name = String (
125
220
display_name = _ ("Display Name" ),
126
221
help = _ (
@@ -130,6 +225,7 @@ class LTIFields:
130
225
scope = Scope .settings ,
131
226
default = "LTI" ,
132
227
)
228
+
133
229
lti_id = String (
134
230
display_name = _ ("LTI ID" ),
135
231
help = Text (_ (
@@ -145,6 +241,7 @@ class LTIFields:
145
241
default = '' ,
146
242
scope = Scope .settings
147
243
)
244
+
148
245
launch_url = String (
149
246
display_name = _ ("LTI URL" ),
150
247
help = Text (_ (
@@ -158,6 +255,7 @@ class LTIFields:
158
255
),
159
256
default = 'http://www.example.com' ,
160
257
scope = Scope .settings )
258
+
161
259
custom_parameters = List (
162
260
display_name = _ ("Custom Parameters" ),
163
261
help = Text (_ (
@@ -170,6 +268,7 @@ class LTIFields:
170
268
anchor_close = HTML ("</a>" )
171
269
),
172
270
scope = Scope .settings )
271
+
173
272
open_in_a_new_page = Boolean (
174
273
display_name = _ ("Open in New Page" ),
175
274
help = _ (
@@ -180,6 +279,7 @@ class LTIFields:
180
279
default = True ,
181
280
scope = Scope .settings
182
281
)
282
+
183
283
has_score = Boolean (
184
284
display_name = _ ("Scored" ),
185
285
help = _ (
@@ -188,6 +288,7 @@ class LTIFields:
188
288
default = False ,
189
289
scope = Scope .settings
190
290
)
291
+
191
292
weight = Float (
192
293
display_name = _ ("Weight" ),
193
294
help = _ (
@@ -199,16 +300,19 @@ class LTIFields:
199
300
scope = Scope .settings ,
200
301
values = {"min" : 0 },
201
302
)
303
+
202
304
module_score = Float (
203
305
help = _ ("The score kept in the xblock KVS -- duplicate of the published score in django DB" ),
204
306
default = None ,
205
307
scope = Scope .user_state
206
308
)
309
+
207
310
score_comment = String (
208
311
help = _ ("Comment as returned from grader, LTI2.0 spec" ),
209
312
default = "" ,
210
313
scope = Scope .user_state
211
314
)
315
+
212
316
hide_launch = Boolean (
213
317
display_name = _ ("Hide External Tool" ),
214
318
help = _ (
@@ -229,6 +333,7 @@ class LTIFields:
229
333
default = False ,
230
334
scope = Scope .settings
231
335
)
336
+
232
337
ask_to_send_email = Boolean (
233
338
display_name = _ ("Request user's email" ),
234
339
# Translators: This is used to request the user's email for a third party service.
@@ -262,100 +367,12 @@ class LTIFields:
262
367
default = True ,
263
368
scope = Scope .settings
264
369
)
265
-
266
-
267
- @XBlock .needs ("i18n" )
268
- @XBlock .needs ("user" )
269
- @XBlock .needs ("rebind_user" )
270
- class LTIBlock (
271
- XBlock ,
272
- LTIFields ,
273
- LTI20BlockMixin ,
274
- ): # pylint: disable=abstract-method
275
- """
276
- THIS MODULE IS DEPRECATED IN FAVOR OF https://github.com/openedx/xblock-lti-consumer
277
-
278
- Module provides LTI integration to course.
279
-
280
- Except usual Xmodule structure it proceeds with OAuth signing.
281
- How it works::
282
-
283
- 1. Get credentials from course settings.
284
-
285
- 2. There is minimal set of parameters need to be signed (presented for Vitalsource)::
286
-
287
- user_id
288
- oauth_callback
289
- lis_outcome_service_url
290
- lis_result_sourcedid
291
- launch_presentation_return_url
292
- lti_message_type
293
- lti_version
294
- roles
295
- *+ all custom parameters*
296
-
297
- These parameters should be encoded and signed by *OAuth1* together with
298
- `launch_url` and *POST* request type.
299
-
300
- 3. Signing proceeds with client key/secret pair obtained from course settings.
301
- That pair should be obtained from LTI provider and set into course settings by course author.
302
- After that signature and other OAuth data are generated.
303
-
304
- OAuth data which is generated after signing is usual::
305
-
306
- oauth_callback
307
- oauth_nonce
308
- oauth_consumer_key
309
- oauth_signature_method
310
- oauth_timestamp
311
- oauth_version
312
-
313
-
314
- 4. All that data is passed to form and sent to LTI provider server by browser via
315
- autosubmit via JavaScript.
316
-
317
- Form example::
318
-
319
- <form
320
- action="${launch_url}"
321
- name="ltiLaunchForm-${element_id}"
322
- class="ltiLaunchForm"
323
- method="post"
324
- target="ltiLaunchFrame-${element_id}"
325
- encType="application/x-www-form-urlencoded"
326
- >
327
- <input name="launch_presentation_return_url" value="" />
328
- <input name="lis_outcome_service_url" value="" />
329
- <input name="lis_result_sourcedid" value="" />
330
- <input name="lti_message_type" value="basic-lti-launch-request" />
331
- <input name="lti_version" value="LTI-1p0" />
332
- <input name="oauth_callback" value="about:blank" />
333
- <input name="oauth_consumer_key" value="${oauth_consumer_key}" />
334
- <input name="oauth_nonce" value="${oauth_nonce}" />
335
- <input name="oauth_signature_method" value="HMAC-SHA1" />
336
- <input name="oauth_timestamp" value="${oauth_timestamp}" />
337
- <input name="oauth_version" value="1.0" />
338
- <input name="user_id" value="${user_id}" />
339
- <input name="role" value="student" />
340
- <input name="oauth_signature" value="${oauth_signature}" />
341
-
342
- <input name="custom_1" value="${custom_param_1_value}" />
343
- <input name="custom_2" value="${custom_param_2_value}" />
344
- <input name="custom_..." value="${custom_param_..._value}" />
345
-
346
- <input type="submit" value="Press to Launch" />
347
- </form>
348
-
349
- 5. LTI provider has same secret key and it signs data string via *OAuth1* and compares signatures.
350
-
351
- If signatures are correct, LTI provider redirects iframe source to LTI tool web page,
352
- and LTI tool is rendered to iframe inside course.
353
-
354
- Otherwise error message from LTI provider is generated.
355
- """
356
-
357
- # Indicates that this XBlock has been extracted from edx-platform.
358
- is_extracted = True
370
+
371
+ editable_fields = (
372
+ "accept_grades_past_due" , "button_text" , "custom_parameters" , "display_name" ,
373
+ "hide_launch" , "description" , "lti_id" , "launch_url" , "open_in_a_new_page" ,
374
+ "ask_to_send_email" , "ask_to_send_username" , "has_score" , "weight" ,
375
+ )
359
376
360
377
def max_score (self ):
361
378
return self .weight if self .has_score else None
@@ -509,7 +526,7 @@ def preview_handler(self, _, __):
509
526
"""
510
527
This is called to get context with new oauth params to iframe.
511
528
"""
512
- template = resource_loader .load_unicode ("templates/lti_form.html" ). format ( ** self .get_context ())
529
+ template = resource_loader .render_django_template ("templates/lti_form.html" , self .get_context ())
513
530
return Response (template , content_type = 'text/html' )
514
531
515
532
@XBlock .handler
0 commit comments