MDL-67585 core_course: add hook get_all_content_items
[moodle.git] / mod / lti / lib.php
CommitLineData
aa6eca66 1<?php
61eb12d4
CS
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//
aa6eca66
CS
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
e3f69b58 33// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
aa6eca66
CS
34
35/**
61eb12d4 36 * This file contains a library of functions and constants for the lti module
aa6eca66 37 *
2b17ec3d 38 * @package mod_lti
61eb12d4 39 * @copyright 2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
aa6eca66 40 * marc.alier@upc.edu
61eb12d4
CS
41 * @copyright 2009 Universitat Politecnica de Catalunya http://www.upc.edu
42 * @author Marc Alier
43 * @author Jordi Piguillem
44 * @author Nikolas Galanis
8f45215d 45 * @author Chris Scribner
61eb12d4 46 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
aa6eca66
CS
47 */
48
49defined('MOODLE_INTERNAL') || die;
50
aa6eca66
CS
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
55 */
56function lti_supports($feature) {
e3f69b58 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
69 default:
70 return null;
aa6eca66
CS
71 }
72}
73
74/**
75 * Given an object containing all the necessary data,
76 * (defined by the form in mod.html) this function
77 * will create a new instance and return the id number
78 * of the new instance.
79 *
80 * @param object $instance An object from the form in mod.html
81 * @return int The id of the newly inserted basiclti record
82 **/
c69bd1af 83function lti_add_instance($lti, $mform) {
42a2c7f1
CS
84 global $DB, $CFG;
85 require_once($CFG->dirroot.'/mod/lti/locallib.php');
e27cb316 86
e3f69b58 87 if (!isset($lti->toolurl)) {
88 $lti->toolurl = '';
89 }
90
8aec804a
JO
91 lti_load_tool_if_cartridge($lti);
92
c69bd1af
EL
93 $lti->timecreated = time();
94 $lti->timemodified = $lti->timecreated;
95 $lti->servicesalt = uniqid('', true);
77a827e1
SC
96 if (!isset($lti->typeid)) {
97 $lti->typeid = null;
98 }
e27cb316 99
8fa50fdd
MN
100 lti_force_type_config_settings($lti, lti_get_type_config_by_instance($lti));
101
5582fe49 102 if (empty($lti->typeid) && isset($lti->urlmatchedtypeid)) {
ea5d0515
AF
103 $lti->typeid = $lti->urlmatchedtypeid;
104 }
105
8fa50fdd
MN
106 if (!isset($lti->instructorchoiceacceptgrades) || $lti->instructorchoiceacceptgrades != LTI_SETTING_ALWAYS) {
107 // The instance does not accept grades back from the provider, so set to "No grade" value 0.
108 $lti->grade = 0;
c69bd1af 109 }
aa6eca66 110
c69bd1af 111 $lti->id = $DB->insert_record('lti', $lti);
e27cb316 112
8fa50fdd 113 if (isset($lti->instructorchoiceacceptgrades) && $lti->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS) {
c69bd1af
EL
114 if (!isset($lti->cmidnumber)) {
115 $lti->cmidnumber = '';
32c079dc 116 }
e27cb316 117
c69bd1af 118 lti_grade_item_update($lti);
aa6eca66
CS
119 }
120
b3bd7a66
MN
121 $completiontimeexpected = !empty($lti->completionexpected) ? $lti->completionexpected : null;
122 \core_completion\api::update_completion_date_event($lti->coursemodule, 'lti', $lti->id, $completiontimeexpected);
123
c69bd1af 124 return $lti->id;
aa6eca66
CS
125}
126
127/**
128 * Given an object containing all the necessary data,
129 * (defined by the form in mod.html) this function
130 * will update an existing instance with new data.
131 *
132 * @param object $instance An object from the form in mod.html
133 * @return boolean Success/Fail
134 **/
c69bd1af 135function lti_update_instance($lti, $mform) {
42a2c7f1
CS
136 global $DB, $CFG;
137 require_once($CFG->dirroot.'/mod/lti/locallib.php');
aa6eca66 138
8aec804a
JO
139 lti_load_tool_if_cartridge($lti);
140
c69bd1af
EL
141 $lti->timemodified = time();
142 $lti->id = $lti->instance;
aa6eca66 143
b07878ec
CS
144 if (!isset($lti->showtitlelaunch)) {
145 $lti->showtitlelaunch = 0;
aa6eca66 146 }
e27cb316 147
b07878ec
CS
148 if (!isset($lti->showdescriptionlaunch)) {
149 $lti->showdescriptionlaunch = 0;
aa6eca66 150 }
e27cb316 151
8fa50fdd 152 lti_force_type_config_settings($lti, lti_get_type_config_by_instance($lti));
e27cb316 153
8fa50fdd 154 if (isset($lti->instructorchoiceacceptgrades) && $lti->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS) {
c69bd1af 155 lti_grade_item_update($lti);
aa6eca66 156 } else {
8fa50fdd
MN
157 // Instance is no longer accepting grades from Provider, set grade to "No grade" value 0.
158 $lti->grade = 0;
159 $lti->instructorchoiceacceptgrades = 0;
160
c69bd1af 161 lti_grade_item_delete($lti);
aa6eca66
CS
162 }
163
ea5d0515
AF
164 if ($lti->typeid == 0 && isset($lti->urlmatchedtypeid)) {
165 $lti->typeid = $lti->urlmatchedtypeid;
166 }
167
b3bd7a66
MN
168 $completiontimeexpected = !empty($lti->completionexpected) ? $lti->completionexpected : null;
169 \core_completion\api::update_completion_date_event($lti->coursemodule, 'lti', $lti->id, $completiontimeexpected);
170
c69bd1af 171 return $DB->update_record('lti', $lti);
aa6eca66
CS
172}
173
174/**
175 * Given an ID of an instance of this module,
176 * this function will permanently delete the instance
177 * and any data that depends on it.
178 *
179 * @param int $id Id of the module instance
180 * @return boolean Success/Failure
181 **/
182function lti_delete_instance($id) {
183 global $DB;
184
185 if (! $basiclti = $DB->get_record("lti", array("id" => $id))) {
186 return false;
187 }
188
189 $result = true;
190
e3f69b58 191 // Delete any dependent records here.
aa6eca66
CS
192 lti_grade_item_delete($basiclti);
193
e3f69b58 194 $ltitype = $DB->get_record('lti_types', array('id' => $basiclti->typeid));
496bf3ea
DM
195 if ($ltitype) {
196 $DB->delete_records('lti_tool_settings',
197 array('toolproxyid' => $ltitype->toolproxyid, 'course' => $basiclti->course, 'coursemoduleid' => $id));
198 }
e3f69b58 199
b3bd7a66
MN
200 $cm = get_coursemodule_from_instance('lti', $id);
201 \core_completion\api::update_completion_date_event($cm->id, 'lti', $id, null);
202
40fe1538 203 // We must delete the module record after we delete the grade item.
aa6eca66
CS
204 return $DB->delete_records("lti", array("id" => $basiclti->id));
205}
206
01e8bfd7
JO
207/**
208 * Return aliases of this activity. LTI should have an alias for each configured tool type
2348c137 209 * This is so you can add an external tool types directly to the activity chooser
01e8bfd7 210 *
520add19
JD
211 * @deprecated since 3.9
212 * @todo MDL-68011 This is to be moved from here to deprecatedlib.php in Moodle 4.3
2348c137
MG
213 * @param stdClass $defaultitem default item that would be added to the activity chooser if this callback was not present.
214 * It has properties: archetype, name, title, help, icon, link
f418d899
JD
215 * @return array An array of aliases for this activity. Each element is an object with same list of properties as $defaultitem,
216 * plus an additional property, helplink.
2348c137 217 * Properties title and link are required
01e8bfd7 218 **/
2348c137 219function lti_get_shortcuts($defaultitem) {
01e8bfd7
JO
220 global $CFG, $COURSE;
221 require_once($CFG->dirroot.'/mod/lti/locallib.php');
222
2348c137 223 $types = lti_get_configured_types($COURSE->id, $defaultitem->link->param('sr'));
477e8717 224 if (has_capability('mod/lti:addmanualinstance', context_course::instance($COURSE->id))) {
e3b82acd 225 $types[] = $defaultitem;
226 }
2348c137
MG
227
228 // Add items defined in ltisource plugins.
229 foreach (core_component::get_plugin_list('ltisource') as $pluginname => $dir) {
2348c137
MG
230 // LTISOURCE plugins can also implement callback get_shortcuts() to add items to the activity chooser.
231 // The return values are the same as of the 'mod' callbacks except that $defaultitem is only passed for reference and
232 // should not be added to the return value.
233 if ($moretypes = component_callback("ltisource_$pluginname", 'get_shortcuts', array($defaultitem))) {
234 $types = array_merge($types, $moretypes);
976b5bca
CS
235 }
236 }
237 return $types;
238}
239
8fc7d83f
JD
240/**
241 * Return the preconfigured tools which are configured for inclusion in the activity picker.
242 *
243 * @param \core_course\local\entity\content_item $defaultmodulecontentitem reference to the content item for the LTI module.
244 * @param \stdClass $user the user object, to use for cap checks if desired.
245 * @param stdClass $course the course to scope items to.
246 * @return array the array of content items.
247 */
248function lti_get_course_content_items(\core_course\local\entity\content_item $defaultmodulecontentitem, \stdClass $user,
249 \stdClass $course) {
250 global $CFG, $OUTPUT;
251 require_once($CFG->dirroot.'/mod/lti/locallib.php');
252
253 $types = [];
254
255 // The 'External tool' entry (the main module content item), should always take the id of 1.
256 if (has_capability('mod/lti:addmanualinstance', context_course::instance($course->id), $user)) {
257 $types = [new \core_course\local\entity\content_item(
258 1,
259 $defaultmodulecontentitem->get_name(),
260 $defaultmodulecontentitem->get_title(),
261 $defaultmodulecontentitem->get_link(),
262 $defaultmodulecontentitem->get_icon(),
263 $defaultmodulecontentitem->get_help(),
264 $defaultmodulecontentitem->get_archetype(),
265 $defaultmodulecontentitem->get_component_name()
266 )];
267 }
268
269 // Other, preconfigured tools take their own id + 1, so we'll never clash with the module's entry.
270 $preconfiguredtools = lti_get_configured_types($course->id, $defaultmodulecontentitem->get_link()->param('sr'));
271 foreach ($preconfiguredtools as $preconfiguredtool) {
272
273 // Append the help link to the help text.
274 if (isset($preconfiguredtool->help)) {
275 if (isset($preconfiguredtool->helplink)) {
276 $linktext = get_string('morehelp');
277 $preconfiguredtool->help .= html_writer::tag('div',
278 $OUTPUT->doc_link($preconfiguredtool->helplink, $linktext, true), ['class' => 'helpdoclink']);
279 }
280 } else {
281 $preconfiguredtool->help = '';
282 }
283
284 $types[] = new \core_course\local\entity\content_item(
285 $preconfiguredtool->id + 1,
286 $preconfiguredtool->name,
287 new \core_course\local\entity\string_title($preconfiguredtool->title),
288 $preconfiguredtool->link,
289 $preconfiguredtool->icon,
290 $preconfiguredtool->help,
291 $defaultmodulecontentitem->get_archetype(),
292 $defaultmodulecontentitem->get_component_name()
293 );
294 }
295 return $types;
296}
297
57dfcf95
JD
298/**
299 * Return all content items which can be added to any course.
300 *
301 * @param \core_course\local\entity\content_item $defaultmodulecontentitem
302 * @return array the array of content items.
303 */
304function mod_lti_get_all_content_items(\core_course\local\entity\content_item $defaultmodulecontentitem): array {
305 global $OUTPUT, $CFG;
306 require_once($CFG->dirroot . '/mod/lti/locallib.php'); // For access to constants.
307
308 // The 'External tool' entry (the main module content item), should always take the id of 1.
309 $types = [new \core_course\local\entity\content_item(
310 1,
311 $defaultmodulecontentitem->get_name(),
312 $defaultmodulecontentitem->get_title(),
313 $defaultmodulecontentitem->get_link(),
314 $defaultmodulecontentitem->get_icon(),
315 $defaultmodulecontentitem->get_help(),
316 $defaultmodulecontentitem->get_archetype(),
317 $defaultmodulecontentitem->get_component_name()
318 )];
319
320 foreach (lti_get_lti_types() as $ltitype) {
321 if ($ltitype->coursevisible != LTI_COURSEVISIBLE_ACTIVITYCHOOSER) {
322 continue;
323 }
324 $type = new stdClass();
325 $type->id = $ltitype->id;
326 $type->modclass = MOD_CLASS_ACTIVITY;
327 $type->name = 'lti_type_' . $ltitype->id;
328 // Clean the name. We don't want tags here.
329 $type->title = clean_param($ltitype->name, PARAM_NOTAGS);
330 $trimmeddescription = trim($ltitype->description);
331 $type->help = '';
332 if ($trimmeddescription != '') {
333 // Clean the description. We don't want tags here.
334 $type->help = clean_param($trimmeddescription, PARAM_NOTAGS);
335 $type->helplink = get_string('modulename_shortcut_link', 'lti');
336 }
337 if (empty($ltitype->icon)) {
338 $type->icon = $OUTPUT->pix_icon('icon', '', 'lti', array('class' => 'icon'));
339 } else {
340 $type->icon = html_writer::empty_tag('img', array('src' => $ltitype->icon, 'alt' => $ltitype->name, 'class' => 'icon'));
341 }
342 $type->link = new moodle_url('/course/modedit.php', array('add' => 'lti', 'return' => 0, 'typeid' => $ltitype->id));
343
344 $types[] = new \core_course\local\entity\content_item(
345 $type->id + 1,
346 $type->name,
347 new \core_course\local\entity\string_title($type->title),
348 $type->link,
349 $type->icon,
350 $type->help,
351 $defaultmodulecontentitem->get_archetype(),
352 $defaultmodulecontentitem->get_component_name()
353 );
354 }
355
356 return $types;
357}
358
6c64e8ac
EL
359/**
360 * Given a coursemodule object, this function returns the extra
361 * information needed to print this activity in various places.
362 * For this module we just need to support external urls as
363 * activity icons
364 *
3de55d24 365 * @param stdClass $coursemodule
6c64e8ac
EL
366 * @return cached_cm_info info
367 */
ea04a9f9 368function lti_get_coursemodule_info($coursemodule) {
42a2c7f1
CS
369 global $DB, $CFG;
370 require_once($CFG->dirroot.'/mod/lti/locallib.php');
e27cb316 371
6c64e8ac 372 if (!$lti = $DB->get_record('lti', array('id' => $coursemodule->instance),
3f358828 373 'icon, secureicon, intro, introformat, name, typeid, toolurl, launchcontainer')) {
6c64e8ac
EL
374 return null;
375 }
c07aec16 376
6c64e8ac 377 $info = new cached_cm_info();
e27cb316 378
b07878ec
CS
379 if ($coursemodule->showdescription) {
380 // Convert intro to html. Do not filter cached version, filters run at display time.
381 $info->content = format_module_intro('lti', $lti, $coursemodule->id, false);
382 }
e27cb316 383
3f358828 384 if (!empty($lti->typeid)) {
385 $toolconfig = lti_get_type_config($lti->typeid);
386 } else if ($tool = lti_get_tool_by_url_match($lti->toolurl)) {
3de55d24
TH
387 $toolconfig = lti_get_type_config($tool->id);
388 } else {
389 $toolconfig = array();
390 }
3f358828 391
392 // We want to use the right icon based on whether the
393 // current page is being requested over http or https.
394 if (lti_request_is_using_ssl() &&
395 (!empty($lti->secureicon) || (isset($toolconfig['secureicon']) && !empty($toolconfig['secureicon'])))) {
396 if (!empty($lti->secureicon)) {
397 $info->iconurl = new moodle_url($lti->secureicon);
398 } else {
399 $info->iconurl = new moodle_url($toolconfig['secureicon']);
400 }
401 } else if (!empty($lti->icon)) {
402 $info->iconurl = new moodle_url($lti->icon);
403 } else if (isset($toolconfig['icon']) && !empty($toolconfig['icon'])) {
404 $info->iconurl = new moodle_url($toolconfig['icon']);
405 }
406
407 // Does the link open in a new window?
3de55d24
TH
408 $launchcontainer = lti_get_launch_container($lti, $toolconfig);
409 if ($launchcontainer == LTI_LAUNCH_CONTAINER_WINDOW) {
410 $launchurl = new moodle_url('/mod/lti/launch.php', array('id' => $coursemodule->id));
b346737e 411 $info->onclick = "window.open('" . $launchurl->out(false) . "', 'lti-".$coursemodule->id."'); return false;";
3de55d24
TH
412 }
413
b07878ec 414 $info->name = $lti->name;
194f2c60 415
c07aec16
CS
416 return $info;
417}
418
aa6eca66
CS
419/**
420 * Return a small object with summary information about what a
421 * user has done with a given particular instance of this module
422 * Used for user activity reports.
423 * $return->time = the time they did it
424 * $return->info = a short text description
425 *
426 * @return null
427 * @TODO: implement this moodle function (if needed)
428 **/
429function lti_user_outline($course, $user, $mod, $basiclti) {
64ce589b 430 return null;
aa6eca66
CS
431}
432
433/**
434 * Print a detailed representation of what a user has done with
435 * a given particular instance of this module, for user activity reports.
436 *
437 * @return boolean
438 * @TODO: implement this moodle function (if needed)
439 **/
440function lti_user_complete($course, $user, $mod, $basiclti) {
441 return true;
442}
443
444/**
445 * Given a course and a time, this module should find recent activity
446 * that has occurred in basiclti activities and print it out.
447 * Return true if there was output, or false is there was none.
448 *
449 * @uses $CFG
450 * @return boolean
451 * @TODO: implement this moodle function
452 **/
453function lti_print_recent_activity($course, $isteacher, $timestart) {
e3f69b58 454 return false; // True if anything was printed, otherwise false.
aa6eca66
CS
455}
456
457/**
458 * Function to be run periodically according to the moodle cron
459 * This function searches for things that need to be done, such
460 * as sending out mail, toggling flags etc ...
461 *
462 * @uses $CFG
463 * @return boolean
464 **/
465function lti_cron () {
466 return true;
467}
468
469/**
470 * Must return an array of grades for a given instance of this module,
471 * indexed by user. It also returns a maximum allowed grade.
472 *
473 * Example:
474 * $return->grades = array of grades;
475 * $return->maxgrade = maximum allowed grade;
476 *
477 * return $return;
478 *
479 * @param int $basicltiid ID of an instance of this module
480 * @return mixed Null or object with an array of grades and with the maximum grade
481 *
482 * @TODO: implement this moodle function (if needed)
483 **/
484function lti_grades($basicltiid) {
485 return null;
486}
487
aa6eca66 488/**
c0375ba7
AA
489 * @deprecated since Moodle 3.8
490 */
491function lti_scale_used() {
492 throw new coding_exception('lti_scale_used() can not be used anymore. Plugins can implement ' .
493 '<modname>_scale_used_anywhere, all implementations of <modname>_scale_used are now ignored');
aa6eca66
CS
494}
495
496/**
497 * Checks if scale is being used by any instance of basiclti.
498 * This function was added in 1.9
499 *
500 * This is used to find out if scale used anywhere
501 * @param $scaleid int
502 * @return boolean True if the scale is used by any basiclti
503 *
504 */
505function lti_scale_used_anywhere($scaleid) {
506 global $DB;
507
508 if ($scaleid and $DB->record_exists('lti', array('grade' => -$scaleid))) {
509 return true;
510 } else {
511 return false;
512 }
513}
514
515/**
516 * Execute post-install custom actions for the module
517 * This function was added in 1.9
518 *
519 * @return boolean true if success, false on error
520 */
521function lti_install() {
522 return true;
523}
524
525/**
526 * Execute post-uninstall custom actions for the module
527 * This function was added in 1.9
528 *
529 * @return boolean true if success, false on error
530 */
531function lti_uninstall() {
532 return true;
533}
534
535/**
536 * Returns available Basic LTI types
537 *
538 * @return array of basicLTI types
539 */
540function lti_get_lti_types() {
541 global $DB;
542
cc193e0d
RW
543 return $DB->get_records('lti_types', null, 'state DESC, timemodified DESC');
544}
545
546/**
547 * Returns available Basic LTI types that match the given
548 * tool proxy id
549 *
af9d3a92 550 * @param int $toolproxyid Tool proxy id
cc193e0d
RW
551 * @return array of basicLTI types
552 */
553function lti_get_lti_types_from_proxy_id($toolproxyid) {
554 global $DB;
555
556 return $DB->get_records('lti_types', array('toolproxyid' => $toolproxyid), 'state DESC, timemodified DESC');
aa6eca66
CS
557}
558
aa6eca66
CS
559/**
560 * Create grade item for given basiclti
561 *
a153c9f2 562 * @category grade
aa6eca66
CS
563 * @param object $basiclti object with extra cmidnumber
564 * @param mixed optional array/object of grade(s); 'reset' means reset grades in gradebook
565 * @return int 0 if ok, error code otherwise
566 */
e3f69b58 567function lti_grade_item_update($basiclti, $grades = null) {
aa6eca66
CS
568 global $CFG;
569 require_once($CFG->libdir.'/gradelib.php');
4d5a33e4
JA
570 require_once($CFG->dirroot.'/mod/lti/servicelib.php');
571
572 if (!lti_accepts_grades($basiclti)) {
573 return 0;
574 }
aa6eca66 575
e3f69b58 576 $params = array('itemname' => $basiclti->name, 'idnumber' => $basiclti->cmidnumber);
aa6eca66
CS
577
578 if ($basiclti->grade > 0) {
579 $params['gradetype'] = GRADE_TYPE_VALUE;
580 $params['grademax'] = $basiclti->grade;
581 $params['grademin'] = 0;
582
583 } else if ($basiclti->grade < 0) {
584 $params['gradetype'] = GRADE_TYPE_SCALE;
585 $params['scaleid'] = -$basiclti->grade;
586
587 } else {
e3f69b58 588 $params['gradetype'] = GRADE_TYPE_TEXT; // Allow text comments only.
aa6eca66
CS
589 }
590
e3f69b58 591 if ($grades === 'reset') {
aa6eca66
CS
592 $params['reset'] = true;
593 $grades = null;
594 }
595
596 return grade_update('mod/lti', $basiclti->course, 'mod', 'lti', $basiclti->id, 0, $grades, $params);
597}
598
77a827e1
SC
599/**
600 * Update activity grades
601 *
602 * @param stdClass $basiclti The LTI instance
603 * @param int $userid Specific user only, 0 means all.
604 * @param bool $nullifnone Not used
605 */
606function lti_update_grades($basiclti, $userid=0, $nullifnone=true) {
607 global $CFG;
608 require_once($CFG->dirroot.'/mod/lti/servicelib.php');
609 // LTI doesn't have its own grade table so the only thing to do is update the grade item.
610 if (lti_accepts_grades($basiclti)) {
611 lti_grade_item_update($basiclti);
612 }
613}
614
aa6eca66
CS
615/**
616 * Delete grade item for given basiclti
617 *
a153c9f2 618 * @category grade
aa6eca66
CS
619 * @param object $basiclti object
620 * @return object basiclti
621 */
622function lti_grade_item_delete($basiclti) {
623 global $CFG;
624 require_once($CFG->libdir.'/gradelib.php');
625
e3f69b58 626 return grade_update('mod/lti', $basiclti->course, 'mod', 'lti', $basiclti->id, 0, null, array('deleted' => 1));
aa6eca66
CS
627}
628
8fa50fdd
MN
629/**
630 * Log post actions
631 *
632 * @return array
633 */
634function lti_get_post_actions() {
635 return array();
636}
637
638/**
639 * Log view actions
640 *
641 * @return array
642 */
643function lti_get_view_actions() {
644 return array('view all', 'view');
645}
4bed1682
JL
646
647/**
648 * Mark the activity completed (if required) and trigger the course_module_viewed event.
649 *
650 * @param stdClass $lti lti object
651 * @param stdClass $course course object
652 * @param stdClass $cm course module object
653 * @param stdClass $context context object
654 * @since Moodle 3.0
655 */
656function lti_view($lti, $course, $cm, $context) {
657
658 // Trigger course_module_viewed event.
659 $params = array(
660 'context' => $context,
661 'objectid' => $lti->id
662 );
663
664 $event = \mod_lti\event\course_module_viewed::create($params);
665 $event->add_record_snapshot('course_modules', $cm);
666 $event->add_record_snapshot('course', $course);
667 $event->add_record_snapshot('lti', $lti);
668 $event->trigger();
669
670 // Completion.
671 $completion = new completion_info($course);
672 $completion->set_module_viewed($cm);
673}
02a73d76
JL
674
675/**
676 * Check if the module has any update that affects the current user since a given time.
677 *
678 * @param cm_info $cm course module data
679 * @param int $from the time to check updates from
680 * @param array $filter if we need to check only specific updates
681 * @return stdClass an object with the different type of areas indicating if they were updated or not
682 * @since Moodle 3.2
683 */
684function lti_check_updates_since(cm_info $cm, $from, $filter = array()) {
685 global $DB, $USER;
686
687 $updates = course_check_module_updates_since($cm, $from, array(), $filter);
688
689 // Check if there is a new submission.
65b2669d 690 $updates->submissions = (object) array('updated' => false);
02a73d76
JL
691 $select = 'ltiid = :id AND userid = :userid AND (datesubmitted > :since1 OR dateupdated > :since2)';
692 $params = array('id' => $cm->instance, 'userid' => $USER->id, 'since1' => $from, 'since2' => $from);
65b2669d
JL
693 $submissions = $DB->get_records_select('lti_submission', $select, $params, '', 'id');
694 if (!empty($submissions)) {
695 $updates->submissions->updated = true;
696 $updates->submissions->itemids = array_keys($submissions);
697 }
02a73d76 698
0a348387
JL
699 // Now, teachers should see other students updates.
700 if (has_capability('mod/lti:manage', $cm->context)) {
701 $select = 'ltiid = :id AND (datesubmitted > :since1 OR dateupdated > :since2)';
702 $params = array('id' => $cm->instance, 'since1' => $from, 'since2' => $from);
703
704 if (groups_get_activity_groupmode($cm) == SEPARATEGROUPS) {
705 $groupusers = array_keys(groups_get_activity_shared_group_members($cm));
706 if (empty($groupusers)) {
707 return $updates;
708 }
709 list($insql, $inparams) = $DB->get_in_or_equal($groupusers, SQL_PARAMS_NAMED);
710 $select .= ' AND userid ' . $insql;
711 $params = array_merge($params, $inparams);
712 }
713
714 $updates->usersubmissions = (object) array('updated' => false);
715 $submissions = $DB->get_records_select('lti_submission', $select, $params, '', 'id');
716 if (!empty($submissions)) {
717 $updates->usersubmissions->updated = true;
718 $updates->usersubmissions->itemids = array_keys($submissions);
719 }
720 }
721
02a73d76
JL
722 return $updates;
723}
2b931458
DW
724
725/**
726 * Get icon mapping for font-awesome.
727 */
728function mod_lti_get_fontawesome_icon_map() {
729 return [
ad056aa2 730 'mod_lti:warning' => 'fa-exclamation text-warning',
2b931458
DW
731 ];
732}
b3bd7a66
MN
733
734/**
59391e80
MN
735 * This function receives a calendar event and returns the action associated with it, or null if there is none.
736 *
737 * This is used by block_myoverview in order to display the event appropriately. If null is returned then the event
738 * is not displayed on the block.
b3bd7a66 739 *
e1cd93ce 740 * @param calendar_event $event
b3bd7a66 741 * @param \core_calendar\action_factory $factory
58182fa8 742 * @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default).
01f96180 743 * @return \core_calendar\local\event\entities\action_interface|null
b3bd7a66 744 */
e1cd93ce 745function mod_lti_core_calendar_provide_event_action(calendar_event $event,
58182fa8
SR
746 \core_calendar\action_factory $factory,
747 int $userid = 0) {
748 global $USER;
749
750 if (empty($userid)) {
751 $userid = $USER->id;
752 }
753
754 $cm = get_fast_modinfo($event->courseid, $userid)->instances['lti'][$event->instance];
b3bd7a66 755
70e7f3b9
SR
756 if (!$cm->uservisible) {
757 // The module is not visible to the user for any reason.
758 return null;
759 }
760
50d845e3 761 $completion = new \completion_info($cm->get_course());
b3bd7a66 762
58182fa8 763 $completiondata = $completion->get_data($cm, false, $userid);
b3bd7a66
MN
764
765 if ($completiondata->completionstate != COMPLETION_INCOMPLETE) {
766 return null;
767 }
768
769 return $factory->create_instance(
770 get_string('view'),
771 new \moodle_url('/mod/lti/view.php', ['id' => $cm->id]),
772 1,
773 true
774 );
939218c2 775}