Setting some default parameters when adding an lti instance
[moodle.git] / mod / lti / locallib.php
CommitLineData
b7e436b0
CS
1<?php\r
2// This file is part of BasicLTI4Moodle\r
3//\r
4// BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability)\r
5// consumer for Moodle 1.9 and Moodle 2.0. BasicLTI is a IMS Standard that allows web\r
6// based learning tools to be easily integrated in LMS as native ones. The IMS BasicLTI\r
7// specification is part of the IMS standard Common Cartridge 1.1 Sakai and other main LMS\r
8// are already supporting or going to support BasicLTI. This project Implements the consumer\r
9// for Moodle. Moodle is a Free Open source Learning Management System by Martin Dougiamas.\r
10// BasicLTI4Moodle is a project iniciated and leaded by Ludo(Marc Alier) and Jordi Piguillem\r
11// at the GESSI research group at UPC.\r
12// SimpleLTI consumer for Moodle is an implementation of the early specification of LTI\r
13// by Charles Severance (Dr Chuck) htp://dr-chuck.com , developed by Jordi Piguillem in a\r
14// Google Summer of Code 2008 project co-mentored by Charles Severance and Marc Alier.\r
15//\r
16// BasicLTI4Moodle is copyright 2009 by Marc Alier Forment, Jordi Piguillem and Nikolas Galanis\r
17// of the Universitat Politecnica de Catalunya http://www.upc.edu\r
18// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu\r
19//\r
20// Moodle is free software: you can redistribute it and/or modify\r
21// it under the terms of the GNU General Public License as published by\r
22// the Free Software Foundation, either version 3 of the License, or\r
23// (at your option) any later version.\r
24//\r
25// Moodle is distributed in the hope that it will be useful,\r
26// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
27// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
28// GNU General Public License for more details.\r
29//\r
30// You should have received a copy of the GNU General Public License\r
31// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\r
32\r
33/**\r
34 * This file contains the library of functions and constants for the basiclti module\r
35 *\r
73300339 36 * @package lti\r
b7e436b0
CS
37 * @copyright 2009 Marc Alier, Jordi Piguillem, Nikolas Galanis\r
38 * marc.alier@upc.edu\r
39 * @copyright 2009 Universitat Politecnica de Catalunya http://www.upc.edu\r
40 *\r
41 * @author Marc Alier\r
42 * @author Jordi Piguillem\r
43 * @author Nikolas Galanis\r
44 *\r
45 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\r
46 */\r
47\r
48defined('MOODLE_INTERNAL') || die;\r
49\r
73300339 50require_once($CFG->dirroot.'/mod/lti/OAuth.php');\r
b7e436b0 51\r
73300339 52define('LTI_URL_DOMAIN_REGEX', '/(?:https?:\/\/)?(?:www\.)?([^\/]+)(?:\/|$)/i');\r
5f24742f 53\r
73300339
CS
54define('LTI_LAUNCH_CONTAINER_DEFAULT', 1);\r
55define('LTI_LAUNCH_CONTAINER_EMBED', 2);\r
56define('LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS', 3);\r
57define('LTI_LAUNCH_CONTAINER_WINDOW', 4);\r
d97d72aa 58\r
879e97bd 59define('LTI_TOOL_STATE_ANY', 0);\r
a4a07996
CS
60define('LTI_TOOL_STATE_CONFIGURED', 1);\r
61define('LTI_TOOL_STATE_PENDING', 2);\r
62define('LTI_TOOL_STATE_REJECTED', 3);\r
63\r
a0eeacf9
CS
64define('LTI_SETTING_NEVER', 0);\r
65define('LTI_SETTING_ALWAYS', 1);\r
66define('LTI_SETTING_DEFAULT', 2);\r
67\r
b7e436b0
CS
68/**\r
69 * Prints a Basic LTI activity\r
70 *\r
71 * $param int $basicltiid Basic LTI activity id\r
72 */\r
73300339 73function lti_view($instance, $makeobject=false) {\r
a0eeacf9 74 global $PAGE, $CFG;\r
b7e436b0 75\r
5f24742f 76 if(empty($instance->typeid)){\r
73300339 77 $tool = lti_get_tool_by_url_match($instance->toolurl);\r
5f24742f
CS
78 if($tool){\r
79 $typeid = $tool->id;\r
80 } else {\r
a0eeacf9 81 $typeid = null;\r
5f24742f
CS
82 }\r
83 } else {\r
84 $typeid = $instance->typeid;\r
85 }\r
86 \r
a0eeacf9
CS
87 if($typeid){\r
88 $typeconfig = lti_get_type_config($typeid);\r
89 } else {\r
90 //There is no admin configuration for this tool. Use configuration in the lti instance record plus some defaults.\r
91 $typeconfig = (array)$instance;\r
92 \r
93 $typeconfig['sendname'] = $instance->instructorchoicesendname;\r
94 $typeconfig['sendemailaddr'] = $instance->instructorchoicesendemailaddr;\r
95 $typeconfig['customparameters'] = $instance->instructorcustomparameters;\r
96 }\r
97 \r
98 //Default the organizationid if not specified\r
99 if(empty($typeconfig['organizationid'])){\r
100 $urlparts = parse_url($CFG->wwwroot);\r
101 \r
102 $typeconfig['organizationid'] = $urlparts['host'];\r
103 }\r
104 \r
5f24742f
CS
105 $endpoint = !empty($instance->toolurl) ? $instance->toolurl : $typeconfig['toolurl'];\r
106 $key = !empty($instance->resourcekey) ? $instance->resourcekey : $typeconfig['resourcekey'];\r
107 $secret = !empty($instance->password) ? $instance->password : $typeconfig['password'];\r
b7e436b0
CS
108 $orgid = $typeconfig['organizationid'];\r
109 /* Suppress this for now - Chuck\r
110 $orgdesc = $typeconfig['organizationdescr'];\r
111 */\r
112\r
113 $course = $PAGE->course;\r
73300339 114 $requestparams = lti_build_request($instance, $typeconfig, $course);\r
b7e436b0
CS
115\r
116 // Make sure we let the tool know what LMS they are being called from\r
117 $requestparams["ext_lms"] = "moodle-2";\r
118\r
119 // Add oauth_callback to be compliant with the 1.0A spec\r
120 $requestparams["oauth_callback"] = "about:blank";\r
121\r
73300339 122 $submittext = get_string('press_to_submit', 'lti');\r
b7e436b0
CS
123 $parms = sign_parameters($requestparams, $endpoint, "POST", $key, $secret, $submittext, $orgid /*, $orgdesc*/);\r
124\r
125 $debuglaunch = ( $instance->debuglaunch == 1 );\r
0d8afb44
CS
126 \r
127 $content = post_launch_html($parms, $endpoint, $debuglaunch);\r
128 \r
0d8afb44 129 echo $content;\r
b7e436b0
CS
130}\r
131\r
132/**\r
133 * This function builds the request that must be sent to the tool producer\r
134 *\r
135 * @param object $instance Basic LTI instance object\r
136 * @param object $typeconfig Basic LTI tool configuration\r
137 * @param object $course Course object\r
138 *\r
139 * @return array $request Request details\r
140 */\r
73300339 141function lti_build_request($instance, $typeconfig, $course) {\r
b7e436b0
CS
142 global $USER, $CFG;\r
143\r
144 $context = get_context_instance(CONTEXT_COURSE, $course->id);\r
73300339 145 $role = lti_get_ims_role($USER, $context);\r
b7e436b0
CS
146\r
147 $locale = $course->lang;\r
148 if ( strlen($locale) < 1 ) {\r
149 $locale = $CFG->lang;\r
150 }\r
151\r
152 $requestparams = array(\r
153 "resource_link_id" => $instance->id,\r
154 "resource_link_title" => $instance->name,\r
155 "resource_link_description" => $instance->intro,\r
156 "user_id" => $USER->id,\r
157 "roles" => $role,\r
158 "context_id" => $course->id,\r
159 "context_label" => $course->shortname,\r
160 "context_title" => $course->fullname,\r
161 "launch_presentation_locale" => $locale,\r
162 );\r
163\r
5f24742f 164 $placementsecret = $typeconfig['servicesalt'];\r
b7e436b0
CS
165 if ( isset($placementsecret) ) {\r
166 $suffix = ':::' . $USER->id . ':::' . $instance->id;\r
167 $plaintext = $placementsecret . $suffix;\r
168 $hashsig = hash('sha256', $plaintext, false);\r
169 $sourcedid = $hashsig . $suffix;\r
170 }\r
171\r
172 if ( isset($placementsecret) &&\r
173 ( $typeconfig['acceptgrades'] == 1 ||\r
174 ( $typeconfig['acceptgrades'] == 2 && $instance->instructorchoiceacceptgrades == 1 ) ) ) {\r
175 $requestparams["lis_result_sourcedid"] = $sourcedid;\r
73300339 176 $requestparams["ext_ims_lis_basic_outcome_url"] = $CFG->wwwroot.'/mod/lti/service.php';\r
b7e436b0
CS
177 }\r
178\r
179 if ( isset($placementsecret) &&\r
180 ( $typeconfig['allowroster'] == 1 ||\r
181 ( $typeconfig['allowroster'] == 2 && $instance->instructorchoiceallowroster == 1 ) ) ) {\r
182 $requestparams["ext_ims_lis_memberships_id"] = $sourcedid;\r
73300339 183 $requestparams["ext_ims_lis_memberships_url"] = $CFG->wwwroot.'/mod/lti/service.php';\r
b7e436b0
CS
184 }\r
185\r
b7e436b0
CS
186 // Send user's name and email data if appropriate\r
187 if ( $typeconfig['sendname'] == 1 ||\r
188 ( $typeconfig['sendname'] == 2 && $instance->instructorchoicesendname == 1 ) ) {\r
189 $requestparams["lis_person_name_given"] = $USER->firstname;\r
190 $requestparams["lis_person_name_family"] = $USER->lastname;\r
191 $requestparams["lis_person_name_full"] = $USER->firstname." ".$USER->lastname;\r
192 }\r
193\r
194 if ( $typeconfig['sendemailaddr'] == 1 ||\r
195 ( $typeconfig['sendemailaddr'] == 2 && $instance->instructorchoicesendemailaddr == 1 ) ) {\r
196 $requestparams["lis_person_contact_email_primary"] = $USER->email;\r
197 }\r
198\r
199 // Concatenate the custom parameters from the administrator and the instructor\r
200 // Instructor parameters are only taken into consideration if the administrator\r
201 // has giver permission\r
202 $customstr = $typeconfig['customparameters'];\r
203 $instructorcustomstr = $instance->instructorcustomparameters;\r
204 $custom = array();\r
205 $instructorcustom = array();\r
206 if ($customstr) {\r
207 $custom = split_custom_parameters($customstr);\r
208 }\r
209 if (!isset($typeconfig['allowinstructorcustom']) || $typeconfig['allowinstructorcustom'] == 0) {\r
210 $requestparams = array_merge($custom, $requestparams);\r
211 } else {\r
212 if ($instructorcustomstr) {\r
213 $instructorcustom = split_custom_parameters($instructorcustomstr);\r
214 }\r
215 foreach ($instructorcustom as $key => $val) {\r
216 if (array_key_exists($key, $custom)) {\r
217 // Ignore the instructor's parameter\r
218 } else {\r
219 $custom[$key] = $val;\r
220 }\r
221 }\r
222 $requestparams = array_merge($custom, $requestparams);\r
223 }\r
224\r
225 return $requestparams;\r
226}\r
227\r
228/**\r
229 * Splits the custom parameters field to the various parameters\r
230 *\r
231 * @param string $customstr String containing the parameters\r
232 *\r
233 * @return Array of custom parameters\r
234 */\r
235function split_custom_parameters($customstr) {\r
236 $textlib = textlib_get_instance();\r
237\r
238 $lines = preg_split("/[\n;]/", $customstr);\r
239 $retval = array();\r
240 foreach ($lines as $line) {\r
241 $pos = strpos($line, "=");\r
242 if ( $pos === false || $pos < 1 ) {\r
243 continue;\r
244 }\r
245 $key = trim($textlib->substr($line, 0, $pos));\r
246 $val = trim($textlib->substr($line, $pos+1));\r
247 $key = map_keyname($key);\r
248 $retval['custom_'.$key] = $val;\r
249 }\r
250 return $retval;\r
251}\r
252\r
253/**\r
254 * Used for building the names of the different custom parameters\r
255 *\r
256 * @param string $key Parameter name\r
257 *\r
258 * @return string Processed name\r
259 */\r
260function map_keyname($key) {\r
261 $textlib = textlib_get_instance();\r
262\r
263 $newkey = "";\r
264 $key = $textlib->strtolower(trim($key));\r
265 foreach (str_split($key) as $ch) {\r
266 if ( ($ch >= 'a' && $ch <= 'z') || ($ch >= '0' && $ch <= '9') ) {\r
267 $newkey .= $ch;\r
268 } else {\r
269 $newkey .= '_';\r
270 }\r
271 }\r
272 return $newkey;\r
273}\r
274\r
275/**\r
276 * Returns the IMS user role in a given context\r
277 *\r
278 * This function queries Moodle for an user role and\r
279 * returns the correspondant IMS role\r
280 *\r
281 * @param StdClass $user Moodle user instance\r
282 * @param StdClass $context Moodle context\r
283 *\r
284 * @return string IMS Role\r
285 *\r
286 */\r
73300339 287function lti_get_ims_role($user, $context) {\r
b7e436b0
CS
288\r
289 $roles = get_user_roles($context, $user->id);\r
290 $rolesname = array();\r
291 foreach ($roles as $role) {\r
292 $rolesname[] = $role->shortname;\r
293 }\r
294\r
295 if (in_array('admin', $rolesname) || in_array('coursecreator', $rolesname)) {\r
73300339 296 return get_string('imsroleadmin', 'lti');\r
b7e436b0
CS
297 }\r
298\r
299 if (in_array('editingteacher', $rolesname) || in_array('teacher', $rolesname)) {\r
73300339 300 return get_string('imsroleinstructor', 'lti');\r
b7e436b0
CS
301 }\r
302\r
73300339 303 return get_string('imsrolelearner', 'lti');\r
b7e436b0
CS
304}\r
305\r
306/**\r
307 * Returns configuration details for the tool\r
308 *\r
309 * @param int $typeid Basic LTI tool typeid\r
310 *\r
311 * @return array Tool Configuration\r
312 */\r
73300339 313function lti_get_type_config($typeid) {\r
b7e436b0
CS
314 global $DB;\r
315\r
316 $typeconfig = array();\r
73300339 317 $configs = $DB->get_records('lti_types_config', array('typeid' => $typeid));\r
b7e436b0
CS
318 if (!empty($configs)) {\r
319 foreach ($configs as $config) {\r
320 $typeconfig[$config->name] = $config->value;\r
321 }\r
322 }\r
323 return $typeconfig;\r
324}\r
325\r
a0eeacf9
CS
326function lti_get_tools_by_url($url, $state){\r
327 $domain = lti_get_domain_from_url($url);\r
5f24742f 328 \r
a0eeacf9
CS
329 return lti_get_tools_by_domain($domain, $state);\r
330}\r
331\r
332function lti_get_tools_by_domain($domain, $state = null, $courseid = null){\r
333 global $DB, $SITE;\r
334 \r
335 $filters = array('tooldomain' => $domain);\r
336 \r
337 $statefilter = '';\r
338 $coursefilter = '';\r
339 \r
340 if($state){\r
341 $statefilter = 'AND state = :state';\r
342 }\r
343 \r
344 if($courseid && $courseid != $SITE->id){\r
345 $coursefilter = 'OR course = :courseid';\r
346 }\r
347 \r
348 $query = <<<QUERY\r
349 SELECT * FROM {lti_types}\r
350 WHERE\r
351 tooldomain = :tooldomain\r
352 AND (course = :siteid $coursefilter)\r
353 $statefilter\r
354QUERY;\r
355 \r
356 return $DB->get_records_sql($query, array(\r
357 'courseid' => $courseid, \r
358 'siteid' => $SITE->id, \r
359 'tooldomain' => $domain, \r
360 'state' => $state\r
361 ));\r
b7e436b0
CS
362}\r
363\r
364/**\r
365 * Returns all basicLTI tools configured by the administrator\r
366 *\r
367 */\r
73300339 368function lti_filter_get_types() {\r
b7e436b0
CS
369 global $DB;\r
370\r
73300339 371 return $DB->get_records('lti_types');\r
b7e436b0
CS
372}\r
373\r
73300339 374function lti_get_types_for_add_instance(){\r
0d8afb44 375 global $DB;\r
73300339 376 $admintypes = $DB->get_records('lti_types', array('coursevisible' => 1));\r
285f8250
CS
377 \r
378 $types = array();\r
73300339 379 $types[0] = get_string('automatic', 'lti');\r
285f8250
CS
380 \r
381 foreach($admintypes as $type) {\r
382 $types[$type->id] = $type->name;\r
383 }\r
384 \r
385 return $types;\r
386}\r
387\r
73300339 388function lti_get_domain_from_url($url){\r
5f24742f
CS
389 $matches = array();\r
390 \r
73300339 391 if(preg_match(LTI_URL_DOMAIN_REGEX, $url, $matches)){\r
5f24742f
CS
392 return $matches[1];\r
393 }\r
394}\r
395\r
879e97bd
CS
396function lti_get_tool_by_url_match($url, $courseid = null, $state = LTI_TOOL_STATE_CONFIGURED){\r
397 $possibletools = lti_get_tools_by_url($url, $state, $courseid);\r
5f24742f 398 \r
73300339 399 return lti_get_best_tool_by_url($url, $possibletools);\r
5f24742f
CS
400}\r
401\r
a0eeacf9
CS
402function lti_get_url_thumbprint($url){\r
403 $urlparts = parse_url(strtolower($url));\r
404 if(!isset($urlparts['path'])){\r
405 $urlparts['path'] = '';\r
406 }\r
407 \r
408 if(substr($urlparts['host'], 0, 3) === 'www'){\r
409 $urllparts['host'] = substr(3);\r
410 }\r
411 \r
412 return $urllower = $urlparts['host'] . '/' . $urlparts['path'];\r
413}\r
414\r
73300339 415function lti_get_best_tool_by_url($url, $tools){\r
5f24742f
CS
416 if(count($tools) === 0){\r
417 return null;\r
418 }\r
419 \r
a0eeacf9 420 $urllower = lti_get_url_thumbprint($url);\r
5f24742f
CS
421 \r
422 foreach($tools as $tool){\r
423 $tool->_matchscore = 0;\r
a0eeacf9
CS
424 \r
425 $toolbaseurllower = lti_get_url_thumbprint($tool->baseurl);\r
5f24742f
CS
426 \r
427 if($urllower === $toolbaseurllower){\r
a0eeacf9 428 //100 points for exact match\r
5f24742f 429 $tool->_matchscore += 100;\r
a0eeacf9
CS
430 } else if(substr($urllower, 0, strlen($toolbaseurllower)) === $toolbaseurllower){\r
431 //50 points if it starts with the base URL\r
5f24742f
CS
432 $tool->_matchscore += 50;\r
433 }\r
434 }\r
435 \r
436 $bestmatch = array_reduce($tools, function($value, $tool){\r
437 if($tool->_matchscore > $value->_matchscore){\r
438 return $tool;\r
439 } else {\r
440 return $value;\r
441 }\r
442 \r
443 }, (object)array('_matchscore' => -1));\r
444 \r
a0eeacf9
CS
445 //None of the tools are suitable for this URL\r
446 if($bestmatch->_matchscore <= 0){\r
447 return null;\r
448 }\r
449 \r
5f24742f
CS
450 return $bestmatch;\r
451}\r
452\r
b7e436b0
CS
453/**\r
454 * Prints the various configured tool types\r
455 *\r
456 */\r
73300339 457function lti_filter_print_types() {\r
b7e436b0
CS
458 global $CFG;\r
459\r
73300339 460 $types = lti_filter_get_types();\r
b7e436b0
CS
461 if (!empty($types)) {\r
462 echo '<ul>';\r
463 foreach ($types as $type) {\r
464 echo '<li>'.\r
465 $type->name.\r
466 '<span class="commands">'.\r
467 '<a class="editing_update" href="typessettings.php?action=update&amp;id='.$type->id.'&amp;sesskey='.sesskey().'" title="Update">'.\r
468 '<img class="iconsmall" alt="Update" src="'.$CFG->wwwroot.'/pix/t/edit.gif"/>'.\r
469 '</a>'.\r
470 '<a class="editing_delete" href="typessettings.php?action=delete&amp;id='.$type->id.'&amp;sesskey='.sesskey().'" title="Delete">'.\r
471 '<img class="iconsmall" alt="Delete" src="'.$CFG->wwwroot.'/pix/t/delete.gif"/>'.\r
472 '</a>'.\r
473 '</span>'.\r
474 '</li>';\r
475\r
476 }\r
477 echo '</ul>';\r
478 } else {\r
479 echo '<div class="message">';\r
73300339 480 echo get_string('notypes', 'lti');\r
b7e436b0
CS
481 echo '</div>';\r
482 }\r
483}\r
484\r
485/**\r
486 * Delete a Basic LTI configuration\r
487 *\r
488 * @param int $id Configuration id\r
489 */\r
73300339 490function lti_delete_type($id) {\r
b7e436b0
CS
491 global $DB;\r
492\r
a4a07996
CS
493 //We should probably just copy the launch URL to the tool instances in this case... using a single query\r
494 /*\r
73300339 495 $instances = $DB->get_records('lti', array('typeid' => $id));\r
b7e436b0
CS
496 foreach ($instances as $instance) {\r
497 $instance->typeid = 0;\r
73300339 498 $DB->update_record('lti', $instance);\r
a4a07996 499 }*/\r
b7e436b0 500\r
73300339
CS
501 $DB->delete_records('lti_types', array('id' => $id));\r
502 $DB->delete_records('lti_types_config', array('typeid' => $id));\r
b7e436b0
CS
503}\r
504\r
a4a07996
CS
505function lti_set_state_for_type($id, $state){\r
506 global $DB;\r
507 \r
508 $DB->update_record('lti_types', array('id' => $id, 'state' => $state));\r
509}\r
510\r
b7e436b0
CS
511/**\r
512 * Transforms a basic LTI object to an array\r
513 *\r
73300339 514 * @param object $ltiobject Basic LTI object\r
b7e436b0
CS
515 *\r
516 * @return array Basic LTI configuration details\r
517 */\r
73300339 518function lti_get_config($ltiobject) {\r
b7e436b0 519 $typeconfig = array();\r
73300339
CS
520 $typeconfig = (array)$ltiobject;\r
521 $additionalconfig = lti_get_type_config($ltiobject->typeid);\r
b7e436b0
CS
522 $typeconfig = array_merge($typeconfig, $additionalconfig);\r
523 return $typeconfig;\r
524}\r
525\r
526/**\r
527 *\r
528 * Generates some of the tool configuration based on the instance details\r
529 *\r
530 * @param int $id\r
531 *\r
532 * @return Instance configuration\r
533 *\r
534 */\r
73300339 535function lti_get_type_config_from_instance($id) {\r
b7e436b0
CS
536 global $DB;\r
537\r
73300339
CS
538 $instance = $DB->get_record('lti', array('id' => $id));\r
539 $config = lti_get_config($instance);\r
b7e436b0
CS
540\r
541 $type = new stdClass();\r
542 $type->lti_fix = $id;\r
543 if (isset($config['toolurl'])) {\r
544 $type->lti_toolurl = $config['toolurl'];\r
545 }\r
b7e436b0
CS
546 if (isset($config['instructorchoicesendname'])) {\r
547 $type->lti_sendname = $config['instructorchoicesendname'];\r
548 }\r
549 if (isset($config['instructorchoicesendemailaddr'])) {\r
550 $type->lti_sendemailaddr = $config['instructorchoicesendemailaddr'];\r
551 }\r
552 if (isset($config['instructorchoiceacceptgrades'])) {\r
553 $type->lti_acceptgrades = $config['instructorchoiceacceptgrades'];\r
554 }\r
555 if (isset($config['instructorchoiceallowroster'])) {\r
556 $type->lti_allowroster = $config['instructorchoiceallowroster'];\r
557 }\r
d97d72aa 558\r
b7e436b0
CS
559 if (isset($config['instructorcustomparameters'])) {\r
560 $type->lti_allowsetting = $config['instructorcustomparameters'];\r
561 }\r
562 return $type;\r
563}\r
564\r
565/**\r
566 * Generates some of the tool configuration based on the admin configuration details\r
567 *\r
568 * @param int $id\r
569 *\r
570 * @return Configuration details\r
571 */\r
73300339 572function lti_get_type_type_config($id) {\r
b7e436b0
CS
573 global $DB;\r
574\r
73300339
CS
575 $basicltitype = $DB->get_record('lti_types', array('id' => $id));\r
576 $config = lti_get_type_config($id);\r
b7e436b0
CS
577\r
578 $type->lti_typename = $basicltitype->name;\r
a4a07996
CS
579 \r
580 $type->lti_toolurl = $basicltitype->baseurl;\r
581 \r
b7e436b0
CS
582 if (isset($config['resourcekey'])) {\r
583 $type->lti_resourcekey = $config['resourcekey'];\r
584 }\r
585 if (isset($config['password'])) {\r
586 $type->lti_password = $config['password'];\r
587 }\r
d97d72aa 588\r
b7e436b0
CS
589 if (isset($config['sendname'])) {\r
590 $type->lti_sendname = $config['sendname'];\r
591 }\r
592 if (isset($config['instructorchoicesendname'])){\r
593 $type->lti_instructorchoicesendname = $config['instructorchoicesendname'];\r
594 }\r
595 if (isset($config['sendemailaddr'])){\r
596 $type->lti_sendemailaddr = $config['sendemailaddr'];\r
597 }\r
598 if (isset($config['instructorchoicesendemailaddr'])){\r
599 $type->lti_instructorchoicesendemailaddr = $config['instructorchoicesendemailaddr'];\r
600 }\r
601 if (isset($config['acceptgrades'])){\r
602 $type->lti_acceptgrades = $config['acceptgrades'];\r
603 }\r
604 if (isset($config['instructorchoiceacceptgrades'])){\r
605 $type->lti_instructorchoiceacceptgrades = $config['instructorchoiceacceptgrades'];\r
606 }\r
607 if (isset($config['allowroster'])){\r
608 $type->lti_allowroster = $config['allowroster'];\r
609 }\r
610 if (isset($config['instructorchoiceallowroster'])){\r
611 $type->lti_instructorchoiceallowroster = $config['instructorchoiceallowroster'];\r
612 }\r
d97d72aa 613\r
b7e436b0
CS
614 if (isset($config['customparameters'])) {\r
615 $type->lti_customparameters = $config['customparameters'];\r
616 }\r
d97d72aa 617\r
b7e436b0
CS
618 if (isset($config['organizationid'])) {\r
619 $type->lti_organizationid = $config['organizationid'];\r
620 }\r
621 if (isset($config['organizationurl'])) {\r
622 $type->lti_organizationurl = $config['organizationurl'];\r
623 }\r
624 if (isset($config['organizationdescr'])) {\r
625 $type->lti_organizationdescr = $config['organizationdescr'];\r
626 }\r
d97d72aa
CS
627 if (isset($config['launchcontainer'])) {\r
628 $type->lti_launchcontainer = $config['launchcontainer'];\r
b7e436b0 629 }\r
0d8afb44
CS
630 \r
631 if (isset($config['coursevisible'])) {\r
632 $type->lti_coursevisible = $config['coursevisible'];\r
633 }\r
634 \r
b7e436b0
CS
635 if (isset($config['debuglaunch'])) {\r
636 $type->lti_debuglaunch = $config['debuglaunch'];\r
637 }\r
0d8afb44 638 \r
b7e436b0
CS
639 if (isset($config['module_class_type'])) {\r
640 $type->lti_module_class_type = $config['module_class_type'];\r
641 }\r
642\r
643 return $type;\r
644}\r
645\r
879e97bd
CS
646function lti_prepare_type_for_save($type, $config){\r
647 $type->baseurl = $config->lti_toolurl;\r
648 $type->tooldomain = lti_get_domain_from_url($config->lti_toolurl);\r
649 $type->name = $config->lti_typename;\r
650 \r
651 $type->coursevisible = !empty($config->lti_coursevisible) ? $config->lti_coursevisible : 0;\r
652 $config->lti_coursevisible = $type->coursevisible;\r
653 \r
654 $type->timemodified = time();\r
655 \r
656 unset ($config->lti_typename);\r
657 unset ($config->lti_toolurl);\r
658}\r
659\r
660function lti_update_type($type, $config){\r
661 global $DB;\r
662 \r
663 lti_prepare_type_for_save($type, $config);\r
664 \r
665 if ($DB->update_record('lti_types', $type)) {\r
666 foreach ($config as $key => $value) {\r
667 if (substr($key, 0, 4)=='lti_' && !is_null($value)) {\r
668 $record = new StdClass();\r
669 $record->typeid = $type->id;\r
670 $record->name = substr($key, 4);\r
671 $record->value = $value;\r
672 \r
673 lti_update_config($record);\r
674 }\r
675 }\r
676 }\r
677}\r
678\r
679function lti_add_type($type, $config){\r
680 global $USER, $SITE, $DB;\r
681 \r
682 lti_prepare_type_for_save($type, $config);\r
683 \r
684 if(!isset($type->state)){\r
685 $type->state = LTI_TOOL_STATE_PENDING;\r
686 }\r
687 \r
688 if(!isset($type->timecreated)){\r
689 $type->timecreated = time();\r
690 }\r
691 \r
692 if(!isset($type->createdby)){\r
693 $type->createdby = $USER->id;\r
694 }\r
695 \r
696 if(!isset($type->course)){\r
697 $type->course = $SITE->id;\r
698 }\r
699 \r
700 //Create a salt value to be used for signing passed data to extension services\r
701 $config->lti_servicesalt = uniqid('', true);\r
702\r
703 $id = $DB->insert_record('lti_types', $type);\r
704\r
705 if ($id) {\r
706 foreach ($config as $key => $value) {\r
707 if (substr($key, 0, 4)=='lti_' && !is_null($value)) {\r
708 $record = new StdClass();\r
709 $record->typeid = $id;\r
710 $record->name = substr($key, 4);\r
711 $record->value = $value;\r
712\r
713 lti_add_config($record);\r
714 }\r
715 }\r
716 }\r
717}\r
718\r
b7e436b0
CS
719/**\r
720 * Add a tool configuration in the database\r
721 *\r
722 * @param $config Tool configuration\r
723 *\r
724 * @return int Record id number\r
725 */\r
73300339 726function lti_add_config($config) {\r
b7e436b0
CS
727 global $DB;\r
728\r
73300339 729 return $DB->insert_record('lti_types_config', $config);\r
b7e436b0
CS
730}\r
731\r
732/**\r
733 * Updates a tool configuration in the database\r
734 *\r
735 * @param $config Tool configuration\r
736 *\r
737 * @return Record id number\r
738 */\r
73300339 739function lti_update_config($config) {\r
b7e436b0
CS
740 global $DB;\r
741\r
742 $return = true;\r
73300339 743 $old = $DB->get_record('lti_types_config', array('typeid' => $config->typeid, 'name' => $config->name));\r
5f24742f
CS
744 \r
745 if ($old) {\r
b7e436b0 746 $config->id = $old->id;\r
73300339 747 $return = $DB->update_record('lti_types_config', $config);\r
b7e436b0 748 } else {\r
73300339 749 $return = $DB->insert_record('lti_types_config', $config);\r
b7e436b0
CS
750 }\r
751 return $return;\r
752}\r
753\r
b7e436b0
CS
754/**\r
755 * Signs the petition to launch the external tool using OAuth\r
756 *\r
757 * @param $oldparms Parameters to be passed for signing\r
758 * @param $endpoint url of the external tool\r
759 * @param $method Method for sending the parameters (e.g. POST)\r
760 * @param $oauth_consumoer_key Key\r
761 * @param $oauth_consumoer_secret Secret\r
762 * @param $submittext The text for the submit button\r
763 * @param $orgid LMS name\r
764 * @param $orgdesc LMS key\r
765 */\r
766function sign_parameters($oldparms, $endpoint, $method, $oauthconsumerkey, $oauthconsumersecret, $submittext, $orgid /*, $orgdesc*/) {\r
767 global $lastbasestring;\r
768 $parms = $oldparms;\r
769 $parms["lti_version"] = "LTI-1p0";\r
770 $parms["lti_message_type"] = "basic-lti-launch-request";\r
771 if ( $orgid ) {\r
772 $parms["tool_consumer_instance_guid"] = $orgid;\r
773 }\r
774 /* Suppress this for now - Chuck\r
775 if ( $orgdesc ) $parms["tool_consumer_instance_description"] = $orgdesc;\r
776 */\r
777 $parms["ext_submit"] = $submittext;\r
778\r
779 $testtoken = '';\r
780\r
781 $hmacmethod = new OAuthSignatureMethod_HMAC_SHA1();\r
782 $testconsumer = new OAuthConsumer($oauthconsumerkey, $oauthconsumersecret, null);\r
783\r
784 $accreq = OAuthRequest::from_consumer_and_token($testconsumer, $testtoken, $method, $endpoint, $parms);\r
785 $accreq->sign_request($hmacmethod, $testconsumer, $testtoken);\r
786\r
787 // Pass this back up "out of band" for debugging\r
788 $lastbasestring = $accreq->get_signature_base_string();\r
789\r
790 $newparms = $accreq->get_parameters();\r
791\r
792 return $newparms;\r
793}\r
794\r
795/**\r
796 * Posts the launch petition HTML\r
797 *\r
798 * @param $newparms Signed parameters\r
799 * @param $endpoint URL of the external tool\r
800 * @param $debug Debug (true/false)\r
801 */\r
0d8afb44 802function post_launch_html($newparms, $endpoint, $debug=false) {\r
b7e436b0 803 global $lastbasestring;\r
d97d72aa
CS
804 \r
805 $r = "<form action=\"".$endpoint."\" name=\"ltiLaunchForm\" id=\"ltiLaunchForm\" method=\"post\" encType=\"application/x-www-form-urlencoded\">\n";\r
806 \r
b7e436b0
CS
807 $submittext = $newparms['ext_submit'];\r
808\r
809 // Contruct html for the launch parameters\r
810 foreach ($newparms as $key => $value) {\r
811 $key = htmlspecialchars($key);\r
812 $value = htmlspecialchars($value);\r
813 if ( $key == "ext_submit" ) {\r
814 $r .= "<input type=\"submit\" name=\"";\r
815 } else {\r
816 $r .= "<input type=\"hidden\" name=\"";\r
817 }\r
818 $r .= $key;\r
819 $r .= "\" value=\"";\r
820 $r .= $value;\r
821 $r .= "\"/>\n";\r
822 }\r
823\r
824 if ( $debug ) {\r
825 $r .= "<script language=\"javascript\"> \n";\r
826 $r .= " //<![CDATA[ \n";\r
827 $r .= "function basicltiDebugToggle() {\n";\r
828 $r .= " var ele = document.getElementById(\"basicltiDebug\");\n";\r
829 $r .= " if(ele.style.display == \"block\") {\n";\r
830 $r .= " ele.style.display = \"none\";\n";\r
831 $r .= " }\n";\r
832 $r .= " else {\n";\r
833 $r .= " ele.style.display = \"block\";\n";\r
834 $r .= " }\n";\r
835 $r .= "} \n";\r
836 $r .= " //]]> \n";\r
837 $r .= "</script>\n";\r
838 $r .= "<a id=\"displayText\" href=\"javascript:basicltiDebugToggle();\">";\r
73300339 839 $r .= get_string("toggle_debug_data", "lti")."</a>\n";\r
b7e436b0 840 $r .= "<div id=\"basicltiDebug\" style=\"display:none\">\n";\r
73300339 841 $r .= "<b>".get_string("basiclti_endpoint", "lti")."</b><br/>\n";\r
b7e436b0 842 $r .= $endpoint . "<br/>\n&nbsp;<br/>\n";\r
73300339 843 $r .= "<b>".get_string("basiclti_parameters", "lti")."</b><br/>\n";\r
b7e436b0
CS
844 foreach ($newparms as $key => $value) {\r
845 $key = htmlspecialchars($key);\r
846 $value = htmlspecialchars($value);\r
847 $r .= "$key = $value<br/>\n";\r
848 }\r
849 $r .= "&nbsp;<br/>\n";\r
73300339 850 $r .= "<p><b>".get_string("basiclti_base_string", "lti")."</b><br/>\n".$lastbasestring."</p>\n";\r
b7e436b0
CS
851 $r .= "</div>\n";\r
852 }\r
853 $r .= "</form>\n";\r
854\r
855 if ( ! $debug ) {\r
856 $ext_submit = "ext_submit";\r
857 $ext_submit_text = $submittext;\r
858 $r .= " <script type=\"text/javascript\"> \n" .\r
859 " //<![CDATA[ \n" .\r
860 " document.getElementById(\"ltiLaunchForm\").style.display = \"none\";\n" .\r
861 " nei = document.createElement('input');\n" .\r
862 " nei.setAttribute('type', 'hidden');\n" .\r
863 " nei.setAttribute('name', '".$ext_submit."');\n" .\r
864 " nei.setAttribute('value', '".$ext_submit_text."');\n" .\r
865 " document.getElementById(\"ltiLaunchForm\").appendChild(nei);\n" .\r
866 " document.ltiLaunchForm.submit(); \n" .\r
867 " //]]> \n" .\r
868 " </script> \n";\r
869 }\r
870 return $r;\r
871}\r
872\r
873/**\r
874 * Returns a link with info about the state of the basiclti submissions\r
875 *\r
876 * This is used by view_header to put this link at the top right of the page.\r
877 * For teachers it gives the number of submitted assignments with a link\r
878 * For students it gives the time of their submission.\r
879 * This will be suitable for most assignment types.\r
880 *\r
881 * @global object\r
882 * @global object\r
883 * @param bool $allgroup print all groups info if user can access all groups, suitable for index.php\r
884 * @return string\r
885 */\r
886function submittedlink($cm, $allgroups=false) {\r
887 global $CFG;\r
888\r
889 $submitted = '';\r
73300339 890 $urlbase = "{$CFG->wwwroot}/mod/lti/";\r
b7e436b0
CS
891\r
892 $context = get_context_instance(CONTEXT_MODULE, $cm->id);\r
73300339 893 if (has_capability('mod/lti:grade', $context)) {\r
b7e436b0
CS
894 if ($allgroups and has_capability('moodle/site:accessallgroups', $context)) {\r
895 $group = 0;\r
896 } else {\r
897 $group = groups_get_activity_group($cm);\r
898 }\r
899\r
900 $submitted = '<a href="'.$urlbase.'submissions.php?id='.$cm->id.'">'.\r
73300339 901 get_string('viewsubmissions', 'lti').'</a>';\r
b7e436b0
CS
902 } else {\r
903 if (isloggedin()) {\r
904 // TODO Insert code for students if needed\r
905 }\r
906 }\r
907\r
908 return $submitted;\r
909}\r
910\r