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