Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 // 17 // This file is part of BasicLTI4Moodle 18 // 19 // BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability) 20 // consumer for Moodle 1.9 and Moodle 2.0. BasicLTI is a IMS Standard that allows web 21 // based learning tools to be easily integrated in LMS as native ones. The IMS BasicLTI 22 // specification is part of the IMS standard Common Cartridge 1.1 Sakai and other main LMS 23 // are already supporting or going to support BasicLTI. This project Implements the consumer 24 // for Moodle. Moodle is a Free Open source Learning Management System by Martin Dougiamas. 25 // BasicLTI4Moodle is a project iniciated and leaded by Ludo(Marc Alier) and Jordi Piguillem 26 // at the GESSI research group at UPC. 27 // SimpleLTI consumer for Moodle is an implementation of the early specification of LTI 28 // by Charles Severance (Dr Chuck) htp://dr-chuck.com , developed by Jordi Piguillem in a 29 // Google Summer of Code 2008 project co-mentored by Charles Severance and Marc Alier. 30 // 31 // BasicLTI4Moodle is copyright 2009 by Marc Alier Forment, Jordi Piguillem and Nikolas Galanis 32 // of the Universitat Politecnica de Catalunya http://www.upc.edu 33 // Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu. 34 35 /** 36 * This file contains a library of functions and constants for the lti module 37 * 38 * @package mod_lti 39 * @copyright 2009 Marc Alier, Jordi Piguillem, Nikolas Galanis 40 * marc.alier@upc.edu 41 * @copyright 2009 Universitat Politecnica de Catalunya http://www.upc.edu 42 * @author Marc Alier 43 * @author Jordi Piguillem 44 * @author Nikolas Galanis 45 * @author Chris Scribner 46 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 47 */ 48 49 defined('MOODLE_INTERNAL') || die; 50 51 /** 52 * List of features supported in URL module 53 * @param string $feature FEATURE_xx constant for requested feature 54 * @return mixed True if module supports feature, false if not, null if doesn't know or string for the module purpose. 55 */ 56 function lti_supports($feature) { 57 switch ($feature) { 58 case FEATURE_GROUPS: 59 case FEATURE_GROUPINGS: 60 return false; 61 case FEATURE_MOD_INTRO: 62 case FEATURE_COMPLETION_TRACKS_VIEWS: 63 case FEATURE_GRADE_HAS_GRADE: 64 case FEATURE_GRADE_OUTCOMES: 65 case FEATURE_BACKUP_MOODLE2: 66 case FEATURE_SHOW_DESCRIPTION: 67 return true; 68 case FEATURE_MOD_PURPOSE: 69 return MOD_PURPOSE_CONTENT; 70 71 default: 72 return null; 73 } 74 } 75 76 /** 77 * Given an object containing all the necessary data, 78 * (defined by the form in mod.html) this function 79 * will create a new instance and return the id number 80 * of the new instance. 81 * 82 * @param object $instance An object from the form in mod.html 83 * @return int The id of the newly inserted basiclti record 84 **/ 85 function lti_add_instance($lti, $mform) { 86 global $DB, $CFG; 87 require_once($CFG->dirroot.'/mod/lti/locallib.php'); 88 89 if (!isset($lti->toolurl)) { 90 $lti->toolurl = ''; 91 } 92 93 lti_load_tool_if_cartridge($lti); 94 95 $lti->timecreated = time(); 96 $lti->timemodified = $lti->timecreated; 97 $lti->servicesalt = uniqid('', true); 98 if (!isset($lti->typeid)) { 99 $lti->typeid = null; 100 } 101 102 lti_force_type_config_settings($lti, lti_get_type_config_by_instance($lti)); 103 104 if (empty($lti->typeid) && isset($lti->urlmatchedtypeid)) { 105 $lti->typeid = $lti->urlmatchedtypeid; 106 } 107 108 if (!isset($lti->instructorchoiceacceptgrades) || $lti->instructorchoiceacceptgrades != LTI_SETTING_ALWAYS) { 109 // The instance does not accept grades back from the provider, so set to "No grade" value 0. 110 $lti->grade = 0; 111 } 112 113 $lti->id = $DB->insert_record('lti', $lti); 114 115 if (isset($lti->instructorchoiceacceptgrades) && $lti->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS) { 116 if (!isset($lti->cmidnumber)) { 117 $lti->cmidnumber = ''; 118 } 119 120 lti_grade_item_update($lti); 121 } 122 123 $services = lti_get_services(); 124 foreach ($services as $service) { 125 $service->instance_added( $lti ); 126 } 127 128 $completiontimeexpected = !empty($lti->completionexpected) ? $lti->completionexpected : null; 129 \core_completion\api::update_completion_date_event($lti->coursemodule, 'lti', $lti->id, $completiontimeexpected); 130 131 return $lti->id; 132 } 133 134 /** 135 * Given an object containing all the necessary data, 136 * (defined by the form in mod.html) this function 137 * will update an existing instance with new data. 138 * 139 * @param object $instance An object from the form in mod.html 140 * @return boolean Success/Fail 141 **/ 142 function lti_update_instance($lti, $mform) { 143 global $DB, $CFG; 144 require_once($CFG->dirroot.'/mod/lti/locallib.php'); 145 146 lti_load_tool_if_cartridge($lti); 147 148 $lti->timemodified = time(); 149 $lti->id = $lti->instance; 150 151 if (!isset($lti->showtitlelaunch)) { 152 $lti->showtitlelaunch = 0; 153 } 154 155 if (!isset($lti->showdescriptionlaunch)) { 156 $lti->showdescriptionlaunch = 0; 157 } 158 159 lti_force_type_config_settings($lti, lti_get_type_config_by_instance($lti)); 160 161 if (isset($lti->instructorchoiceacceptgrades) && $lti->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS) { 162 lti_grade_item_update($lti); 163 } else { 164 // Instance is no longer accepting grades from Provider, set grade to "No grade" value 0. 165 $lti->grade = 0; 166 $lti->instructorchoiceacceptgrades = 0; 167 168 lti_grade_item_delete($lti); 169 } 170 171 if ($lti->typeid == 0 && isset($lti->urlmatchedtypeid)) { 172 $lti->typeid = $lti->urlmatchedtypeid; 173 } 174 175 $services = lti_get_services(); 176 foreach ($services as $service) { 177 $service->instance_updated( $lti ); 178 } 179 180 $completiontimeexpected = !empty($lti->completionexpected) ? $lti->completionexpected : null; 181 \core_completion\api::update_completion_date_event($lti->coursemodule, 'lti', $lti->id, $completiontimeexpected); 182 183 return $DB->update_record('lti', $lti); 184 } 185 186 /** 187 * Given an ID of an instance of this module, 188 * this function will permanently delete the instance 189 * and any data that depends on it. 190 * 191 * @param int $id Id of the module instance 192 * @return boolean Success/Failure 193 **/ 194 function lti_delete_instance($id) { 195 global $DB, $CFG; 196 require_once($CFG->dirroot.'/mod/lti/locallib.php'); 197 198 if (! $basiclti = $DB->get_record("lti", array("id" => $id))) { 199 return false; 200 } 201 202 $result = true; 203 204 // Delete any dependent records here. 205 lti_grade_item_delete($basiclti); 206 207 $ltitype = $DB->get_record('lti_types', array('id' => $basiclti->typeid)); 208 if ($ltitype) { 209 $DB->delete_records('lti_tool_settings', 210 array('toolproxyid' => $ltitype->toolproxyid, 'course' => $basiclti->course, 'coursemoduleid' => $id)); 211 } 212 213 $cm = get_coursemodule_from_instance('lti', $id); 214 \core_completion\api::update_completion_date_event($cm->id, 'lti', $id, null); 215 216 // We must delete the module record after we delete the grade item. 217 if ($DB->delete_records("lti", array("id" => $basiclti->id)) ) { 218 $services = lti_get_services(); 219 foreach ($services as $service) { 220 $service->instance_deleted( $id ); 221 } 222 return true; 223 } 224 return false; 225 226 } 227 228 /** 229 * Return the preconfigured tools which are configured for inclusion in the activity picker. 230 * 231 * @param \core_course\local\entity\content_item $defaultmodulecontentitem reference to the content item for the LTI module. 232 * @param \stdClass $user the user object, to use for cap checks if desired. 233 * @param stdClass $course the course to scope items to. 234 * @return array the array of content items. 235 */ 236 function lti_get_course_content_items(\core_course\local\entity\content_item $defaultmodulecontentitem, \stdClass $user, 237 \stdClass $course) { 238 global $CFG, $OUTPUT; 239 require_once($CFG->dirroot.'/mod/lti/locallib.php'); 240 241 $types = []; 242 243 // Use of a tool type, whether site or course level, is controlled by the following cap. 244 if (!has_capability('mod/lti:addpreconfiguredinstance', \core\context\course::instance($course->id), $user)) { 245 return $types; 246 } 247 $preconfiguredtools = lti_get_configured_types($course->id, $defaultmodulecontentitem->get_link()->param('sr')); 248 249 foreach ($preconfiguredtools as $preconfiguredtool) { 250 251 // Append the help link to the help text. 252 if (isset($preconfiguredtool->help)) { 253 if (isset($preconfiguredtool->helplink)) { 254 $linktext = get_string('morehelp'); 255 $preconfiguredtool->help .= html_writer::tag('div', 256 $OUTPUT->doc_link($preconfiguredtool->helplink, $linktext, true), ['class' => 'helpdoclink']); 257 } 258 } else { 259 $preconfiguredtool->help = ''; 260 } 261 262 // Preconfigured tools take their own id + 1. This logic exists because, previously, the entry permitting manual instance 263 // creation (the $defaultmodulecontentitem, or 'External tool' item) was included and had the id 1. This logic prevented id 264 // collisions. 265 $types[] = new \core_course\local\entity\content_item( 266 $preconfiguredtool->id + 1, 267 $preconfiguredtool->name, 268 new \core_course\local\entity\string_title($preconfiguredtool->title), 269 $preconfiguredtool->link, 270 $preconfiguredtool->icon, 271 $preconfiguredtool->help, 272 $defaultmodulecontentitem->get_archetype(), 273 $defaultmodulecontentitem->get_component_name(), 274 $defaultmodulecontentitem->get_purpose() 275 ); 276 } 277 return $types; 278 } 279 280 /** 281 * Return all content items which can be added to any course. 282 * 283 * @param \core_course\local\entity\content_item $defaultmodulecontentitem 284 * @return array the array of content items. 285 */ 286 function mod_lti_get_all_content_items(\core_course\local\entity\content_item $defaultmodulecontentitem): array { 287 global $OUTPUT, $CFG; 288 require_once($CFG->dirroot . '/mod/lti/locallib.php'); // For access to constants. 289 290 $types = []; 291 292 foreach (lti_get_lti_types() as $ltitype) { 293 if ($ltitype->coursevisible != LTI_COURSEVISIBLE_ACTIVITYCHOOSER) { 294 continue; 295 } 296 $type = new stdClass(); 297 $type->id = $ltitype->id; 298 $type->modclass = MOD_CLASS_ACTIVITY; 299 $type->name = 'lti_type_' . $ltitype->id; 300 // Clean the name. We don't want tags here. 301 $type->title = clean_param($ltitype->name, PARAM_NOTAGS); 302 $trimmeddescription = trim($ltitype->description ?? ''); 303 $type->help = ''; 304 if ($trimmeddescription != '') { 305 // Clean the description. We don't want tags here. 306 $type->help = clean_param($trimmeddescription, PARAM_NOTAGS); 307 $type->helplink = get_string('modulename_shortcut_link', 'lti'); 308 } 309 if (empty($ltitype->icon)) { 310 $type->icon = $OUTPUT->pix_icon('monologo', '', 'lti', array('class' => 'icon')); 311 } else { 312 $type->icon = html_writer::empty_tag('img', array('src' => $ltitype->icon, 'alt' => $ltitype->name, 'class' => 'icon')); 313 } 314 $type->link = new moodle_url('/course/modedit.php', array('add' => 'lti', 'return' => 0, 'typeid' => $ltitype->id)); 315 316 // Preconfigured tools take their own id + 1. This logic exists because, previously, the entry permitting manual instance 317 // creation (the $defaultmodulecontentitem, or 'External tool' item) was included and had the id 1. This logic prevented id 318 // collisions. 319 $types[] = new \core_course\local\entity\content_item( 320 $type->id + 1, 321 $type->name, 322 new \core_course\local\entity\string_title($type->title), 323 $type->link, 324 $type->icon, 325 $type->help, 326 $defaultmodulecontentitem->get_archetype(), 327 $defaultmodulecontentitem->get_component_name(), 328 $defaultmodulecontentitem->get_purpose() 329 ); 330 } 331 332 return $types; 333 } 334 335 /** 336 * Given a coursemodule object, this function returns the extra 337 * information needed to print this activity in various places. 338 * For this module we just need to support external urls as 339 * activity icons 340 * 341 * @param stdClass $coursemodule 342 * @return cached_cm_info info 343 */ 344 function lti_get_coursemodule_info($coursemodule) { 345 global $DB, $CFG; 346 require_once($CFG->dirroot.'/mod/lti/locallib.php'); 347 348 if (!$lti = $DB->get_record('lti', array('id' => $coursemodule->instance), 349 'icon, secureicon, intro, introformat, name, typeid, toolurl, launchcontainer')) { 350 return null; 351 } 352 353 $info = new cached_cm_info(); 354 355 if ($coursemodule->showdescription) { 356 // Convert intro to html. Do not filter cached version, filters run at display time. 357 $info->content = format_module_intro('lti', $lti, $coursemodule->id, false); 358 } 359 360 if (!empty($lti->typeid)) { 361 $toolconfig = lti_get_type_config($lti->typeid); 362 } else if ($tool = lti_get_tool_by_url_match($lti->toolurl)) { 363 $toolconfig = lti_get_type_config($tool->id); 364 } else { 365 $toolconfig = array(); 366 } 367 368 // We want to use the right icon based on whether the 369 // current page is being requested over http or https. 370 if (lti_request_is_using_ssl() && 371 (!empty($lti->secureicon) || (isset($toolconfig['secureicon']) && !empty($toolconfig['secureicon'])))) { 372 if (!empty($lti->secureicon)) { 373 $info->iconurl = new moodle_url($lti->secureicon); 374 } else { 375 $info->iconurl = new moodle_url($toolconfig['secureicon']); 376 } 377 } else if (!empty($lti->icon)) { 378 $info->iconurl = new moodle_url($lti->icon); 379 } else if (isset($toolconfig['icon']) && !empty($toolconfig['icon'])) { 380 $info->iconurl = new moodle_url($toolconfig['icon']); 381 } 382 383 // Does the link open in a new window? 384 $launchcontainer = lti_get_launch_container($lti, $toolconfig); 385 if ($launchcontainer == LTI_LAUNCH_CONTAINER_WINDOW) { 386 $launchurl = new moodle_url('/mod/lti/launch.php', array('id' => $coursemodule->id)); 387 $info->onclick = "window.open('" . $launchurl->out(false) . "', 'lti-".$coursemodule->id."'); return false;"; 388 } 389 390 $info->name = $lti->name; 391 392 return $info; 393 } 394 395 /** 396 * Return a small object with summary information about what a 397 * user has done with a given particular instance of this module 398 * Used for user activity reports. 399 * $return->time = the time they did it 400 * $return->info = a short text description 401 * 402 * @return null 403 * @TODO: implement this moodle function (if needed) 404 **/ 405 function lti_user_outline($course, $user, $mod, $basiclti) { 406 return null; 407 } 408 409 /** 410 * Print a detailed representation of what a user has done with 411 * a given particular instance of this module, for user activity reports. 412 * 413 * @return boolean 414 * @TODO: implement this moodle function (if needed) 415 **/ 416 function lti_user_complete($course, $user, $mod, $basiclti) { 417 return true; 418 } 419 420 /** 421 * Given a course and a time, this module should find recent activity 422 * that has occurred in basiclti activities and print it out. 423 * Return true if there was output, or false is there was none. 424 * 425 * @uses $CFG 426 * @return boolean 427 * @TODO: implement this moodle function 428 **/ 429 function lti_print_recent_activity($course, $isteacher, $timestart) { 430 return false; // True if anything was printed, otherwise false. 431 } 432 433 /** 434 * Function to be run periodically according to the moodle cron 435 * This function searches for things that need to be done, such 436 * as sending out mail, toggling flags etc ... 437 * 438 * @uses $CFG 439 * @return boolean 440 **/ 441 function lti_cron () { 442 return true; 443 } 444 445 /** 446 * Must return an array of grades for a given instance of this module, 447 * indexed by user. It also returns a maximum allowed grade. 448 * 449 * Example: 450 * $return->grades = array of grades; 451 * $return->maxgrade = maximum allowed grade; 452 * 453 * return $return; 454 * 455 * @param int $basicltiid ID of an instance of this module 456 * @return mixed Null or object with an array of grades and with the maximum grade 457 * 458 * @TODO: implement this moodle function (if needed) 459 **/ 460 function lti_grades($basicltiid) { 461 return null; 462 } 463 464 /** 465 * @deprecated since Moodle 3.8 466 */ 467 function lti_scale_used() { 468 throw new coding_exception('lti_scale_used() can not be used anymore. Plugins can implement ' . 469 '<modname>_scale_used_anywhere, all implementations of <modname>_scale_used are now ignored'); 470 } 471 472 /** 473 * Checks if scale is being used by any instance of basiclti. 474 * This function was added in 1.9 475 * 476 * This is used to find out if scale used anywhere 477 * @param $scaleid int 478 * @return boolean True if the scale is used by any basiclti 479 * 480 */ 481 function lti_scale_used_anywhere($scaleid) { 482 global $DB; 483 484 if ($scaleid and $DB->record_exists('lti', array('grade' => -$scaleid))) { 485 return true; 486 } else { 487 return false; 488 } 489 } 490 491 /** 492 * Execute post-install custom actions for the module 493 * This function was added in 1.9 494 * 495 * @return boolean true if success, false on error 496 */ 497 function lti_install() { 498 return true; 499 } 500 501 /** 502 * Execute post-uninstall custom actions for the module 503 * This function was added in 1.9 504 * 505 * @return boolean true if success, false on error 506 */ 507 function lti_uninstall() { 508 return true; 509 } 510 511 /** 512 * Returns available Basic LTI types 513 * 514 * @return array of basicLTI types 515 */ 516 function lti_get_lti_types() { 517 global $DB; 518 519 return $DB->get_records('lti_types', null, 'state DESC, timemodified DESC'); 520 } 521 522 /** 523 * Returns available Basic LTI types that match the given 524 * tool proxy id 525 * 526 * @param int $toolproxyid Tool proxy id 527 * @return array of basicLTI types 528 */ 529 function lti_get_lti_types_from_proxy_id($toolproxyid) { 530 global $DB; 531 532 return $DB->get_records('lti_types', array('toolproxyid' => $toolproxyid), 'state DESC, timemodified DESC'); 533 } 534 535 /** 536 * Create grade item for given basiclti 537 * 538 * @category grade 539 * @param object $basiclti object with extra cmidnumber 540 * @param mixed optional array/object of grade(s); 'reset' means reset grades in gradebook 541 * @return int 0 if ok, error code otherwise 542 */ 543 function lti_grade_item_update($basiclti, $grades = null) { 544 global $CFG; 545 require_once($CFG->libdir.'/gradelib.php'); 546 require_once($CFG->dirroot.'/mod/lti/servicelib.php'); 547 548 if (!lti_accepts_grades($basiclti)) { 549 return 0; 550 } 551 552 $params = array('itemname' => $basiclti->name, 'idnumber' => $basiclti->cmidnumber); 553 554 if ($basiclti->grade > 0) { 555 $params['gradetype'] = GRADE_TYPE_VALUE; 556 $params['grademax'] = $basiclti->grade; 557 $params['grademin'] = 0; 558 559 } else if ($basiclti->grade < 0) { 560 $params['gradetype'] = GRADE_TYPE_SCALE; 561 $params['scaleid'] = -$basiclti->grade; 562 563 } else { 564 $params['gradetype'] = GRADE_TYPE_TEXT; // Allow text comments only. 565 } 566 567 if ($grades === 'reset') { 568 $params['reset'] = true; 569 $grades = null; 570 } 571 572 return grade_update('mod/lti', $basiclti->course, 'mod', 'lti', $basiclti->id, 0, $grades, $params); 573 } 574 575 /** 576 * Update activity grades 577 * 578 * @param stdClass $basiclti The LTI instance 579 * @param int $userid Specific user only, 0 means all. 580 * @param bool $nullifnone Not used 581 */ 582 function lti_update_grades($basiclti, $userid=0, $nullifnone=true) { 583 global $CFG; 584 require_once($CFG->dirroot.'/mod/lti/servicelib.php'); 585 // LTI doesn't have its own grade table so the only thing to do is update the grade item. 586 if (lti_accepts_grades($basiclti)) { 587 lti_grade_item_update($basiclti); 588 } 589 } 590 591 /** 592 * Delete grade item for given basiclti 593 * 594 * @category grade 595 * @param object $basiclti object 596 * @return object basiclti 597 */ 598 function lti_grade_item_delete($basiclti) { 599 global $CFG; 600 require_once($CFG->libdir.'/gradelib.php'); 601 602 return grade_update('mod/lti', $basiclti->course, 'mod', 'lti', $basiclti->id, 0, null, array('deleted' => 1)); 603 } 604 605 /** 606 * Log post actions 607 * 608 * @return array 609 */ 610 function lti_get_post_actions() { 611 return array(); 612 } 613 614 /** 615 * Log view actions 616 * 617 * @return array 618 */ 619 function lti_get_view_actions() { 620 return array('view all', 'view'); 621 } 622 623 /** 624 * Mark the activity completed (if required) and trigger the course_module_viewed event. 625 * 626 * @param stdClass $lti lti object 627 * @param stdClass $course course object 628 * @param stdClass $cm course module object 629 * @param stdClass $context context object 630 * @since Moodle 3.0 631 */ 632 function lti_view($lti, $course, $cm, $context) { 633 634 // Trigger course_module_viewed event. 635 $params = array( 636 'context' => $context, 637 'objectid' => $lti->id 638 ); 639 640 $event = \mod_lti\event\course_module_viewed::create($params); 641 $event->add_record_snapshot('course_modules', $cm); 642 $event->add_record_snapshot('course', $course); 643 $event->add_record_snapshot('lti', $lti); 644 $event->trigger(); 645 646 // Completion. 647 $completion = new completion_info($course); 648 $completion->set_module_viewed($cm); 649 } 650 651 /** 652 * Check if the module has any update that affects the current user since a given time. 653 * 654 * @param cm_info $cm course module data 655 * @param int $from the time to check updates from 656 * @param array $filter if we need to check only specific updates 657 * @return stdClass an object with the different type of areas indicating if they were updated or not 658 * @since Moodle 3.2 659 */ 660 function lti_check_updates_since(cm_info $cm, $from, $filter = array()) { 661 global $DB, $USER; 662 663 $updates = course_check_module_updates_since($cm, $from, array(), $filter); 664 665 // Check if there is a new submission. 666 $updates->submissions = (object) array('updated' => false); 667 $select = 'ltiid = :id AND userid = :userid AND (datesubmitted > :since1 OR dateupdated > :since2)'; 668 $params = array('id' => $cm->instance, 'userid' => $USER->id, 'since1' => $from, 'since2' => $from); 669 $submissions = $DB->get_records_select('lti_submission', $select, $params, '', 'id'); 670 if (!empty($submissions)) { 671 $updates->submissions->updated = true; 672 $updates->submissions->itemids = array_keys($submissions); 673 } 674 675 // Now, teachers should see other students updates. 676 if (has_capability('mod/lti:manage', $cm->context)) { 677 $select = 'ltiid = :id AND (datesubmitted > :since1 OR dateupdated > :since2)'; 678 $params = array('id' => $cm->instance, 'since1' => $from, 'since2' => $from); 679 680 if (groups_get_activity_groupmode($cm) == SEPARATEGROUPS) { 681 $groupusers = array_keys(groups_get_activity_shared_group_members($cm)); 682 if (empty($groupusers)) { 683 return $updates; 684 } 685 list($insql, $inparams) = $DB->get_in_or_equal($groupusers, SQL_PARAMS_NAMED); 686 $select .= ' AND userid ' . $insql; 687 $params = array_merge($params, $inparams); 688 } 689 690 $updates->usersubmissions = (object) array('updated' => false); 691 $submissions = $DB->get_records_select('lti_submission', $select, $params, '', 'id'); 692 if (!empty($submissions)) { 693 $updates->usersubmissions->updated = true; 694 $updates->usersubmissions->itemids = array_keys($submissions); 695 } 696 } 697 698 return $updates; 699 } 700 701 /** 702 * Get icon mapping for font-awesome. 703 */ 704 function mod_lti_get_fontawesome_icon_map() { 705 return [ 706 'mod_lti:warning' => 'fa-exclamation text-warning', 707 ]; 708 } 709 710 /** 711 * This function receives a calendar event and returns the action associated with it, or null if there is none. 712 * 713 * This is used by block_myoverview in order to display the event appropriately. If null is returned then the event 714 * is not displayed on the block. 715 * 716 * @param calendar_event $event 717 * @param \core_calendar\action_factory $factory 718 * @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default). 719 * @return \core_calendar\local\event\entities\action_interface|null 720 */ 721 function mod_lti_core_calendar_provide_event_action(calendar_event $event, 722 \core_calendar\action_factory $factory, 723 int $userid = 0) { 724 global $USER; 725 726 if (empty($userid)) { 727 $userid = $USER->id; 728 } 729 730 $cm = get_fast_modinfo($event->courseid, $userid)->instances['lti'][$event->instance]; 731 732 if (!$cm->uservisible) { 733 // The module is not visible to the user for any reason. 734 return null; 735 } 736 737 $completion = new \completion_info($cm->get_course()); 738 739 $completiondata = $completion->get_data($cm, false, $userid); 740 741 if ($completiondata->completionstate != COMPLETION_INCOMPLETE) { 742 return null; 743 } 744 745 return $factory->create_instance( 746 get_string('view'), 747 new \moodle_url('/mod/lti/view.php', ['id' => $cm->id]), 748 1, 749 true 750 ); 751 } 752 753 /** 754 * Extend the course navigation with an "LTI External tools" link which redirects to a list of all tools available for course use. 755 * 756 * @param settings_navigation $navigation The settings navigation object 757 * @param stdClass $course The course 758 * @param stdclass $context Course context 759 * @return void 760 */ 761 function mod_lti_extend_navigation_course($navigation, $course, $context): void { 762 if (has_capability('mod/lti:addpreconfiguredinstance', $context)) { 763 $url = new moodle_url('/mod/lti/coursetools.php', ['id' => $course->id]); 764 $settingsnode = navigation_node::create(get_string('courseexternaltools', 'mod_lti'), $url, navigation_node::TYPE_SETTING, 765 null, 'coursetools', new pix_icon('i/settings', '')); 766 $navigation->add_node($settingsnode); 767 } 768 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body