Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 401 and 402] [Versions 401 and 403]

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