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 namespace gradereport_user\external; 18 19 use external_api; 20 use context_course; 21 use core_user; 22 use external_description; 23 use external_format_value; 24 use external_function_parameters; 25 use external_multiple_structure; 26 use external_single_structure; 27 use external_value; 28 use external_warnings; 29 use grade_plugin_return; 30 use graded_users_iterator; 31 use moodle_exception; 32 use stdClass; 33 use gradereport_user\report\user as user_report; 34 35 defined('MOODLE_INTERNAL') || die; 36 37 require_once($CFG->libdir.'/externallib.php'); 38 require_once($CFG->dirroot.'/grade/lib.php'); 39 40 /** 41 * External grade report API implementation 42 * 43 * @package gradereport_user 44 * @copyright 2015 Juan Leyva <juan@moodle.com> 45 * @category external 46 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 47 */ 48 class user extends external_api { 49 50 /** 51 * Validate access permissions to the report 52 * 53 * @param int $courseid the courseid 54 * @param int $userid the user id to retrieve data from 55 * @param int $groupid the group id 56 * @return array with the parameters cleaned and other required information 57 * @since Moodle 3.2 58 */ 59 protected static function check_report_access(int $courseid, int $userid, int $groupid = 0): array { 60 global $USER; 61 62 // Validate the parameter. 63 $params = self::validate_parameters(self::get_grades_table_parameters(), 64 [ 65 'courseid' => $courseid, 66 'userid' => $userid, 67 'groupid' => $groupid, 68 ] 69 ); 70 71 // Compact/extract functions are not recommended. 72 $courseid = $params['courseid']; 73 $userid = $params['userid']; 74 $groupid = $params['groupid']; 75 76 // Function get_course internally throws an exception if the course doesn't exist. 77 $course = get_course($courseid); 78 79 $context = context_course::instance($courseid); 80 self::validate_context($context); 81 82 // Specific capabilities. 83 require_capability('gradereport/user:view', $context); 84 85 $user = null; 86 87 if (empty($userid)) { 88 require_capability('moodle/grade:viewall', $context); 89 } else { 90 $user = core_user::get_user($userid, '*', MUST_EXIST); 91 core_user::require_active_user($user); 92 // Check if we can view the user group (if any). 93 // When userid == 0, we are retrieving all the users, we'll check then if a groupid is required. 94 if (!groups_user_groups_visible($course, $user->id)) { 95 throw new moodle_exception('notingroup'); 96 } 97 } 98 99 $access = false; 100 101 if (has_capability('moodle/grade:viewall', $context)) { 102 // Can view all course grades. 103 $access = true; 104 } else if ($userid == $USER->id && has_capability('moodle/grade:view', $context) && $course->showgrades) { 105 // View own grades. 106 $access = true; 107 } 108 109 if (!$access) { 110 throw new moodle_exception('nopermissiontoviewgrades', 'error'); 111 } 112 113 if (!empty($groupid)) { 114 // Determine is the group is visible to user. 115 if (!groups_group_visible($groupid, $course)) { 116 throw new moodle_exception('notingroup'); 117 } 118 } else { 119 // Check to see if groups are being used here. 120 if ($groupmode = groups_get_course_groupmode($course)) { 121 $groupid = groups_get_course_group($course); 122 // Determine is the group is visible to user (this is particullary for the group 0). 123 if (!groups_group_visible($groupid, $course)) { 124 throw new moodle_exception('notingroup'); 125 } 126 } else { 127 $groupid = 0; 128 } 129 } 130 131 return [$params, $course, $context, $user, $groupid]; 132 } 133 134 /** 135 * Get the report data 136 * @param stdClass $course course object 137 * @param stdClass $context context object 138 * @param null|stdClass $user user object (it can be null for all the users) 139 * @param int $userid the user to retrieve data from, 0 for all 140 * @param int $groupid the group id to filter 141 * @param bool $tabledata whether to get the table data (true) or the gradeitemdata 142 * @return array data and possible warnings 143 * @since Moodle 3.2 144 */ 145 protected static function get_report_data( 146 stdClass $course, 147 stdClass $context, 148 ?stdClass $user, 149 int $userid, 150 int $groupid, 151 bool $tabledata = true 152 ): array { 153 global $CFG; 154 155 $warnings = []; 156 // Require files here to save some memory in case validation fails. 157 require_once($CFG->dirroot . '/group/lib.php'); 158 require_once($CFG->libdir . '/gradelib.php'); 159 require_once($CFG->dirroot . '/grade/lib.php'); 160 require_once($CFG->dirroot . '/grade/report/user/lib.php'); 161 162 // Force regrade to update items marked as 'needupdate'. 163 grade_regrade_final_grades($course->id); 164 165 $gpr = new grade_plugin_return( 166 [ 167 'type' => 'report', 168 'plugin' => 'user', 169 'courseid' => $course->id, 170 'courseidnumber' => $course->idnumber, 171 'userid' => $userid 172 ] 173 ); 174 175 $reportdata = []; 176 177 // Just one user. 178 if ($user) { 179 $report = new user_report($course->id, $gpr, $context, $userid); 180 $report->fill_table(); 181 182 $gradeuserdata = [ 183 'courseid' => $course->id, 184 'courseidnumber' => $course->idnumber, 185 'userid' => $user->id, 186 'userfullname' => fullname($user), 187 'useridnumber' => $user->idnumber, 188 'maxdepth' => $report->maxdepth, 189 ]; 190 if ($tabledata) { 191 $gradeuserdata['tabledata'] = $report->tabledata; 192 } else { 193 $gradeuserdata['gradeitems'] = $report->gradeitemsdata; 194 } 195 $reportdata[] = $gradeuserdata; 196 } else { 197 $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol); 198 $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol); 199 $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $context); 200 201 $gui = new graded_users_iterator($course, null, $groupid); 202 $gui->require_active_enrolment($showonlyactiveenrol); 203 $gui->init(); 204 205 while ($userdata = $gui->next_user()) { 206 $currentuser = $userdata->user; 207 $report = new user_report($course->id, $gpr, $context, $currentuser->id); 208 $report->fill_table(); 209 210 $gradeuserdata = [ 211 'courseid' => $course->id, 212 'courseidnumber' => $course->idnumber, 213 'userid' => $currentuser->id, 214 'userfullname' => fullname($currentuser), 215 'useridnumber' => $currentuser->idnumber, 216 'maxdepth' => $report->maxdepth, 217 ]; 218 if ($tabledata) { 219 $gradeuserdata['tabledata'] = $report->tabledata; 220 } else { 221 $gradeuserdata['gradeitems'] = $report->gradeitemsdata; 222 } 223 $reportdata[] = $gradeuserdata; 224 } 225 $gui->close(); 226 } 227 return [$reportdata, $warnings]; 228 } 229 230 /** 231 * Describes the parameters for get_grades_table. 232 * 233 * @return external_function_parameters 234 * @since Moodle 2.9 235 */ 236 public static function get_grades_table_parameters(): external_function_parameters { 237 return new external_function_parameters ( 238 [ 239 'courseid' => new external_value(PARAM_INT, 'Course Id', VALUE_REQUIRED), 240 'userid' => new external_value(PARAM_INT, 'Return grades only for this user (optional)', VALUE_DEFAULT, 0), 241 'groupid' => new external_value(PARAM_INT, 'Get users from this group only', VALUE_DEFAULT, 0) 242 ] 243 ); 244 } 245 246 /** 247 * Returns a list of grades tables for users in a course. 248 * 249 * @param int $courseid Course Id 250 * @param int $userid Only this user (optional) 251 * @param int $groupid Get users from this group only 252 * 253 * @return array the grades tables 254 * @since Moodle 2.9 255 */ 256 public static function get_grades_table(int $courseid, int $userid = 0, int $groupid = 0): array { 257 258 list($params, $course, $context, $user, $groupid) = self::check_report_access($courseid, $userid, $groupid); 259 $userid = $params['userid']; 260 261 // We pass userid because it can be still 0. 262 list($tables, $warnings) = self::get_report_data($course, $context, $user, $userid, $groupid); 263 264 return [ 265 'tables' => $tables, 266 'warnings' => $warnings 267 ]; 268 } 269 270 /** 271 * Creates a table column structure 272 * 273 * @return array 274 * @since Moodle 2.9 275 */ 276 private static function grades_table_column(): array { 277 return [ 278 'class' => new external_value(PARAM_RAW, 'class'), 279 'content' => new external_value(PARAM_RAW, 'cell content'), 280 'headers' => new external_value(PARAM_RAW, 'headers') 281 ]; 282 } 283 284 /** 285 * Describes tget_grades_table return value. 286 * 287 * @return external_single_structure 288 * @since Moodle 2.9 289 */ 290 public static function get_grades_table_returns(): external_single_structure { 291 return new external_single_structure( 292 [ 293 'tables' => new external_multiple_structure( 294 new external_single_structure( 295 [ 296 'courseid' => new external_value(PARAM_INT, 'course id'), 297 'userid' => new external_value(PARAM_INT, 'user id'), 298 'userfullname' => new external_value(PARAM_TEXT, 'user fullname'), 299 'maxdepth' => new external_value(PARAM_INT, 'table max depth (needed for printing it)'), 300 'tabledata' => new external_multiple_structure( 301 new external_single_structure( 302 [ 303 'itemname' => new external_single_structure( 304 [ 305 'class' => new external_value(PARAM_RAW, 'class'), 306 'colspan' => new external_value(PARAM_INT, 'col span'), 307 'content' => new external_value(PARAM_RAW, 'cell content'), 308 'id' => new external_value(PARAM_ALPHANUMEXT, 'id') 309 ], 'The item returned data', VALUE_OPTIONAL 310 ), 311 'leader' => new external_single_structure( 312 [ 313 'class' => new external_value(PARAM_RAW, 'class'), 314 'rowspan' => new external_value(PARAM_INT, 'row span') 315 ], 'The item returned data', VALUE_OPTIONAL 316 ), 317 'weight' => new external_single_structure( 318 self::grades_table_column(), 'weight column', VALUE_OPTIONAL 319 ), 320 'grade' => new external_single_structure( 321 self::grades_table_column(), 'grade column', VALUE_OPTIONAL 322 ), 323 'range' => new external_single_structure( 324 self::grades_table_column(), 'range column', VALUE_OPTIONAL 325 ), 326 'percentage' => new external_single_structure( 327 self::grades_table_column(), 'percentage column', VALUE_OPTIONAL 328 ), 329 'lettergrade' => new external_single_structure( 330 self::grades_table_column(), 'lettergrade column', VALUE_OPTIONAL 331 ), 332 'rank' => new external_single_structure( 333 self::grades_table_column(), 'rank column', VALUE_OPTIONAL 334 ), 335 'average' => new external_single_structure( 336 self::grades_table_column(), 'average column', VALUE_OPTIONAL 337 ), 338 'feedback' => new external_single_structure( 339 self::grades_table_column(), 'feedback column', VALUE_OPTIONAL 340 ), 341 'contributiontocoursetotal' => new external_single_structure( 342 self::grades_table_column(), 'contributiontocoursetotal column', VALUE_OPTIONAL 343 ), 344 'parentcategories' => new external_multiple_structure( 345 new external_value(PARAM_INT, 'Parent grade category ID.') 346 ), 347 ], 'table' 348 ) 349 ) 350 ] 351 ) 352 ), 353 'warnings' => new external_warnings() 354 ] 355 ); 356 } 357 358 /** 359 * Returns description of method parameters 360 * 361 * @return external_function_parameters 362 * @since Moodle 2.9 363 */ 364 public static function view_grade_report_parameters(): external_function_parameters { 365 return new external_function_parameters( 366 [ 367 'courseid' => new external_value(PARAM_INT, 'id of the course'), 368 'userid' => new external_value(PARAM_INT, 'id of the user, 0 means current user', VALUE_DEFAULT, 0), 369 ] 370 ); 371 } 372 373 /** 374 * Trigger the user report events, do the same that the web interface view of the report 375 * 376 * @param int $courseid id of course 377 * @param int $userid id of the user the report belongs to 378 * @return array of warnings and status result 379 * @since Moodle 2.9 380 * @throws moodle_exception 381 */ 382 public static function view_grade_report(int $courseid, int $userid = 0): array { 383 global $CFG, $USER; 384 require_once($CFG->dirroot . "/grade/lib.php"); 385 require_once($CFG->dirroot . "/grade/report/user/lib.php"); 386 387 $params = self::validate_parameters(self::view_grade_report_parameters(), 388 [ 389 'courseid' => $courseid, 390 'userid' => $userid 391 ]); 392 393 $warnings = []; 394 395 $course = get_course($params['courseid']); 396 397 $context = context_course::instance($course->id); 398 self::validate_context($context); 399 400 $userid = $params['userid']; 401 if (empty($userid)) { 402 $userid = $USER->id; 403 } else { 404 $user = core_user::get_user($userid, '*', MUST_EXIST); 405 core_user::require_active_user($user); 406 } 407 408 $access = false; 409 410 if (has_capability('moodle/grade:viewall', $context)) { 411 // Can view all course grades (any user). 412 $access = true; 413 } else if ($userid == $USER->id && has_capability('moodle/grade:view', $context) && $course->showgrades) { 414 // View own grades. 415 $access = true; 416 } 417 418 if (!$access) { 419 throw new moodle_exception('nopermissiontoviewgrades', 'error'); 420 } 421 422 // Create a report instance. We don't need the gpr second parameter. 423 $report = new user_report($course->id, null, $context, $userid); 424 $report->viewed(); 425 426 return [ 427 'status' => true, 428 'warnings' => $warnings 429 ]; 430 } 431 432 /** 433 * Returns description of method result value 434 * 435 * @return external_description 436 * @since Moodle 2.9 437 */ 438 public static function view_grade_report_returns(): external_description { 439 return new external_single_structure( 440 [ 441 'status' => new external_value(PARAM_BOOL, 'status: true if success'), 442 'warnings' => new external_warnings() 443 ] 444 ); 445 } 446 447 /** 448 * Describes the parameters for get_grade_items. 449 * 450 * @return external_function_parameters 451 * @since Moodle 3.2 452 */ 453 public static function get_grade_items_parameters(): external_function_parameters { 454 return self::get_grades_table_parameters(); 455 } 456 457 /** 458 * Returns the complete list of grade items for users in a course. 459 * 460 * @param int $courseid Course Id 461 * @param int $userid Only this user (optional) 462 * @param int $groupid Get users from this group only 463 * 464 * @return array the grades tables 465 * @since Moodle 3.2 466 */ 467 public static function get_grade_items(int $courseid, int $userid = 0, int $groupid = 0): array { 468 469 list($params, $course, $context, $user, $groupid) = self::check_report_access($courseid, $userid, $groupid); 470 $userid = $params['userid']; 471 472 // We pass userid because it can be still 0. 473 list($gradeitems, $warnings) = self::get_report_data($course, $context, $user, $userid, $groupid, false); 474 475 foreach ($gradeitems as $gradeitem) { 476 if (isset($gradeitem['feedback']) && isset($gradeitem['feedbackformat'])) { 477 list($gradeitem['feedback'], $gradeitem['feedbackformat']) = 478 external_format_text($gradeitem['feedback'], $gradeitem['feedbackformat'], $context->id); 479 } 480 } 481 482 return [ 483 'usergrades' => $gradeitems, 484 'warnings' => $warnings 485 ]; 486 } 487 488 /** 489 * Describes tget_grade_items return value. 490 * 491 * @return external_single_structure 492 * @since Moodle 3.2 493 */ 494 public static function get_grade_items_returns(): external_single_structure { 495 return new external_single_structure( 496 [ 497 'usergrades' => new external_multiple_structure( 498 new external_single_structure( 499 [ 500 'courseid' => new external_value(PARAM_INT, 'course id'), 501 'courseidnumber' => new external_value(PARAM_TEXT, 'course idnumber'), 502 'userid' => new external_value(PARAM_INT, 'user id'), 503 'userfullname' => new external_value(PARAM_TEXT, 'user fullname'), 504 'useridnumber' => new external_value( 505 core_user::get_property_type('idnumber'), 'user idnumber'), 506 'maxdepth' => new external_value(PARAM_INT, 'table max depth (needed for printing it)'), 507 'gradeitems' => new external_multiple_structure( 508 new external_single_structure( 509 [ 510 'id' => new external_value(PARAM_INT, 'Grade item id'), 511 'itemname' => new external_value(PARAM_CLEANHTML, 'Grade item name'), 512 'itemtype' => new external_value(PARAM_ALPHA, 'Grade item type'), 513 'itemmodule' => new external_value(PARAM_PLUGIN, 'Grade item module'), 514 'iteminstance' => new external_value(PARAM_INT, 'Grade item instance'), 515 'itemnumber' => new external_value(PARAM_INT, 'Grade item item number'), 516 'idnumber' => new external_value(PARAM_TEXT, 'Grade item idnumber'), 517 'categoryid' => new external_value(PARAM_INT, 'Grade item category id'), 518 'outcomeid' => new external_value(PARAM_INT, 'Outcome id'), 519 'scaleid' => new external_value(PARAM_INT, 'Scale id'), 520 'locked' => new external_value(PARAM_BOOL, 'Grade item for user locked?', VALUE_OPTIONAL), 521 'cmid' => new external_value(PARAM_INT, 'Course module id (if type mod)', VALUE_OPTIONAL), 522 'weightraw' => new external_value(PARAM_FLOAT, 'Weight raw', VALUE_OPTIONAL), 523 'weightformatted' => new external_value(PARAM_NOTAGS, 'Weight', VALUE_OPTIONAL), 524 'status' => new external_value(PARAM_ALPHA, 'Status', VALUE_OPTIONAL), 525 'graderaw' => new external_value(PARAM_FLOAT, 'Grade raw', VALUE_OPTIONAL), 526 'gradedatesubmitted' => new external_value(PARAM_INT, 'Grade submit date', VALUE_OPTIONAL), 527 'gradedategraded' => new external_value(PARAM_INT, 'Grade graded date', VALUE_OPTIONAL), 528 'gradehiddenbydate' => new external_value(PARAM_BOOL, 'Grade hidden by date?', VALUE_OPTIONAL), 529 'gradeneedsupdate' => new external_value(PARAM_BOOL, 'Grade needs update?', VALUE_OPTIONAL), 530 'gradeishidden' => new external_value(PARAM_BOOL, 'Grade is hidden?', VALUE_OPTIONAL), 531 'gradeislocked' => new external_value(PARAM_BOOL, 'Grade is locked?', VALUE_OPTIONAL), 532 'gradeisoverridden' => new external_value(PARAM_BOOL, 'Grade overridden?', VALUE_OPTIONAL), 533 'gradeformatted' => new external_value(PARAM_RAW, 'The grade formatted', VALUE_OPTIONAL), 534 'grademin' => new external_value(PARAM_FLOAT, 'Grade min', VALUE_OPTIONAL), 535 'grademax' => new external_value(PARAM_FLOAT, 'Grade max', VALUE_OPTIONAL), 536 'rangeformatted' => new external_value(PARAM_NOTAGS, 'Range formatted', VALUE_OPTIONAL), 537 'percentageformatted' => new external_value(PARAM_NOTAGS, 'Percentage', VALUE_OPTIONAL), 538 'lettergradeformatted' => new external_value(PARAM_NOTAGS, 'Letter grade', VALUE_OPTIONAL), 539 'rank' => new external_value(PARAM_INT, 'Rank in the course', VALUE_OPTIONAL), 540 'numusers' => new external_value(PARAM_INT, 'Num users in course', VALUE_OPTIONAL), 541 'averageformatted' => new external_value(PARAM_NOTAGS, 'Grade average', VALUE_OPTIONAL), 542 'feedback' => new external_value(PARAM_RAW, 'Grade feedback', VALUE_OPTIONAL), 543 'feedbackformat' => new external_format_value('feedback', VALUE_OPTIONAL), 544 ], 'Grade items' 545 ) 546 ) 547 ] 548 ) 549 ), 550 'warnings' => new external_warnings() 551 ] 552 ); 553 } 554 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body