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 * Workshop external API 19 * 20 * @package mod_workshop 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.4 25 */ 26 27 defined('MOODLE_INTERNAL') || die; 28 29 require_once($CFG->dirroot . '/mod/workshop/locallib.php'); 30 31 use core_external\external_api; 32 use core_external\external_files; 33 use core_external\external_function_parameters; 34 use core_external\external_multiple_structure; 35 use core_external\external_single_structure; 36 use core_external\external_value; 37 use core_external\external_warnings; 38 use core_external\util; 39 use mod_workshop\external\workshop_summary_exporter; 40 use mod_workshop\external\submission_exporter; 41 use mod_workshop\external\assessment_exporter; 42 43 /** 44 * Workshop external functions 45 * 46 * @package mod_workshop 47 * @category external 48 * @copyright 2017 Juan Leyva <juan@moodle.com> 49 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 50 * @since Moodle 3.4 51 */ 52 class mod_workshop_external extends external_api { 53 54 /** 55 * Describes the parameters for get_workshops_by_courses. 56 * 57 * @return external_function_parameters 58 * @since Moodle 3.4 59 */ 60 public static function get_workshops_by_courses_parameters() { 61 return new external_function_parameters ( 62 array( 63 'courseids' => new external_multiple_structure( 64 new external_value(PARAM_INT, 'Course id'), 'Array of course ids', VALUE_DEFAULT, array() 65 ), 66 ) 67 ); 68 } 69 70 /** 71 * Returns a list of workshops in a provided list of courses. 72 * If no list is provided all workshops that the user can view will be returned. 73 * 74 * @param array $courseids course ids 75 * @return array of warnings and workshops 76 * @since Moodle 3.4 77 */ 78 public static function get_workshops_by_courses($courseids = array()) { 79 global $PAGE; 80 81 $warnings = array(); 82 $returnedworkshops = array(); 83 84 $params = array( 85 'courseids' => $courseids, 86 ); 87 $params = self::validate_parameters(self::get_workshops_by_courses_parameters(), $params); 88 89 $mycourses = array(); 90 if (empty($params['courseids'])) { 91 $mycourses = enrol_get_my_courses(); 92 $params['courseids'] = array_keys($mycourses); 93 } 94 95 // Ensure there are courseids to loop through. 96 if (!empty($params['courseids'])) { 97 98 list($courses, $warnings) = util::validate_courses($params['courseids'], $mycourses); 99 $output = $PAGE->get_renderer('core'); 100 101 // Get the workshops in this course, this function checks users visibility permissions. 102 // We can avoid then additional validate_context calls. 103 $workshops = get_all_instances_in_courses("workshop", $courses); 104 foreach ($workshops as $workshop) { 105 106 $context = context_module::instance($workshop->coursemodule); 107 // Remove fields that are not from the workshop (added by get_all_instances_in_courses). 108 unset($workshop->coursemodule, $workshop->context, $workshop->visible, $workshop->section, $workshop->groupmode, 109 $workshop->groupingid); 110 111 $exporter = new workshop_summary_exporter($workshop, array('context' => $context)); 112 $returnedworkshops[] = $exporter->export($output); 113 } 114 } 115 116 $result = array( 117 'workshops' => $returnedworkshops, 118 'warnings' => $warnings 119 ); 120 return $result; 121 } 122 123 /** 124 * Describes the get_workshops_by_courses return value. 125 * 126 * @return external_single_structure 127 * @since Moodle 3.4 128 */ 129 public static function get_workshops_by_courses_returns() { 130 return new external_single_structure( 131 array( 132 'workshops' => new external_multiple_structure( 133 workshop_summary_exporter::get_read_structure() 134 ), 135 'warnings' => new external_warnings(), 136 ) 137 ); 138 } 139 140 /** 141 * Utility function for validating a workshop. 142 * 143 * @param int $workshopid workshop instance id 144 * @return array array containing the workshop object, course, context and course module objects 145 * @since Moodle 3.4 146 */ 147 protected static function validate_workshop($workshopid) { 148 global $DB, $USER; 149 150 // Request and permission validation. 151 $workshop = $DB->get_record('workshop', array('id' => $workshopid), '*', MUST_EXIST); 152 list($course, $cm) = get_course_and_cm_from_instance($workshop, 'workshop'); 153 154 $context = context_module::instance($cm->id); 155 self::validate_context($context); 156 157 $workshop = new workshop($workshop, $cm, $course); 158 159 return array($workshop, $course, $cm, $context); 160 } 161 162 163 /** 164 * Describes the parameters for get_workshop_access_information. 165 * 166 * @return external_external_function_parameters 167 * @since Moodle 3.4 168 */ 169 public static function get_workshop_access_information_parameters() { 170 return new external_function_parameters ( 171 array( 172 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.') 173 ) 174 ); 175 } 176 177 /** 178 * Return access information for a given workshop. 179 * 180 * @param int $workshopid workshop instance id 181 * @return array of warnings and the access information 182 * @since Moodle 3.4 183 * @throws moodle_exception 184 */ 185 public static function get_workshop_access_information($workshopid) { 186 global $USER; 187 188 $params = self::validate_parameters(self::get_workshop_access_information_parameters(), array('workshopid' => $workshopid)); 189 190 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']); 191 192 $result = array(); 193 // Return all the available capabilities. 194 $capabilities = load_capability_def('mod_workshop'); 195 foreach ($capabilities as $capname => $capdata) { 196 // Get fields like cansubmit so it is consistent with the access_information function implemented in other modules. 197 $field = 'can' . str_replace('mod/workshop:', '', $capname); 198 $result[$field] = has_capability($capname, $context); 199 } 200 201 // Now, specific features access information. 202 $result['creatingsubmissionallowed'] = $workshop->creating_submission_allowed($USER->id); 203 $result['modifyingsubmissionallowed'] = $workshop->modifying_submission_allowed($USER->id); 204 $result['assessingallowed'] = $workshop->assessing_allowed($USER->id); 205 $result['assessingexamplesallowed'] = $workshop->assessing_examples_allowed(); 206 if (is_null($result['assessingexamplesallowed'])) { 207 $result['assessingexamplesallowed'] = false; 208 } 209 $result['examplesassessedbeforesubmission'] = $workshop->check_examples_assessed_before_submission($USER->id); 210 list($result['examplesassessedbeforeassessment'], $code) = $workshop->check_examples_assessed_before_assessment($USER->id); 211 212 $result['warnings'] = array(); 213 return $result; 214 } 215 216 /** 217 * Describes the get_workshop_access_information return value. 218 * 219 * @return external_single_structure 220 * @since Moodle 3.4 221 */ 222 public static function get_workshop_access_information_returns() { 223 224 $structure = array( 225 'creatingsubmissionallowed' => new external_value(PARAM_BOOL, 226 'Is the given user allowed to create their submission?'), 227 'modifyingsubmissionallowed' => new external_value(PARAM_BOOL, 228 'Is the user allowed to modify his existing submission?'), 229 'assessingallowed' => new external_value(PARAM_BOOL, 230 'Is the user allowed to create/edit his assessments?'), 231 'assessingexamplesallowed' => new external_value(PARAM_BOOL, 232 'Are reviewers allowed to create/edit their assessments of the example submissions?.'), 233 'examplesassessedbeforesubmission' => new external_value(PARAM_BOOL, 234 'Whether the given user has assessed all his required examples before submission 235 (always true if there are not examples to assess or not configured to check before submission).'), 236 'examplesassessedbeforeassessment' => new external_value(PARAM_BOOL, 237 'Whether the given user has assessed all his required examples before assessment 238 (always true if there are not examples to assessor not configured to check before assessment).'), 239 'warnings' => new external_warnings() 240 ); 241 242 $capabilities = load_capability_def('mod_workshop'); 243 foreach ($capabilities as $capname => $capdata) { 244 // Get fields like cansubmit so it is consistent with the access_information function implemented in other modules. 245 $field = 'can' . str_replace('mod/workshop:', '', $capname); 246 $structure[$field] = new external_value(PARAM_BOOL, 'Whether the user has the capability ' . $capname . ' allowed.'); 247 } 248 249 return new external_single_structure($structure); 250 } 251 252 /** 253 * Describes the parameters for get_user_plan. 254 * 255 * @return external_external_function_parameters 256 * @since Moodle 3.4 257 */ 258 public static function get_user_plan_parameters() { 259 return new external_function_parameters ( 260 array( 261 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'), 262 'userid' => new external_value(PARAM_INT, 'User id (empty or 0 for current user).', VALUE_DEFAULT, 0), 263 ) 264 ); 265 } 266 267 /** 268 * Return the planner information for the given user. 269 * 270 * @param int $workshopid workshop instance id 271 * @param int $userid user id 272 * @return array of warnings and the user plan 273 * @since Moodle 3.4 274 * @throws moodle_exception 275 */ 276 public static function get_user_plan($workshopid, $userid = 0) { 277 global $USER; 278 279 $params = array( 280 'workshopid' => $workshopid, 281 'userid' => $userid, 282 ); 283 $params = self::validate_parameters(self::get_user_plan_parameters(), $params); 284 285 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']); 286 287 // Extra checks so only users with permissions can view other users plans. 288 if (empty($params['userid']) || $params['userid'] == $USER->id) { 289 $userid = $USER->id; 290 } else { 291 require_capability('moodle/course:manageactivities', $context); 292 $user = core_user::get_user($params['userid'], '*', MUST_EXIST); 293 core_user::require_active_user($user); 294 if (!$workshop->check_group_membership($user->id)) { 295 throw new moodle_exception('notingroup'); 296 } 297 $userid = $user->id; 298 } 299 300 // Get the user plan information ready for external functions. 301 $userplan = new workshop_user_plan($workshop, $userid); 302 $userplan = array('phases' => $userplan->phases, 'examples' => $userplan->get_examples()); 303 foreach ($userplan['phases'] as $phasecode => $phase) { 304 $phase->code = $phasecode; 305 $userplan['phases'][$phasecode] = (array) $phase; 306 foreach ($userplan['phases'][$phasecode]['tasks'] as $taskcode => $task) { 307 $task->code = $taskcode; 308 if ($task->link instanceof moodle_url) { 309 $task->link = $task->link->out(false); 310 } 311 $userplan['phases'][$phasecode]['tasks'][$taskcode] = (array) $task; 312 } 313 foreach ($userplan['phases'][$phasecode]['actions'] as $actioncode => $action) { 314 if ($action->url instanceof moodle_url) { 315 $action->url = $action->url->out(false); 316 } 317 $userplan['phases'][$phasecode]['actions'][$actioncode] = (array) $action; 318 } 319 } 320 321 $result['userplan'] = $userplan; 322 $result['warnings'] = array(); 323 return $result; 324 } 325 326 /** 327 * Describes the get_user_plan return value. 328 * 329 * @return external_single_structure 330 * @since Moodle 3.4 331 */ 332 public static function get_user_plan_returns() { 333 return new external_single_structure( 334 array( 335 'userplan' => new external_single_structure( 336 array( 337 'phases' => new external_multiple_structure( 338 new external_single_structure( 339 array( 340 'code' => new external_value(PARAM_INT, 'Phase code.'), 341 'title' => new external_value(PARAM_NOTAGS, 'Phase title.'), 342 'active' => new external_value(PARAM_BOOL, 'Whether is the active task.'), 343 'tasks' => new external_multiple_structure( 344 new external_single_structure( 345 array( 346 'code' => new external_value(PARAM_ALPHA, 'Task code.'), 347 'title' => new external_value(PARAM_RAW, 'Task title.'), 348 'link' => new external_value(PARAM_URL, 'Link to task.'), 349 'details' => new external_value(PARAM_RAW, 'Task details.', VALUE_OPTIONAL), 350 'completed' => new external_value(PARAM_NOTAGS, 351 'Completion information (maybe empty, maybe a boolean or generic info.'), 352 ) 353 ) 354 ), 355 'actions' => new external_multiple_structure( 356 new external_single_structure( 357 array( 358 'type' => new external_value(PARAM_ALPHA, 'Action type.', VALUE_OPTIONAL), 359 'label' => new external_value(PARAM_RAW, 'Action label.', VALUE_OPTIONAL), 360 'url' => new external_value(PARAM_URL, 'Link to action.'), 361 'method' => new external_value(PARAM_ALPHA, 'Get or post.', VALUE_OPTIONAL), 362 ) 363 ) 364 ), 365 ) 366 ) 367 ), 368 'examples' => new external_multiple_structure( 369 new external_single_structure( 370 array( 371 'id' => new external_value(PARAM_INT, 'Example submission id.'), 372 'title' => new external_value(PARAM_RAW, 'Example submission title.'), 373 'assessmentid' => new external_value(PARAM_INT, 'Example submission assessment id.'), 374 'grade' => new external_value(PARAM_FLOAT, 'The submission grade.'), 375 'gradinggrade' => new external_value(PARAM_FLOAT, 'The assessment grade.'), 376 ) 377 ) 378 ), 379 ) 380 ), 381 'warnings' => new external_warnings(), 382 ) 383 ); 384 } 385 386 /** 387 * Describes the parameters for view_workshop. 388 * 389 * @return external_function_parameters 390 * @since Moodle 3.4 391 */ 392 public static function view_workshop_parameters() { 393 return new external_function_parameters ( 394 array( 395 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id'), 396 ) 397 ); 398 } 399 400 /** 401 * Trigger the course module viewed event and update the module completion status. 402 * 403 * @param int $workshopid workshop instance id 404 * @return array of warnings and status result 405 * @since Moodle 3.4 406 * @throws moodle_exception 407 */ 408 public static function view_workshop($workshopid) { 409 410 $params = array('workshopid' => $workshopid); 411 $params = self::validate_parameters(self::view_workshop_parameters(), $params); 412 $warnings = array(); 413 414 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']); 415 416 $workshop->set_module_viewed(); 417 418 $result = array( 419 'status' => true, 420 'warnings' => $warnings, 421 ); 422 return $result; 423 } 424 425 /** 426 * Describes the view_workshop return value. 427 * 428 * @return external_single_structure 429 * @since Moodle 3.4 430 */ 431 public static function view_workshop_returns() { 432 return new external_single_structure( 433 array( 434 'status' => new external_value(PARAM_BOOL, 'status: true if success'), 435 'warnings' => new external_warnings(), 436 ) 437 ); 438 } 439 440 /** 441 * Returns the description of the external function parameters. 442 * 443 * @return external_function_parameters 444 * @since Moodle 3.4 445 */ 446 public static function add_submission_parameters() { 447 return new external_function_parameters(array( 448 'workshopid' => new external_value(PARAM_INT, 'Workshop id'), 449 'title' => new external_value(PARAM_TEXT, 'Submission title'), 450 'content' => new external_value(PARAM_RAW, 'Submission text content', VALUE_DEFAULT, ''), 451 'contentformat' => new external_value(PARAM_INT, 'The format used for the content', VALUE_DEFAULT, FORMAT_MOODLE), 452 'inlineattachmentsid' => new external_value(PARAM_INT, 'The draft file area id for inline attachments in the content', 453 VALUE_DEFAULT, 0), 454 'attachmentsid' => new external_value(PARAM_INT, 'The draft file area id for attachments', VALUE_DEFAULT, 0), 455 )); 456 } 457 458 /** 459 * Add a new submission to a given workshop. 460 * 461 * @param int $workshopid the workshop id 462 * @param string $title the submission title 463 * @param string $content the submission text content 464 * @param int $contentformat the format used for the content 465 * @param int $inlineattachmentsid the draft file area id for inline attachments in the content 466 * @param int $attachmentsid the draft file area id for attachments 467 * @return array Containing the new created submission id and warnings. 468 * @since Moodle 3.4 469 * @throws moodle_exception 470 */ 471 public static function add_submission($workshopid, $title, $content = '', $contentformat = FORMAT_MOODLE, 472 $inlineattachmentsid = 0, $attachmentsid = 0) { 473 global $USER; 474 475 $params = self::validate_parameters(self::add_submission_parameters(), array( 476 'workshopid' => $workshopid, 477 'title' => $title, 478 'content' => $content, 479 'contentformat' => $contentformat, 480 'inlineattachmentsid' => $inlineattachmentsid, 481 'attachmentsid' => $attachmentsid, 482 )); 483 $warnings = array(); 484 485 // Get and validate the workshop. 486 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']); 487 require_capability('mod/workshop:submit', $context); 488 489 // Check if we can submit now. 490 $canaddsubmission = $workshop->creating_submission_allowed($USER->id); 491 $canaddsubmission = $canaddsubmission && $workshop->check_examples_assessed_before_submission($USER->id); 492 if (!$canaddsubmission) { 493 throw new moodle_exception('nopermissions', 'error', '', 'add submission'); 494 } 495 496 // Prepare the submission object. 497 $submission = new stdClass; 498 $submission->id = null; 499 $submission->cmid = $cm->id; 500 $submission->example = 0; 501 $submission->title = trim($params['title']); 502 $submission->content_editor = array( 503 'text' => $params['content'], 504 'format' => $params['contentformat'], 505 'itemid' => $params['inlineattachmentsid'], 506 ); 507 $submission->attachment_filemanager = $params['attachmentsid']; 508 509 if (empty($submission->title)) { 510 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'title'); 511 } 512 513 $errors = $workshop->validate_submission_data((array) $submission); 514 // We can get several errors, return them in warnings. 515 if (!empty($errors)) { 516 $submission->id = 0; 517 foreach ($errors as $itemname => $message) { 518 $warnings[] = array( 519 'item' => $itemname, 520 'itemid' => 0, 521 'warningcode' => 'fielderror', 522 'message' => s($message) 523 ); 524 } 525 return array( 526 'status' => false, 527 'warnings' => $warnings 528 ); 529 } else { 530 $submission->id = $workshop->edit_submission($submission); 531 return array( 532 'status' => true, 533 'submissionid' => $submission->id, 534 'warnings' => $warnings 535 ); 536 } 537 } 538 539 /** 540 * Returns the description of the external function return value. 541 * 542 * @return \core_external\external_description 543 * @since Moodle 3.4 544 */ 545 public static function add_submission_returns() { 546 return new external_single_structure(array( 547 'status' => new external_value(PARAM_BOOL, 'True if the submission was created false otherwise.'), 548 'submissionid' => new external_value(PARAM_INT, 'New workshop submission id.', VALUE_OPTIONAL), 549 'warnings' => new external_warnings() 550 )); 551 } 552 553 /** 554 * Returns the description of the external function parameters. 555 * 556 * @return external_function_parameters 557 * @since Moodle 3.4 558 */ 559 public static function update_submission_parameters() { 560 return new external_function_parameters(array( 561 'submissionid' => new external_value(PARAM_INT, 'Submission id'), 562 'title' => new external_value(PARAM_TEXT, 'Submission title'), 563 'content' => new external_value(PARAM_RAW, 'Submission text content', VALUE_DEFAULT, ''), 564 'contentformat' => new external_value(PARAM_INT, 'The format used for the content', VALUE_DEFAULT, FORMAT_MOODLE), 565 'inlineattachmentsid' => new external_value(PARAM_INT, 'The draft file area id for inline attachments in the content', 566 VALUE_DEFAULT, 0), 567 'attachmentsid' => new external_value(PARAM_INT, 'The draft file area id for attachments', VALUE_DEFAULT, 0), 568 )); 569 } 570 571 572 /** 573 * Updates the given submission. 574 * 575 * @param int $submissionid the submission id 576 * @param string $title the submission title 577 * @param string $content the submission text content 578 * @param int $contentformat the format used for the content 579 * @param int $inlineattachmentsid the draft file area id for inline attachments in the content 580 * @param int $attachmentsid the draft file area id for attachments 581 * @return array whether the submission was updated and warnings. 582 * @since Moodle 3.4 583 * @throws moodle_exception 584 */ 585 public static function update_submission($submissionid, $title, $content = '', $contentformat = FORMAT_MOODLE, 586 $inlineattachmentsid = 0, $attachmentsid = 0) { 587 global $USER, $DB; 588 589 $params = self::validate_parameters(self::update_submission_parameters(), array( 590 'submissionid' => $submissionid, 591 'title' => $title, 592 'content' => $content, 593 'contentformat' => $contentformat, 594 'inlineattachmentsid' => $inlineattachmentsid, 595 'attachmentsid' => $attachmentsid, 596 )); 597 $warnings = array(); 598 599 // Get and validate the submission and workshop. 600 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST); 601 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid); 602 require_capability('mod/workshop:submit', $context); 603 604 // Check if we can update the submission. 605 $canupdatesubmission = $submission->authorid == $USER->id; 606 $canupdatesubmission = $canupdatesubmission && $workshop->modifying_submission_allowed($USER->id); 607 $canupdatesubmission = $canupdatesubmission && $workshop->check_examples_assessed_before_submission($USER->id); 608 if (!$canupdatesubmission) { 609 throw new moodle_exception('nopermissions', 'error', '', 'update submission'); 610 } 611 612 // Prepare the submission object. 613 $submission->title = trim($params['title']); 614 if (empty($submission->title)) { 615 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'title'); 616 } 617 $submission->content_editor = array( 618 'text' => $params['content'], 619 'format' => $params['contentformat'], 620 'itemid' => $params['inlineattachmentsid'], 621 ); 622 $submission->attachment_filemanager = $params['attachmentsid']; 623 624 $errors = $workshop->validate_submission_data((array) $submission); 625 // We can get several errors, return them in warnings. 626 if (!empty($errors)) { 627 $status = false; 628 foreach ($errors as $itemname => $message) { 629 $warnings[] = array( 630 'item' => $itemname, 631 'itemid' => 0, 632 'warningcode' => 'fielderror', 633 'message' => s($message) 634 ); 635 } 636 } else { 637 $status = true; 638 $submission->id = $workshop->edit_submission($submission); 639 } 640 641 return array( 642 'status' => $status, 643 'warnings' => $warnings 644 ); 645 } 646 647 /** 648 * Returns the description of the external function return value. 649 * 650 * @return \core_external\external_description 651 * @since Moodle 3.4 652 */ 653 public static function update_submission_returns() { 654 return new external_single_structure(array( 655 'status' => new external_value(PARAM_BOOL, 'True if the submission was updated false otherwise.'), 656 'warnings' => new external_warnings() 657 )); 658 } 659 660 /** 661 * Returns the description of the external function parameters. 662 * 663 * @return external_function_parameters 664 * @since Moodle 3.4 665 */ 666 public static function delete_submission_parameters() { 667 return new external_function_parameters( 668 array( 669 'submissionid' => new external_value(PARAM_INT, 'Submission id'), 670 ) 671 ); 672 } 673 674 675 /** 676 * Deletes the given submission. 677 * 678 * @param int $submissionid the submission id. 679 * @return array containing the result status and warnings. 680 * @since Moodle 3.4 681 * @throws moodle_exception 682 */ 683 public static function delete_submission($submissionid) { 684 global $USER, $DB; 685 686 $params = self::validate_parameters(self::delete_submission_parameters(), array('submissionid' => $submissionid)); 687 $warnings = array(); 688 689 // Get and validate the submission and workshop. 690 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST); 691 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid); 692 693 // Check if we can delete the submission. 694 if (!has_capability('mod/workshop:deletesubmissions', $context)) { 695 require_capability('mod/workshop:submit', $context); 696 // We can delete our own submission, on time and not yet assessed. 697 $candeletesubmission = $submission->authorid == $USER->id; 698 $candeletesubmission = $candeletesubmission && $workshop->modifying_submission_allowed($USER->id); 699 $candeletesubmission = $candeletesubmission && count($workshop->get_assessments_of_submission($submission->id)) == 0; 700 if (!$candeletesubmission) { 701 throw new moodle_exception('nopermissions', 'error', '', 'delete submission'); 702 } 703 } 704 705 $workshop->delete_submission($submission); 706 707 return array( 708 'status' => true, 709 'warnings' => $warnings 710 ); 711 } 712 713 /** 714 * Returns the description of the external function return value. 715 * 716 * @return \core_external\external_description 717 * @since Moodle 3.4 718 */ 719 public static function delete_submission_returns() { 720 return new external_single_structure(array( 721 'status' => new external_value(PARAM_BOOL, 'True if the submission was deleted.'), 722 'warnings' => new external_warnings() 723 )); 724 } 725 726 /** 727 * Helper method for returning the submission data according the current user capabilities and current phase. 728 * 729 * @param stdClass $submission the submission data 730 * @param workshop $workshop the workshop class 731 * @param bool $canviewauthorpublished whether the user has the capability mod/workshop:viewauthorpublished on 732 * @param bool $canviewauthornames whether the user has the capability mod/workshop:vviewauthornames on 733 * @param bool $canviewallsubmissions whether the user has the capability mod/workshop:viewallsubmissions on 734 * @return stdClass object with the submission data filtered 735 * @since Moodle 3.4 736 */ 737 protected static function prepare_submission_for_external($submission, workshop $workshop, $canviewauthorpublished = null, 738 $canviewauthornames = null, $canviewallsubmissions = null) { 739 global $USER; 740 741 if (is_null($canviewauthorpublished)) { 742 $canviewauthorpublished = has_capability('mod/workshop:viewauthorpublished', $workshop->context); 743 } 744 if (is_null($canviewauthornames)) { 745 $canviewauthornames = has_capability('mod/workshop:viewauthornames', $workshop->context); 746 } 747 if (is_null($canviewallsubmissions)) { 748 $canviewallsubmissions = has_capability('mod/workshop:viewallsubmissions', $workshop->context); 749 } 750 751 $ownsubmission = $submission->authorid == $USER->id; 752 if (!$canviewauthornames && !$ownsubmission) { 753 $submission->authorid = 0; 754 } 755 756 // Remove grade, gradeover, gradeoverby, feedbackauthor and timegraded for non-teachers or invalid phase. 757 // WS mod_workshop_external::get_grades should be used for retrieving grades by students. 758 if ($workshop->phase < workshop::PHASE_EVALUATION || !$canviewallsubmissions) { 759 $properties = submission_exporter::properties_definition(); 760 foreach ($properties as $attribute => $settings) { 761 // Special case, the feedbackauthor (and who did it) should be returned if the workshop is closed and 762 // the user can view it. 763 if (($attribute == 'feedbackauthor' || $attribute == 'gradeoverby') && 764 $workshop->phase == workshop::PHASE_CLOSED && $ownsubmission) { 765 continue; 766 } 767 if (!empty($settings['optional'])) { 768 unset($submission->{$attribute}); 769 } 770 } 771 } 772 return $submission; 773 } 774 775 /** 776 * Returns description of method parameters 777 * 778 * @return external_function_parameters 779 * @since Moodle 3.4 780 */ 781 public static function get_submissions_parameters() { 782 return new external_function_parameters( 783 array( 784 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'), 785 'userid' => new external_value(PARAM_INT, 'Get submissions done by this user. Use 0 or empty for the current user', 786 VALUE_DEFAULT, 0), 787 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group. 788 It will return submissions done by users in the given group.', 789 VALUE_DEFAULT, 0), 790 'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0), 791 'perpage' => new external_value(PARAM_INT, 'The number of records to return per page.', VALUE_DEFAULT, 0), 792 ) 793 ); 794 } 795 796 /** 797 * Retrieves all the workshop submissions visible by the current user or the one done by the given user 798 * (except example submissions). 799 * 800 * @param int $workshopid the workshop instance id 801 * @param int $userid get submissions done by this user 802 * @param int $groupid (optional) group id, 0 means that the function will determine the user group 803 * @param int $page page of records to return 804 * @param int $perpage number of records to return per page 805 * @return array of warnings and the entries 806 * @since Moodle 3.4 807 * @throws moodle_exception 808 */ 809 public static function get_submissions($workshopid, $userid = 0, $groupid = 0, $page = 0, $perpage = 0) { 810 global $PAGE, $USER; 811 812 $params = array('workshopid' => $workshopid, 'userid' => $userid, 'groupid' => $groupid, 813 'page' => $page, 'perpage' => $perpage); 814 $params = self::validate_parameters(self::get_submissions_parameters(), $params); 815 $submissions = $warnings = array(); 816 817 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']); 818 819 if (empty($params['groupid'])) { 820 // Check to see if groups are being used here. 821 if ($groupmode = groups_get_activity_groupmode($cm)) { 822 $groupid = groups_get_activity_group($cm); 823 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups). 824 if (!groups_group_visible($groupid, $course, $cm)) { 825 throw new moodle_exception('notingroup'); 826 } 827 } else { 828 $groupid = 0; 829 } 830 } 831 832 if (!empty($params['userid']) && $params['userid'] != $USER->id) { 833 $user = core_user::get_user($params['userid'], '*', MUST_EXIST); 834 core_user::require_active_user($user); 835 if (!$workshop->check_group_membership($user->id)) { 836 throw new moodle_exception('notingroup'); 837 } 838 } 839 840 $totalfilesize = 0; 841 list($submissionsrecords, $totalcount) = 842 $workshop->get_visible_submissions($params['userid'], $groupid, $params['page'], $params['perpage']); 843 844 if ($totalcount) { 845 846 $canviewauthorpublished = has_capability('mod/workshop:viewauthorpublished', $context); 847 $canviewauthornames = has_capability('mod/workshop:viewauthornames', $context); 848 $canviewallsubmissions = has_capability('mod/workshop:viewallsubmissions', $context); 849 850 $related = array('context' => $context); 851 foreach ($submissionsrecords as $submission) { 852 $submission = self::prepare_submission_for_external($submission, $workshop, $canviewauthorpublished, 853 $canviewauthornames, $canviewallsubmissions); 854 855 $exporter = new submission_exporter($submission, $related); 856 $submissions[] = $exporter->export($PAGE->get_renderer('core')); 857 } 858 859 // Retrieve total files size for the submissions (so external clients know how many data they'd need to download). 860 $fs = get_file_storage(); 861 $files = $fs->get_area_files($context->id, 'mod_workshop', array('submission_content', 'submission_attachment')); 862 foreach ($files as $file) { 863 if ($file->is_directory()) { 864 continue; 865 } 866 $totalfilesize += $file->get_filesize(); 867 } 868 } 869 870 return array( 871 'submissions' => $submissions, 872 'totalcount' => $totalcount, 873 'totalfilesize' => $totalfilesize, 874 ); 875 } 876 877 /** 878 * Returns description of method result value 879 * 880 * @return \core_external\external_description 881 * @since Moodle 3.4 882 */ 883 public static function get_submissions_returns() { 884 return new external_single_structure( 885 array( 886 'submissions' => new external_multiple_structure( 887 submission_exporter::get_read_structure() 888 ), 889 'totalcount' => new external_value(PARAM_INT, 'Total count of submissions.'), 890 'totalfilesize' => new external_value(PARAM_INT, 'Total size (bytes) of the files attached to all the 891 submissions (even the ones not returned due to pagination).'), 892 'warnings' => new external_warnings() 893 ) 894 ); 895 } 896 897 /** 898 * Helper method for validating a submission. 899 * 900 * @param stdClass $submission submission object 901 * @param workshop $workshop workshop instance 902 * @return void 903 * @since Moodle 3.4 904 */ 905 protected static function validate_submission($submission, workshop $workshop) { 906 global $USER; 907 908 $workshopclosed = $workshop->phase == workshop::PHASE_CLOSED; 909 $canviewpublished = has_capability('mod/workshop:viewpublishedsubmissions', $workshop->context); 910 911 $canview = $submission->authorid == $USER->id; // I did it. 912 $canview = $canview || !empty($workshop->get_assessment_of_submission_by_user($submission->id, $USER->id)); // I reviewed. 913 $canview = $canview || has_capability('mod/workshop:viewallsubmissions', $workshop->context); // I can view all. 914 $canview = $canview || ($submission->published && $workshopclosed && $canviewpublished); // It has been published. 915 916 if ($canview) { 917 // Here we should check if the user share group. 918 if ($submission->authorid != $USER->id && 919 !groups_user_groups_visible($workshop->course, $submission->authorid, $workshop->cm)) { 920 throw new moodle_exception('notingroup'); 921 } 922 } else { 923 throw new moodle_exception('nopermissions', 'error', '', 'view submission'); 924 } 925 } 926 927 /** 928 * Returns the description of the external function parameters. 929 * 930 * @return external_function_parameters 931 * @since Moodle 3.4 932 */ 933 public static function get_submission_parameters() { 934 return new external_function_parameters( 935 array( 936 'submissionid' => new external_value(PARAM_INT, 'Submission id'), 937 ) 938 ); 939 } 940 941 942 /** 943 * Retrieves the given submission. 944 * 945 * @param int $submissionid the submission id 946 * @return array containing the submission and warnings. 947 * @since Moodle 3.4 948 * @throws moodle_exception 949 */ 950 public static function get_submission($submissionid) { 951 global $USER, $DB, $PAGE; 952 953 $params = self::validate_parameters(self::get_submission_parameters(), array('submissionid' => $submissionid)); 954 $warnings = array(); 955 956 // Get and validate the submission and workshop. 957 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST); 958 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid); 959 960 self::validate_submission($submission, $workshop); 961 962 $submission = self::prepare_submission_for_external($submission, $workshop); 963 964 $related = array('context' => $context); 965 $exporter = new submission_exporter($submission, $related); 966 return array( 967 'submission' => $exporter->export($PAGE->get_renderer('core')), 968 'warnings' => $warnings 969 ); 970 } 971 972 /** 973 * Returns description of method result value 974 * 975 * @return \core_external\external_description 976 * @since Moodle 3.4 977 */ 978 public static function get_submission_returns() { 979 return new external_single_structure( 980 array( 981 'submission' => submission_exporter::get_read_structure(), 982 'warnings' => new external_warnings() 983 ) 984 ); 985 } 986 987 /** 988 * Helper method for validating if the current user can view the submission assessments. 989 * 990 * @param stdClass $submission submission object 991 * @param workshop $workshop workshop instance 992 * @return void 993 * @since Moodle 3.4 994 */ 995 protected static function check_view_submission_assessments($submission, workshop $workshop) { 996 global $USER; 997 998 $ownsubmission = $submission->authorid == $USER->id; 999 $canview = has_capability('mod/workshop:viewallassessments', $workshop->context) || 1000 ($ownsubmission && $workshop->assessments_available()); 1001 1002 if ($canview) { 1003 // Here we should check if the user share group. 1004 if ($submission->authorid != $USER->id && 1005 !groups_user_groups_visible($workshop->course, $submission->authorid, $workshop->cm)) { 1006 throw new moodle_exception('notingroup'); 1007 } 1008 } else { 1009 throw new moodle_exception('nopermissions', 'error', '', 'view assessment'); 1010 } 1011 } 1012 1013 /** 1014 * Helper method for returning the assessment data according the current user capabilities and current phase. 1015 * 1016 * @param stdClass $assessment the assessment data 1017 * @param workshop $workshop the workshop class 1018 * @return stdClass object with the assessment data filtered or null if is not viewable yet 1019 * @since Moodle 3.4 1020 */ 1021 protected static function prepare_assessment_for_external($assessment, workshop $workshop) { 1022 global $USER; 1023 static $canviewallassessments = null; 1024 static $canviewreviewers = null; 1025 static $canoverridegrades = null; 1026 1027 // Remove all the properties that does not belong to the assessment table. 1028 $properties = assessment_exporter::properties_definition(); 1029 foreach ($assessment as $key => $value) { 1030 if (!isset($properties[$key])) { 1031 unset($assessment->{$key}); 1032 } 1033 } 1034 1035 if (is_null($canviewallassessments)) { 1036 $canviewallassessments = has_capability('mod/workshop:viewallassessments', $workshop->context); 1037 } 1038 if (is_null($canviewreviewers)) { 1039 $canviewreviewers = has_capability('mod/workshop:viewreviewernames', $workshop->context); 1040 } 1041 if (is_null($canoverridegrades)) { 1042 $canoverridegrades = has_capability('mod/workshop:overridegrades', $workshop->context); 1043 } 1044 1045 $isreviewer = $assessment->reviewerid == $USER->id; 1046 1047 if (!$isreviewer && is_null($assessment->grade) && !$canviewallassessments) { 1048 // Students do not see peer-assessment that are not graded yet. 1049 return null; 1050 } 1051 1052 // Remove the feedback for the reviewer if: 1053 // I can't see it in the evaluation phase because I'm not a teacher or the reviewer AND 1054 // I can't see it in the assessment phase because I'm not a teacher. 1055 if (($workshop->phase < workshop::PHASE_EVALUATION || !($isreviewer || $canviewallassessments)) && 1056 ($workshop->phase < workshop::PHASE_ASSESSMENT || !$canviewallassessments) ) { 1057 // Remove all the feedback information (all the optional fields). 1058 foreach ($properties as $attribute => $settings) { 1059 if (!empty($settings['optional'])) { 1060 unset($assessment->{$attribute}); 1061 } 1062 } 1063 } 1064 1065 if (!$isreviewer && !$canviewreviewers) { 1066 $assessment->reviewerid = 0; 1067 } 1068 1069 return $assessment; 1070 } 1071 1072 /** 1073 * Returns the description of the external function parameters. 1074 * 1075 * @return external_function_parameters 1076 * @since Moodle 3.4 1077 */ 1078 public static function get_submission_assessments_parameters() { 1079 return new external_function_parameters( 1080 array( 1081 'submissionid' => new external_value(PARAM_INT, 'Submission id'), 1082 ) 1083 ); 1084 } 1085 1086 1087 /** 1088 * Retrieves the given submission assessments. 1089 * 1090 * @param int $submissionid the submission id 1091 * @return array containing the assessments and warnings. 1092 * @since Moodle 3.4 1093 * @throws moodle_exception 1094 */ 1095 public static function get_submission_assessments($submissionid) { 1096 global $USER, $DB, $PAGE; 1097 1098 $params = self::validate_parameters(self::get_submission_assessments_parameters(), array('submissionid' => $submissionid)); 1099 $warnings = $assessments = array(); 1100 1101 // Get and validate the submission and workshop. 1102 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST); 1103 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid); 1104 1105 // Check that we can get the assessments and get them. 1106 self::check_view_submission_assessments($submission, $workshop); 1107 $assessmentsrecords = $workshop->get_assessments_of_submission($submission->id); 1108 1109 $related = array('context' => $context); 1110 foreach ($assessmentsrecords as $assessment) { 1111 $assessment = self::prepare_assessment_for_external($assessment, $workshop); 1112 if (empty($assessment)) { 1113 continue; 1114 } 1115 $exporter = new assessment_exporter($assessment, $related); 1116 $assessments[] = $exporter->export($PAGE->get_renderer('core')); 1117 } 1118 1119 return array( 1120 'assessments' => $assessments, 1121 'warnings' => $warnings 1122 ); 1123 } 1124 1125 /** 1126 * Returns description of method result value 1127 * 1128 * @return \core_external\external_description 1129 * @since Moodle 3.4 1130 */ 1131 public static function get_submission_assessments_returns() { 1132 return new external_single_structure( 1133 array( 1134 'assessments' => new external_multiple_structure( 1135 assessment_exporter::get_read_structure() 1136 ), 1137 'warnings' => new external_warnings() 1138 ) 1139 ); 1140 } 1141 1142 /** 1143 * Returns the description of the external function parameters. 1144 * 1145 * @return external_function_parameters 1146 * @since Moodle 3.4 1147 */ 1148 public static function get_assessment_parameters() { 1149 return new external_function_parameters( 1150 array( 1151 'assessmentid' => new external_value(PARAM_INT, 'Assessment id'), 1152 ) 1153 ); 1154 } 1155 1156 1157 /** 1158 * Retrieves the given assessment. 1159 * 1160 * @param int $assessmentid the assessment id 1161 * @return array containing the assessment and warnings. 1162 * @since Moodle 3.4 1163 * @throws moodle_exception 1164 */ 1165 public static function get_assessment($assessmentid) { 1166 global $DB, $PAGE; 1167 1168 $params = self::validate_parameters(self::get_assessment_parameters(), array('assessmentid' => $assessmentid)); 1169 $warnings = array(); 1170 1171 // Get and validate the assessment, submission and workshop. 1172 $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST); 1173 $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST); 1174 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid); 1175 1176 // Check that we can get the assessment. 1177 $workshop->check_view_assessment($assessment, $submission); 1178 1179 $assessment = $workshop->get_assessment_by_id($assessment->id); 1180 $assessment = self::prepare_assessment_for_external($assessment, $workshop); 1181 if (empty($assessment)) { 1182 throw new moodle_exception('nopermissions', 'error', '', 'view assessment'); 1183 } 1184 $related = array('context' => $context); 1185 $exporter = new assessment_exporter($assessment, $related); 1186 1187 return array( 1188 'assessment' => $exporter->export($PAGE->get_renderer('core')), 1189 'warnings' => $warnings 1190 ); 1191 } 1192 1193 /** 1194 * Returns description of method result value 1195 * 1196 * @return \core_external\external_description 1197 * @since Moodle 3.4 1198 */ 1199 public static function get_assessment_returns() { 1200 return new external_single_structure( 1201 array( 1202 'assessment' => assessment_exporter::get_read_structure(), 1203 'warnings' => new external_warnings() 1204 ) 1205 ); 1206 } 1207 1208 /** 1209 * Returns the description of the external function parameters. 1210 * 1211 * @return external_function_parameters 1212 * @since Moodle 3.4 1213 */ 1214 public static function get_assessment_form_definition_parameters() { 1215 return new external_function_parameters( 1216 array( 1217 'assessmentid' => new external_value(PARAM_INT, 'Assessment id'), 1218 'mode' => new external_value(PARAM_ALPHA, 'The form mode (assessment or preview)', VALUE_DEFAULT, 'assessment'), 1219 ) 1220 ); 1221 } 1222 1223 1224 /** 1225 * Retrieves the assessment form definition (data required to be able to display the assessment form). 1226 * 1227 * @param int $assessmentid the assessment id 1228 * @param string $mode the form mode (assessment or preview) 1229 * @return array containing the assessment and warnings. 1230 * @since Moodle 3.4 1231 * @throws moodle_exception 1232 */ 1233 public static function get_assessment_form_definition($assessmentid, $mode = 'assessment') { 1234 global $DB, $USER; 1235 1236 $params = self::validate_parameters( 1237 self::get_assessment_form_definition_parameters(), array('assessmentid' => $assessmentid, 'mode' => $mode) 1238 ); 1239 $warnings = $pending = array(); 1240 1241 if ($params['mode'] != 'assessment' && $params['mode'] != 'preview') { 1242 throw new invalid_parameter_exception('Invalid value for mode parameter (value: ' . $params['mode'] . ')'); 1243 } 1244 1245 // Get and validate the assessment, submission and workshop. 1246 $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST); 1247 $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST); 1248 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid); 1249 1250 // Check we can view the assessment (so we can get the form data). 1251 $workshop->check_view_assessment($assessment, $submission); 1252 1253 $cansetassessmentweight = has_capability('mod/workshop:allocate', $context); 1254 $pending = $workshop->get_pending_assessments_by_reviewer($assessment->reviewerid, $assessment->id); 1255 1256 // Retrieve the data from the strategy plugin. 1257 $strategy = $workshop->grading_strategy_instance(); 1258 $strategyname = str_replace('_strategy', '', get_class($strategy)); // Get strategy name. 1259 $mform = $strategy->get_assessment_form(null, $params['mode'], $assessment, true, 1260 array('editableweight' => $cansetassessmentweight, 'pending' => !empty($pending))); 1261 $formdata = $mform->get_customdata(); 1262 1263 $result = array( 1264 'dimenssionscount' => $formdata['nodims'], 1265 'descriptionfiles' => util::get_area_files($context->id, $strategyname, 'description'), 1266 'warnings' => $warnings 1267 ); 1268 // Include missing dimension fields. 1269 for ($i = 0; $i < $formdata['nodims']; $i++) { 1270 $formdata['fields']->{'gradeid__idx_' . $i} = 0; 1271 $formdata['fields']->{'peercomment__idx_' . $i} = ''; 1272 } 1273 1274 // Convert all the form data for external. 1275 foreach (array('options', 'fields', 'current') as $typeofdata) { 1276 $result[$typeofdata] = array(); 1277 1278 if (!empty($formdata[$typeofdata])) { 1279 $alldata = (array) $formdata[$typeofdata]; 1280 foreach ($alldata as $key => $val) { 1281 if (strpos($key, 'description__idx_')) { 1282 // Format dimension description. 1283 $id = str_replace('description__idx_', '', $key); 1284 list($val, $format) = \core_external\util::format_text($val, $alldata['dimensionid__idx_' . $id . 'format'], 1285 $context->id, $strategyname, 'description', $alldata['dimensionid__idx_' . $id]); 1286 } 1287 $result[$typeofdata][] = array( 1288 'name' => $key, 1289 'value' => $val 1290 ); 1291 } 1292 } 1293 } 1294 1295 // Get dimensions info. 1296 $grader = $workshop->grading_strategy_instance(); 1297 $result['dimensionsinfo'] = $grader->get_dimensions_info(); 1298 1299 return $result; 1300 } 1301 1302 /** 1303 * Returns description of method result value 1304 * 1305 * @return \core_external\external_description 1306 * @since Moodle 3.4 1307 */ 1308 public static function get_assessment_form_definition_returns() { 1309 return new external_single_structure( 1310 array( 1311 'dimenssionscount' => new external_value(PARAM_INT, 'The number of dimenssions used by the form.'), 1312 'descriptionfiles' => new external_files('Files in the description text'), 1313 'options' => new external_multiple_structure( 1314 new external_single_structure( 1315 array( 1316 'name' => new external_value(PARAM_ALPHANUMEXT, 'Option name.'), 1317 'value' => new external_value(PARAM_NOTAGS, 'Option value.') 1318 ) 1319 ), 'The form options.' 1320 ), 1321 'fields' => new external_multiple_structure( 1322 new external_single_structure( 1323 array( 1324 'name' => new external_value(PARAM_ALPHANUMEXT, 'Field name.'), 1325 'value' => new external_value(PARAM_RAW, 'Field default value.') 1326 ) 1327 ), 'The form fields.' 1328 ), 1329 'current' => new external_multiple_structure( 1330 new external_single_structure( 1331 array( 1332 'name' => new external_value(PARAM_ALPHANUMEXT, 'Field name.'), 1333 'value' => new external_value(PARAM_RAW, 'Current field value.') 1334 ) 1335 ), 'The current field values.' 1336 ), 1337 'dimensionsinfo' => new external_multiple_structure( 1338 new external_single_structure( 1339 array( 1340 'id' => new external_value(PARAM_INT, 'Dimension id.'), 1341 'min' => new external_value(PARAM_FLOAT, 'Minimum grade for the dimension.'), 1342 'max' => new external_value(PARAM_FLOAT, 'Maximum grade for the dimension.'), 1343 'weight' => new external_value(PARAM_TEXT, 'The weight of the dimension.'), 1344 'scale' => new external_value(PARAM_TEXT, 'Scale items (if used).', VALUE_OPTIONAL), 1345 ) 1346 ), 'The dimensions general information.' 1347 ), 1348 'warnings' => new external_warnings() 1349 ) 1350 ); 1351 } 1352 1353 /** 1354 * Returns the description of the external function parameters. 1355 * 1356 * @return external_function_parameters 1357 * @since Moodle 3.4 1358 */ 1359 public static function get_reviewer_assessments_parameters() { 1360 return new external_function_parameters( 1361 array( 1362 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'), 1363 'userid' => new external_value(PARAM_INT, 'User id who did the assessment review (empty or 0 for current user).', 1364 VALUE_DEFAULT, 0), 1365 ) 1366 ); 1367 } 1368 1369 1370 /** 1371 * Retrieves all the assessments reviewed by the given user. 1372 * 1373 * @param int $workshopid the workshop instance id 1374 * @param int $userid the reviewer user id 1375 * @return array containing the user assessments and warnings. 1376 * @since Moodle 3.4 1377 * @throws moodle_exception 1378 */ 1379 public static function get_reviewer_assessments($workshopid, $userid = 0) { 1380 global $USER, $DB, $PAGE; 1381 1382 $params = self::validate_parameters( 1383 self::get_reviewer_assessments_parameters(), array('workshopid' => $workshopid, 'userid' => $userid) 1384 ); 1385 $warnings = $assessments = array(); 1386 1387 // Get and validate the submission and workshop. 1388 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']); 1389 1390 // Extra checks so only users with permissions can view other users assessments. 1391 if (empty($params['userid']) || $params['userid'] == $USER->id) { 1392 $userid = $USER->id; 1393 list($assessed, $notice) = $workshop->check_examples_assessed_before_assessment($userid); 1394 if (!$assessed) { 1395 throw new moodle_exception($notice, 'mod_workshop'); 1396 } 1397 if ($workshop->phase < workshop::PHASE_ASSESSMENT) { // Can view assessments only in assessment phase onwards. 1398 throw new moodle_exception('nopermissions', 'error', '', 'view assessments'); 1399 } 1400 } else { 1401 require_capability('mod/workshop:viewallassessments', $context); 1402 $user = core_user::get_user($params['userid'], '*', MUST_EXIST); 1403 core_user::require_active_user($user); 1404 if (!$workshop->check_group_membership($user->id)) { 1405 throw new moodle_exception('notingroup'); 1406 } 1407 $userid = $user->id; 1408 } 1409 // Now get all my assessments (includes those pending review). 1410 $assessmentsrecords = $workshop->get_assessments_by_reviewer($userid); 1411 1412 $related = array('context' => $context); 1413 foreach ($assessmentsrecords as $assessment) { 1414 $assessment = self::prepare_assessment_for_external($assessment, $workshop); 1415 if (empty($assessment)) { 1416 continue; 1417 } 1418 $exporter = new assessment_exporter($assessment, $related); 1419 $assessments[] = $exporter->export($PAGE->get_renderer('core')); 1420 } 1421 1422 return array( 1423 'assessments' => $assessments, 1424 'warnings' => $warnings 1425 ); 1426 } 1427 1428 /** 1429 * Returns description of method result value 1430 * 1431 * @return \core_external\external_description 1432 * @since Moodle 3.4 1433 */ 1434 public static function get_reviewer_assessments_returns() { 1435 return new external_single_structure( 1436 array( 1437 'assessments' => new external_multiple_structure( 1438 assessment_exporter::get_read_structure() 1439 ), 1440 'warnings' => new external_warnings() 1441 ) 1442 ); 1443 } 1444 1445 /** 1446 * Returns the description of the external function parameters. 1447 * 1448 * @return external_function_parameters 1449 * @since Moodle 3.4 1450 */ 1451 public static function update_assessment_parameters() { 1452 return new external_function_parameters( 1453 array( 1454 'assessmentid' => new external_value(PARAM_INT, 'Assessment id.'), 1455 'data' => new external_multiple_structure ( 1456 new external_single_structure( 1457 array( 1458 'name' => new external_value(PARAM_ALPHANUMEXT, 1459 'The assessment data (use WS get_assessment_form_definition for obtaining the data to sent). 1460 Apart from that data, you can optionally send: 1461 feedbackauthor (str); the feedback for the submission author 1462 feedbackauthorformat (int); the format of the feedbackauthor 1463 feedbackauthorinlineattachmentsid (int); the draft file area for the editor attachments 1464 feedbackauthorattachmentsid (int); the draft file area id for the feedback attachments' 1465 ), 1466 'value' => new external_value(PARAM_RAW, 'The value of the option.') 1467 ) 1468 ), 'Assessment data' 1469 ) 1470 ) 1471 ); 1472 } 1473 1474 1475 /** 1476 * Updates an assessment. 1477 * 1478 * @param int $assessmentid the assessment id 1479 * @param array $data the assessment data 1480 * @return array indicates if the assessment was updated, the new raw grade and possible warnings. 1481 * @since Moodle 3.4 1482 * @throws moodle_exception 1483 */ 1484 public static function update_assessment($assessmentid, $data) { 1485 global $DB, $USER; 1486 1487 $params = self::validate_parameters( 1488 self::update_assessment_parameters(), array('assessmentid' => $assessmentid, 'data' => $data) 1489 ); 1490 $warnings = array(); 1491 1492 // Get and validate the assessment, submission and workshop. 1493 $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST); 1494 $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST); 1495 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid); 1496 1497 // Check we can edit the assessment. 1498 $workshop->check_edit_assessment($assessment, $submission); 1499 1500 // Process data. 1501 $data = new stdClass; 1502 $data->feedbackauthor_editor = array(); 1503 1504 foreach ($params['data'] as $wsdata) { 1505 $name = trim($wsdata['name']); 1506 switch ($name) { 1507 case 'feedbackauthor': 1508 $data->feedbackauthor_editor['text'] = $wsdata['value']; 1509 break; 1510 case 'feedbackauthorformat': 1511 $data->feedbackauthor_editor['format'] = clean_param($wsdata['value'], PARAM_FORMAT); 1512 break; 1513 case 'feedbackauthorinlineattachmentsid': 1514 $data->feedbackauthor_editor['itemid'] = clean_param($wsdata['value'], PARAM_INT); 1515 break; 1516 case 'feedbackauthorattachmentsid': 1517 $data->feedbackauthorattachment_filemanager = clean_param($wsdata['value'], PARAM_INT); 1518 break; 1519 default: 1520 $data->{$wsdata['name']} = $wsdata['value']; // Validation will be done in the form->validation. 1521 } 1522 } 1523 1524 $cansetassessmentweight = has_capability('mod/workshop:allocate', $context); 1525 $pending = $workshop->get_pending_assessments_by_reviewer($assessment->reviewerid, $assessment->id); 1526 // Retrieve the data from the strategy plugin. 1527 $strategy = $workshop->grading_strategy_instance(); 1528 $mform = $strategy->get_assessment_form(null, 'assessment', $assessment, true, 1529 array('editableweight' => $cansetassessmentweight, 'pending' => !empty($pending))); 1530 1531 $errors = $mform->validation((array) $data, array()); 1532 // We can get several errors, return them in warnings. 1533 if (!empty($errors)) { 1534 $status = false; 1535 $rawgrade = null; 1536 foreach ($errors as $itemname => $message) { 1537 $warnings[] = array( 1538 'item' => $itemname, 1539 'itemid' => 0, 1540 'warningcode' => 'fielderror', 1541 'message' => s($message) 1542 ); 1543 } 1544 } else { 1545 $rawgrade = $workshop->edit_assessment($assessment, $submission, $data, $strategy); 1546 $status = true; 1547 } 1548 1549 return array( 1550 'status' => $status, 1551 'rawgrade' => $rawgrade, 1552 'warnings' => $warnings, 1553 ); 1554 } 1555 1556 /** 1557 * Returns description of method result value 1558 * 1559 * @return \core_external\external_description 1560 * @since Moodle 3.4 1561 */ 1562 public static function update_assessment_returns() { 1563 return new external_single_structure( 1564 array( 1565 'status' => new external_value(PARAM_BOOL, 'status: true if the assessment was added or updated false otherwise.'), 1566 'rawgrade' => new external_value(PARAM_FLOAT, 'Raw percentual grade (0.00000 to 100.00000) for submission.', 1567 VALUE_OPTIONAL), 1568 'warnings' => new external_warnings() 1569 ) 1570 ); 1571 } 1572 1573 /** 1574 * Returns the description of the external function parameters. 1575 * 1576 * @return external_external_function_parameters 1577 * @since Moodle 3.4 1578 */ 1579 public static function get_grades_parameters() { 1580 return new external_function_parameters ( 1581 array( 1582 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'), 1583 'userid' => new external_value(PARAM_INT, 'User id (empty or 0 for current user).', VALUE_DEFAULT, 0), 1584 ) 1585 ); 1586 } 1587 1588 /** 1589 * Returns the grades information for the given workshop and user. 1590 * 1591 * @param int $workshopid workshop instance id 1592 * @param int $userid user id 1593 * @return array of warnings and the user plan 1594 * @since Moodle 3.4 1595 * @throws moodle_exception 1596 */ 1597 public static function get_grades($workshopid, $userid = 0) { 1598 global $USER; 1599 1600 $params = array( 1601 'workshopid' => $workshopid, 1602 'userid' => $userid, 1603 ); 1604 $params = self::validate_parameters(self::get_grades_parameters(), $params); 1605 $warnings = array(); 1606 1607 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']); 1608 1609 // Extra checks so only users with permissions can view other users plans. 1610 if (empty($params['userid']) || $params['userid'] == $USER->id) { 1611 $userid = $USER->id; 1612 } else { 1613 require_capability('mod/workshop:viewallassessments', $context); 1614 $user = core_user::get_user($params['userid'], '*', MUST_EXIST); 1615 core_user::require_active_user($user); 1616 if (!$workshop->check_group_membership($user->id)) { 1617 throw new moodle_exception('notingroup'); 1618 } 1619 $userid = $user->id; 1620 } 1621 1622 $finalgrades = $workshop->get_gradebook_grades($userid); 1623 1624 $result = array('warnings' => $warnings); 1625 if ($finalgrades !== false) { 1626 if (!empty($finalgrades->submissiongrade)) { 1627 if (is_numeric($finalgrades->submissiongrade->grade)) { 1628 $result['submissionrawgrade'] = $finalgrades->submissiongrade->grade; 1629 } 1630 $result['submissionlongstrgrade'] = $finalgrades->submissiongrade->str_long_grade; 1631 $result['submissiongradehidden'] = $finalgrades->submissiongrade->hidden; 1632 } 1633 if (!empty($finalgrades->assessmentgrade)) { 1634 if (is_numeric($finalgrades->assessmentgrade->grade)) { 1635 $result['assessmentrawgrade'] = $finalgrades->assessmentgrade->grade; 1636 } 1637 $result['assessmentlongstrgrade'] = $finalgrades->assessmentgrade->str_long_grade; 1638 $result['assessmentgradehidden'] = $finalgrades->assessmentgrade->hidden; 1639 } 1640 } 1641 1642 return $result; 1643 } 1644 1645 /** 1646 * Returns description of method result value. 1647 * 1648 * @return external_single_structure 1649 * @since Moodle 3.4 1650 */ 1651 public static function get_grades_returns() { 1652 return new external_single_structure( 1653 array( 1654 'assessmentrawgrade' => new external_value(PARAM_FLOAT, 'The assessment raw (numeric) grade.', VALUE_OPTIONAL), 1655 'assessmentlongstrgrade' => new external_value(PARAM_NOTAGS, 'The assessment string grade.', VALUE_OPTIONAL), 1656 'assessmentgradehidden' => new external_value(PARAM_BOOL, 'Whether the grade is hidden or not.', VALUE_OPTIONAL), 1657 'submissionrawgrade' => new external_value(PARAM_FLOAT, 'The submission raw (numeric) grade.', VALUE_OPTIONAL), 1658 'submissionlongstrgrade' => new external_value(PARAM_NOTAGS, 'The submission string grade.', VALUE_OPTIONAL), 1659 'submissiongradehidden' => new external_value(PARAM_BOOL, 'Whether the grade is hidden or not.', VALUE_OPTIONAL), 1660 'warnings' => new external_warnings(), 1661 ) 1662 ); 1663 } 1664 1665 /** 1666 * Returns the description of the external function parameters. 1667 * 1668 * @return external_function_parameters 1669 * @since Moodle 3.4 1670 */ 1671 public static function evaluate_assessment_parameters() { 1672 return new external_function_parameters( 1673 array( 1674 'assessmentid' => new external_value(PARAM_INT, 'Assessment id.'), 1675 'feedbacktext' => new external_value(PARAM_RAW, 'The feedback for the reviewer.', VALUE_DEFAULT, ''), 1676 'feedbackformat' => new external_value(PARAM_INT, 'The feedback format for text.', VALUE_DEFAULT, FORMAT_MOODLE), 1677 'weight' => new external_value(PARAM_INT, 'The new weight for the assessment.', VALUE_DEFAULT, 1), 1678 'gradinggradeover' => new external_value(PARAM_ALPHANUMEXT, 'The new grading grade.', VALUE_DEFAULT, ''), 1679 ) 1680 ); 1681 } 1682 1683 1684 /** 1685 * Evaluates an assessment (used by teachers for provide feedback to the reviewer). 1686 * 1687 * @param int $assessmentid the assessment id 1688 * @param str $feedbacktext the feedback for the reviewer 1689 * @param int $feedbackformat the feedback format for the reviewer text 1690 * @param int $weight the new weight for the assessment 1691 * @param mixed $gradinggradeover the new grading grade (empty for no overriding the grade) 1692 * @return array containing the status and warnings. 1693 * @since Moodle 3.4 1694 * @throws moodle_exception 1695 */ 1696 public static function evaluate_assessment($assessmentid, $feedbacktext = '', $feedbackformat = FORMAT_MOODLE, $weight = 1, 1697 $gradinggradeover = '') { 1698 global $DB; 1699 1700 $params = self::validate_parameters( 1701 self::evaluate_assessment_parameters(), 1702 array( 1703 'assessmentid' => $assessmentid, 1704 'feedbacktext' => $feedbacktext, 1705 'feedbackformat' => $feedbackformat, 1706 'weight' => $weight, 1707 'gradinggradeover' => $gradinggradeover, 1708 ) 1709 ); 1710 $warnings = array(); 1711 1712 // Get and validate the assessment, submission and workshop. 1713 $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST); 1714 $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST); 1715 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid); 1716 1717 // Check we can evaluate the assessment. 1718 $workshop->check_view_assessment($assessment, $submission); 1719 $cansetassessmentweight = has_capability('mod/workshop:allocate', $context); 1720 $canoverridegrades = has_capability('mod/workshop:overridegrades', $context); 1721 if (!$canoverridegrades && !$cansetassessmentweight) { 1722 throw new moodle_exception('nopermissions', 'error', '', 'evaluate assessments'); 1723 } 1724 1725 // Process data. 1726 $data = new stdClass; 1727 $data->asid = $assessment->id; 1728 $data->feedbackreviewer_editor = array( 1729 'text' => $params['feedbacktext'], 1730 'format' => $params['feedbackformat'], 1731 ); 1732 $data->weight = $params['weight']; 1733 $data->gradinggradeover = $params['gradinggradeover']; 1734 1735 $options = array( 1736 'editable' => true, 1737 'editableweight' => $cansetassessmentweight, 1738 'overridablegradinggrade' => $canoverridegrades 1739 ); 1740 $feedbackform = $workshop->get_feedbackreviewer_form(null, $assessment, $options); 1741 1742 $errors = $feedbackform->validation((array) $data, array()); 1743 // Extra checks for the new grade and weight. 1744 $possibleweights = workshop::available_assessment_weights_list(); 1745 if ($data->weight < 0 || $data->weight > max(array_keys($possibleweights))) { 1746 $errors['weight'] = 'The new weight must be higher or equal to 0 and cannot be higher than the maximum weight for 1747 assessment.'; 1748 } 1749 if (is_numeric($data->gradinggradeover) && 1750 ($data->gradinggradeover < 0 || $data->gradinggradeover > $workshop->gradinggrade)) { 1751 $errors['gradinggradeover'] = 'The new grade must be higher or equal to 0 and cannot be higher than the maximum grade 1752 for assessment.'; 1753 } 1754 1755 // We can get several errors, return them in warnings. 1756 if (!empty($errors)) { 1757 $status = false; 1758 foreach ($errors as $itemname => $message) { 1759 $warnings[] = array( 1760 'item' => $itemname, 1761 'itemid' => 0, 1762 'warningcode' => 'fielderror', 1763 'message' => s($message) 1764 ); 1765 } 1766 } else { 1767 $workshop->evaluate_assessment($assessment, $data, $cansetassessmentweight, $canoverridegrades); 1768 $status = true; 1769 } 1770 1771 return array( 1772 'status' => $status, 1773 'warnings' => $warnings, 1774 ); 1775 } 1776 1777 /** 1778 * Returns description of method result value 1779 * 1780 * @return \core_external\external_description 1781 * @since Moodle 3.4 1782 */ 1783 public static function evaluate_assessment_returns() { 1784 return new external_single_structure( 1785 array( 1786 'status' => new external_value(PARAM_BOOL, 'status: true if the assessment was evaluated, false otherwise.'), 1787 'warnings' => new external_warnings() 1788 ) 1789 ); 1790 } 1791 1792 /** 1793 * Returns description of method parameters 1794 * 1795 * @return external_function_parameters 1796 * @since Moodle 3.4 1797 */ 1798 public static function get_grades_report_parameters() { 1799 return new external_function_parameters( 1800 array( 1801 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'), 1802 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group.', 1803 VALUE_DEFAULT, 0), 1804 'sortby' => new external_value(PARAM_ALPHA, 'sort by this element: lastname, firstname, submissiontitle, 1805 submissionmodified, submissiongrade, gradinggrade.', VALUE_DEFAULT, 'lastname'), 1806 'sortdirection' => new external_value(PARAM_ALPHA, 'sort direction: ASC or DESC', VALUE_DEFAULT, 'ASC'), 1807 'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0), 1808 'perpage' => new external_value(PARAM_INT, 'The number of records to return per page.', VALUE_DEFAULT, 0), 1809 ) 1810 ); 1811 } 1812 1813 /** 1814 * Retrieves the assessment grades report. 1815 * 1816 * @param int $workshopid the workshop instance id 1817 * @param int $groupid (optional) group id, 0 means that the function will determine the user group 1818 * @param string $sortby sort by this element 1819 * @param string $sortdirection sort direction: ASC or DESC 1820 * @param int $page page of records to return 1821 * @param int $perpage number of records to return per page 1822 * @return array of warnings and the report data 1823 * @since Moodle 3.4 1824 * @throws moodle_exception 1825 */ 1826 public static function get_grades_report($workshopid, $groupid = 0, $sortby = 'lastname', $sortdirection = 'ASC', 1827 $page = 0, $perpage = 0) { 1828 global $USER; 1829 1830 $params = array('workshopid' => $workshopid, 'groupid' => $groupid, 'sortby' => $sortby, 'sortdirection' => $sortdirection, 1831 'page' => $page, 'perpage' => $perpage); 1832 $params = self::validate_parameters(self::get_grades_report_parameters(), $params); 1833 $submissions = $warnings = array(); 1834 1835 $sortallowedvalues = array('lastname', 'firstname', 'submissiontitle', 'submissionmodified', 'submissiongrade', 1836 'gradinggrade'); 1837 if (!in_array($params['sortby'], $sortallowedvalues)) { 1838 throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' . 1839 'allowed values are: ' . implode(',', $sortallowedvalues)); 1840 } 1841 1842 $sortdirection = strtoupper($params['sortdirection']); 1843 $directionallowedvalues = array('ASC', 'DESC'); 1844 if (!in_array($sortdirection, $directionallowedvalues)) { 1845 throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' . 1846 'allowed values are: ' . implode(',', $directionallowedvalues)); 1847 } 1848 1849 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']); 1850 require_capability('mod/workshop:viewallassessments', $context); 1851 1852 if (!empty($params['groupid'])) { 1853 $groupid = $params['groupid']; 1854 // Determine is the group is visible to user. 1855 if (!groups_group_visible($groupid, $course, $cm)) { 1856 throw new moodle_exception('notingroup'); 1857 } 1858 } else { 1859 // Check to see if groups are being used here. 1860 if ($groupmode = groups_get_activity_groupmode($cm)) { 1861 $groupid = groups_get_activity_group($cm); 1862 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups). 1863 if (!groups_group_visible($groupid, $course, $cm)) { 1864 throw new moodle_exception('notingroup'); 1865 } 1866 } else { 1867 $groupid = 0; 1868 } 1869 } 1870 1871 if ($workshop->phase >= workshop::PHASE_SUBMISSION) { 1872 $showauthornames = has_capability('mod/workshop:viewauthornames', $context); 1873 $showreviewernames = has_capability('mod/workshop:viewreviewernames', $context); 1874 1875 if ($workshop->phase >= workshop::PHASE_EVALUATION) { 1876 $showsubmissiongrade = true; 1877 $showgradinggrade = true; 1878 } else { 1879 $showsubmissiongrade = false; 1880 $showgradinggrade = false; 1881 } 1882 1883 $data = $workshop->prepare_grading_report_data($USER->id, $groupid, $params['page'], $params['perpage'], 1884 $params['sortby'], $sortdirection); 1885 1886 if (!empty($data)) { 1887 // Populate the display options for the submissions report. 1888 $reportopts = new stdclass(); 1889 $reportopts->showauthornames = $showauthornames; 1890 $reportopts->showreviewernames = $showreviewernames; 1891 $reportopts->sortby = $params['sortby']; 1892 $reportopts->sorthow = $sortdirection; 1893 $reportopts->showsubmissiongrade = $showsubmissiongrade; 1894 $reportopts->showgradinggrade = $showgradinggrade; 1895 $reportopts->workshopphase = $workshop->phase; 1896 1897 $report = new workshop_grading_report($data, $reportopts); 1898 return array( 1899 'report' => $report->export_data_for_external(), 1900 'warnings' => array(), 1901 ); 1902 } 1903 } 1904 throw new moodle_exception('nothingfound', 'workshop'); 1905 } 1906 1907 /** 1908 * Returns description of method result value 1909 * 1910 * @return \core_external\external_description 1911 * @since Moodle 3.4 1912 */ 1913 public static function get_grades_report_returns() { 1914 1915 $reviewstructure = new external_single_structure( 1916 array( 1917 'userid' => new external_value(PARAM_INT, 'The id of the user (0 when is configured to do not display names).'), 1918 'assessmentid' => new external_value(PARAM_INT, 'The id of the assessment.'), 1919 'submissionid' => new external_value(PARAM_INT, 'The id of the submission assessed.'), 1920 'grade' => new external_value(PARAM_FLOAT, 'The grade for submission.'), 1921 'gradinggrade' => new external_value(PARAM_FLOAT, 'The grade for assessment.'), 1922 'gradinggradeover' => new external_value(PARAM_FLOAT, 'The aggregated grade overrided.'), 1923 'weight' => new external_value(PARAM_INT, 'The weight of the assessment for aggregation.'), 1924 ) 1925 ); 1926 1927 return new external_single_structure( 1928 array( 1929 'report' => new external_single_structure( 1930 array( 1931 'grades' => new external_multiple_structure( 1932 new external_single_structure( 1933 array( 1934 'userid' => new external_value(PARAM_INT, 'The id of the user being displayed in the report.'), 1935 'submissionid' => new external_value(PARAM_INT, 'Submission id.'), 1936 'submissiontitle' => new external_value(PARAM_RAW, 'Submission title.'), 1937 'submissionmodified' => new external_value(PARAM_INT, 'Timestamp submission was updated.'), 1938 'submissiongrade' => new external_value(PARAM_FLOAT, 'Aggregated grade for the submission.', 1939 VALUE_OPTIONAL), 1940 'gradinggrade' => new external_value(PARAM_FLOAT, 'Computed grade for the assessment.', 1941 VALUE_OPTIONAL), 1942 'submissiongradeover' => new external_value(PARAM_FLOAT, 'Grade for the assessment overrided 1943 by the teacher.', VALUE_OPTIONAL), 1944 'submissiongradeoverby' => new external_value(PARAM_INT, 'The id of the user who overrided 1945 the grade.', VALUE_OPTIONAL), 1946 'submissionpublished' => new external_value(PARAM_INT, 'Whether is a submission published.', 1947 VALUE_OPTIONAL), 1948 'reviewedby' => new external_multiple_structure($reviewstructure, 'The users who reviewed the 1949 user submission.', VALUE_OPTIONAL), 1950 'reviewerof' => new external_multiple_structure($reviewstructure, 'The assessments the user 1951 reviewed.', VALUE_OPTIONAL), 1952 ) 1953 ) 1954 ), 1955 'totalcount' => new external_value(PARAM_INT, 'Number of total submissions.'), 1956 ) 1957 ), 1958 'warnings' => new external_warnings() 1959 ) 1960 ); 1961 } 1962 1963 /** 1964 * Describes the parameters for view_submission. 1965 * 1966 * @return external_function_parameters 1967 * @since Moodle 3.4 1968 */ 1969 public static function view_submission_parameters() { 1970 return new external_function_parameters ( 1971 array( 1972 'submissionid' => new external_value(PARAM_INT, 'Submission id'), 1973 ) 1974 ); 1975 } 1976 1977 /** 1978 * Trigger the submission viewed event. 1979 * 1980 * @param int $submissionid submission id 1981 * @return array of warnings and status result 1982 * @since Moodle 3.4 1983 * @throws moodle_exception 1984 */ 1985 public static function view_submission($submissionid) { 1986 global $DB; 1987 1988 $params = self::validate_parameters(self::view_submission_parameters(), array('submissionid' => $submissionid)); 1989 $warnings = array(); 1990 1991 // Get and validate the submission and workshop. 1992 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST); 1993 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid); 1994 1995 self::validate_submission($submission, $workshop); 1996 1997 $workshop->set_submission_viewed($submission); 1998 1999 $result = array( 2000 'status' => true, 2001 'warnings' => $warnings, 2002 ); 2003 return $result; 2004 } 2005 2006 /** 2007 * Describes the view_submission return value. 2008 * 2009 * @return external_single_structure 2010 * @since Moodle 3.4 2011 */ 2012 public static function view_submission_returns() { 2013 return new external_single_structure( 2014 array( 2015 'status' => new external_value(PARAM_BOOL, 'status: true if success'), 2016 'warnings' => new external_warnings(), 2017 ) 2018 ); 2019 } 2020 2021 /** 2022 * Returns the description of the external function parameters. 2023 * 2024 * @return external_function_parameters 2025 * @since Moodle 3.4 2026 */ 2027 public static function evaluate_submission_parameters() { 2028 return new external_function_parameters( 2029 array( 2030 'submissionid' => new external_value(PARAM_INT, 'submission id.'), 2031 'feedbacktext' => new external_value(PARAM_RAW, 'The feedback for the author.', VALUE_DEFAULT, ''), 2032 'feedbackformat' => new external_value(PARAM_INT, 'The feedback format for text.', VALUE_DEFAULT, FORMAT_MOODLE), 2033 'published' => new external_value(PARAM_BOOL, 'Publish the submission for others?.', VALUE_DEFAULT, false), 2034 'gradeover' => new external_value(PARAM_ALPHANUMEXT, 'The new submission grade.', VALUE_DEFAULT, ''), 2035 ) 2036 ); 2037 } 2038 2039 2040 /** 2041 * Evaluates a submission (used by teachers for provide feedback or override the submission grade). 2042 * 2043 * @param int $submissionid the submission id 2044 * @param str $feedbacktext the feedback for the author 2045 * @param int $feedbackformat the feedback format for the reviewer text 2046 * @param bool $published whether to publish the submission for other users 2047 * @param mixed $gradeover the new submission grade (empty for no overriding the grade) 2048 * @return array containing the status and warnings. 2049 * @since Moodle 3.4 2050 * @throws moodle_exception 2051 */ 2052 public static function evaluate_submission($submissionid, $feedbacktext = '', $feedbackformat = FORMAT_MOODLE, $published = 1, 2053 $gradeover = '') { 2054 global $DB; 2055 2056 $params = self::validate_parameters( 2057 self::evaluate_submission_parameters(), 2058 array( 2059 'submissionid' => $submissionid, 2060 'feedbacktext' => $feedbacktext, 2061 'feedbackformat' => $feedbackformat, 2062 'published' => $published, 2063 'gradeover' => $gradeover, 2064 ) 2065 ); 2066 $warnings = array(); 2067 2068 // Get and validate the submission, submission and workshop. 2069 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST); 2070 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid); 2071 2072 // Check we can evaluate the submission. 2073 self::validate_submission($submission, $workshop); 2074 $canpublish = has_capability('mod/workshop:publishsubmissions', $context); 2075 $canoverride = ($workshop->phase == workshop::PHASE_EVALUATION && 2076 has_capability('mod/workshop:overridegrades', $context)); 2077 2078 if (!$canpublish && !$canoverride) { 2079 throw new moodle_exception('nopermissions', 'error', '', 'evaluate submission'); 2080 } 2081 2082 // Process data. 2083 $data = new stdClass; 2084 $data->id = $submission->id; 2085 $data->feedbackauthor_editor = array( 2086 'text' => $params['feedbacktext'], 2087 'format' => $params['feedbackformat'], 2088 ); 2089 $data->published = $params['published']; 2090 $data->gradeover = $params['gradeover']; 2091 2092 $options = array( 2093 'editable' => true, 2094 'editablepublished' => $canpublish, 2095 'overridablegrade' => $canoverride 2096 ); 2097 $feedbackform = $workshop->get_feedbackauthor_form(null, $submission, $options); 2098 2099 $errors = $feedbackform->validation((array) $data, array()); 2100 // Extra checks for the new grade (if set). 2101 if (is_numeric($data->gradeover) && $data->gradeover > $workshop->grade) { 2102 $errors['gradeover'] = 'The new grade cannot be higher than the maximum grade for submission.'; 2103 } 2104 2105 // We can get several errors, return them in warnings. 2106 if (!empty($errors)) { 2107 $status = false; 2108 foreach ($errors as $itemname => $message) { 2109 $warnings[] = array( 2110 'item' => $itemname, 2111 'itemid' => 0, 2112 'warningcode' => 'fielderror', 2113 'message' => s($message) 2114 ); 2115 } 2116 } else { 2117 $workshop->evaluate_submission($submission, $data, $canpublish, $canoverride); 2118 $status = true; 2119 } 2120 2121 return array( 2122 'status' => $status, 2123 'warnings' => $warnings, 2124 ); 2125 } 2126 2127 /** 2128 * Returns description of method result value 2129 * 2130 * @return \core_external\external_description 2131 * @since Moodle 3.4 2132 */ 2133 public static function evaluate_submission_returns() { 2134 return new external_single_structure( 2135 array( 2136 'status' => new external_value(PARAM_BOOL, 'status: true if the submission was evaluated, false otherwise.'), 2137 'warnings' => new external_warnings() 2138 ) 2139 ); 2140 } 2141 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body