Differences Between: [Versions 400 and 401] [Versions 400 and 402] [Versions 400 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 * The xapi_handler for xAPI statements. 19 * 20 * @package mod_h5pactivity 21 * @since Moodle 3.9 22 * @copyright 2020 Ferran Recio <ferran@moodle.com> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 namespace mod_h5pactivity\xapi; 27 28 use mod_h5pactivity\local\attempt; 29 use mod_h5pactivity\local\manager; 30 use mod_h5pactivity\event\statement_received; 31 use core_xapi\local\statement; 32 use core_xapi\handler as handler_base; 33 use core\event\base as event_base; 34 use context_module; 35 36 defined('MOODLE_INTERNAL') || die(); 37 38 global $CFG; 39 require_once($CFG->dirroot.'/mod/h5pactivity/lib.php'); 40 41 /** 42 * Class xapi_handler for H5P statements. 43 * 44 * @package mod_h5pactivity 45 * @since Moodle 3.9 46 * @copyright 2020 Ferran Recio <ferran@moodle.com> 47 */ 48 class handler extends handler_base { 49 50 /** 51 * Convert a statement object into a Moodle xAPI Event. 52 * 53 * If a statement is accepted by the xAPI webservice the component must provide 54 * an event to handle that statement, otherwise the statement will be rejected. 55 * 56 * @param statement $statement 57 * @return core\event\base|null a Moodle event to trigger 58 */ 59 public function statement_to_event(statement $statement): ?event_base { 60 61 // Only process statements with results. 62 $xapiresult = $statement->get_result(); 63 if (empty($xapiresult)) { 64 return null; 65 } 66 67 // Statements can contain any verb, for security reasons each 68 // plugin needs to filter it's own specific verbs. For now the only verbs the H5P 69 // plugin keeps track on are "answered" and "completed" because they are realted to grading. 70 // In the future this list can be increased to track more user interactions. 71 $validvalues = [ 72 'http://adlnet.gov/expapi/verbs/answered', 73 'http://adlnet.gov/expapi/verbs/completed', 74 ]; 75 $xapiverbid = $statement->get_verb_id(); 76 if (!in_array($xapiverbid, $validvalues)) { 77 return null; 78 } 79 80 // Validate object. 81 $xapiobject = $statement->get_activity_id(); 82 83 // H5P add some extra params to ID to define subcontents. 84 $parts = explode('?', $xapiobject, 2); 85 $contextid = array_shift($parts); 86 $subcontent = str_replace('subContentId=', '', array_shift($parts)); 87 if (empty($contextid) || !is_numeric($contextid)) { 88 return null; 89 } 90 $context = \context::instance_by_id($contextid); 91 if (!$context instanceof \context_module) { 92 return null; 93 } 94 95 // As the activity does not accept group statement, the code can assume that the 96 // statement user is valid (otherwise the xAPI library will reject the statement). 97 $user = $statement->get_user(); 98 if (!has_capability('mod/h5pactivity:view', $context, $user)) { 99 return null; 100 } 101 102 $cm = get_coursemodule_from_id('h5pactivity', $context->instanceid, 0, false); 103 if (!$cm) { 104 return null; 105 } 106 107 $manager = manager::create_from_coursemodule($cm); 108 109 if (!$manager->is_tracking_enabled($user)) { 110 return null; 111 } 112 113 // For now, attempts are only processed on a single batch starting with the final "completed" 114 // and "answered" statements (this could change in the future). This initial statement have no 115 // subcontent defined as they are the main finishing statement. For this reason, this statement 116 // indicates a new attempt creation. This way, simpler H5P activies like multichoice can generate 117 // an attempt each time the user answers while complex like question-set could group all questions 118 // in a single attempt (using subcontents). 119 if (empty($subcontent)) { 120 $attempt = attempt::new_attempt($user, $cm); 121 } else { 122 $attempt = attempt::last_attempt($user, $cm); 123 } 124 if (!$attempt) { 125 return null; 126 } 127 $result = $attempt->save_statement($statement, $subcontent); 128 if (!$result) { 129 return null; 130 } 131 132 // Update activity if necessary. 133 if ($attempt->get_scoreupdated()) { 134 $grader = $manager->get_grader(); 135 $grader->update_grades($user->id); 136 } 137 138 // Convert into a Moodle event. 139 $minstatement = $statement->minify(); 140 $params = [ 141 'other' => $minstatement, 142 'context' => $context, 143 'objectid' => $cm->instance, 144 'userid' => $user->id, 145 ]; 146 return statement_received::create($params); 147 } 148 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body