7474from web_fragments .fragment import Fragment
7575from xblock .core import List , Scope , String , XBlock
7676from 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
7883
7984from openedx .core .djangolib .markup import HTML , Text
8085from .lti_2_util import LTI20BlockMixin , LTIError
@@ -101,26 +106,116 @@ def noop(text):
101106
102107_ = noop
103108
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
105117 """
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::
108147
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
112154
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::
116155
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.
119158
120- Default non-empty URL for `launch_url` is needed due to oauthlib demand (URL scheme should be presented) ::
159+ Form example ::
121160
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.
123197 """
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
124219 display_name = String (
125220 display_name = _ ("Display Name" ),
126221 help = _ (
@@ -130,6 +225,7 @@ class LTIFields:
130225 scope = Scope .settings ,
131226 default = "LTI" ,
132227 )
228+
133229 lti_id = String (
134230 display_name = _ ("LTI ID" ),
135231 help = Text (_ (
@@ -145,6 +241,7 @@ class LTIFields:
145241 default = '' ,
146242 scope = Scope .settings
147243 )
244+
148245 launch_url = String (
149246 display_name = _ ("LTI URL" ),
150247 help = Text (_ (
@@ -158,6 +255,7 @@ class LTIFields:
158255 ),
159256 default = 'http://www.example.com' ,
160257 scope = Scope .settings )
258+
161259 custom_parameters = List (
162260 display_name = _ ("Custom Parameters" ),
163261 help = Text (_ (
@@ -170,6 +268,7 @@ class LTIFields:
170268 anchor_close = HTML ("</a>" )
171269 ),
172270 scope = Scope .settings )
271+
173272 open_in_a_new_page = Boolean (
174273 display_name = _ ("Open in New Page" ),
175274 help = _ (
@@ -180,6 +279,7 @@ class LTIFields:
180279 default = True ,
181280 scope = Scope .settings
182281 )
282+
183283 has_score = Boolean (
184284 display_name = _ ("Scored" ),
185285 help = _ (
@@ -188,6 +288,7 @@ class LTIFields:
188288 default = False ,
189289 scope = Scope .settings
190290 )
291+
191292 weight = Float (
192293 display_name = _ ("Weight" ),
193294 help = _ (
@@ -199,16 +300,19 @@ class LTIFields:
199300 scope = Scope .settings ,
200301 values = {"min" : 0 },
201302 )
303+
202304 module_score = Float (
203305 help = _ ("The score kept in the xblock KVS -- duplicate of the published score in django DB" ),
204306 default = None ,
205307 scope = Scope .user_state
206308 )
309+
207310 score_comment = String (
208311 help = _ ("Comment as returned from grader, LTI2.0 spec" ),
209312 default = "" ,
210313 scope = Scope .user_state
211314 )
315+
212316 hide_launch = Boolean (
213317 display_name = _ ("Hide External Tool" ),
214318 help = _ (
@@ -229,6 +333,7 @@ class LTIFields:
229333 default = False ,
230334 scope = Scope .settings
231335 )
336+
232337 ask_to_send_email = Boolean (
233338 display_name = _ ("Request user's email" ),
234339 # Translators: This is used to request the user's email for a third party service.
@@ -262,100 +367,12 @@ class LTIFields:
262367 default = True ,
263368 scope = Scope .settings
264369 )
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+ )
359376
360377 def max_score (self ):
361378 return self .weight if self .has_score else None
@@ -509,7 +526,7 @@ def preview_handler(self, _, __):
509526 """
510527 This is called to get context with new oauth params to iframe.
511528 """
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 ())
513530 return Response (template , content_type = 'text/html' )
514531
515532 @XBlock .handler
0 commit comments