See Release Notes
Long Term Support Release
Differences Between: [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 * This is the external method for getting the information needed to present a results report. 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\external; 27 28 defined('MOODLE_INTERNAL') || die(); 29 30 require_once($CFG->libdir . '/externallib.php'); 31 32 use mod_h5pactivity\local\manager; 33 use mod_h5pactivity\local\report\results as report_results; 34 use external_api; 35 use external_function_parameters; 36 use external_value; 37 use external_multiple_structure; 38 use external_single_structure; 39 use external_warnings; 40 use moodle_exception; 41 use context_module; 42 use stdClass; 43 44 /** 45 * This is the external method for getting the information needed to present a results report. 46 * 47 * @copyright 2020 Ferran Recio <ferran@moodle.com> 48 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 49 */ 50 class get_results extends external_api { 51 52 /** 53 * Webservice parameters. 54 * 55 * @return external_function_parameters 56 */ 57 public static function execute_parameters(): external_function_parameters { 58 return new external_function_parameters( 59 [ 60 'h5pactivityid' => new external_value(PARAM_INT, 'h5p activity instance id'), 61 'attemptids' => new external_multiple_structure( 62 new external_value(PARAM_INT, 'The attempt id'), 63 'Attempt ids', VALUE_DEFAULT, [] 64 ), 65 ] 66 ); 67 } 68 69 /** 70 * Return user attempts results information in a h5p activity. 71 * 72 * In case an empty array of attempt ids is passed, the method will load all 73 * activity attempts from the current user. 74 * 75 * @throws moodle_exception if the user cannot see the report 76 * @param int $h5pactivityid The h5p activity id 77 * @param int[] $attemptids The attempt ids 78 * @return stdClass report data 79 */ 80 public static function execute(int $h5pactivityid, array $attemptids = []): stdClass { 81 global $USER; 82 83 $params = external_api::validate_parameters(self::execute_parameters(), [ 84 'h5pactivityid' => $h5pactivityid, 85 'attemptids' => $attemptids, 86 ]); 87 $h5pactivityid = $params['h5pactivityid']; 88 $attemptids = $params['attemptids']; 89 90 $warnings = []; 91 92 // Request and permission validation. 93 list ($course, $cm) = get_course_and_cm_from_instance($h5pactivityid, 'h5pactivity'); 94 95 $context = context_module::instance($cm->id); 96 self::validate_context($context); 97 98 $manager = manager::create_from_coursemodule($cm); 99 100 if (empty($attemptids)) { 101 $attemptids = []; 102 foreach ($manager->get_user_attempts($USER->id) as $attempt) { 103 $attemptids[] = $attempt->get_id(); 104 } 105 } 106 107 $attempts = []; 108 foreach ($attemptids as $attemptid) { 109 $report = $manager->get_report(null, $attemptid); 110 111 if ($report && $report instanceof report_results) { 112 $attempts[] = self::export_attempt($report); 113 } else { 114 $warnings[] = [ 115 'item' => 'h5pactivity_attempts', 116 'itemid' => $attemptid, 117 'warningcode' => '1', 118 'message' => "Cannot access attempt", 119 ]; 120 } 121 } 122 123 $result = (object)[ 124 'activityid' => $h5pactivityid, 125 'attempts' => $attempts, 126 'warnings' => $warnings, 127 ]; 128 129 return $result; 130 } 131 132 /** 133 * Return a data object from an attempt. 134 * 135 * @param report_results $report the attempt data 136 * @return stdClass a WS compatible version of the attempt 137 */ 138 private static function export_attempt(report_results $report): stdClass { 139 140 $data = $report->export_data_for_external(); 141 142 $attemptdata = $data->attempt; 143 144 $attempt = (object)[ 145 'id' => $attemptdata->id, 146 'h5pactivityid' => $attemptdata->h5pactivityid, 147 'userid' => $attemptdata->userid, 148 'timecreated' => $attemptdata->timecreated, 149 'timemodified' => $attemptdata->timemodified, 150 'attempt' => $attemptdata->attempt, 151 'rawscore' => $attemptdata->rawscore, 152 'maxscore' => $attemptdata->maxscore, 153 'duration' => (empty($attemptdata->durationvalue)) ? 0 : $attemptdata->durationvalue, 154 'scaled' => (empty($attemptdata->scaled)) ? 0 : $attemptdata->scaled, 155 'results' => [], 156 ]; 157 if (isset($attemptdata->completion) && $attemptdata->completion !== null) { 158 $attempt->completion = $attemptdata->completion; 159 } 160 if (isset($attemptdata->success) && $attemptdata->success !== null) { 161 $attempt->success = $attemptdata->success; 162 } 163 foreach ($data->results as $result) { 164 $attempt->results[] = self::export_result($result); 165 } 166 return $attempt; 167 } 168 169 /** 170 * Return a data object from a result. 171 * 172 * @param stdClass $data the result data 173 * @return stdClass a WS compatible version of the result 174 */ 175 private static function export_result(stdClass $data): stdClass { 176 $result = (object)[ 177 'id' => $data->id, 178 'attemptid' => $data->attemptid, 179 'subcontent' => $data->subcontent, 180 'timecreated' => $data->timecreated, 181 'interactiontype' => $data->interactiontype, 182 'description' => $data->description, 183 'rawscore' => $data->rawscore, 184 'maxscore' => $data->maxscore, 185 'duration' => $data->duration, 186 'optionslabel' => $data->optionslabel ?? get_string('choice', 'mod_h5pactivity'), 187 'correctlabel' => $data->correctlabel ?? get_string('correct_answer', 'mod_h5pactivity'), 188 'answerlabel' => $data->answerlabel ?? get_string('attempt_answer', 'mod_h5pactivity'), 189 'track' => $data->track ?? false, 190 ]; 191 if (isset($data->completion) && $data->completion !== null) { 192 $result->completion = $data->completion; 193 } 194 if (isset($data->success) && $data->success !== null) { 195 $result->success = $data->success; 196 } 197 if (isset($data->options)) { 198 $result->options = $data->options; 199 } 200 if (isset($data->content)) { 201 $result->content = $data->content; 202 } 203 return $result; 204 } 205 206 /** 207 * Describes the get_h5pactivity_access_information return value. 208 * 209 * @return external_single_structure 210 */ 211 public static function execute_returns(): external_single_structure { 212 return new external_single_structure([ 213 'activityid' => new external_value(PARAM_INT, 'Activity course module ID'), 214 'attempts' => new external_multiple_structure( 215 self::get_attempt_returns(), 'The complete attempts list' 216 ), 217 'warnings' => new external_warnings(), 218 ], 'Activity attempts results data'); 219 } 220 221 /** 222 * Return the external structure of an attempt 223 * @return external_single_structure 224 */ 225 private static function get_attempt_returns(): external_single_structure { 226 227 $result = new external_single_structure([ 228 'id' => new external_value(PARAM_INT, 'ID of the context'), 229 'h5pactivityid' => new external_value(PARAM_INT, 'ID of the H5P activity'), 230 'userid' => new external_value(PARAM_INT, 'ID of the user'), 231 'timecreated' => new external_value(PARAM_INT, 'Attempt creation'), 232 'timemodified' => new external_value(PARAM_INT, 'Attempt modified'), 233 'attempt' => new external_value(PARAM_INT, 'Attempt number'), 234 'rawscore' => new external_value(PARAM_INT, 'Attempt score value'), 235 'maxscore' => new external_value(PARAM_INT, 'Attempt max score'), 236 'duration' => new external_value(PARAM_INT, 'Attempt duration in seconds'), 237 'completion' => new external_value(PARAM_INT, 'Attempt completion', VALUE_OPTIONAL), 238 'success' => new external_value(PARAM_INT, 'Attempt success', VALUE_OPTIONAL), 239 'scaled' => new external_value(PARAM_FLOAT, 'Attempt scaled'), 240 'results' => new external_multiple_structure( 241 self::get_result_returns(), 242 'The results of the attempt', VALUE_OPTIONAL 243 ), 244 ], 'The attempt general information'); 245 return $result; 246 } 247 248 /** 249 * Return the external structure of a result 250 * @return external_single_structure 251 */ 252 private static function get_result_returns(): external_single_structure { 253 254 $result = new external_single_structure([ 255 'id' => new external_value(PARAM_INT, 'ID of the context'), 256 'attemptid' => new external_value(PARAM_INT, 'ID of the H5P attempt'), 257 'subcontent' => new external_value(PARAM_NOTAGS, 'Subcontent identifier'), 258 'timecreated' => new external_value(PARAM_INT, 'Result creation'), 259 'interactiontype' => new external_value(PARAM_NOTAGS, 'Interaction type'), 260 'description' => new external_value(PARAM_RAW, 'Result description'), 261 'content' => new external_value(PARAM_RAW, 'Result extra content', VALUE_OPTIONAL), 262 'rawscore' => new external_value(PARAM_INT, 'Result score value'), 263 'maxscore' => new external_value(PARAM_INT, 'Result max score'), 264 'duration' => new external_value(PARAM_INT, 'Result duration in seconds', VALUE_OPTIONAL, 0), 265 'completion' => new external_value(PARAM_INT, 'Result completion', VALUE_OPTIONAL), 266 'success' => new external_value(PARAM_INT, 'Result success', VALUE_OPTIONAL), 267 'optionslabel' => new external_value(PARAM_NOTAGS, 'Label used for result options', VALUE_OPTIONAL), 268 'correctlabel' => new external_value(PARAM_NOTAGS, 'Label used for correct answers', VALUE_OPTIONAL), 269 'answerlabel' => new external_value(PARAM_NOTAGS, 'Label used for user answers', VALUE_OPTIONAL), 270 'track' => new external_value(PARAM_BOOL, 'If the result has valid track information', VALUE_OPTIONAL), 271 'options' => new external_multiple_structure( 272 new external_single_structure([ 273 'description' => new external_value(PARAM_RAW, 'Option description', VALUE_OPTIONAL), 274 'id' => new external_value(PARAM_TEXT, 'Option string identifier', VALUE_OPTIONAL), 275 'correctanswer' => self::get_answer_returns('The option correct answer', VALUE_OPTIONAL), 276 'useranswer' => self::get_answer_returns('The option user answer', VALUE_OPTIONAL), 277 ]), 278 'The statement options', VALUE_OPTIONAL 279 ), 280 ], 'A single result statement tracking information'); 281 return $result; 282 } 283 284 /** 285 * Return the external structure of an answer or correctanswer 286 * 287 * @param string $description the return description 288 * @param int $required the return required value 289 * @return external_single_structure 290 */ 291 private static function get_answer_returns(string $description, int $required = VALUE_REQUIRED): external_single_structure { 292 293 $result = new external_single_structure([ 294 'answer' => new external_value(PARAM_NOTAGS, 'Option text value', VALUE_OPTIONAL), 295 'correct' => new external_value(PARAM_BOOL, 'If has to be displayed as correct', VALUE_OPTIONAL), 296 'incorrect' => new external_value(PARAM_BOOL, 'If has to be displayed as incorrect', VALUE_OPTIONAL), 297 'text' => new external_value(PARAM_BOOL, 'If has to be displayed as simple text', VALUE_OPTIONAL), 298 'checked' => new external_value(PARAM_BOOL, 'If has to be displayed as a checked option', VALUE_OPTIONAL), 299 'unchecked' => new external_value(PARAM_BOOL, 'If has to be displayed as a unchecked option', VALUE_OPTIONAL), 300 'pass' => new external_value(PARAM_BOOL, 'If has to be displayed as passed', VALUE_OPTIONAL), 301 'fail' => new external_value(PARAM_BOOL, 'If has to be displayed as failed', VALUE_OPTIONAL), 302 ], $description, $required); 303 return $result; 304 } 305 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body