Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]
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 /** 18 * Lesson external API 19 * 20 * @package mod_lesson 21 * @category external 22 * @copyright 2017 Juan Leyva <juan@moodle.com> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 * @since Moodle 3.3 25 */ 26 27 defined('MOODLE_INTERNAL') || die; 28 29 require_once($CFG->dirroot . '/mod/lesson/locallib.php'); 30 31 use mod_lesson\external\lesson_summary_exporter; 32 use core_external\external_api; 33 use core_external\external_files; 34 use core_external\external_format_value; 35 use core_external\external_function_parameters; 36 use core_external\external_multiple_structure; 37 use core_external\external_single_structure; 38 use core_external\external_value; 39 use core_external\external_warnings; 40 use core_external\util; 41 42 /** 43 * Lesson external functions 44 * 45 * @package mod_lesson 46 * @category external 47 * @copyright 2017 Juan Leyva <juan@moodle.com> 48 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 49 * @since Moodle 3.3 50 */ 51 class mod_lesson_external extends external_api { 52 53 /** 54 * Return a lesson record ready for being exported. 55 * 56 * @param stdClass $lessonrecord lesson record 57 * @param string $password lesson password 58 * @return stdClass the lesson record ready for exporting. 59 */ 60 protected static function get_lesson_summary_for_exporter($lessonrecord, $password = '') { 61 global $USER; 62 63 $lesson = new lesson($lessonrecord); 64 $lesson->update_effective_access($USER->id); 65 $lessonrecord->lang = $lesson->get_cm()->lang; 66 $lessonavailable = $lesson->get_time_restriction_status() === false; 67 $lessonavailable = $lessonavailable && $lesson->get_password_restriction_status($password) === false; 68 $lessonavailable = $lessonavailable && $lesson->get_dependencies_restriction_status() === false; 69 $canmanage = $lesson->can_manage(); 70 71 if (!$canmanage && !$lessonavailable) { 72 $fields = array('intro', 'introfiles', 'mediafiles', 'practice', 'modattempts', 'usepassword', 73 'grade', 'custom', 'ongoing', 'usemaxgrade', 74 'maxanswers', 'maxattempts', 'review', 'nextpagedefault', 'feedback', 'minquestions', 75 'maxpages', 'timelimit', 'retake', 'mediafile', 'mediaheight', 'mediawidth', 76 'mediaclose', 'slideshow', 'width', 'height', 'bgcolor', 'displayleft', 'displayleftif', 77 'progressbar'); 78 79 foreach ($fields as $field) { 80 unset($lessonrecord->{$field}); 81 } 82 } 83 84 // Fields only for managers. 85 if (!$canmanage) { 86 $fields = array('password', 'dependency', 'conditions', 'activitylink', 'available', 'deadline', 87 'timemodified', 'completionendreached', 'completiontimespent'); 88 89 foreach ($fields as $field) { 90 unset($lessonrecord->{$field}); 91 } 92 } 93 return $lessonrecord; 94 } 95 96 /** 97 * Describes the parameters for get_lessons_by_courses. 98 * 99 * @return external_function_parameters 100 * @since Moodle 3.3 101 */ 102 public static function get_lessons_by_courses_parameters() { 103 return new external_function_parameters ( 104 array( 105 'courseids' => new external_multiple_structure( 106 new external_value(PARAM_INT, 'course id'), 'Array of course ids', VALUE_DEFAULT, array() 107 ), 108 ) 109 ); 110 } 111 112 /** 113 * Returns a list of lessons in a provided list of courses, 114 * if no list is provided all lessons that the user can view will be returned. 115 * 116 * @param array $courseids Array of course ids 117 * @return array of lessons details 118 * @since Moodle 3.3 119 */ 120 public static function get_lessons_by_courses($courseids = array()) { 121 global $PAGE; 122 123 $warnings = array(); 124 $returnedlessons = array(); 125 126 $params = array( 127 'courseids' => $courseids, 128 ); 129 $params = self::validate_parameters(self::get_lessons_by_courses_parameters(), $params); 130 131 $mycourses = array(); 132 if (empty($params['courseids'])) { 133 $mycourses = enrol_get_my_courses(); 134 $params['courseids'] = array_keys($mycourses); 135 } 136 137 // Ensure there are courseids to loop through. 138 if (!empty($params['courseids'])) { 139 140 list($courses, $warnings) = util::validate_courses($params['courseids'], $mycourses); 141 142 // Get the lessons in this course, this function checks users visibility permissions. 143 // We can avoid then additional validate_context calls. 144 $lessons = get_all_instances_in_courses("lesson", $courses); 145 foreach ($lessons as $lessonrecord) { 146 $context = context_module::instance($lessonrecord->coursemodule); 147 148 // Remove fields added by get_all_instances_in_courses. 149 unset($lessonrecord->coursemodule, $lessonrecord->section, $lessonrecord->visible, $lessonrecord->groupmode, 150 $lessonrecord->groupingid); 151 152 $lessonrecord = self::get_lesson_summary_for_exporter($lessonrecord); 153 154 $exporter = new lesson_summary_exporter($lessonrecord, array('context' => $context)); 155 $lesson = $exporter->export($PAGE->get_renderer('core')); 156 $lesson->name = \core_external\util::format_string($lesson->name, $context); 157 $returnedlessons[] = $lesson; 158 } 159 } 160 $result = array(); 161 $result['lessons'] = $returnedlessons; 162 $result['warnings'] = $warnings; 163 return $result; 164 } 165 166 /** 167 * Describes the get_lessons_by_courses return value. 168 * 169 * @return external_single_structure 170 * @since Moodle 3.3 171 */ 172 public static function get_lessons_by_courses_returns() { 173 return new external_single_structure( 174 array( 175 'lessons' => new external_multiple_structure( 176 lesson_summary_exporter::get_read_structure() 177 ), 178 'warnings' => new external_warnings(), 179 ) 180 ); 181 } 182 183 /** 184 * Utility function for validating a lesson. 185 * 186 * @param int $lessonid lesson instance id 187 * @return array array containing the lesson, course, context and course module objects 188 * @since Moodle 3.3 189 */ 190 protected static function validate_lesson($lessonid) { 191 global $DB, $USER; 192 193 // Request and permission validation. 194 $lessonrecord = $DB->get_record('lesson', array('id' => $lessonid), '*', MUST_EXIST); 195 list($course, $cm) = get_course_and_cm_from_instance($lessonrecord, 'lesson'); 196 197 $lesson = new lesson($lessonrecord, $cm, $course); 198 $lesson->update_effective_access($USER->id); 199 200 $context = $lesson->context; 201 self::validate_context($context); 202 203 return array($lesson, $course, $cm, $context, $lessonrecord); 204 } 205 206 /** 207 * Validates a new attempt. 208 * 209 * @param lesson $lesson lesson instance 210 * @param array $params request parameters 211 * @param boolean $return whether to return the errors or throw exceptions 212 * @return array the errors (if return set to true) 213 * @since Moodle 3.3 214 */ 215 protected static function validate_attempt(lesson $lesson, $params, $return = false) { 216 global $USER, $CFG; 217 218 $errors = array(); 219 220 // Avoid checkings for managers. 221 if ($lesson->can_manage()) { 222 return []; 223 } 224 225 // Dead line. 226 if ($timerestriction = $lesson->get_time_restriction_status()) { 227 $error = ["$timerestriction->reason" => userdate($timerestriction->time)]; 228 if (!$return) { 229 throw new moodle_exception(key($error), 'lesson', '', current($error)); 230 } 231 $errors[key($error)] = current($error); 232 } 233 234 // Password protected lesson code. 235 if ($passwordrestriction = $lesson->get_password_restriction_status($params['password'])) { 236 $error = ["passwordprotectedlesson" => \core_external\util::format_string($lesson->name, $lesson->context)]; 237 if (!$return) { 238 throw new moodle_exception(key($error), 'lesson', '', current($error)); 239 } 240 $errors[key($error)] = current($error); 241 } 242 243 // Check for dependencies. 244 if ($dependenciesrestriction = $lesson->get_dependencies_restriction_status()) { 245 $errorhtmllist = implode(get_string('and', 'lesson') . ', ', $dependenciesrestriction->errors); 246 $error = ["completethefollowingconditions" => $dependenciesrestriction->dependentlesson->name . $errorhtmllist]; 247 if (!$return) { 248 throw new moodle_exception(key($error), 'lesson', '', current($error)); 249 } 250 $errors[key($error)] = current($error); 251 } 252 253 // To check only when no page is set (starting or continuing a lesson). 254 if (empty($params['pageid'])) { 255 // To avoid multiple calls, store the magic property firstpage. 256 $lessonfirstpage = $lesson->firstpage; 257 $lessonfirstpageid = $lessonfirstpage ? $lessonfirstpage->id : false; 258 259 // Check if the lesson does not have pages. 260 if (!$lessonfirstpageid) { 261 $error = ["lessonnotready2" => null]; 262 if (!$return) { 263 throw new moodle_exception(key($error), 'lesson'); 264 } 265 $errors[key($error)] = current($error); 266 } 267 268 // Get the number of retries (also referenced as attempts), and the last page seen. 269 $attemptscount = $lesson->count_user_retries($USER->id); 270 $lastpageseen = $lesson->get_last_page_seen($attemptscount); 271 272 // Check if the user left a timed session with no retakes. 273 if ($lastpageseen !== false && $lastpageseen != LESSON_EOL) { 274 if ($lesson->left_during_timed_session($attemptscount) && $lesson->timelimit && !$lesson->retake) { 275 $error = ["leftduringtimednoretake" => null]; 276 if (!$return) { 277 throw new moodle_exception(key($error), 'lesson'); 278 } 279 $errors[key($error)] = current($error); 280 } 281 } else if ($attemptscount > 0 && !$lesson->retake) { 282 // The user finished the lesson and no retakes are allowed. 283 $error = ["noretake" => null]; 284 if (!$return) { 285 throw new moodle_exception(key($error), 'lesson'); 286 } 287 $errors[key($error)] = current($error); 288 } 289 } else { 290 if (!$timers = $lesson->get_user_timers($USER->id, 'starttime DESC', '*', 0, 1)) { 291 $error = ["cannotfindtimer" => null]; 292 if (!$return) { 293 throw new moodle_exception(key($error), 'lesson'); 294 } 295 $errors[key($error)] = current($error); 296 } else { 297 $timer = current($timers); 298 if (!$lesson->check_time($timer)) { 299 $error = ["eolstudentoutoftime" => null]; 300 if (!$return) { 301 throw new moodle_exception(key($error), 'lesson'); 302 } 303 $errors[key($error)] = current($error); 304 } 305 306 // Check if the user want to review an attempt he just finished. 307 if (!empty($params['review'])) { 308 // Allow review only for attempts during active session time. 309 if ($timer->lessontime + $CFG->sessiontimeout > time()) { 310 $ntries = $lesson->count_user_retries($USER->id); 311 $ntries--; // Need to look at the old attempts. 312 if ($params['pageid'] == LESSON_EOL) { 313 if ($attempts = $lesson->get_attempts($ntries)) { 314 $lastattempt = end($attempts); 315 $USER->modattempts[$lesson->id] = $lastattempt->pageid; 316 } 317 } else { 318 if ($attempts = $lesson->get_attempts($ntries, false, $params['pageid'])) { 319 $lastattempt = end($attempts); 320 $USER->modattempts[$lesson->id] = $lastattempt; 321 } 322 } 323 } 324 325 if (!isset($USER->modattempts[$lesson->id])) { 326 $error = ["studentoutoftimeforreview" => null]; 327 if (!$return) { 328 throw new moodle_exception(key($error), 'lesson'); 329 } 330 $errors[key($error)] = current($error); 331 } 332 } 333 } 334 } 335 336 return $errors; 337 } 338 339 /** 340 * Describes the parameters for get_lesson_access_information. 341 * 342 * @return external_function_parameters 343 * @since Moodle 3.3 344 */ 345 public static function get_lesson_access_information_parameters() { 346 return new external_function_parameters ( 347 array( 348 'lessonid' => new external_value(PARAM_INT, 'lesson instance id') 349 ) 350 ); 351 } 352 353 /** 354 * Return access information for a given lesson. 355 * 356 * @param int $lessonid lesson instance id 357 * @return array of warnings and the access information 358 * @since Moodle 3.3 359 * @throws moodle_exception 360 */ 361 public static function get_lesson_access_information($lessonid) { 362 global $DB, $USER; 363 364 $warnings = array(); 365 366 $params = array( 367 'lessonid' => $lessonid 368 ); 369 $params = self::validate_parameters(self::get_lesson_access_information_parameters(), $params); 370 371 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 372 373 $result = array(); 374 // Capabilities first. 375 $result['canmanage'] = $lesson->can_manage(); 376 $result['cangrade'] = has_capability('mod/lesson:grade', $context); 377 $result['canviewreports'] = has_capability('mod/lesson:viewreports', $context); 378 379 // Status information. 380 $result['reviewmode'] = $lesson->is_in_review_mode(); 381 $result['attemptscount'] = $lesson->count_user_retries($USER->id); 382 $lastpageseen = $lesson->get_last_page_seen($result['attemptscount']); 383 $result['lastpageseen'] = ($lastpageseen !== false) ? $lastpageseen : 0; 384 $result['leftduringtimedsession'] = $lesson->left_during_timed_session($result['attemptscount']); 385 // To avoid multiple calls, store the magic property firstpage. 386 $lessonfirstpage = $lesson->firstpage; 387 $result['firstpageid'] = $lessonfirstpage ? $lessonfirstpage->id : 0; 388 389 // Access restrictions now, we emulate a new attempt access to get the possible warnings. 390 $result['preventaccessreasons'] = []; 391 $validationerrors = self::validate_attempt($lesson, ['password' => ''], true); 392 foreach ($validationerrors as $reason => $data) { 393 $result['preventaccessreasons'][] = [ 394 'reason' => $reason, 395 'data' => $data, 396 'message' => get_string($reason, 'lesson', $data), 397 ]; 398 } 399 $result['warnings'] = $warnings; 400 return $result; 401 } 402 403 /** 404 * Describes the get_lesson_access_information return value. 405 * 406 * @return external_single_structure 407 * @since Moodle 3.3 408 */ 409 public static function get_lesson_access_information_returns() { 410 return new external_single_structure( 411 array( 412 'canmanage' => new external_value(PARAM_BOOL, 'Whether the user can manage the lesson or not.'), 413 'cangrade' => new external_value(PARAM_BOOL, 'Whether the user can grade the lesson or not.'), 414 'canviewreports' => new external_value(PARAM_BOOL, 'Whether the user can view the lesson reports or not.'), 415 'reviewmode' => new external_value(PARAM_BOOL, 'Whether the lesson is in review mode for the current user.'), 416 'attemptscount' => new external_value(PARAM_INT, 'The number of attempts done by the user.'), 417 'lastpageseen' => new external_value(PARAM_INT, 'The last page seen id.'), 418 'leftduringtimedsession' => new external_value(PARAM_BOOL, 'Whether the user left during a timed session.'), 419 'firstpageid' => new external_value(PARAM_INT, 'The lesson first page id.'), 420 'preventaccessreasons' => new external_multiple_structure( 421 new external_single_structure( 422 array( 423 'reason' => new external_value(PARAM_ALPHANUMEXT, 'Reason lang string code'), 424 'data' => new external_value(PARAM_RAW, 'Additional data'), 425 'message' => new external_value(PARAM_RAW, 'Complete html message'), 426 ), 427 'The reasons why the user cannot attempt the lesson' 428 ) 429 ), 430 'warnings' => new external_warnings(), 431 ) 432 ); 433 } 434 435 /** 436 * Describes the parameters for view_lesson. 437 * 438 * @return external_function_parameters 439 * @since Moodle 3.3 440 */ 441 public static function view_lesson_parameters() { 442 return new external_function_parameters ( 443 array( 444 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 445 'password' => new external_value(PARAM_RAW, 'lesson password', VALUE_DEFAULT, ''), 446 ) 447 ); 448 } 449 450 /** 451 * Trigger the course module viewed event and update the module completion status. 452 * 453 * @param int $lessonid lesson instance id 454 * @param string $password optional password (the lesson may be protected) 455 * @return array of warnings and status result 456 * @since Moodle 3.3 457 * @throws moodle_exception 458 */ 459 public static function view_lesson($lessonid, $password = '') { 460 global $DB; 461 462 $params = array('lessonid' => $lessonid, 'password' => $password); 463 $params = self::validate_parameters(self::view_lesson_parameters(), $params); 464 $warnings = array(); 465 466 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 467 self::validate_attempt($lesson, $params); 468 469 $lesson->set_module_viewed(); 470 471 $result = array(); 472 $result['status'] = true; 473 $result['warnings'] = $warnings; 474 return $result; 475 } 476 477 /** 478 * Describes the view_lesson return value. 479 * 480 * @return external_single_structure 481 * @since Moodle 3.3 482 */ 483 public static function view_lesson_returns() { 484 return new external_single_structure( 485 array( 486 'status' => new external_value(PARAM_BOOL, 'status: true if success'), 487 'warnings' => new external_warnings(), 488 ) 489 ); 490 } 491 492 /** 493 * Check if the current user can retrieve lesson information (grades, attempts) about the given user. 494 * 495 * @param int $userid the user to check 496 * @param stdClass $course course object 497 * @param stdClass $cm cm object 498 * @param stdClass $context context object 499 * @throws moodle_exception 500 * @since Moodle 3.3 501 */ 502 protected static function check_can_view_user_data($userid, $course, $cm, $context) { 503 $user = core_user::get_user($userid, '*', MUST_EXIST); 504 core_user::require_active_user($user); 505 // Check permissions and that if users share group (if groups enabled). 506 require_capability('mod/lesson:viewreports', $context); 507 if (!groups_user_groups_visible($course, $user->id, $cm)) { 508 throw new moodle_exception('notingroup'); 509 } 510 } 511 512 /** 513 * Describes the parameters for get_questions_attempts. 514 * 515 * @return external_function_parameters 516 * @since Moodle 3.3 517 */ 518 public static function get_questions_attempts_parameters() { 519 return new external_function_parameters ( 520 array( 521 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 522 'attempt' => new external_value(PARAM_INT, 'lesson attempt number'), 523 'correct' => new external_value(PARAM_BOOL, 'only fetch correct attempts', VALUE_DEFAULT, false), 524 'pageid' => new external_value(PARAM_INT, 'only fetch attempts at the given page', VALUE_DEFAULT, null), 525 'userid' => new external_value(PARAM_INT, 'only fetch attempts of the given user', VALUE_DEFAULT, null), 526 ) 527 ); 528 } 529 530 /** 531 * Return the list of page question attempts in a given lesson. 532 * 533 * @param int $lessonid lesson instance id 534 * @param int $attempt the lesson attempt number 535 * @param bool $correct only fetch correct attempts 536 * @param int $pageid only fetch attempts at the given page 537 * @param int $userid only fetch attempts of the given user 538 * @return array of warnings and page attempts 539 * @since Moodle 3.3 540 * @throws moodle_exception 541 */ 542 public static function get_questions_attempts($lessonid, $attempt, $correct = false, $pageid = null, $userid = null) { 543 global $DB, $USER; 544 545 $params = array( 546 'lessonid' => $lessonid, 547 'attempt' => $attempt, 548 'correct' => $correct, 549 'pageid' => $pageid, 550 'userid' => $userid, 551 ); 552 $params = self::validate_parameters(self::get_questions_attempts_parameters(), $params); 553 $warnings = array(); 554 555 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 556 557 // Default value for userid. 558 if (empty($params['userid'])) { 559 $params['userid'] = $USER->id; 560 } 561 562 // Extra checks so only users with permissions can view other users attempts. 563 if ($USER->id != $params['userid']) { 564 self::check_can_view_user_data($params['userid'], $course, $cm, $context); 565 } 566 567 $result = array(); 568 $result['attempts'] = $lesson->get_attempts($params['attempt'], $params['correct'], $params['pageid'], $params['userid']); 569 $result['warnings'] = $warnings; 570 return $result; 571 } 572 573 /** 574 * Describes the get_questions_attempts return value. 575 * 576 * @return external_single_structure 577 * @since Moodle 3.3 578 */ 579 public static function get_questions_attempts_returns() { 580 return new external_single_structure( 581 array( 582 'attempts' => new external_multiple_structure( 583 new external_single_structure( 584 array( 585 'id' => new external_value(PARAM_INT, 'The attempt id'), 586 'lessonid' => new external_value(PARAM_INT, 'The attempt lessonid'), 587 'pageid' => new external_value(PARAM_INT, 'The attempt pageid'), 588 'userid' => new external_value(PARAM_INT, 'The user who did the attempt'), 589 'answerid' => new external_value(PARAM_INT, 'The attempt answerid'), 590 'retry' => new external_value(PARAM_INT, 'The lesson attempt number'), 591 'correct' => new external_value(PARAM_INT, 'If it was the correct answer'), 592 'useranswer' => new external_value(PARAM_RAW, 'The complete user answer'), 593 'timeseen' => new external_value(PARAM_INT, 'The time the question was seen'), 594 ), 595 'The question page attempts' 596 ) 597 ), 598 'warnings' => new external_warnings(), 599 ) 600 ); 601 } 602 603 /** 604 * Describes the parameters for get_user_grade. 605 * 606 * @return external_function_parameters 607 * @since Moodle 3.3 608 */ 609 public static function get_user_grade_parameters() { 610 return new external_function_parameters ( 611 array( 612 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 613 'userid' => new external_value(PARAM_INT, 'the user id (empty for current user)', VALUE_DEFAULT, null), 614 ) 615 ); 616 } 617 618 /** 619 * Return the final grade in the lesson for the given user. 620 * 621 * @param int $lessonid lesson instance id 622 * @param int $userid only fetch grades of this user 623 * @return array of warnings and page attempts 624 * @since Moodle 3.3 625 * @throws moodle_exception 626 */ 627 public static function get_user_grade($lessonid, $userid = null) { 628 global $CFG, $USER; 629 require_once($CFG->libdir . '/gradelib.php'); 630 631 $params = array( 632 'lessonid' => $lessonid, 633 'userid' => $userid, 634 ); 635 $params = self::validate_parameters(self::get_user_grade_parameters(), $params); 636 $warnings = array(); 637 638 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 639 640 // Default value for userid. 641 if (empty($params['userid'])) { 642 $params['userid'] = $USER->id; 643 } 644 645 // Extra checks so only users with permissions can view other users attempts. 646 if ($USER->id != $params['userid']) { 647 self::check_can_view_user_data($params['userid'], $course, $cm, $context); 648 } 649 650 $grade = null; 651 $formattedgrade = null; 652 $grades = lesson_get_user_grades($lesson, $params['userid']); 653 if (!empty($grades)) { 654 $grade = $grades[$params['userid']]->rawgrade; 655 $params = array( 656 'itemtype' => 'mod', 657 'itemmodule' => 'lesson', 658 'iteminstance' => $lesson->id, 659 'courseid' => $course->id, 660 'itemnumber' => 0 661 ); 662 $gradeitem = grade_item::fetch($params); 663 $formattedgrade = grade_format_gradevalue($grade, $gradeitem); 664 } 665 666 $result = array(); 667 $result['grade'] = $grade; 668 $result['formattedgrade'] = $formattedgrade; 669 $result['warnings'] = $warnings; 670 return $result; 671 } 672 673 /** 674 * Describes the get_user_grade return value. 675 * 676 * @return external_single_structure 677 * @since Moodle 3.3 678 */ 679 public static function get_user_grade_returns() { 680 return new external_single_structure( 681 array( 682 'grade' => new external_value(PARAM_FLOAT, 'The lesson final raw grade'), 683 'formattedgrade' => new external_value(PARAM_RAW, 'The lesson final grade formatted'), 684 'warnings' => new external_warnings(), 685 ) 686 ); 687 } 688 689 /** 690 * Describes an attempt grade structure. 691 * 692 * @param int $required if the structure is required or optional 693 * @return external_single_structure the structure 694 * @since Moodle 3.3 695 */ 696 protected static function get_user_attempt_grade_structure($required = VALUE_REQUIRED) { 697 $data = array( 698 'nquestions' => new external_value(PARAM_INT, 'Number of questions answered'), 699 'attempts' => new external_value(PARAM_INT, 'Number of question attempts'), 700 'total' => new external_value(PARAM_FLOAT, 'Max points possible'), 701 'earned' => new external_value(PARAM_FLOAT, 'Points earned by student'), 702 'grade' => new external_value(PARAM_FLOAT, 'Calculated percentage grade'), 703 'nmanual' => new external_value(PARAM_INT, 'Number of manually graded questions'), 704 'manualpoints' => new external_value(PARAM_FLOAT, 'Point value for manually graded questions'), 705 ); 706 return new external_single_structure( 707 $data, 'Attempt grade', $required 708 ); 709 } 710 711 /** 712 * Describes the parameters for get_user_attempt_grade. 713 * 714 * @return external_function_parameters 715 * @since Moodle 3.3 716 */ 717 public static function get_user_attempt_grade_parameters() { 718 return new external_function_parameters ( 719 array( 720 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 721 'lessonattempt' => new external_value(PARAM_INT, 'lesson attempt number'), 722 'userid' => new external_value(PARAM_INT, 'the user id (empty for current user)', VALUE_DEFAULT, null), 723 ) 724 ); 725 } 726 727 /** 728 * Return grade information in the attempt for a given user. 729 * 730 * @param int $lessonid lesson instance id 731 * @param int $lessonattempt lesson attempt number 732 * @param int $userid only fetch attempts of the given user 733 * @return array of warnings and page attempts 734 * @since Moodle 3.3 735 * @throws moodle_exception 736 */ 737 public static function get_user_attempt_grade($lessonid, $lessonattempt, $userid = null) { 738 global $CFG, $USER; 739 require_once($CFG->libdir . '/gradelib.php'); 740 741 $params = array( 742 'lessonid' => $lessonid, 743 'lessonattempt' => $lessonattempt, 744 'userid' => $userid, 745 ); 746 $params = self::validate_parameters(self::get_user_attempt_grade_parameters(), $params); 747 $warnings = array(); 748 749 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 750 751 // Default value for userid. 752 if (empty($params['userid'])) { 753 $params['userid'] = $USER->id; 754 } 755 756 // Extra checks so only users with permissions can view other users attempts. 757 if ($USER->id != $params['userid']) { 758 self::check_can_view_user_data($params['userid'], $course, $cm, $context); 759 } 760 761 $result = array(); 762 $result['grade'] = (array) lesson_grade($lesson, $params['lessonattempt'], $params['userid']); 763 $result['warnings'] = $warnings; 764 return $result; 765 } 766 767 /** 768 * Describes the get_user_attempt_grade return value. 769 * 770 * @return external_single_structure 771 * @since Moodle 3.3 772 */ 773 public static function get_user_attempt_grade_returns() { 774 return new external_single_structure( 775 array( 776 'grade' => self::get_user_attempt_grade_structure(), 777 'warnings' => new external_warnings(), 778 ) 779 ); 780 } 781 782 /** 783 * Describes the parameters for get_content_pages_viewed. 784 * 785 * @return external_function_parameters 786 * @since Moodle 3.3 787 */ 788 public static function get_content_pages_viewed_parameters() { 789 return new external_function_parameters ( 790 array( 791 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 792 'lessonattempt' => new external_value(PARAM_INT, 'lesson attempt number'), 793 'userid' => new external_value(PARAM_INT, 'the user id (empty for current user)', VALUE_DEFAULT, null), 794 ) 795 ); 796 } 797 798 /** 799 * Return the list of content pages viewed by a user during a lesson attempt. 800 * 801 * @param int $lessonid lesson instance id 802 * @param int $lessonattempt lesson attempt number 803 * @param int $userid only fetch attempts of the given user 804 * @return array of warnings and page attempts 805 * @since Moodle 3.3 806 * @throws moodle_exception 807 */ 808 public static function get_content_pages_viewed($lessonid, $lessonattempt, $userid = null) { 809 global $USER; 810 811 $params = array( 812 'lessonid' => $lessonid, 813 'lessonattempt' => $lessonattempt, 814 'userid' => $userid, 815 ); 816 $params = self::validate_parameters(self::get_content_pages_viewed_parameters(), $params); 817 $warnings = array(); 818 819 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 820 821 // Default value for userid. 822 if (empty($params['userid'])) { 823 $params['userid'] = $USER->id; 824 } 825 826 // Extra checks so only users with permissions can view other users attempts. 827 if ($USER->id != $params['userid']) { 828 self::check_can_view_user_data($params['userid'], $course, $cm, $context); 829 } 830 831 $pages = $lesson->get_content_pages_viewed($params['lessonattempt'], $params['userid']); 832 833 $result = array(); 834 $result['pages'] = $pages; 835 $result['warnings'] = $warnings; 836 return $result; 837 } 838 839 /** 840 * Describes the get_content_pages_viewed return value. 841 * 842 * @return external_single_structure 843 * @since Moodle 3.3 844 */ 845 public static function get_content_pages_viewed_returns() { 846 return new external_single_structure( 847 array( 848 'pages' => new external_multiple_structure( 849 new external_single_structure( 850 array( 851 'id' => new external_value(PARAM_INT, 'The attempt id.'), 852 'lessonid' => new external_value(PARAM_INT, 'The lesson id.'), 853 'pageid' => new external_value(PARAM_INT, 'The page id.'), 854 'userid' => new external_value(PARAM_INT, 'The user who viewed the page.'), 855 'retry' => new external_value(PARAM_INT, 'The lesson attempt number.'), 856 'flag' => new external_value(PARAM_INT, '1 if the next page was calculated randomly.'), 857 'timeseen' => new external_value(PARAM_INT, 'The time the page was seen.'), 858 'nextpageid' => new external_value(PARAM_INT, 'The next page chosen id.'), 859 ), 860 'The content pages viewed.' 861 ) 862 ), 863 'warnings' => new external_warnings(), 864 ) 865 ); 866 } 867 868 /** 869 * Describes the parameters for get_user_timers. 870 * 871 * @return external_function_parameters 872 * @since Moodle 3.3 873 */ 874 public static function get_user_timers_parameters() { 875 return new external_function_parameters ( 876 array( 877 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 878 'userid' => new external_value(PARAM_INT, 'the user id (empty for current user)', VALUE_DEFAULT, null), 879 ) 880 ); 881 } 882 883 /** 884 * Return the timers in the current lesson for the given user. 885 * 886 * @param int $lessonid lesson instance id 887 * @param int $userid only fetch timers of the given user 888 * @return array of warnings and timers 889 * @since Moodle 3.3 890 * @throws moodle_exception 891 */ 892 public static function get_user_timers($lessonid, $userid = null) { 893 global $USER; 894 895 $params = array( 896 'lessonid' => $lessonid, 897 'userid' => $userid, 898 ); 899 $params = self::validate_parameters(self::get_user_timers_parameters(), $params); 900 $warnings = array(); 901 902 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 903 904 // Default value for userid. 905 if (empty($params['userid'])) { 906 $params['userid'] = $USER->id; 907 } 908 909 // Extra checks so only users with permissions can view other users attempts. 910 if ($USER->id != $params['userid']) { 911 self::check_can_view_user_data($params['userid'], $course, $cm, $context); 912 } 913 914 $timers = $lesson->get_user_timers($params['userid']); 915 916 $result = array(); 917 $result['timers'] = $timers; 918 $result['warnings'] = $warnings; 919 return $result; 920 } 921 922 /** 923 * Describes the get_user_timers return value. 924 * 925 * @return external_single_structure 926 * @since Moodle 3.3 927 */ 928 public static function get_user_timers_returns() { 929 return new external_single_structure( 930 array( 931 'timers' => new external_multiple_structure( 932 new external_single_structure( 933 array( 934 'id' => new external_value(PARAM_INT, 'The attempt id'), 935 'lessonid' => new external_value(PARAM_INT, 'The lesson id'), 936 'userid' => new external_value(PARAM_INT, 'The user id'), 937 'starttime' => new external_value(PARAM_INT, 'First access time for a new timer session'), 938 'lessontime' => new external_value(PARAM_INT, 'Last access time to the lesson during the timer session'), 939 'completed' => new external_value(PARAM_INT, 'If the lesson for this timer was completed'), 940 'timemodifiedoffline' => new external_value(PARAM_INT, 'Last modified time via webservices.'), 941 ), 942 'The timers' 943 ) 944 ), 945 'warnings' => new external_warnings(), 946 ) 947 ); 948 } 949 950 /** 951 * Describes the external structure for a lesson page. 952 * 953 * @return external_single_structure 954 * @since Moodle 3.3 955 */ 956 protected static function get_page_structure($required = VALUE_REQUIRED) { 957 return new external_single_structure( 958 array( 959 'id' => new external_value(PARAM_INT, 'The id of this lesson page'), 960 'lessonid' => new external_value(PARAM_INT, 'The id of the lesson this page belongs to'), 961 'prevpageid' => new external_value(PARAM_INT, 'The id of the page before this one'), 962 'nextpageid' => new external_value(PARAM_INT, 'The id of the next page in the page sequence'), 963 'qtype' => new external_value(PARAM_INT, 'Identifies the page type of this page'), 964 'qoption' => new external_value(PARAM_INT, 'Used to record page type specific options'), 965 'layout' => new external_value(PARAM_INT, 'Used to record page specific layout selections'), 966 'display' => new external_value(PARAM_INT, 'Used to record page specific display selections'), 967 'timecreated' => new external_value(PARAM_INT, 'Timestamp for when the page was created'), 968 'timemodified' => new external_value(PARAM_INT, 'Timestamp for when the page was last modified'), 969 'title' => new external_value(PARAM_RAW, 'The title of this page', VALUE_OPTIONAL), 970 'contents' => new external_value(PARAM_RAW, 'The contents of this page', VALUE_OPTIONAL), 971 'contentsformat' => new external_format_value('contents', VALUE_OPTIONAL), 972 'displayinmenublock' => new external_value(PARAM_BOOL, 'Toggles display in the left menu block'), 973 'type' => new external_value(PARAM_INT, 'The type of the page [question | structure]'), 974 'typeid' => new external_value(PARAM_INT, 'The unique identifier for the page type'), 975 'typestring' => new external_value(PARAM_RAW, 'The string that describes this page type'), 976 ), 977 'Page fields', $required 978 ); 979 } 980 981 /** 982 * Returns the fields of a page object 983 * @param lesson_page $page the lesson page 984 * @param bool $returncontents whether to return the page title and contents 985 * @return stdClass the fields matching the external page structure 986 * @since Moodle 3.3 987 */ 988 protected static function get_page_fields(lesson_page $page, $returncontents = false) { 989 $lesson = $page->lesson; 990 $context = $lesson->context; 991 992 $pagedata = new stdClass; // Contains the data that will be returned by the WS. 993 994 // Return the visible data. 995 $visibleproperties = array('id', 'lessonid', 'prevpageid', 'nextpageid', 'qtype', 'qoption', 'layout', 'display', 996 'displayinmenublock', 'type', 'typeid', 'typestring', 'timecreated', 'timemodified'); 997 foreach ($visibleproperties as $prop) { 998 $pagedata->{$prop} = $page->{$prop}; 999 } 1000 1001 // Check if we can see title (contents required custom rendering, we won't returning it here @see get_page_data). 1002 $canmanage = $lesson->can_manage(); 1003 // If we are managers or the menu block is enabled and is a content page visible always return contents. 1004 if ($returncontents || $canmanage || (lesson_displayleftif($lesson) && $page->displayinmenublock && $page->display)) { 1005 $pagedata->title = \core_external\util::format_string($page->title, $context); 1006 1007 $options = array('noclean' => true); 1008 [$pagedata->contents, $pagedata->contentsformat] = \core_external\util::format_text( 1009 $page->contents, 1010 $page->contentsformat, 1011 $context, 1012 'mod_lesson', 1013 'page_contents', 1014 $page->id, 1015 $options 1016 ); 1017 } 1018 return $pagedata; 1019 } 1020 1021 /** 1022 * Describes the parameters for get_pages. 1023 * 1024 * @return external_function_parameters 1025 * @since Moodle 3.3 1026 */ 1027 public static function get_pages_parameters() { 1028 return new external_function_parameters ( 1029 array( 1030 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 1031 'password' => new external_value(PARAM_RAW, 'optional password (the lesson may be protected)', VALUE_DEFAULT, ''), 1032 ) 1033 ); 1034 } 1035 1036 /** 1037 * Return the list of pages in a lesson (based on the user permissions). 1038 * 1039 * @param int $lessonid lesson instance id 1040 * @param string $password optional password (the lesson may be protected) 1041 * @return array of warnings and status result 1042 * @since Moodle 3.3 1043 * @throws moodle_exception 1044 */ 1045 public static function get_pages($lessonid, $password = '') { 1046 1047 $params = array('lessonid' => $lessonid, 'password' => $password); 1048 $params = self::validate_parameters(self::get_pages_parameters(), $params); 1049 $warnings = array(); 1050 1051 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 1052 self::validate_attempt($lesson, $params); 1053 1054 $lessonpages = $lesson->load_all_pages(); 1055 $pages = array(); 1056 1057 foreach ($lessonpages as $page) { 1058 $pagedata = new stdClass(); 1059 1060 // Get the page object fields. 1061 $pagedata->page = self::get_page_fields($page); 1062 1063 // Now, calculate the file area files (maybe we need to download a lesson for offline usage). 1064 $pagedata->filescount = 0; 1065 $pagedata->filessizetotal = 0; 1066 $files = $page->get_files(false); // Get files excluding directories. 1067 foreach ($files as $file) { 1068 $pagedata->filescount++; 1069 $pagedata->filessizetotal += $file->get_filesize(); 1070 } 1071 1072 // Now the possible answers and page jumps ids. 1073 $pagedata->answerids = array(); 1074 $pagedata->jumps = array(); 1075 $answers = $page->get_answers(); 1076 foreach ($answers as $answer) { 1077 $pagedata->answerids[] = $answer->id; 1078 $pagedata->jumps[] = $answer->jumpto; 1079 $files = $answer->get_files(false); // Get files excluding directories. 1080 foreach ($files as $file) { 1081 $pagedata->filescount++; 1082 $pagedata->filessizetotal += $file->get_filesize(); 1083 } 1084 } 1085 $pages[] = $pagedata; 1086 } 1087 1088 $result = array(); 1089 $result['pages'] = $pages; 1090 $result['warnings'] = $warnings; 1091 return $result; 1092 } 1093 1094 /** 1095 * Describes the get_pages return value. 1096 * 1097 * @return external_single_structure 1098 * @since Moodle 3.3 1099 */ 1100 public static function get_pages_returns() { 1101 return new external_single_structure( 1102 array( 1103 'pages' => new external_multiple_structure( 1104 new external_single_structure( 1105 array( 1106 'page' => self::get_page_structure(), 1107 'answerids' => new external_multiple_structure( 1108 new external_value(PARAM_INT, 'Answer id'), 'List of answers ids (empty for content pages in Moodle 1.9)' 1109 ), 1110 'jumps' => new external_multiple_structure( 1111 new external_value(PARAM_INT, 'Page to jump id'), 'List of possible page jumps' 1112 ), 1113 'filescount' => new external_value(PARAM_INT, 'The total number of files attached to the page'), 1114 'filessizetotal' => new external_value(PARAM_INT, 'The total size of the files'), 1115 ), 1116 'The lesson pages' 1117 ) 1118 ), 1119 'warnings' => new external_warnings(), 1120 ) 1121 ); 1122 } 1123 1124 /** 1125 * Describes the parameters for launch_attempt. 1126 * 1127 * @return external_function_parameters 1128 * @since Moodle 3.3 1129 */ 1130 public static function launch_attempt_parameters() { 1131 return new external_function_parameters ( 1132 array( 1133 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 1134 'password' => new external_value(PARAM_RAW, 'optional password (the lesson may be protected)', VALUE_DEFAULT, ''), 1135 'pageid' => new external_value(PARAM_INT, 'page id to continue from (only when continuing an attempt)', VALUE_DEFAULT, 0), 1136 'review' => new external_value(PARAM_BOOL, 'if we want to review just after finishing', VALUE_DEFAULT, false), 1137 ) 1138 ); 1139 } 1140 1141 /** 1142 * Return lesson messages formatted according the external_messages structure 1143 * 1144 * @param lesson $lesson lesson instance 1145 * @return array messages formatted 1146 * @since Moodle 3.3 1147 */ 1148 protected static function format_lesson_messages($lesson) { 1149 $messages = array(); 1150 foreach ($lesson->messages as $message) { 1151 $messages[] = array( 1152 'message' => $message[0], 1153 'type' => $message[1], 1154 ); 1155 } 1156 return $messages; 1157 } 1158 1159 /** 1160 * Return a external structure representing messages. 1161 * 1162 * @return external_multiple_structure messages structure 1163 * @since Moodle 3.3 1164 */ 1165 protected static function external_messages() { 1166 return new external_multiple_structure( 1167 new external_single_structure( 1168 array( 1169 'message' => new external_value(PARAM_RAW, 'Message.'), 1170 'type' => new external_value(PARAM_ALPHANUMEXT, 'Message type: usually a CSS identifier like: 1171 success, info, warning, error, notifyproblem, notifyerror, notifytiny, notifysuccess') 1172 ), 'The lesson generated messages' 1173 ) 1174 ); 1175 } 1176 1177 /** 1178 * Starts a new attempt or continues an existing one. 1179 * 1180 * @param int $lessonid lesson instance id 1181 * @param string $password optional password (the lesson may be protected) 1182 * @param int $pageid page id to continue from (only when continuing an attempt) 1183 * @param bool $review if we want to review just after finishing 1184 * @return array of warnings and status result 1185 * @since Moodle 3.3 1186 * @throws moodle_exception 1187 */ 1188 public static function launch_attempt($lessonid, $password = '', $pageid = 0, $review = false) { 1189 global $CFG, $USER; 1190 1191 $params = array('lessonid' => $lessonid, 'password' => $password, 'pageid' => $pageid, 'review' => $review); 1192 $params = self::validate_parameters(self::launch_attempt_parameters(), $params); 1193 $warnings = array(); 1194 1195 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 1196 self::validate_attempt($lesson, $params); 1197 1198 $newpageid = 0; 1199 // Starting a new lesson attempt. 1200 if (empty($params['pageid'])) { 1201 // Check if there is a recent timer created during the active session. 1202 $alreadystarted = false; 1203 if ($timers = $lesson->get_user_timers($USER->id, 'starttime DESC', '*', 0, 1)) { 1204 $timer = array_shift($timers); 1205 $endtime = $lesson->timelimit > 0 ? min($CFG->sessiontimeout, $lesson->timelimit) : $CFG->sessiontimeout; 1206 if (!$timer->completed && $timer->starttime > time() - $endtime) { 1207 $alreadystarted = true; 1208 } 1209 } 1210 if (!$alreadystarted && !$lesson->can_manage()) { 1211 $lesson->start_timer(); 1212 } 1213 } else { 1214 if ($params['pageid'] == LESSON_EOL) { 1215 throw new moodle_exception('endoflesson', 'lesson'); 1216 } 1217 $timer = $lesson->update_timer(true, true); 1218 if (!$lesson->check_time($timer)) { 1219 throw new moodle_exception('eolstudentoutoftime', 'lesson'); 1220 } 1221 } 1222 $messages = self::format_lesson_messages($lesson); 1223 1224 $result = array( 1225 'status' => true, 1226 'messages' => $messages, 1227 'warnings' => $warnings, 1228 ); 1229 return $result; 1230 } 1231 1232 /** 1233 * Describes the launch_attempt return value. 1234 * 1235 * @return external_single_structure 1236 * @since Moodle 3.3 1237 */ 1238 public static function launch_attempt_returns() { 1239 return new external_single_structure( 1240 array( 1241 'messages' => self::external_messages(), 1242 'warnings' => new external_warnings(), 1243 ) 1244 ); 1245 } 1246 1247 /** 1248 * Describes the parameters for get_page_data. 1249 * 1250 * @return external_function_parameters 1251 * @since Moodle 3.3 1252 */ 1253 public static function get_page_data_parameters() { 1254 return new external_function_parameters ( 1255 array( 1256 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 1257 'pageid' => new external_value(PARAM_INT, 'the page id'), 1258 'password' => new external_value(PARAM_RAW, 'optional password (the lesson may be protected)', VALUE_DEFAULT, ''), 1259 'review' => new external_value(PARAM_BOOL, 'if we want to review just after finishing (1 hour margin)', 1260 VALUE_DEFAULT, false), 1261 'returncontents' => new external_value(PARAM_BOOL, 'if we must return the complete page contents once rendered', 1262 VALUE_DEFAULT, false), 1263 ) 1264 ); 1265 } 1266 1267 /** 1268 * Return information of a given page, including its contents. 1269 * 1270 * @param int $lessonid lesson instance id 1271 * @param int $pageid page id 1272 * @param string $password optional password (the lesson may be protected) 1273 * @param bool $review if we want to review just after finishing (1 hour margin) 1274 * @param bool $returncontents if we must return the complete page contents once rendered 1275 * @return array of warnings and status result 1276 * @since Moodle 3.3 1277 * @throws moodle_exception 1278 */ 1279 public static function get_page_data($lessonid, $pageid, $password = '', $review = false, $returncontents = false) { 1280 global $PAGE, $USER; 1281 1282 $params = array('lessonid' => $lessonid, 'password' => $password, 'pageid' => $pageid, 'review' => $review, 1283 'returncontents' => $returncontents); 1284 $params = self::validate_parameters(self::get_page_data_parameters(), $params); 1285 1286 $warnings = $contentfiles = $answerfiles = $responsefiles = $answers = array(); 1287 $pagecontent = $ongoingscore = ''; 1288 $progress = $pagedata = null; 1289 1290 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 1291 self::validate_attempt($lesson, $params); 1292 1293 $pageid = $params['pageid']; 1294 1295 // This is called if a student leaves during a lesson. 1296 if ($pageid == LESSON_UNSEENBRANCHPAGE) { 1297 $pageid = lesson_unseen_question_jump($lesson, $USER->id, $pageid); 1298 } 1299 1300 if ($pageid != LESSON_EOL) { 1301 $reviewmode = $lesson->is_in_review_mode(); 1302 $lessonoutput = $PAGE->get_renderer('mod_lesson'); 1303 // Prepare page contents avoiding redirections. 1304 list($pageid, $page, $pagecontent) = $lesson->prepare_page_and_contents($pageid, $lessonoutput, $reviewmode, false); 1305 1306 if ($pageid > 0) { 1307 1308 $pagedata = self::get_page_fields($page, true); 1309 1310 // Files. 1311 $contentfiles = util::get_area_files($context->id, 'mod_lesson', 'page_contents', $page->id); 1312 1313 // Answers. 1314 $answers = array(); 1315 $pageanswers = $page->get_answers(); 1316 foreach ($pageanswers as $a) { 1317 $answer = array( 1318 'id' => $a->id, 1319 'answerfiles' => util::get_area_files($context->id, 'mod_lesson', 'page_answers', $a->id), 1320 'responsefiles' => util::get_area_files($context->id, 'mod_lesson', 'page_responses', $a->id), 1321 ); 1322 // For managers, return all the information (including correct answers, jumps). 1323 // If the teacher enabled offline attempts, this information will be downloaded too. 1324 if ($lesson->can_manage() || $lesson->allowofflineattempts) { 1325 $extraproperties = array('jumpto', 'grade', 'score', 'flags', 'timecreated', 'timemodified'); 1326 foreach ($extraproperties as $prop) { 1327 $answer[$prop] = $a->{$prop}; 1328 } 1329 1330 $options = array('noclean' => true); 1331 [$answer['answer'], $answer['answerformat']] = \core_external\util::format_text( 1332 $a->answer, 1333 $a->answerformat, 1334 $context, 1335 'mod_lesson', 1336 'page_answers', 1337 $a->id, 1338 $options 1339 ); 1340 [$answer['response'], $answer['responseformat']] = \core_external\util::format_text( 1341 $a->response, 1342 $a->responseformat, 1343 $context, 1344 'mod_lesson', 1345 'page_responses', 1346 $a->id, 1347 $options 1348 ); 1349 } 1350 $answers[] = $answer; 1351 } 1352 1353 // Additional lesson information. 1354 if (!$lesson->can_manage()) { 1355 if ($lesson->ongoing && !$reviewmode) { 1356 $ongoingscore = $lesson->get_ongoing_score_message(); 1357 } 1358 if ($lesson->progressbar) { 1359 $progress = $lesson->calculate_progress(); 1360 } 1361 } 1362 } 1363 } 1364 1365 $messages = self::format_lesson_messages($lesson); 1366 1367 $result = array( 1368 'newpageid' => $pageid, 1369 'ongoingscore' => $ongoingscore, 1370 'progress' => $progress, 1371 'contentfiles' => $contentfiles, 1372 'answers' => $answers, 1373 'messages' => $messages, 1374 'warnings' => $warnings, 1375 'displaymenu' => !empty(lesson_displayleftif($lesson)), 1376 ); 1377 1378 if (!empty($pagedata)) { 1379 $result['page'] = $pagedata; 1380 } 1381 if ($params['returncontents']) { 1382 $result['pagecontent'] = $pagecontent; // Return the complete page contents rendered. 1383 } 1384 1385 return $result; 1386 } 1387 1388 /** 1389 * Describes the get_page_data return value. 1390 * 1391 * @return external_single_structure 1392 * @since Moodle 3.3 1393 */ 1394 public static function get_page_data_returns() { 1395 return new external_single_structure( 1396 array( 1397 'page' => self::get_page_structure(VALUE_OPTIONAL), 1398 'newpageid' => new external_value(PARAM_INT, 'New page id (if a jump was made)'), 1399 'pagecontent' => new external_value(PARAM_RAW, 'Page html content', VALUE_OPTIONAL), 1400 'ongoingscore' => new external_value(PARAM_TEXT, 'The ongoing score message'), 1401 'progress' => new external_value(PARAM_INT, 'Progress percentage in the lesson'), 1402 'contentfiles' => new external_files(), 1403 'answers' => new external_multiple_structure( 1404 new external_single_structure( 1405 array( 1406 'id' => new external_value(PARAM_INT, 'The ID of this answer in the database'), 1407 'answerfiles' => new external_files(), 1408 'responsefiles' => new external_files(), 1409 'jumpto' => new external_value(PARAM_INT, 'Identifies where the user goes upon completing a page with this answer', 1410 VALUE_OPTIONAL), 1411 'grade' => new external_value(PARAM_INT, 'The grade this answer is worth', VALUE_OPTIONAL), 1412 'score' => new external_value(PARAM_INT, 'The score this answer will give', VALUE_OPTIONAL), 1413 'flags' => new external_value(PARAM_INT, 'Used to store options for the answer', VALUE_OPTIONAL), 1414 'timecreated' => new external_value(PARAM_INT, 'A timestamp of when the answer was created', VALUE_OPTIONAL), 1415 'timemodified' => new external_value(PARAM_INT, 'A timestamp of when the answer was modified', VALUE_OPTIONAL), 1416 'answer' => new external_value(PARAM_RAW, 'Possible answer text', VALUE_OPTIONAL), 1417 'answerformat' => new external_format_value('answer', VALUE_OPTIONAL), 1418 'response' => new external_value(PARAM_RAW, 'Response text for the answer', VALUE_OPTIONAL), 1419 'responseformat' => new external_format_value('response', VALUE_OPTIONAL), 1420 ), 'The page answers' 1421 1422 ) 1423 ), 1424 'messages' => self::external_messages(), 1425 'displaymenu' => new external_value(PARAM_BOOL, 'Whether we should display the menu or not in this page.'), 1426 'warnings' => new external_warnings(), 1427 ) 1428 ); 1429 } 1430 1431 /** 1432 * Describes the parameters for process_page. 1433 * 1434 * @return external_function_parameters 1435 * @since Moodle 3.3 1436 */ 1437 public static function process_page_parameters() { 1438 return new external_function_parameters ( 1439 array( 1440 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 1441 'pageid' => new external_value(PARAM_INT, 'the page id'), 1442 'data' => new external_multiple_structure( 1443 new external_single_structure( 1444 array( 1445 'name' => new external_value(PARAM_RAW, 'data name'), 1446 'value' => new external_value(PARAM_RAW, 'data value'), 1447 ) 1448 ), 'the data to be saved' 1449 ), 1450 'password' => new external_value(PARAM_RAW, 'optional password (the lesson may be protected)', VALUE_DEFAULT, ''), 1451 'review' => new external_value(PARAM_BOOL, 'if we want to review just after finishing (1 hour margin)', 1452 VALUE_DEFAULT, false), 1453 ) 1454 ); 1455 } 1456 1457 /** 1458 * Processes page responses 1459 * 1460 * @param int $lessonid lesson instance id 1461 * @param int $pageid page id 1462 * @param array $data the data to be saved 1463 * @param string $password optional password (the lesson may be protected) 1464 * @param bool $review if we want to review just after finishing (1 hour margin) 1465 * @return array of warnings and status result 1466 * @since Moodle 3.3 1467 * @throws moodle_exception 1468 */ 1469 public static function process_page($lessonid, $pageid, $data, $password = '', $review = false) { 1470 global $USER; 1471 1472 $params = array('lessonid' => $lessonid, 'pageid' => $pageid, 'data' => $data, 'password' => $password, 1473 'review' => $review); 1474 $params = self::validate_parameters(self::process_page_parameters(), $params); 1475 1476 $warnings = array(); 1477 $pagecontent = $ongoingscore = ''; 1478 $progress = null; 1479 1480 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 1481 1482 // Update timer so the validation can check the time restrictions. 1483 $timer = $lesson->update_timer(); 1484 self::validate_attempt($lesson, $params); 1485 1486 // Create the $_POST object required by the lesson question engine. 1487 $_POST = array(); 1488 foreach ($data as $element) { 1489 // First check if we are handling editor fields like answer[text]. 1490 if (preg_match('/(.+)\[(.+)\]$/', $element['name'], $matches)) { 1491 $_POST[$matches[1]][$matches[2]] = $element['value']; 1492 } else { 1493 $_POST[$element['name']] = $element['value']; 1494 } 1495 } 1496 1497 // Ignore sesskey (deep in some APIs), the request is already validated. 1498 $USER->ignoresesskey = true; 1499 1500 // Process page. 1501 $page = $lesson->load_page($params['pageid']); 1502 $result = $lesson->process_page_responses($page); 1503 1504 // Prepare messages. 1505 $reviewmode = $lesson->is_in_review_mode(); 1506 $lesson->add_messages_on_page_process($page, $result, $reviewmode); 1507 1508 // Additional lesson information. 1509 if (!$lesson->can_manage()) { 1510 if ($lesson->ongoing && !$reviewmode) { 1511 $ongoingscore = $lesson->get_ongoing_score_message(); 1512 } 1513 if ($lesson->progressbar) { 1514 $progress = $lesson->calculate_progress(); 1515 } 1516 } 1517 1518 // Check conditionally everything coming from result (except newpageid because is always set). 1519 $result = array( 1520 'newpageid' => (int) $result->newpageid, 1521 'inmediatejump' => $result->inmediatejump, 1522 'nodefaultresponse' => !empty($result->nodefaultresponse), 1523 'feedback' => (isset($result->feedback)) ? $result->feedback : '', 1524 'attemptsremaining' => (isset($result->attemptsremaining)) ? $result->attemptsremaining : null, 1525 'correctanswer' => !empty($result->correctanswer), 1526 'noanswer' => !empty($result->noanswer), 1527 'isessayquestion' => !empty($result->isessayquestion), 1528 'maxattemptsreached' => !empty($result->maxattemptsreached), 1529 'response' => (isset($result->response)) ? $result->response : '', 1530 'studentanswer' => (isset($result->studentanswer)) ? $result->studentanswer : '', 1531 'userresponse' => (isset($result->userresponse)) ? $result->userresponse : '', 1532 'reviewmode' => $reviewmode, 1533 'ongoingscore' => $ongoingscore, 1534 'progress' => $progress, 1535 'displaymenu' => !empty(lesson_displayleftif($lesson)), 1536 'messages' => self::format_lesson_messages($lesson), 1537 'warnings' => $warnings, 1538 ); 1539 return $result; 1540 } 1541 1542 /** 1543 * Describes the process_page return value. 1544 * 1545 * @return external_single_structure 1546 * @since Moodle 3.3 1547 */ 1548 public static function process_page_returns() { 1549 return new external_single_structure( 1550 array( 1551 'newpageid' => new external_value(PARAM_INT, 'New page id (if a jump was made).'), 1552 'inmediatejump' => new external_value(PARAM_BOOL, 'Whether the page processing redirect directly to anoter page.'), 1553 'nodefaultresponse' => new external_value(PARAM_BOOL, 'Whether there is not a default response.'), 1554 'feedback' => new external_value(PARAM_RAW, 'The response feedback.'), 1555 'attemptsremaining' => new external_value(PARAM_INT, 'Number of attempts remaining.'), 1556 'correctanswer' => new external_value(PARAM_BOOL, 'Whether the answer is correct.'), 1557 'noanswer' => new external_value(PARAM_BOOL, 'Whether there aren\'t answers.'), 1558 'isessayquestion' => new external_value(PARAM_BOOL, 'Whether is a essay question.'), 1559 'maxattemptsreached' => new external_value(PARAM_BOOL, 'Whether we reachered the max number of attempts.'), 1560 'response' => new external_value(PARAM_RAW, 'The response.'), 1561 'studentanswer' => new external_value(PARAM_RAW, 'The student answer.'), 1562 'userresponse' => new external_value(PARAM_RAW, 'The user response.'), 1563 'reviewmode' => new external_value(PARAM_BOOL, 'Whether the user is reviewing.'), 1564 'ongoingscore' => new external_value(PARAM_TEXT, 'The ongoing message.'), 1565 'progress' => new external_value(PARAM_INT, 'Progress percentage in the lesson.'), 1566 'displaymenu' => new external_value(PARAM_BOOL, 'Whether we should display the menu or not in this page.'), 1567 'messages' => self::external_messages(), 1568 'warnings' => new external_warnings(), 1569 ) 1570 ); 1571 } 1572 1573 /** 1574 * Describes the parameters for finish_attempt. 1575 * 1576 * @return external_function_parameters 1577 * @since Moodle 3.3 1578 */ 1579 public static function finish_attempt_parameters() { 1580 return new external_function_parameters ( 1581 array( 1582 'lessonid' => new external_value(PARAM_INT, 'Lesson instance id.'), 1583 'password' => new external_value(PARAM_RAW, 'Optional password (the lesson may be protected).', VALUE_DEFAULT, ''), 1584 'outoftime' => new external_value(PARAM_BOOL, 'If the user run out of time.', VALUE_DEFAULT, false), 1585 'review' => new external_value(PARAM_BOOL, 'If we want to review just after finishing (1 hour margin).', 1586 VALUE_DEFAULT, false), 1587 ) 1588 ); 1589 } 1590 1591 /** 1592 * Finishes the current attempt. 1593 * 1594 * @param int $lessonid lesson instance id 1595 * @param string $password optional password (the lesson may be protected) 1596 * @param bool $outoftime optional if the user run out of time 1597 * @param bool $review if we want to review just after finishing (1 hour margin) 1598 * @return array of warnings and information about the finished attempt 1599 * @since Moodle 3.3 1600 * @throws moodle_exception 1601 */ 1602 public static function finish_attempt($lessonid, $password = '', $outoftime = false, $review = false) { 1603 1604 $params = array('lessonid' => $lessonid, 'password' => $password, 'outoftime' => $outoftime, 'review' => $review); 1605 $params = self::validate_parameters(self::finish_attempt_parameters(), $params); 1606 1607 $warnings = array(); 1608 1609 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 1610 1611 // Update timer so the validation can check the time restrictions. 1612 $timer = $lesson->update_timer(); 1613 1614 // Return the validation to avoid exceptions in case the user is out of time. 1615 $params['pageid'] = LESSON_EOL; 1616 $validation = self::validate_attempt($lesson, $params, true); 1617 1618 if (array_key_exists('eolstudentoutoftime', $validation)) { 1619 // Maybe we run out of time just now. 1620 $params['outoftime'] = true; 1621 unset($validation['eolstudentoutoftime']); 1622 } 1623 // Check if there are more errors. 1624 if (!empty($validation)) { 1625 reset($validation); 1626 throw new moodle_exception(key($validation), 'lesson', '', current($validation)); // Throw first error. 1627 } 1628 1629 // Set out of time to normal (it is the only existing mode). 1630 $outoftimemode = $params['outoftime'] ? 'normal' : ''; 1631 $result = $lesson->process_eol_page($outoftimemode); 1632 1633 // Return the data. 1634 $validmessages = array( 1635 'notenoughtimespent', 'numberofpagesviewed', 'youshouldview', 'numberofcorrectanswers', 1636 'displayscorewithessays', 'displayscorewithoutessays', 'yourcurrentgradeisoutof', 'eolstudentoutoftimenoanswers', 1637 'welldone', 'displayofgrade', 'modattemptsnoteacher', 'progresscompleted'); 1638 1639 $data = array(); 1640 foreach ($result as $el => $value) { 1641 if ($value !== false) { 1642 $message = ''; 1643 if (in_array($el, $validmessages)) { // Check if the data comes with an informative message. 1644 $a = (is_bool($value)) ? null : $value; 1645 $message = get_string($el, 'lesson', $a); 1646 } 1647 // Return the data. 1648 $data[] = array( 1649 'name' => $el, 1650 'value' => (is_bool($value)) ? 1 : json_encode($value), // The data can be a php object. 1651 'message' => $message 1652 ); 1653 } 1654 } 1655 1656 $result = array( 1657 'data' => $data, 1658 'messages' => self::format_lesson_messages($lesson), 1659 'warnings' => $warnings, 1660 ); 1661 return $result; 1662 } 1663 1664 /** 1665 * Describes the finish_attempt return value. 1666 * 1667 * @return external_single_structure 1668 * @since Moodle 3.3 1669 */ 1670 public static function finish_attempt_returns() { 1671 return new external_single_structure( 1672 array( 1673 'data' => new external_multiple_structure( 1674 new external_single_structure( 1675 array( 1676 'name' => new external_value(PARAM_ALPHANUMEXT, 'Data name.'), 1677 'value' => new external_value(PARAM_RAW, 'Data value.'), 1678 'message' => new external_value(PARAM_RAW, 'Data message (translated string).'), 1679 ) 1680 ), 'The EOL page information data.' 1681 ), 1682 'messages' => self::external_messages(), 1683 'warnings' => new external_warnings(), 1684 ) 1685 ); 1686 } 1687 1688 /** 1689 * Describes the parameters for get_attempts_overview. 1690 * 1691 * @return external_function_parameters 1692 * @since Moodle 3.3 1693 */ 1694 public static function get_attempts_overview_parameters() { 1695 return new external_function_parameters ( 1696 array( 1697 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 1698 'groupid' => new external_value(PARAM_INT, 'group id, 0 means that the function will determine the user group', 1699 VALUE_DEFAULT, 0), 1700 ) 1701 ); 1702 } 1703 1704 /** 1705 * Get a list of all the attempts made by users in a lesson. 1706 * 1707 * @param int $lessonid lesson instance id 1708 * @param int $groupid group id, 0 means that the function will determine the user group 1709 * @return array of warnings and status result 1710 * @since Moodle 3.3 1711 * @throws moodle_exception 1712 */ 1713 public static function get_attempts_overview($lessonid, $groupid = 0) { 1714 1715 $params = array('lessonid' => $lessonid, 'groupid' => $groupid); 1716 $params = self::validate_parameters(self::get_attempts_overview_parameters(), $params); 1717 $warnings = array(); 1718 1719 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 1720 require_capability('mod/lesson:viewreports', $context); 1721 1722 if (!empty($params['groupid'])) { 1723 $groupid = $params['groupid']; 1724 // Determine is the group is visible to user. 1725 if (!groups_group_visible($groupid, $course, $cm)) { 1726 throw new moodle_exception('notingroup'); 1727 } 1728 } else { 1729 // Check to see if groups are being used here. 1730 if ($groupmode = groups_get_activity_groupmode($cm)) { 1731 $groupid = groups_get_activity_group($cm); 1732 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups). 1733 if (!groups_group_visible($groupid, $course, $cm)) { 1734 throw new moodle_exception('notingroup'); 1735 } 1736 } else { 1737 $groupid = 0; 1738 } 1739 } 1740 1741 $result = array( 1742 'warnings' => $warnings 1743 ); 1744 1745 list($table, $data) = lesson_get_overview_report_table_and_data($lesson, $groupid); 1746 if ($data !== false) { 1747 $result['data'] = $data; 1748 } 1749 1750 return $result; 1751 } 1752 1753 /** 1754 * Describes the get_attempts_overview return value. 1755 * 1756 * @return external_single_structure 1757 * @since Moodle 3.3 1758 */ 1759 public static function get_attempts_overview_returns() { 1760 return new external_single_structure( 1761 array( 1762 'data' => new external_single_structure( 1763 array( 1764 'lessonscored' => new external_value(PARAM_BOOL, 'True if the lesson was scored.'), 1765 'numofattempts' => new external_value(PARAM_INT, 'Number of attempts.'), 1766 'avescore' => new external_value(PARAM_FLOAT, 'Average score.'), 1767 'highscore' => new external_value(PARAM_FLOAT, 'High score.'), 1768 'lowscore' => new external_value(PARAM_FLOAT, 'Low score.'), 1769 'avetime' => new external_value(PARAM_INT, 'Average time (spent in taking the lesson).'), 1770 'hightime' => new external_value(PARAM_INT, 'High time.'), 1771 'lowtime' => new external_value(PARAM_INT, 'Low time.'), 1772 'students' => new external_multiple_structure( 1773 new external_single_structure( 1774 array( 1775 'id' => new external_value(PARAM_INT, 'User id.'), 1776 'fullname' => new external_value(PARAM_TEXT, 'User full name.'), 1777 'bestgrade' => new external_value(PARAM_FLOAT, 'Best grade.'), 1778 'attempts' => new external_multiple_structure( 1779 new external_single_structure( 1780 array( 1781 'try' => new external_value(PARAM_INT, 'Attempt number.'), 1782 'grade' => new external_value(PARAM_FLOAT, 'Attempt grade.'), 1783 'timestart' => new external_value(PARAM_INT, 'Attempt time started.'), 1784 'timeend' => new external_value(PARAM_INT, 'Attempt last time continued.'), 1785 'end' => new external_value(PARAM_INT, 'Attempt time ended.'), 1786 ) 1787 ) 1788 ) 1789 ) 1790 ), 'Students data, including attempts.', VALUE_OPTIONAL 1791 ), 1792 ), 1793 'Attempts overview data (empty for no attemps).', VALUE_OPTIONAL 1794 ), 1795 'warnings' => new external_warnings(), 1796 ) 1797 ); 1798 } 1799 1800 /** 1801 * Describes the parameters for get_user_attempt. 1802 * 1803 * @return external_function_parameters 1804 * @since Moodle 3.3 1805 */ 1806 public static function get_user_attempt_parameters() { 1807 return new external_function_parameters ( 1808 array( 1809 'lessonid' => new external_value(PARAM_INT, 'Lesson instance id.'), 1810 'userid' => new external_value(PARAM_INT, 'The user id. 0 for current user.'), 1811 'lessonattempt' => new external_value(PARAM_INT, 'The attempt number.'), 1812 ) 1813 ); 1814 } 1815 1816 /** 1817 * Return information about the given user attempt (including answers). 1818 * 1819 * @param int $lessonid lesson instance id 1820 * @param int $userid the user id 1821 * @param int $lessonattempt the attempt number 1822 * @return array of warnings and page attempts 1823 * @since Moodle 3.3 1824 * @throws moodle_exception 1825 */ 1826 public static function get_user_attempt($lessonid, $userid, $lessonattempt) { 1827 global $USER; 1828 1829 $params = array( 1830 'lessonid' => $lessonid, 1831 'userid' => $userid, 1832 'lessonattempt' => $lessonattempt, 1833 ); 1834 $params = self::validate_parameters(self::get_user_attempt_parameters(), $params); 1835 $warnings = array(); 1836 1837 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 1838 1839 // Default value for userid. 1840 if (empty($params['userid'])) { 1841 $params['userid'] = $USER->id; 1842 } 1843 1844 // Extra checks so only users with permissions can view other users attempts. 1845 if ($USER->id != $params['userid']) { 1846 self::check_can_view_user_data($params['userid'], $course, $cm, $context); 1847 } 1848 1849 list($answerpages, $userstats) = lesson_get_user_detailed_report_data($lesson, $userid, $params['lessonattempt']); 1850 // Convert page object to page record. 1851 foreach ($answerpages as $answerp) { 1852 $answerp->page = self::get_page_fields($answerp->page); 1853 } 1854 1855 $result = array( 1856 'answerpages' => $answerpages, 1857 'userstats' => $userstats, 1858 'warnings' => $warnings, 1859 ); 1860 return $result; 1861 } 1862 1863 /** 1864 * Describes the get_user_attempt return value. 1865 * 1866 * @return external_single_structure 1867 * @since Moodle 3.3 1868 */ 1869 public static function get_user_attempt_returns() { 1870 return new external_single_structure( 1871 array( 1872 'answerpages' => new external_multiple_structure( 1873 new external_single_structure( 1874 array( 1875 'page' => self::get_page_structure(VALUE_OPTIONAL), 1876 'title' => new external_value(PARAM_RAW, 'Page title.'), 1877 'contents' => new external_value(PARAM_RAW, 'Page contents.'), 1878 'qtype' => new external_value(PARAM_TEXT, 'Identifies the page type of this page.'), 1879 'grayout' => new external_value(PARAM_INT, 'If is required to apply a grayout.'), 1880 'answerdata' => new external_single_structure( 1881 array( 1882 'score' => new external_value(PARAM_TEXT, 'The score (text version).'), 1883 'response' => new external_value(PARAM_RAW, 'The response text.'), 1884 'responseformat' => new external_format_value('response.'), 1885 'answers' => new external_multiple_structure( 1886 new external_multiple_structure(new external_value(PARAM_RAW, 'Possible answers and info.')), 1887 'User answers', 1888 VALUE_OPTIONAL 1889 ), 1890 ), 'Answer data (empty in content pages created in Moodle 1.x).', VALUE_OPTIONAL 1891 ) 1892 ) 1893 ) 1894 ), 1895 'userstats' => new external_single_structure( 1896 array( 1897 'grade' => new external_value(PARAM_FLOAT, 'Attempt final grade.'), 1898 'completed' => new external_value(PARAM_INT, 'Time completed.'), 1899 'timetotake' => new external_value(PARAM_INT, 'Time taken.'), 1900 'gradeinfo' => self::get_user_attempt_grade_structure(VALUE_OPTIONAL) 1901 ) 1902 ), 1903 'warnings' => new external_warnings(), 1904 ) 1905 ); 1906 } 1907 1908 /** 1909 * Describes the parameters for get_pages_possible_jumps. 1910 * 1911 * @return external_function_parameters 1912 * @since Moodle 3.3 1913 */ 1914 public static function get_pages_possible_jumps_parameters() { 1915 return new external_function_parameters ( 1916 array( 1917 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 1918 ) 1919 ); 1920 } 1921 1922 /** 1923 * Return all the possible jumps for the pages in a given lesson. 1924 * 1925 * You may expect different results on consecutive executions due to the random nature of the lesson module. 1926 * 1927 * @param int $lessonid lesson instance id 1928 * @return array of warnings and possible jumps 1929 * @since Moodle 3.3 1930 * @throws moodle_exception 1931 */ 1932 public static function get_pages_possible_jumps($lessonid) { 1933 global $USER; 1934 1935 $params = array('lessonid' => $lessonid); 1936 $params = self::validate_parameters(self::get_pages_possible_jumps_parameters(), $params); 1937 1938 $warnings = $jumps = array(); 1939 1940 list($lesson, $course, $cm, $context) = self::validate_lesson($params['lessonid']); 1941 1942 // Only return for managers or if offline attempts are enabled. 1943 if ($lesson->can_manage() || $lesson->allowofflineattempts) { 1944 1945 $lessonpages = $lesson->load_all_pages(); 1946 foreach ($lessonpages as $page) { 1947 $jump = array(); 1948 $jump['pageid'] = $page->id; 1949 1950 $answers = $page->get_answers(); 1951 if (count($answers) > 0) { 1952 foreach ($answers as $answer) { 1953 $jump['answerid'] = $answer->id; 1954 $jump['jumpto'] = $answer->jumpto; 1955 $jump['calculatedjump'] = $lesson->calculate_new_page_on_jump($page, $answer->jumpto); 1956 // Special case, only applies to branch/end of branch. 1957 if ($jump['calculatedjump'] == LESSON_RANDOMBRANCH) { 1958 $jump['calculatedjump'] = lesson_unseen_branch_jump($lesson, $USER->id); 1959 } 1960 $jumps[] = $jump; 1961 } 1962 } else { 1963 // Imported lessons from 1.x. 1964 $jump['answerid'] = 0; 1965 $jump['jumpto'] = $page->nextpageid; 1966 $jump['calculatedjump'] = $lesson->calculate_new_page_on_jump($page, $page->nextpageid); 1967 $jumps[] = $jump; 1968 } 1969 } 1970 } 1971 1972 $result = array( 1973 'jumps' => $jumps, 1974 'warnings' => $warnings, 1975 ); 1976 return $result; 1977 } 1978 1979 /** 1980 * Describes the get_pages_possible_jumps return value. 1981 * 1982 * @return external_single_structure 1983 * @since Moodle 3.3 1984 */ 1985 public static function get_pages_possible_jumps_returns() { 1986 return new external_single_structure( 1987 array( 1988 'jumps' => new external_multiple_structure( 1989 new external_single_structure( 1990 array( 1991 'pageid' => new external_value(PARAM_INT, 'The page id'), 1992 'answerid' => new external_value(PARAM_INT, 'The answer id'), 1993 'jumpto' => new external_value(PARAM_INT, 'The jump (page id or type of jump)'), 1994 'calculatedjump' => new external_value(PARAM_INT, 'The real page id (or EOL) to jump'), 1995 ), 'Jump for a page answer' 1996 ) 1997 ), 1998 'warnings' => new external_warnings(), 1999 ) 2000 ); 2001 } 2002 2003 /** 2004 * Describes the parameters for get_lesson. 2005 * 2006 * @return external_function_parameters 2007 * @since Moodle 3.3 2008 */ 2009 public static function get_lesson_parameters() { 2010 return new external_function_parameters ( 2011 array( 2012 'lessonid' => new external_value(PARAM_INT, 'lesson instance id'), 2013 'password' => new external_value(PARAM_RAW, 'lesson password', VALUE_DEFAULT, ''), 2014 ) 2015 ); 2016 } 2017 2018 /** 2019 * Return information of a given lesson. 2020 * 2021 * @param int $lessonid lesson instance id 2022 * @param string $password optional password (the lesson may be protected) 2023 * @return array of warnings and status result 2024 * @since Moodle 3.3 2025 * @throws moodle_exception 2026 */ 2027 public static function get_lesson($lessonid, $password = '') { 2028 global $PAGE; 2029 2030 $params = array('lessonid' => $lessonid, 'password' => $password); 2031 $params = self::validate_parameters(self::get_lesson_parameters(), $params); 2032 $warnings = array(); 2033 2034 list($lesson, $course, $cm, $context, $lessonrecord) = self::validate_lesson($params['lessonid']); 2035 2036 $lessonrecord = self::get_lesson_summary_for_exporter($lessonrecord, $params['password']); 2037 $exporter = new lesson_summary_exporter($lessonrecord, array('context' => $context)); 2038 2039 $result = array(); 2040 $result['lesson'] = $exporter->export($PAGE->get_renderer('core')); 2041 $result['warnings'] = $warnings; 2042 return $result; 2043 } 2044 2045 /** 2046 * Describes the get_lesson return value. 2047 * 2048 * @return external_single_structure 2049 * @since Moodle 3.3 2050 */ 2051 public static function get_lesson_returns() { 2052 return new external_single_structure( 2053 array( 2054 'lesson' => lesson_summary_exporter::get_read_structure(), 2055 'warnings' => new external_warnings(), 2056 ) 2057 ); 2058 } 2059 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body