Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Web services relating to fetching of a marking guide for the grading panel. 19 * 20 * @package gradingform_guide 21 * @copyright 2019 Andrew Nicols <andrew@nicols.co.uk> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 declare(strict_types = 1); 26 27 namespace gradingform_guide\grades\grader\gradingpanel\external; 28 29 global $CFG; 30 31 use coding_exception; 32 use context; 33 use core_user; 34 use core_grades\component_gradeitem as gradeitem; 35 use core_grades\component_gradeitems; 36 use core_external\external_api; 37 use core_external\external_function_parameters; 38 use core_external\external_multiple_structure; 39 use core_external\external_single_structure; 40 use core_external\external_value; 41 use core_external\external_warnings; 42 use moodle_exception; 43 use stdClass; 44 require_once($CFG->dirroot.'/grade/grading/form/guide/lib.php'); 45 46 /** 47 * Web services relating to fetching of a marking guide for the grading panel. 48 * 49 * @package gradingform_guide 50 * @copyright 2019 Andrew Nicols <andrew@nicols.co.uk> 51 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 52 */ 53 class fetch extends external_api { 54 55 /** 56 * Describes the parameters for fetching the grading panel for a simple grade. 57 * 58 * @return external_function_parameters 59 * @since Moodle 3.8 60 */ 61 public static function execute_parameters(): external_function_parameters { 62 return new external_function_parameters ([ 63 'component' => new external_value( 64 PARAM_ALPHANUMEXT, 65 'The name of the component', 66 VALUE_REQUIRED 67 ), 68 'contextid' => new external_value( 69 PARAM_INT, 70 'The ID of the context being graded', 71 VALUE_REQUIRED 72 ), 73 'itemname' => new external_value( 74 PARAM_ALPHANUM, 75 'The grade item itemname being graded', 76 VALUE_REQUIRED 77 ), 78 'gradeduserid' => new external_value( 79 PARAM_INT, 80 'The ID of the user show', 81 VALUE_REQUIRED 82 ), 83 ]); 84 } 85 86 /** 87 * Fetch the data required to build a grading panel for a simple grade. 88 * 89 * @param string $component 90 * @param int $contextid 91 * @param string $itemname 92 * @param int $gradeduserid 93 * @return array 94 * @throws \dml_exception 95 * @throws \invalid_parameter_exception 96 * @throws \restricted_context_exception 97 * @throws coding_exception 98 * @throws moodle_exception 99 * @since Moodle 3.8 100 */ 101 public static function execute(string $component, int $contextid, string $itemname, int $gradeduserid): array { 102 global $CFG, $USER; 103 require_once("{$CFG->libdir}/gradelib.php"); 104 [ 105 'component' => $component, 106 'contextid' => $contextid, 107 'itemname' => $itemname, 108 'gradeduserid' => $gradeduserid, 109 ] = self::validate_parameters(self::execute_parameters(), [ 110 'component' => $component, 111 'contextid' => $contextid, 112 'itemname' => $itemname, 113 'gradeduserid' => $gradeduserid, 114 ]); 115 116 // Validate the context. 117 $context = context::instance_by_id($contextid); 118 self::validate_context($context); 119 120 // Validate that the supplied itemname is a gradable item. 121 if (!component_gradeitems::is_valid_itemname($component, $itemname)) { 122 throw new coding_exception("The '{$itemname}' item is not valid for the '{$component}' component"); 123 } 124 125 // Fetch the gradeitem instance. 126 $gradeitem = gradeitem::instance($component, $context, $itemname); 127 128 if (MARKING_GUIDE !== $gradeitem->get_advanced_grading_method()) { 129 throw new moodle_exception( 130 "The {$itemname} item in {$component}/{$contextid} is not configured for advanced grading with a marking guide" 131 ); 132 } 133 134 // Fetch the actual data. 135 $gradeduser = core_user::get_user($gradeduserid, '*', MUST_EXIST); 136 137 // One can access its own grades. Others just if they're graders. 138 if ($gradeduserid != $USER->id) { 139 $gradeitem->require_user_can_grade($gradeduser, $USER); 140 } 141 142 return self::get_fetch_data($gradeitem, $gradeduser); 143 } 144 145 /** 146 * Get the data to be fetched. 147 * 148 * @param gradeitem $gradeitem 149 * @param stdClass $gradeduser 150 * @return array 151 */ 152 public static function get_fetch_data(gradeitem $gradeitem, stdClass $gradeduser): array { 153 global $USER; 154 155 $hasgrade = $gradeitem->user_has_grade($gradeduser); 156 $grade = $gradeitem->get_formatted_grade_for_user($gradeduser, $USER); 157 $instance = $gradeitem->get_advanced_grading_instance($USER, $grade); 158 if (!$instance) { 159 throw new moodle_exception('error:gradingunavailable', 'grading'); 160 } 161 $controller = $instance->get_controller(); 162 $definition = $controller->get_definition(); 163 $fillings = $instance->get_guide_filling(); 164 $context = $controller->get_context(); 165 $definitionid = (int) $definition->id; 166 167 // Set up some items we need to return on other interfaces. 168 $gradegrade = \grade_grade::fetch(['itemid' => $gradeitem->get_grade_item()->id, 'userid' => $gradeduser->id]); 169 $gradername = $gradegrade ? fullname(\core_user::get_user($gradegrade->usermodified)) : null; 170 $maxgrade = max(array_keys($controller->get_grade_range())); 171 172 $criterion = []; 173 if ($definition->guide_criteria) { 174 $criterion = array_map(function($criterion) use ($definitionid, $fillings, $context) { 175 $result = [ 176 'id' => $criterion['id'], 177 'name' => $criterion['shortname'], 178 'maxscore' => $criterion['maxscore'], 179 'description' => self::get_formatted_text( 180 $context, 181 $definitionid, 182 'description', 183 $criterion['description'], 184 (int) $criterion['descriptionformat'] 185 ), 186 'descriptionmarkers' => self::get_formatted_text( 187 $context, 188 $definitionid, 189 'descriptionmarkers', 190 $criterion['descriptionmarkers'], 191 (int) $criterion['descriptionmarkersformat'] 192 ), 193 'score' => null, 194 'remark' => null, 195 ]; 196 197 if (array_key_exists($criterion['id'], $fillings['criteria'])) { 198 $filling = $fillings['criteria'][$criterion['id']]; 199 200 $result['score'] = $filling['score']; 201 $result['remark'] = self::get_formatted_text( 202 $context, 203 $definitionid, 204 'remark', 205 $filling['remark'], 206 (int) $filling['remarkformat'] 207 ); 208 } 209 210 return $result; 211 }, $definition->guide_criteria); 212 } 213 214 $comments = []; 215 if ($definition->guide_comments) { 216 $comments = array_map(function($comment) use ($definitionid, $context) { 217 return [ 218 'id' => $comment['id'], 219 'sortorder' => $comment['sortorder'], 220 'description' => self::get_formatted_text( 221 $context, 222 $definitionid, 223 'description', 224 $comment['description'], 225 (int) $comment['descriptionformat'] 226 ), 227 ]; 228 }, $definition->guide_comments); 229 } 230 231 return [ 232 'templatename' => 'gradingform_guide/grades/grader/gradingpanel', 233 'hasgrade' => $hasgrade, 234 'grade' => [ 235 'instanceid' => $instance->get_id(), 236 'criterion' => $criterion, 237 'hascomments' => !empty($comments), 238 'comments' => $comments, 239 'usergrade' => $grade->usergrade, 240 'maxgrade' => $maxgrade, 241 'gradedby' => $gradername, 242 'timecreated' => $grade->timecreated, 243 'timemodified' => $grade->timemodified, 244 ], 245 'warnings' => [], 246 ]; 247 } 248 249 /** 250 * Describes the data returned from the external function. 251 * 252 * @return external_single_structure 253 * @since Moodle 3.8 254 */ 255 public static function execute_returns(): external_single_structure { 256 return new external_single_structure([ 257 'templatename' => new external_value(PARAM_SAFEPATH, 'The template to use when rendering this data'), 258 'hasgrade' => new external_value(PARAM_BOOL, 'Does the user have a grade?'), 259 'grade' => new external_single_structure([ 260 'instanceid' => new external_value(PARAM_INT, 'The id of the current grading instance'), 261 'criterion' => new external_multiple_structure( 262 new external_single_structure([ 263 'id' => new external_value(PARAM_INT, 'The id of the criterion'), 264 'name' => new external_value(PARAM_RAW, 'The name of the criterion'), 265 'maxscore' => new external_value(PARAM_FLOAT, 'The maximum score for this criterion'), 266 'description' => new external_value(PARAM_RAW, 'The description of the criterion'), 267 'descriptionmarkers' => new external_value(PARAM_RAW, 'The description of the criterion for markers'), 268 'score' => new external_value(PARAM_FLOAT, 'The current score for user being assessed', VALUE_OPTIONAL), 269 'remark' => new external_value(PARAM_RAW, 'Any remarks for this criterion for the user being assessed', VALUE_OPTIONAL), 270 ]), 271 'The criterion by which this item will be graded' 272 ), 273 'hascomments' => new external_value(PARAM_BOOL, 'Whether there are any frequently-used comments'), 274 'comments' => new external_multiple_structure( 275 new external_single_structure([ 276 'id' => new external_value(PARAM_INT, 'Comment id'), 277 'sortorder' => new external_value(PARAM_INT, 'The sortorder of this comment'), 278 'description' => new external_value(PARAM_RAW, 'The comment value'), 279 ]), 280 'Frequently used comments' 281 ), 282 'usergrade' => new external_value(PARAM_RAW, 'Current user grade'), 283 'maxgrade' => new external_value(PARAM_RAW, 'Max possible grade'), 284 'gradedby' => new external_value(PARAM_RAW, 'The assumed grader of this grading instance'), 285 'timecreated' => new external_value(PARAM_INT, 'The time that the grade was created'), 286 'timemodified' => new external_value(PARAM_INT, 'The time that the grade was last updated'), 287 ]), 288 'warnings' => new external_warnings(), 289 ]); 290 } 291 292 /** 293 * Get a formatted version of the remark/description/etc. 294 * 295 * @param context $context 296 * @param int $definitionid 297 * @param string $filearea The file area of the field 298 * @param string $text The text to be formatted 299 * @param int $format The input format of the string 300 * @return string 301 */ 302 protected static function get_formatted_text(context $context, int $definitionid, string $filearea, string $text, int $format): string { 303 $formatoptions = [ 304 'noclean' => false, 305 'trusted' => false, 306 'filter' => true, 307 ]; 308 309 [$newtext] = \core_external\util::format_text( 310 $text, 311 $format, 312 $context, 313 'grading', 314 $filearea, 315 $definitionid, 316 $formatoptions 317 ); 318 319 return $newtext; 320 } 321 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body