Search moodle.org's
Developer Documentation

   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   * External assign API
  19   *
  20   * @package    mod_assign
  21   * @since      Moodle 2.4
  22   * @copyright  2012 Paul Charsley
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die;
  27  
  28  require_once("$CFG->libdir/externallib.php");
  29  
  30  /**
  31   * Assign functions
  32   * @copyright 2012 Paul Charsley
  33   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   */
  35  class mod_assign_external extends external_api {
  36  
  37      /**
  38       * Generate a warning in a standard structure for a known failure.
  39       *
  40       * @param int $assignmentid - The assignment
  41       * @param string $warningcode - The key for the warning message
  42       * @param string $detail - A description of the error
  43       * @return array - Warning structure containing item, itemid, warningcode, message
  44       */
  45      private static function generate_warning($assignmentid, $warningcode, $detail) {
  46          $warningmessages = array(
  47              'couldnotlock'=>'Could not lock the submission for this user.',
  48              'couldnotunlock'=>'Could not unlock the submission for this user.',
  49              'couldnotsubmitforgrading'=>'Could not submit assignment for grading.',
  50              'couldnotrevealidentities'=>'Could not reveal identities.',
  51              'couldnotgrantextensions'=>'Could not grant submission date extensions.',
  52              'couldnotrevert'=>'Could not revert submission to draft.',
  53              'invalidparameters'=>'Invalid parameters.',
  54              'couldnotsavesubmission'=>'Could not save submission.',
  55              'couldnotsavegrade'=>'Could not save grade.'
  56          );
  57  
  58          $message = $warningmessages[$warningcode];
  59          if (empty($message)) {
  60              $message = 'Unknown warning type.';
  61          }
  62  
  63          return array('item'=>$detail,
  64                       'itemid'=>$assignmentid,
  65                       'warningcode'=>$warningcode,
  66                       'message'=>$message);
  67      }
  68  
  69      /**
  70       * Describes the parameters for get_grades
  71       * @return external_external_function_parameters
  72       * @since  Moodle 2.4
  73       */
  74      public static function get_grades_parameters() {
  75          return new external_function_parameters(
  76              array(
  77                  'assignmentids' => new external_multiple_structure(
  78                      new external_value(PARAM_INT, 'assignment id'),
  79                      '1 or more assignment ids',
  80                      VALUE_REQUIRED),
  81                  'since' => new external_value(PARAM_INT,
  82                            'timestamp, only return records where timemodified >= since',
  83                            VALUE_DEFAULT, 0)
  84              )
  85          );
  86      }
  87  
  88      /**
  89       * Returns grade information from assign_grades for the requested assignment ids
  90       * @param int[] $assignmentids
  91       * @param int $since only return records with timemodified >= since
  92       * @return array of grade records for each requested assignment
  93       * @since  Moodle 2.4
  94       */
  95      public static function get_grades($assignmentids, $since = 0) {
  96          global $DB;
  97          $params = self::validate_parameters(self::get_grades_parameters(),
  98                          array('assignmentids' => $assignmentids,
  99                                'since' => $since));
 100  
 101          $assignments = array();
 102          $warnings = array();
 103          $requestedassignmentids = $params['assignmentids'];
 104  
 105          // Check the user is allowed to get the grades for the assignments requested.
 106          $placeholders = array();
 107          list($sqlassignmentids, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED);
 108          $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module ".
 109                 "WHERE md.name = :modname AND cm.instance ".$sqlassignmentids;
 110          $placeholders['modname'] = 'assign';
 111          $cms = $DB->get_records_sql($sql, $placeholders);
 112          foreach ($cms as $cm) {
 113              try {
 114                  $context = context_module::instance($cm->id);
 115                  self::validate_context($context);
 116                  require_capability('mod/assign:grade', $context);
 117              } catch (Exception $e) {
 118                  $requestedassignmentids = array_diff($requestedassignmentids, array($cm->instance));
 119                  $warning = array();
 120                  $warning['item'] = 'assignment';
 121                  $warning['itemid'] = $cm->instance;
 122                  $warning['warningcode'] = '1';
 123                  $warning['message'] = 'No access rights in module context';
 124                  $warnings[] = $warning;
 125              }
 126          }
 127  
 128          // Create the query and populate an array of grade records from the recordset results.
 129          if (count ($requestedassignmentids) > 0) {
 130              $placeholders = array();
 131              list($inorequalsql, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED);
 132  
 133              $sql = "SELECT ag.id,
 134                             ag.assignment,
 135                             ag.userid,
 136                             ag.timecreated,
 137                             ag.timemodified,
 138                             ag.grader,
 139                             ag.grade,
 140                             ag.attemptnumber
 141                        FROM {assign_grades} ag, {assign_submission} s
 142                       WHERE s.assignment $inorequalsql
 143                         AND s.userid = ag.userid
 144                         AND s.latest = 1
 145                         AND s.attemptnumber = ag.attemptnumber
 146                         AND ag.timemodified  >= :since
 147                         AND ag.assignment = s.assignment
 148                    ORDER BY ag.assignment, ag.id";
 149  
 150              $placeholders['since'] = $params['since'];
 151              $rs = $DB->get_recordset_sql($sql, $placeholders);
 152              $currentassignmentid = null;
 153              $assignment = null;
 154              foreach ($rs as $rd) {
 155                  $grade = array();
 156                  $grade['id'] = $rd->id;
 157                  $grade['userid'] = $rd->userid;
 158                  $grade['timecreated'] = $rd->timecreated;
 159                  $grade['timemodified'] = $rd->timemodified;
 160                  $grade['grader'] = $rd->grader;
 161                  $grade['attemptnumber'] = $rd->attemptnumber;
 162                  $grade['grade'] = (string)$rd->grade;
 163  
 164                  if (is_null($currentassignmentid) || ($rd->assignment != $currentassignmentid )) {
 165                      if (!is_null($assignment)) {
 166                          $assignments[] = $assignment;
 167                      }
 168                      $assignment = array();
 169                      $assignment['assignmentid'] = $rd->assignment;
 170                      $assignment['grades'] = array();
 171                      $requestedassignmentids = array_diff($requestedassignmentids, array($rd->assignment));
 172                  }
 173                  $assignment['grades'][] = $grade;
 174  
 175                  $currentassignmentid = $rd->assignment;
 176              }
 177              if (!is_null($assignment)) {
 178                  $assignments[] = $assignment;
 179              }
 180              $rs->close();
 181          }
 182          foreach ($requestedassignmentids as $assignmentid) {
 183              $warning = array();
 184              $warning['item'] = 'assignment';
 185              $warning['itemid'] = $assignmentid;
 186              $warning['warningcode'] = '3';
 187              $warning['message'] = 'No grades found';
 188              $warnings[] = $warning;
 189          }
 190  
 191          $result = array();
 192          $result['assignments'] = $assignments;
 193          $result['warnings'] = $warnings;
 194          return $result;
 195      }
 196  
 197      /**
 198       * Creates an assign_grades external_single_structure
 199       * @return external_single_structure
 200       * @since  Moodle 2.4
 201       */
 202      private static function assign_grades() {
 203          return new external_single_structure(
 204              array (
 205                  'assignmentid'    => new external_value(PARAM_INT, 'assignment id'),
 206                  'grades'   => new external_multiple_structure(new external_single_structure(
 207                          array(
 208                              'id'            => new external_value(PARAM_INT, 'grade id'),
 209                              'userid'        => new external_value(PARAM_INT, 'student id'),
 210                              'attemptnumber' => new external_value(PARAM_INT, 'attempt number'),
 211                              'timecreated'   => new external_value(PARAM_INT, 'grade creation time'),
 212                              'timemodified'  => new external_value(PARAM_INT, 'grade last modified time'),
 213                              'grader'        => new external_value(PARAM_INT, 'grader'),
 214                              'grade'         => new external_value(PARAM_TEXT, 'grade')
 215                          )
 216                      )
 217                  )
 218              )
 219          );
 220      }
 221  
 222      /**
 223       * Describes the get_grades return value
 224       * @return external_single_structure
 225       * @since  Moodle 2.4
 226       */
 227      public static function get_grades_returns() {
 228          return new external_single_structure(
 229              array(
 230                  'assignments' => new external_multiple_structure(self::assign_grades(), 'list of assignment grade information'),
 231                  'warnings'      => new external_warnings('item is always \'assignment\'',
 232                      'when errorcode is 3 then itemid is an assignment id. When errorcode is 1, itemid is a course module id',
 233                      'errorcode can be 3 (no grades found) or 1 (no permission to get grades)')
 234              )
 235          );
 236      }
 237  
 238      /**
 239       * Returns description of method parameters
 240       *
 241       * @return external_function_parameters
 242       * @since  Moodle 2.4
 243       */
 244      public static function get_assignments_parameters() {
 245          return new external_function_parameters(
 246              array(
 247                  'courseids' => new external_multiple_structure(
 248                      new external_value(PARAM_INT, 'course id'),
 249                      '0 or more course ids',
 250                      VALUE_DEFAULT, array()
 251                  ),
 252                  'capabilities'  => new external_multiple_structure(
 253                      new external_value(PARAM_CAPABILITY, 'capability'),
 254                      'list of capabilities used to filter courses',
 255                      VALUE_DEFAULT, array()
 256                  )
 257              )
 258          );
 259      }
 260  
 261      /**
 262       * Returns an array of courses the user is enrolled in, and for each course all of the assignments that the user can
 263       * view within that course.
 264       *
 265       * @param array $courseids An optional array of course ids. If provided only assignments within the given course
 266       * will be returned. If the user is not enrolled in a given course a warning will be generated and returned.
 267       * @param array $capabilities An array of additional capability checks you wish to be made on the course context.
 268       * @return An array of courses and warnings.
 269       * @since  Moodle 2.4
 270       */
 271      public static function get_assignments($courseids = array(), $capabilities = array()) {
 272          global $USER, $DB;
 273  
 274          $params = self::validate_parameters(
 275              self::get_assignments_parameters(),
 276              array('courseids' => $courseids, 'capabilities' => $capabilities)
 277          );
 278  
 279          $warnings = array();
 280          $fields = 'sortorder,shortname,fullname,timemodified';
 281          $courses = enrol_get_users_courses($USER->id, true, $fields);
 282          // Used to test for ids that have been requested but can't be returned.
 283          if (count($params['courseids']) > 0) {
 284              foreach ($params['courseids'] as $courseid) {
 285                  if (!in_array($courseid, array_keys($courses))) {
 286                      unset($courses[$courseid]);
 287                      $warnings[] = array(
 288                          'item' => 'course',
 289                          'itemid' => $courseid,
 290                          'warningcode' => '2',
 291                          'message' => 'User is not enrolled or does not have requested capability'
 292                      );
 293                  }
 294              }
 295          }
 296          foreach ($courses as $id => $course) {
 297              if (count($params['courseids']) > 0 && !in_array($id, $params['courseids'])) {
 298                  unset($courses[$id]);
 299              }
 300              $context = context_course::instance($id);
 301              try {
 302                  self::validate_context($context);
 303              } catch (Exception $e) {
 304                  unset($courses[$id]);
 305                  $warnings[] = array(
 306                      'item' => 'course',
 307                      'itemid' => $id,
 308                      'warningcode' => '1',
 309                      'message' => 'No access rights in course context '.$e->getMessage().$e->getTraceAsString()
 310                  );
 311                  continue;
 312              }
 313              if (count($params['capabilities']) > 0 && !has_all_capabilities($params['capabilities'], $context)) {
 314                  unset($courses[$id]);
 315              }
 316          }
 317          $extrafields='m.id as assignmentid, ' .
 318                       'm.course, ' .
 319                       'm.nosubmissions, ' .
 320                       'm.submissiondrafts, ' .
 321                       'm.sendnotifications, '.
 322                       'm.sendlatenotifications, ' .
 323                       'm.sendstudentnotifications, ' .
 324                       'm.duedate, ' .
 325                       'm.allowsubmissionsfromdate, '.
 326                       'm.grade, ' .
 327                       'm.timemodified, '.
 328                       'm.completionsubmit, ' .
 329                       'm.cutoffdate, ' .
 330                       'm.teamsubmission, ' .
 331                       'm.requireallteammemberssubmit, '.
 332                       'm.teamsubmissiongroupingid, ' .
 333                       'm.blindmarking, ' .
 334                       'm.revealidentities, ' .
 335                       'm.attemptreopenmethod, '.
 336                       'm.maxattempts, ' .
 337                       'm.markingworkflow, ' .
 338                       'm.markingallocation, ' .
 339                       'm.requiresubmissionstatement';
 340          $coursearray = array();
 341          foreach ($courses as $id => $course) {
 342              $assignmentarray = array();
 343              // Get a list of assignments for the course.
 344              if ($modules = get_coursemodules_in_course('assign', $courses[$id]->id, $extrafields)) {
 345                  foreach ($modules as $module) {
 346                      $context = context_module::instance($module->id);
 347                      try {
 348                          self::validate_context($context);
 349                          require_capability('mod/assign:view', $context);
 350                      } catch (Exception $e) {
 351                          $warnings[] = array(
 352                              'item' => 'module',
 353                              'itemid' => $module->id,
 354                              'warningcode' => '1',
 355                              'message' => 'No access rights in module context'
 356                          );
 357                          continue;
 358                      }
 359                      $configrecords = $DB->get_recordset('assign_plugin_config', array('assignment' => $module->assignmentid));
 360                      $configarray = array();
 361                      foreach ($configrecords as $configrecord) {
 362                          $configarray[] = array(
 363                              'id' => $configrecord->id,
 364                              'assignment' => $configrecord->assignment,
 365                              'plugin' => $configrecord->plugin,
 366                              'subtype' => $configrecord->subtype,
 367                              'name' => $configrecord->name,
 368                              'value' => $configrecord->value
 369                          );
 370                      }
 371                      $configrecords->close();
 372  
 373                      $assignmentarray[]= array(
 374                          'id' => $module->assignmentid,
 375                          'cmid' => $module->id,
 376                          'course' => $module->course,
 377                          'name' => $module->name,
 378                          'nosubmissions' => $module->nosubmissions,
 379                          'submissiondrafts' => $module->submissiondrafts,
 380                          'sendnotifications' => $module->sendnotifications,
 381                          'sendlatenotifications' => $module->sendlatenotifications,
 382                          'sendstudentnotifications' => $module->sendstudentnotifications,
 383                          'duedate' => $module->duedate,
 384                          'allowsubmissionsfromdate' => $module->allowsubmissionsfromdate,
 385                          'grade' => $module->grade,
 386                          'timemodified' => $module->timemodified,
 387                          'completionsubmit' => $module->completionsubmit,
 388                          'cutoffdate' => $module->cutoffdate,
 389                          'teamsubmission' => $module->teamsubmission,
 390                          'requireallteammemberssubmit' => $module->requireallteammemberssubmit,
 391                          'teamsubmissiongroupingid' => $module->teamsubmissiongroupingid,
 392                          'blindmarking' => $module->blindmarking,
 393                          'revealidentities' => $module->revealidentities,
 394                          'attemptreopenmethod' => $module->attemptreopenmethod,
 395                          'maxattempts' => $module->maxattempts,
 396                          'markingworkflow' => $module->markingworkflow,
 397                          'markingallocation' => $module->markingallocation,
 398                          'requiresubmissionstatement' => $module->requiresubmissionstatement,
 399                          'configs' => $configarray
 400                      );
 401                  }
 402              }
 403              $coursearray[]= array(
 404                  'id' => $courses[$id]->id,
 405                  'fullname' => $courses[$id]->fullname,
 406                  'shortname' => $courses[$id]->shortname,
 407                  'timemodified' => $courses[$id]->timemodified,
 408                  'assignments' => $assignmentarray
 409              );
 410          }
 411  
 412          $result = array(
 413              'courses' => $coursearray,
 414              'warnings' => $warnings
 415          );
 416          return $result;
 417      }
 418  
 419      /**
 420       * Creates an assignment external_single_structure
 421       *
 422       * @return external_single_structure
 423       * @since Moodle 2.4
 424       */
 425      private static function get_assignments_assignment_structure() {
 426          return new external_single_structure(
 427              array(
 428                  'id' => new external_value(PARAM_INT, 'assignment id'),
 429                  'cmid' => new external_value(PARAM_INT, 'course module id'),
 430                  'course' => new external_value(PARAM_INT, 'course id'),
 431                  'name' => new external_value(PARAM_TEXT, 'assignment name'),
 432                  'nosubmissions' => new external_value(PARAM_INT, 'no submissions'),
 433                  'submissiondrafts' => new external_value(PARAM_INT, 'submissions drafts'),
 434                  'sendnotifications' => new external_value(PARAM_INT, 'send notifications'),
 435                  'sendlatenotifications' => new external_value(PARAM_INT, 'send notifications'),
 436                  'sendstudentnotifications' => new external_value(PARAM_INT, 'send student notifications (default)'),
 437                  'duedate' => new external_value(PARAM_INT, 'assignment due date'),
 438                  'allowsubmissionsfromdate' => new external_value(PARAM_INT, 'allow submissions from date'),
 439                  'grade' => new external_value(PARAM_INT, 'grade type'),
 440                  'timemodified' => new external_value(PARAM_INT, 'last time assignment was modified'),
 441                  'completionsubmit' => new external_value(PARAM_INT, 'if enabled, set activity as complete following submission'),
 442                  'cutoffdate' => new external_value(PARAM_INT, 'date after which submission is not accepted without an extension'),
 443                  'teamsubmission' => new external_value(PARAM_INT, 'if enabled, students submit as a team'),
 444                  'requireallteammemberssubmit' => new external_value(PARAM_INT, 'if enabled, all team members must submit'),
 445                  'teamsubmissiongroupingid' => new external_value(PARAM_INT, 'the grouping id for the team submission groups'),
 446                  'blindmarking' => new external_value(PARAM_INT, 'if enabled, hide identities until reveal identities actioned'),
 447                  'revealidentities' => new external_value(PARAM_INT, 'show identities for a blind marking assignment'),
 448                  'attemptreopenmethod' => new external_value(PARAM_TEXT, 'method used to control opening new attempts'),
 449                  'maxattempts' => new external_value(PARAM_INT, 'maximum number of attempts allowed'),
 450                  'markingworkflow' => new external_value(PARAM_INT, 'enable marking workflow'),
 451                  'markingallocation' => new external_value(PARAM_INT, 'enable marking allocation'),
 452                  'requiresubmissionstatement' => new external_value(PARAM_INT, 'student must accept submission statement'),
 453                  'configs' => new external_multiple_structure(self::get_assignments_config_structure(), 'configuration settings')
 454              ), 'assignment information object');
 455      }
 456  
 457      /**
 458       * Creates an assign_plugin_config external_single_structure
 459       *
 460       * @return external_single_structure
 461       * @since Moodle 2.4
 462       */
 463      private static function get_assignments_config_structure() {
 464          return new external_single_structure(
 465              array(
 466                  'id' => new external_value(PARAM_INT, 'assign_plugin_config id'),
 467                  'assignment' => new external_value(PARAM_INT, 'assignment id'),
 468                  'plugin' => new external_value(PARAM_TEXT, 'plugin'),
 469                  'subtype' => new external_value(PARAM_TEXT, 'subtype'),
 470                  'name' => new external_value(PARAM_TEXT, 'name'),
 471                  'value' => new external_value(PARAM_TEXT, 'value')
 472              ), 'assignment configuration object'
 473          );
 474      }
 475  
 476      /**
 477       * Creates a course external_single_structure
 478       *
 479       * @return external_single_structure
 480       * @since Moodle 2.4
 481       */
 482      private static function get_assignments_course_structure() {
 483          return new external_single_structure(
 484              array(
 485                  'id' => new external_value(PARAM_INT, 'course id'),
 486                  'fullname' => new external_value(PARAM_TEXT, 'course full name'),
 487                  'shortname' => new external_value(PARAM_TEXT, 'course short name'),
 488                  'timemodified' => new external_value(PARAM_INT, 'last time modified'),
 489                  'assignments' => new external_multiple_structure(self::get_assignments_assignment_structure(), 'assignment info')
 490                ), 'course information object'
 491          );
 492      }
 493  
 494      /**
 495       * Describes the return value for get_assignments
 496       *
 497       * @return external_single_structure
 498       * @since Moodle 2.4
 499       */
 500      public static function get_assignments_returns() {
 501          return new external_single_structure(
 502              array(
 503                  'courses' => new external_multiple_structure(self::get_assignments_course_structure(), 'list of courses'),
 504                  'warnings'  => new external_warnings('item can be \'course\' (errorcode 1 or 2) or \'module\' (errorcode 1)',
 505                      'When item is a course then itemid is a course id. When the item is a module then itemid is a module id',
 506                      'errorcode can be 1 (no access rights) or 2 (not enrolled or no permissions)')
 507              )
 508          );
 509      }
 510  
 511      /**
 512       * Describes the parameters for get_submissions
 513       *
 514       * @return external_external_function_parameters
 515       * @since Moodle 2.5
 516       */
 517      public static function get_submissions_parameters() {
 518          return new external_function_parameters(
 519              array(
 520                  'assignmentids' => new external_multiple_structure(
 521                      new external_value(PARAM_INT, 'assignment id'),
 522                      '1 or more assignment ids',
 523                      VALUE_REQUIRED),
 524                  'status' => new external_value(PARAM_ALPHA, 'status', VALUE_DEFAULT, ''),
 525                  'since' => new external_value(PARAM_INT, 'submitted since', VALUE_DEFAULT, 0),
 526                  'before' => new external_value(PARAM_INT, 'submitted before', VALUE_DEFAULT, 0)
 527              )
 528          );
 529      }
 530  
 531      /**
 532       * Returns submissions for the requested assignment ids
 533       *
 534       * @param int[] $assignmentids
 535       * @param string $status only return submissions with this status
 536       * @param int $since only return submissions with timemodified >= since
 537       * @param int $before only return submissions with timemodified <= before
 538       * @return array of submissions for each requested assignment
 539       * @since Moodle 2.5
 540       */
 541      public static function get_submissions($assignmentids, $status = '', $since = 0, $before = 0) {
 542          global $DB, $CFG;
 543          require_once("$CFG->dirroot/mod/assign/locallib.php");
 544          $params = self::validate_parameters(self::get_submissions_parameters(),
 545                          array('assignmentids' => $assignmentids,
 546                                'status' => $status,
 547                                'since' => $since,
 548                                'before' => $before));
 549  
 550          $warnings = array();
 551          $assignments = array();
 552  
 553          // Check the user is allowed to get the submissions for the assignments requested.
 554          $placeholders = array();
 555          list($inorequalsql, $placeholders) = $DB->get_in_or_equal($params['assignmentids'], SQL_PARAMS_NAMED);
 556          $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module ".
 557                 "WHERE md.name = :modname AND cm.instance ".$inorequalsql;
 558          $placeholders['modname'] = 'assign';
 559          $cms = $DB->get_records_sql($sql, $placeholders);
 560          $assigns = array();
 561          foreach ($cms as $cm) {
 562              try {
 563                  $context = context_module::instance($cm->id);
 564                  self::validate_context($context);
 565                  require_capability('mod/assign:grade', $context);
 566                  $assign = new assign($context, null, null);
 567                  $assigns[] = $assign;
 568              } catch (Exception $e) {
 569                  $warnings[] = array(
 570                      'item' => 'assignment',
 571                      'itemid' => $cm->instance,
 572                      'warningcode' => '1',
 573                      'message' => 'No access rights in module context'
 574                  );
 575              }
 576          }
 577  
 578          foreach ($assigns as $assign) {
 579              $submissions = array();
 580              $submissionplugins = $assign->get_submission_plugins();
 581              $placeholders = array('assignid1' => $assign->get_instance()->id,
 582                                    'assignid2' => $assign->get_instance()->id);
 583  
 584              $submissionmaxattempt = 'SELECT mxs.userid, MAX(mxs.attemptnumber) AS maxattempt
 585                                       FROM {assign_submission} mxs
 586                                       WHERE mxs.assignment = :assignid1 GROUP BY mxs.userid';
 587  
 588              $sql = "SELECT mas.id, mas.assignment,mas.userid,".
 589                     "mas.timecreated,mas.timemodified,mas.status,mas.groupid,mas.attemptnumber ".
 590                     "FROM {assign_submission} mas ".
 591                     "JOIN ( " . $submissionmaxattempt . " ) smx ON mas.userid = smx.userid ".
 592                     "WHERE mas.assignment = :assignid2 AND mas.attemptnumber = smx.maxattempt";
 593  
 594              if (!empty($params['status'])) {
 595                  $placeholders['status'] = $params['status'];
 596                  $sql = $sql." AND mas.status = :status";
 597              }
 598              if (!empty($params['before'])) {
 599                  $placeholders['since'] = $params['since'];
 600                  $placeholders['before'] = $params['before'];
 601                  $sql = $sql." AND mas.timemodified BETWEEN :since AND :before";
 602              } else {
 603                  $placeholders['since'] = $params['since'];
 604                  $sql = $sql." AND mas.timemodified >= :since";
 605              }
 606  
 607              $submissionrecords = $DB->get_records_sql($sql, $placeholders);
 608  
 609              if (!empty($submissionrecords)) {
 610                  $fs = get_file_storage();
 611                  foreach ($submissionrecords as $submissionrecord) {
 612                      $submission = array(
 613                          'id' => $submissionrecord->id,
 614                          'userid' => $submissionrecord->userid,
 615                          'timecreated' => $submissionrecord->timecreated,
 616                          'timemodified' => $submissionrecord->timemodified,
 617                          'status' => $submissionrecord->status,
 618                          'attemptnumber' => $submissionrecord->attemptnumber,
 619                          'groupid' => $submissionrecord->groupid
 620                      );
 621                      foreach ($submissionplugins as $submissionplugin) {
 622                          $plugin = array(
 623                              'name' => $submissionplugin->get_name(),
 624                              'type' => $submissionplugin->get_type()
 625                          );
 626                          // Subtype is 'assignsubmission', type is currently 'file' or 'onlinetext'.
 627                          $component = $submissionplugin->get_subtype().'_'.$submissionplugin->get_type();
 628  
 629                          $fileareas = $submissionplugin->get_file_areas();
 630                          foreach ($fileareas as $filearea => $name) {
 631                              $fileareainfo = array('area' => $filearea);
 632                              $files = $fs->get_area_files(
 633                                  $assign->get_context()->id,
 634                                  $component,
 635                                  $filearea,
 636                                  $submissionrecord->id,
 637                                  "timemodified",
 638                                  false
 639                              );
 640                              foreach ($files as $file) {
 641                                  $filepath = $file->get_filepath().$file->get_filename();
 642                                  $fileurl = file_encode_url($CFG->wwwroot . '/webservice/pluginfile.php', '/' . $assign->get_context()->id .
 643                                      '/' . $component. '/'. $filearea . '/' . $submissionrecord->id . $filepath);
 644                                  $fileinfo = array(
 645                                      'filepath' => $filepath,
 646                                      'fileurl' => $fileurl
 647                                      );
 648                                  $fileareainfo['files'][] = $fileinfo;
 649                              }
 650                              $plugin['fileareas'][] = $fileareainfo;
 651                          }
 652  
 653                          $editorfields = $submissionplugin->get_editor_fields();
 654                          foreach ($editorfields as $name => $description) {
 655                              $editorfieldinfo = array(
 656                                  'name' => $name,
 657                                  'description' => $description,
 658                                  'text' => $submissionplugin->get_editor_text($name, $submissionrecord->id),
 659                                  'format' => $submissionplugin->get_editor_format($name, $submissionrecord->id)
 660                              );
 661                              $plugin['editorfields'][] = $editorfieldinfo;
 662                          }
 663  
 664                          $submission['plugins'][] = $plugin;
 665                      }
 666                      $submissions[] = $submission;
 667                  }
 668              } else {
 669                  $warnings[] = array(
 670                      'item' => 'module',
 671                      'itemid' => $assign->get_instance()->id,
 672                      'warningcode' => '3',
 673                      'message' => 'No submissions found'
 674                  );
 675              }
 676  
 677              $assignments[] = array(
 678                  'assignmentid' => $assign->get_instance()->id,
 679                  'submissions' => $submissions
 680              );
 681  
 682          }
 683  
 684          $result = array(
 685              'assignments' => $assignments,
 686              'warnings' => $warnings
 687          );
 688          return $result;
 689      }
 690  
 691      /**
 692       * Creates an assign_submissions external_single_structure
 693       *
 694       * @return external_single_structure
 695       * @since Moodle 2.5
 696       */
 697      private static function get_submissions_structure() {
 698          return new external_single_structure(
 699              array (
 700                  'assignmentid' => new external_value(PARAM_INT, 'assignment id'),
 701                  'submissions' => new external_multiple_structure(
 702                      new external_single_structure(
 703                          array(
 704                              'id' => new external_value(PARAM_INT, 'submission id'),
 705                              'userid' => new external_value(PARAM_INT, 'student id'),
 706                              'attemptnumber' => new external_value(PARAM_INT, 'attempt number'),
 707                              'timecreated' => new external_value(PARAM_INT, 'submission creation time'),
 708                              'timemodified' => new external_value(PARAM_INT, 'submission last modified time'),
 709                              'status' => new external_value(PARAM_TEXT, 'submission status'),
 710                              'groupid' => new external_value(PARAM_INT, 'group id'),
 711                              'plugins' => new external_multiple_structure(
 712                                  new external_single_structure(
 713                                      array(
 714                                          'type' => new external_value(PARAM_TEXT, 'submission plugin type'),
 715                                          'name' => new external_value(PARAM_TEXT, 'submission plugin name'),
 716                                          'fileareas' => new external_multiple_structure(
 717                                              new external_single_structure(
 718                                                  array (
 719                                                      'area' => new external_value (PARAM_TEXT, 'file area'),
 720                                                      'files' => new external_multiple_structure(
 721                                                          new external_single_structure(
 722                                                              array (
 723                                                                  'filepath' => new external_value (PARAM_TEXT, 'file path'),
 724                                                                  'fileurl' => new external_value (PARAM_URL, 'file download url',
 725                                                                      VALUE_OPTIONAL)
 726                                                              )
 727                                                          ), 'files', VALUE_OPTIONAL
 728                                                      )
 729                                                  )
 730                                              ), 'fileareas', VALUE_OPTIONAL
 731                                          ),
 732                                          'editorfields' => new external_multiple_structure(
 733                                              new external_single_structure(
 734                                                  array(
 735                                                      'name' => new external_value(PARAM_TEXT, 'field name'),
 736                                                      'description' => new external_value(PARAM_TEXT, 'field description'),
 737                                                      'text' => new external_value (PARAM_RAW, 'field value'),
 738                                                      'format' => new external_format_value ('text')
 739                                                  )
 740                                              )
 741                                              , 'editorfields', VALUE_OPTIONAL
 742                                          )
 743                                      )
 744                                  )
 745                                  , 'plugins', VALUE_OPTIONAL
 746                              )
 747                          )
 748                      )
 749                  )
 750              )
 751          );
 752      }
 753  
 754      /**
 755       * Describes the get_submissions return value
 756       *
 757       * @return external_single_structure
 758       * @since Moodle 2.5
 759       */
 760      public static function get_submissions_returns() {
 761          return new external_single_structure(
 762              array(
 763                  'assignments' => new external_multiple_structure(self::get_submissions_structure(), 'assignment submissions'),
 764                  'warnings' => new external_warnings()
 765              )
 766          );
 767      }
 768  
 769      /**
 770       * Describes the parameters for set_user_flags
 771       * @return external_function_parameters
 772       * @since  Moodle 2.6
 773       */
 774      public static function set_user_flags_parameters() {
 775          return new external_function_parameters(
 776              array(
 777                  'assignmentid'    => new external_value(PARAM_INT, 'assignment id'),
 778                  'userflags' => new external_multiple_structure(
 779                      new external_single_structure(
 780                          array(
 781                              'userid'           => new external_value(PARAM_INT, 'student id'),
 782                              'locked'           => new external_value(PARAM_INT, 'locked', VALUE_OPTIONAL),
 783                              'mailed'           => new external_value(PARAM_INT, 'mailed', VALUE_OPTIONAL),
 784                              'extensionduedate' => new external_value(PARAM_INT, 'extension due date', VALUE_OPTIONAL),
 785                              'workflowstate'    => new external_value(PARAM_TEXT, 'marking workflow state', VALUE_OPTIONAL),
 786                              'allocatedmarker'  => new external_value(PARAM_INT, 'allocated marker', VALUE_OPTIONAL)
 787                          )
 788                      )
 789                  )
 790              )
 791          );
 792      }
 793  
 794      /**
 795       * Create or update user_flags records
 796       *
 797       * @param int $assignmentid the assignment for which the userflags are created or updated
 798       * @param array $userflags  An array of userflags to create or update
 799       * @return array containing success or failure information for each record
 800       * @since Moodle 2.6
 801       */
 802      public static function set_user_flags($assignmentid, $userflags = array()) {
 803          global $CFG, $DB;
 804          require_once($CFG->dirroot . "/mod/assign/locallib.php");
 805  
 806          $params = self::validate_parameters(self::set_user_flags_parameters(),
 807                                              array('assignmentid' => $assignmentid,
 808                                                    'userflags' => $userflags));
 809  
 810          // Load assignment if it exists and if the user has the capability.
 811          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
 812          $context = context_module::instance($cm->id);
 813          self::validate_context($context);
 814          require_capability('mod/assign:grade', $context);
 815          $assign = new assign($context, null, null);
 816  
 817          $results = array();
 818          foreach ($params['userflags'] as $userflag) {
 819              $success = true;
 820              $result = array();
 821  
 822              $record = $assign->get_user_flags($userflag['userid'], false);
 823              if ($record) {
 824                  if (isset($userflag['locked'])) {
 825                      $record->locked = $userflag['locked'];
 826                  }
 827                  if (isset($userflag['mailed'])) {
 828                      $record->mailed = $userflag['mailed'];
 829                  }
 830                  if (isset($userflag['extensionduedate'])) {
 831                      $record->extensionduedate = $userflag['extensionduedate'];
 832                  }
 833                  if (isset($userflag['workflowstate'])) {
 834                      $record->workflowstate = $userflag['workflowstate'];
 835                  }
 836                  if (isset($userflag['allocatedmarker'])) {
 837                      $record->allocatedmarker = $userflag['allocatedmarker'];
 838                  }
 839                  if ($assign->update_user_flags($record)) {
 840                      $result['id'] = $record->id;
 841                      $result['userid'] = $userflag['userid'];
 842                  } else {
 843                      $result['id'] = $record->id;
 844                      $result['userid'] = $userflag['userid'];
 845                      $result['errormessage'] = 'Record created but values could not be set';
 846                  }
 847              } else {
 848                  $record = $assign->get_user_flags($userflag['userid'], true);
 849                  $setfields = isset($userflag['locked'])
 850                               || isset($userflag['mailed'])
 851                               || isset($userflag['extensionduedate'])
 852                               || isset($userflag['workflowstate'])
 853                               || isset($userflag['allocatedmarker']);
 854                  if ($record) {
 855                      if ($setfields) {
 856                          if (isset($userflag['locked'])) {
 857                              $record->locked = $userflag['locked'];
 858                          }
 859                          if (isset($userflag['mailed'])) {
 860                              $record->mailed = $userflag['mailed'];
 861                          }
 862                          if (isset($userflag['extensionduedate'])) {
 863                              $record->extensionduedate = $userflag['extensionduedate'];
 864                          }
 865                          if (isset($userflag['workflowstate'])) {
 866                              $record->workflowstate = $userflag['workflowstate'];
 867                          }
 868                          if (isset($userflag['allocatedmarker'])) {
 869                              $record->allocatedmarker = $userflag['allocatedmarker'];
 870                          }
 871                          if ($assign->update_user_flags($record)) {
 872                              $result['id'] = $record->id;
 873                              $result['userid'] = $userflag['userid'];
 874                          } else {
 875                              $result['id'] = $record->id;
 876                              $result['userid'] = $userflag['userid'];
 877                              $result['errormessage'] = 'Record created but values could not be set';
 878                          }
 879                      } else {
 880                          $result['id'] = $record->id;
 881                          $result['userid'] = $userflag['userid'];
 882                      }
 883                  } else {
 884                      $result['id'] = -1;
 885                      $result['userid'] = $userflag['userid'];
 886                      $result['errormessage'] = 'Record could not be created';
 887                  }
 888              }
 889  
 890              $results[] = $result;
 891          }
 892          return $results;
 893      }
 894  
 895      /**
 896       * Describes the set_user_flags return value
 897       * @return external_multiple_structure
 898       * @since  Moodle 2.6
 899       */
 900      public static function set_user_flags_returns() {
 901          return new external_multiple_structure(
 902              new external_single_structure(
 903                  array(
 904                      'id' => new external_value(PARAM_INT, 'id of record if successful, -1 for failure'),
 905                      'userid' => new external_value(PARAM_INT, 'userid of record'),
 906                      'errormessage' => new external_value(PARAM_TEXT, 'Failure error message', VALUE_OPTIONAL)
 907                  )
 908              )
 909          );
 910      }
 911  
 912      /**
 913       * Describes the parameters for get_user_flags
 914       * @return external_function_parameters
 915       * @since  Moodle 2.6
 916       */
 917      public static function get_user_flags_parameters() {
 918          return new external_function_parameters(
 919              array(
 920                  'assignmentids' => new external_multiple_structure(
 921                      new external_value(PARAM_INT, 'assignment id'),
 922                      '1 or more assignment ids',
 923                      VALUE_REQUIRED)
 924              )
 925          );
 926      }
 927  
 928      /**
 929       * Returns user flag information from assign_user_flags for the requested assignment ids
 930       * @param int[] $assignmentids
 931       * @return array of user flag records for each requested assignment
 932       * @since  Moodle 2.6
 933       */
 934      public static function get_user_flags($assignmentids) {
 935          global $DB;
 936          $params = self::validate_parameters(self::get_user_flags_parameters(),
 937                          array('assignmentids' => $assignmentids));
 938  
 939          $assignments = array();
 940          $warnings = array();
 941          $requestedassignmentids = $params['assignmentids'];
 942  
 943          // Check the user is allowed to get the user flags for the assignments requested.
 944          $placeholders = array();
 945          list($sqlassignmentids, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED);
 946          $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module ".
 947                 "WHERE md.name = :modname AND cm.instance ".$sqlassignmentids;
 948          $placeholders['modname'] = 'assign';
 949          $cms = $DB->get_records_sql($sql, $placeholders);
 950          foreach ($cms as $cm) {
 951              try {
 952                  $context = context_module::instance($cm->id);
 953                  self::validate_context($context);
 954                  require_capability('mod/assign:grade', $context);
 955              } catch (Exception $e) {
 956                  $requestedassignmentids = array_diff($requestedassignmentids, array($cm->instance));
 957                  $warning = array();
 958                  $warning['item'] = 'assignment';
 959                  $warning['itemid'] = $cm->instance;
 960                  $warning['warningcode'] = '1';
 961                  $warning['message'] = 'No access rights in module context';
 962                  $warnings[] = $warning;
 963              }
 964          }
 965  
 966          // Create the query and populate an array of assign_user_flags records from the recordset results.
 967          if (count ($requestedassignmentids) > 0) {
 968              $placeholders = array();
 969              list($inorequalsql, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED);
 970  
 971              $sql = "SELECT auf.id,auf.assignment,auf.userid,auf.locked,auf.mailed,".
 972                     "auf.extensionduedate,auf.workflowstate,auf.allocatedmarker ".
 973                     "FROM {assign_user_flags} auf ".
 974                     "WHERE auf.assignment ".$inorequalsql.
 975                     " ORDER BY auf.assignment, auf.id";
 976  
 977              $rs = $DB->get_recordset_sql($sql, $placeholders);
 978              $currentassignmentid = null;
 979              $assignment = null;
 980              foreach ($rs as $rd) {
 981                  $userflag = array();
 982                  $userflag['id'] = $rd->id;
 983                  $userflag['userid'] = $rd->userid;
 984                  $userflag['locked'] = $rd->locked;
 985                  $userflag['mailed'] = $rd->mailed;
 986                  $userflag['extensionduedate'] = $rd->extensionduedate;
 987                  $userflag['workflowstate'] = $rd->workflowstate;
 988                  $userflag['allocatedmarker'] = $rd->allocatedmarker;
 989  
 990                  if (is_null($currentassignmentid) || ($rd->assignment != $currentassignmentid )) {
 991                      if (!is_null($assignment)) {
 992                          $assignments[] = $assignment;
 993                      }
 994                      $assignment = array();
 995                      $assignment['assignmentid'] = $rd->assignment;
 996                      $assignment['userflags'] = array();
 997                      $requestedassignmentids = array_diff($requestedassignmentids, array($rd->assignment));
 998                  }
 999                  $assignment['userflags'][] = $userflag;
1000  
1001                  $currentassignmentid = $rd->assignment;
1002              }
1003              if (!is_null($assignment)) {
1004                  $assignments[] = $assignment;
1005              }
1006              $rs->close();
1007  
1008          }
1009  
1010          foreach ($requestedassignmentids as $assignmentid) {
1011              $warning = array();
1012              $warning['item'] = 'assignment';
1013              $warning['itemid'] = $assignmentid;
1014              $warning['warningcode'] = '3';
1015              $warning['message'] = 'No user flags found';
1016              $warnings[] = $warning;
1017          }
1018  
1019          $result = array();
1020          $result['assignments'] = $assignments;
1021          $result['warnings'] = $warnings;
1022          return $result;
1023      }
1024  
1025      /**
1026       * Creates an assign_user_flags external_single_structure
1027       * @return external_single_structure
1028       * @since  Moodle 2.6
1029       */
1030      private static function assign_user_flags() {
1031          return new external_single_structure(
1032              array (
1033                  'assignmentid'    => new external_value(PARAM_INT, 'assignment id'),
1034                  'userflags'   => new external_multiple_structure(new external_single_structure(
1035                          array(
1036                              'id'               => new external_value(PARAM_INT, 'user flag id'),
1037                              'userid'           => new external_value(PARAM_INT, 'student id'),
1038                              'locked'           => new external_value(PARAM_INT, 'locked'),
1039                              'mailed'           => new external_value(PARAM_INT, 'mailed'),
1040                              'extensionduedate' => new external_value(PARAM_INT, 'extension due date'),
1041                              'workflowstate'    => new external_value(PARAM_TEXT, 'marking workflow state', VALUE_OPTIONAL),
1042                              'allocatedmarker'  => new external_value(PARAM_INT, 'allocated marker')
1043                          )
1044                      )
1045                  )
1046              )
1047          );
1048      }
1049  
1050      /**
1051       * Describes the get_user_flags return value
1052       * @return external_single_structure
1053       * @since  Moodle 2.6
1054       */
1055      public static function get_user_flags_returns() {
1056          return new external_single_structure(
1057              array(
1058                  'assignments' => new external_multiple_structure(self::assign_user_flags(), 'list of assign user flag information'),
1059                  'warnings'      => new external_warnings('item is always \'assignment\'',
1060                      'when errorcode is 3 then itemid is an assignment id. When errorcode is 1, itemid is a course module id',
1061                      'errorcode can be 3 (no user flags found) or 1 (no permission to get user flags)')
1062              )
1063          );
1064      }
1065  
1066      /**
1067       * Describes the parameters for get_user_mappings
1068       * @return external_function_parameters
1069       * @since  Moodle 2.6
1070       */
1071      public static function get_user_mappings_parameters() {
1072          return new external_function_parameters(
1073              array(
1074                  'assignmentids' => new external_multiple_structure(
1075                      new external_value(PARAM_INT, 'assignment id'),
1076                      '1 or more assignment ids',
1077                      VALUE_REQUIRED)
1078              )
1079          );
1080      }
1081  
1082      /**
1083       * Returns user mapping information from assign_user_mapping for the requested assignment ids
1084       * @param int[] $assignmentids
1085       * @return array of user mapping records for each requested assignment
1086       * @since  Moodle 2.6
1087       */
1088      public static function get_user_mappings($assignmentids) {
1089          global $DB;
1090          $params = self::validate_parameters(self::get_user_mappings_parameters(),
1091                          array('assignmentids' => $assignmentids));
1092  
1093          $assignments = array();
1094          $warnings = array();
1095          $requestedassignmentids = $params['assignmentids'];
1096  
1097          // Check the user is allowed to get the mappings for the assignments requested.
1098          $placeholders = array();
1099          list($sqlassignmentids, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED);
1100          $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module ".
1101                 "WHERE md.name = :modname AND cm.instance ".$sqlassignmentids;
1102          $placeholders['modname'] = 'assign';
1103          $cms = $DB->get_records_sql($sql, $placeholders);
1104          foreach ($cms as $cm) {
1105              try {
1106                  $context = context_module::instance($cm->id);
1107                  self::validate_context($context);
1108                  require_capability('mod/assign:revealidentities', $context);
1109              } catch (Exception $e) {
1110                  $requestedassignmentids = array_diff($requestedassignmentids, array($cm->instance));
1111                  $warning = array();
1112                  $warning['item'] = 'assignment';
1113                  $warning['itemid'] = $cm->instance;
1114                  $warning['warningcode'] = '1';
1115                  $warning['message'] = 'No access rights in module context';
1116                  $warnings[] = $warning;
1117              }
1118          }
1119  
1120          // Create the query and populate an array of assign_user_mapping records from the recordset results.
1121          if (count ($requestedassignmentids) > 0) {
1122              $placeholders = array();
1123              list($inorequalsql, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED);
1124  
1125              $sql = "SELECT aum.id,aum.assignment,aum.userid ".
1126                     "FROM {assign_user_mapping} aum ".
1127                     "WHERE aum.assignment ".$inorequalsql.
1128                     " ORDER BY aum.assignment, aum.id";
1129  
1130              $rs = $DB->get_recordset_sql($sql, $placeholders);
1131              $currentassignmentid = null;
1132              $assignment = null;
1133              foreach ($rs as $rd) {
1134                  $mapping = array();
1135                  $mapping['id'] = $rd->id;
1136                  $mapping['userid'] = $rd->userid;
1137  
1138                  if (is_null($currentassignmentid) || ($rd->assignment != $currentassignmentid )) {
1139                      if (!is_null($assignment)) {
1140                          $assignments[] = $assignment;
1141                      }
1142                      $assignment = array();
1143                      $assignment['assignmentid'] = $rd->assignment;
1144                      $assignment['mappings'] = array();
1145                      $requestedassignmentids = array_diff($requestedassignmentids, array($rd->assignment));
1146                  }
1147                  $assignment['mappings'][] = $mapping;
1148  
1149                  $currentassignmentid = $rd->assignment;
1150              }
1151              if (!is_null($assignment)) {
1152                  $assignments[] = $assignment;
1153              }
1154              $rs->close();
1155  
1156          }
1157  
1158          foreach ($requestedassignmentids as $assignmentid) {
1159              $warning = array();
1160              $warning['item'] = 'assignment';
1161              $warning['itemid'] = $assignmentid;
1162              $warning['warningcode'] = '3';
1163              $warning['message'] = 'No mappings found';
1164              $warnings[] = $warning;
1165          }
1166  
1167          $result = array();
1168          $result['assignments'] = $assignments;
1169          $result['warnings'] = $warnings;
1170          return $result;
1171      }
1172  
1173      /**
1174       * Creates an assign_user_mappings external_single_structure
1175       * @return external_single_structure
1176       * @since  Moodle 2.6
1177       */
1178      private static function assign_user_mappings() {
1179          return new external_single_structure(
1180              array (
1181                  'assignmentid'    => new external_value(PARAM_INT, 'assignment id'),
1182                  'mappings'   => new external_multiple_structure(new external_single_structure(
1183                          array(
1184                              'id'     => new external_value(PARAM_INT, 'user mapping id'),
1185                              'userid' => new external_value(PARAM_INT, 'student id')
1186                          )
1187                      )
1188                  )
1189              )
1190          );
1191      }
1192  
1193      /**
1194       * Describes the get_user_mappings return value
1195       * @return external_single_structure
1196       * @since  Moodle 2.6
1197       */
1198      public static function get_user_mappings_returns() {
1199          return new external_single_structure(
1200              array(
1201                  'assignments' => new external_multiple_structure(self::assign_user_mappings(), 'list of assign user mapping data'),
1202                  'warnings'      => new external_warnings('item is always \'assignment\'',
1203                      'when errorcode is 3 then itemid is an assignment id. When errorcode is 1, itemid is a course module id',
1204                      'errorcode can be 3 (no user mappings found) or 1 (no permission to get user mappings)')
1205              )
1206          );
1207      }
1208  
1209      /**
1210       * Describes the parameters for lock_submissions
1211       * @return external_external_function_parameters
1212       * @since  Moodle 2.6
1213       */
1214      public static function lock_submissions_parameters() {
1215          return new external_function_parameters(
1216              array(
1217                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1218                  'userids' => new external_multiple_structure(
1219                      new external_value(PARAM_INT, 'user id'),
1220                      '1 or more user ids',
1221                      VALUE_REQUIRED),
1222              )
1223          );
1224      }
1225  
1226      /**
1227       * Locks (prevent updates to) submissions in this assignment.
1228       *
1229       * @param int $assignmentid The id of the assignment
1230       * @param array $userids Array of user ids to lock
1231       * @return array of warnings for each submission that could not be locked.
1232       * @since Moodle 2.6
1233       */
1234      public static function lock_submissions($assignmentid, $userids) {
1235          global $CFG;
1236          require_once("$CFG->dirroot/mod/assign/locallib.php");
1237  
1238          $params = self::validate_parameters(self::lock_submissions_parameters(),
1239                          array('assignmentid' => $assignmentid,
1240                                'userids' => $userids));
1241  
1242          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1243          $context = context_module::instance($cm->id);
1244          self::validate_context($context);
1245  
1246          $assignment = new assign($context, $cm, null);
1247  
1248          $warnings = array();
1249          foreach ($params['userids'] as $userid) {
1250              if (!$assignment->lock_submission($userid)) {
1251                  $detail = 'User id: ' . $userid . ', Assignment id: ' . $params['assignmentid'];
1252                  $warnings[] = self::generate_warning($params['assignmentid'],
1253                                                       'couldnotlock',
1254                                                       $detail);
1255              }
1256          }
1257  
1258          return $warnings;
1259      }
1260  
1261      /**
1262       * Describes the return value for lock_submissions
1263       *
1264       * @return external_single_structure
1265       * @since Moodle 2.6
1266       */
1267      public static function lock_submissions_returns() {
1268          return new external_warnings();
1269      }
1270  
1271      /**
1272       * Describes the parameters for revert_submissions_to_draft
1273       * @return external_external_function_parameters
1274       * @since  Moodle 2.6
1275       */
1276      public static function revert_submissions_to_draft_parameters() {
1277          return new external_function_parameters(
1278              array(
1279                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1280                  'userids' => new external_multiple_structure(
1281                      new external_value(PARAM_INT, 'user id'),
1282                      '1 or more user ids',
1283                      VALUE_REQUIRED),
1284              )
1285          );
1286      }
1287  
1288      /**
1289       * Reverts a list of user submissions to draft for a single assignment.
1290       *
1291       * @param int $assignmentid The id of the assignment
1292       * @param array $userids Array of user ids to revert
1293       * @return array of warnings for each submission that could not be reverted.
1294       * @since Moodle 2.6
1295       */
1296      public static function revert_submissions_to_draft($assignmentid, $userids) {
1297          global $CFG;
1298          require_once("$CFG->dirroot/mod/assign/locallib.php");
1299  
1300          $params = self::validate_parameters(self::revert_submissions_to_draft_parameters(),
1301                          array('assignmentid' => $assignmentid,
1302                                'userids' => $userids));
1303  
1304          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1305          $context = context_module::instance($cm->id);
1306          self::validate_context($context);
1307  
1308          $assignment = new assign($context, $cm, null);
1309  
1310          $warnings = array();
1311          foreach ($params['userids'] as $userid) {
1312              if (!$assignment->revert_to_draft($userid)) {
1313                  $detail = 'User id: ' . $userid . ', Assignment id: ' . $params['assignmentid'];
1314                  $warnings[] = self::generate_warning($params['assignmentid'],
1315                                                       'couldnotrevert',
1316                                                       $detail);
1317              }
1318          }
1319  
1320          return $warnings;
1321      }
1322  
1323      /**
1324       * Describes the return value for revert_submissions_to_draft
1325       *
1326       * @return external_single_structure
1327       * @since Moodle 2.6
1328       */
1329      public static function revert_submissions_to_draft_returns() {
1330          return new external_warnings();
1331      }
1332  
1333      /**
1334       * Describes the parameters for unlock_submissions
1335       * @return external_external_function_parameters
1336       * @since  Moodle 2.6
1337       */
1338      public static function unlock_submissions_parameters() {
1339          return new external_function_parameters(
1340              array(
1341                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1342                  'userids' => new external_multiple_structure(
1343                      new external_value(PARAM_INT, 'user id'),
1344                      '1 or more user ids',
1345                      VALUE_REQUIRED),
1346              )
1347          );
1348      }
1349  
1350      /**
1351       * Locks (prevent updates to) submissions in this assignment.
1352       *
1353       * @param int $assignmentid The id of the assignment
1354       * @param array $userids Array of user ids to lock
1355       * @return array of warnings for each submission that could not be locked.
1356       * @since Moodle 2.6
1357       */
1358      public static function unlock_submissions($assignmentid, $userids) {
1359          global $CFG;
1360          require_once("$CFG->dirroot/mod/assign/locallib.php");
1361  
1362          $params = self::validate_parameters(self::unlock_submissions_parameters(),
1363                          array('assignmentid' => $assignmentid,
1364                                'userids' => $userids));
1365  
1366          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1367          $context = context_module::instance($cm->id);
1368          self::validate_context($context);
1369  
1370          $assignment = new assign($context, $cm, null);
1371  
1372          $warnings = array();
1373          foreach ($params['userids'] as $userid) {
1374              if (!$assignment->unlock_submission($userid)) {
1375                  $detail = 'User id: ' . $userid . ', Assignment id: ' . $params['assignmentid'];
1376                  $warnings[] = self::generate_warning($params['assignmentid'],
1377                                                       'couldnotunlock',
1378                                                       $detail);
1379              }
1380          }
1381  
1382          return $warnings;
1383      }
1384  
1385      /**
1386       * Describes the return value for unlock_submissions
1387       *
1388       * @return external_single_structure
1389       * @since Moodle 2.6
1390       */
1391      public static function unlock_submissions_returns() {
1392          return new external_warnings();
1393      }
1394  
1395      /**
1396       * Describes the parameters for submit_for_grading
1397       * @return external_external_function_parameters
1398       * @since  Moodle 2.6
1399       */
1400      public static function submit_for_grading_parameters() {
1401          return new external_function_parameters(
1402              array(
1403                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1404                  'acceptsubmissionstatement' => new external_value(PARAM_BOOL, 'Accept the assignment submission statement')
1405              )
1406          );
1407      }
1408  
1409      /**
1410       * Submit the logged in users assignment for grading.
1411       *
1412       * @param int $assignmentid The id of the assignment
1413       * @return array of warnings to indicate any errors.
1414       * @since Moodle 2.6
1415       */
1416      public static function submit_for_grading($assignmentid, $acceptsubmissionstatement) {
1417          global $CFG, $USER;
1418          require_once("$CFG->dirroot/mod/assign/locallib.php");
1419  
1420          $params = self::validate_parameters(self::submit_for_grading_parameters(),
1421                                              array('assignmentid' => $assignmentid,
1422                                                    'acceptsubmissionstatement' => $acceptsubmissionstatement));
1423  
1424          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1425          $context = context_module::instance($cm->id);
1426          self::validate_context($context);
1427  
1428          $assignment = new assign($context, $cm, null);
1429  
1430          $warnings = array();
1431          $data = new stdClass();
1432          $data->submissionstatement = $params['acceptsubmissionstatement'];
1433          $notices = array();
1434  
1435          if (!$assignment->submit_for_grading($data, $notices)) {
1436              $detail = 'User id: ' . $USER->id . ', Assignment id: ' . $params['assignmentid'] . ' Notices:' . implode(', ', $notices);
1437              $warnings[] = self::generate_warning($params['assignmentid'],
1438                                                   'couldnotsubmitforgrading',
1439                                                   $detail);
1440          }
1441  
1442          return $warnings;
1443      }
1444  
1445      /**
1446       * Describes the return value for submit_for_grading
1447       *
1448       * @return external_single_structure
1449       * @since Moodle 2.6
1450       */
1451      public static function submit_for_grading_returns() {
1452          return new external_warnings();
1453      }
1454  
1455      /**
1456       * Describes the parameters for save_user_extensions
1457       * @return external_external_function_parameters
1458       * @since  Moodle 2.6
1459       */
1460      public static function save_user_extensions_parameters() {
1461          return new external_function_parameters(
1462              array(
1463                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1464                  'userids' => new external_multiple_structure(
1465                      new external_value(PARAM_INT, 'user id'),
1466                      '1 or more user ids',
1467                      VALUE_REQUIRED),
1468                  'dates' => new external_multiple_structure(
1469                      new external_value(PARAM_INT, 'dates'),
1470                      '1 or more extension dates (timestamp)',
1471                      VALUE_REQUIRED),
1472              )
1473          );
1474      }
1475  
1476      /**
1477       * Grant extension dates to students for an assignment.
1478       *
1479       * @param int $assignmentid The id of the assignment
1480       * @param array $userids Array of user ids to grant extensions to
1481       * @param array $dates Array of extension dates
1482       * @return array of warnings for each extension date that could not be granted
1483       * @since Moodle 2.6
1484       */
1485      public static function save_user_extensions($assignmentid, $userids, $dates) {
1486          global $CFG;
1487          require_once("$CFG->dirroot/mod/assign/locallib.php");
1488  
1489          $params = self::validate_parameters(self::save_user_extensions_parameters(),
1490                          array('assignmentid' => $assignmentid,
1491                                'userids' => $userids,
1492                                'dates' => $dates));
1493  
1494          if (count($params['userids']) != count($params['dates'])) {
1495              $detail = 'Length of userids and dates parameters differ.';
1496              $warnings[] = self::generate_warning($params['assignmentid'],
1497                                                   'invalidparameters',
1498                                                   $detail);
1499  
1500              return $warnings;
1501          }
1502  
1503          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1504          $context = context_module::instance($cm->id);
1505          self::validate_context($context);
1506  
1507          $assignment = new assign($context, $cm, null);
1508  
1509          $warnings = array();
1510          foreach ($params['userids'] as $idx => $userid) {
1511              $duedate = $params['dates'][$idx];
1512              if (!$assignment->save_user_extension($userid, $duedate)) {
1513                  $detail = 'User id: ' . $userid . ', Assignment id: ' . $params['assignmentid'] . ', Extension date: ' . $duedate;
1514                  $warnings[] = self::generate_warning($params['assignmentid'],
1515                                                       'couldnotgrantextensions',
1516                                                       $detail);
1517              }
1518          }
1519  
1520          return $warnings;
1521      }
1522  
1523      /**
1524       * Describes the return value for save_user_extensions
1525       *
1526       * @return external_single_structure
1527       * @since Moodle 2.6
1528       */
1529      public static function save_user_extensions_returns() {
1530          return new external_warnings();
1531      }
1532  
1533      /**
1534       * Describes the parameters for reveal_identities
1535       * @return external_external_function_parameters
1536       * @since  Moodle 2.6
1537       */
1538      public static function reveal_identities_parameters() {
1539          return new external_function_parameters(
1540              array(
1541                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on')
1542              )
1543          );
1544      }
1545  
1546      /**
1547       * Reveal the identities of anonymous students to markers for a single assignment.
1548       *
1549       * @param int $assignmentid The id of the assignment
1550       * @return array of warnings to indicate any errors.
1551       * @since Moodle 2.6
1552       */
1553      public static function reveal_identities($assignmentid) {
1554          global $CFG, $USER;
1555          require_once("$CFG->dirroot/mod/assign/locallib.php");
1556  
1557          $params = self::validate_parameters(self::reveal_identities_parameters(),
1558                                              array('assignmentid' => $assignmentid));
1559  
1560          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1561          $context = context_module::instance($cm->id);
1562          self::validate_context($context);
1563  
1564          $assignment = new assign($context, $cm, null);
1565  
1566          $warnings = array();
1567          if (!$assignment->reveal_identities()) {
1568              $detail = 'User id: ' . $USER->id . ', Assignment id: ' . $params['assignmentid'];
1569              $warnings[] = self::generate_warning($params['assignmentid'],
1570                                                   'couldnotrevealidentities',
1571                                                   $detail);
1572          }
1573  
1574          return $warnings;
1575      }
1576  
1577      /**
1578       * Describes the return value for reveal_identities
1579       *
1580       * @return external_single_structure
1581       * @since Moodle 2.6
1582       */
1583      public static function reveal_identities_returns() {
1584          return new external_warnings();
1585      }
1586  
1587      /**
1588       * Describes the parameters for save_submission
1589       * @return external_external_function_parameters
1590       * @since  Moodle 2.6
1591       */
1592      public static function save_submission_parameters() {
1593          global $CFG;
1594          require_once("$CFG->dirroot/mod/assign/locallib.php");
1595          $instance = new assign(null, null, null);
1596          $pluginsubmissionparams = array();
1597  
1598          foreach ($instance->get_submission_plugins() as $plugin) {
1599              $pluginparams = $plugin->get_external_parameters();
1600              if (!empty($pluginparams)) {
1601                  $pluginsubmissionparams = array_merge($pluginsubmissionparams, $pluginparams);
1602              }
1603          }
1604  
1605          return new external_function_parameters(
1606              array(
1607                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1608                  'plugindata' => new external_single_structure(
1609                      $pluginsubmissionparams
1610                  )
1611              )
1612          );
1613      }
1614  
1615      /**
1616       * Save a student submission for a single assignment
1617       *
1618       * @param int $assignmentid The id of the assignment
1619       * @param array $plugindata - The submitted data for plugins
1620       * @return array of warnings to indicate any errors
1621       * @since Moodle 2.6
1622       */
1623      public static function save_submission($assignmentid, $plugindata) {
1624          global $CFG, $USER;
1625          require_once("$CFG->dirroot/mod/assign/locallib.php");
1626  
1627          $params = self::validate_parameters(self::save_submission_parameters(),
1628                                              array('assignmentid' => $assignmentid,
1629                                                    'plugindata' => $plugindata));
1630  
1631          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1632          $context = context_module::instance($cm->id);
1633          self::validate_context($context);
1634  
1635          $assignment = new assign($context, $cm, null);
1636  
1637          $notices = array();
1638  
1639          if (!$assignment->submissions_open($USER->id)) {
1640              $notices[] = get_string('duedatereached', 'assign');
1641          } else {
1642              $submissiondata = (object)$params['plugindata'];
1643              $assignment->save_submission($submissiondata, $notices);
1644          }
1645  
1646          $warnings = array();
1647          foreach ($notices as $notice) {
1648              $warnings[] = self::generate_warning($params['assignmentid'],
1649                                                   'couldnotsavesubmission',
1650                                                   $notice);
1651          }
1652  
1653          return $warnings;
1654      }
1655  
1656      /**
1657       * Describes the return value for save_submission
1658       *
1659       * @return external_single_structure
1660       * @since Moodle 2.6
1661       */
1662      public static function save_submission_returns() {
1663          return new external_warnings();
1664      }
1665  
1666      /**
1667       * Describes the parameters for save_grade
1668       * @return external_external_function_parameters
1669       * @since  Moodle 2.6
1670       */
1671      public static function save_grade_parameters() {
1672          global $CFG;
1673          require_once("$CFG->dirroot/mod/assign/locallib.php");
1674          require_once("$CFG->dirroot/grade/grading/lib.php");
1675          $instance = new assign(null, null, null);
1676          $pluginfeedbackparams = array();
1677  
1678          foreach ($instance->get_feedback_plugins() as $plugin) {
1679              $pluginparams = $plugin->get_external_parameters();
1680              if (!empty($pluginparams)) {
1681                  $pluginfeedbackparams = array_merge($pluginfeedbackparams, $pluginparams);
1682              }
1683          }
1684  
1685          $advancedgradingdata = array();
1686          $methods = array_keys(grading_manager::available_methods(false));
1687          foreach ($methods as $method) {
1688              require_once($CFG->dirroot.'/grade/grading/form/'.$method.'/lib.php');
1689              $details  = call_user_func('gradingform_'.$method.'_controller::get_external_instance_filling_details');
1690              if (!empty($details)) {
1691                  $items = array();
1692                  foreach ($details as $key => $value) {
1693                      $value->required = VALUE_OPTIONAL;
1694                      unset($value->content->keys['id']);
1695                      $items[$key] = new external_multiple_structure (new external_single_structure(
1696                          array(
1697                              'criterionid' => new external_value(PARAM_INT, 'criterion id'),
1698                              'fillings' => $value
1699                          )
1700                      ));
1701                  }
1702                  $advancedgradingdata[$method] = new external_single_structure($items, 'items', VALUE_OPTIONAL);
1703              }
1704          }
1705  
1706          return new external_function_parameters(
1707              array(
1708                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1709                  'userid' => new external_value(PARAM_INT, 'The student id to operate on'),
1710                  'grade' => new external_value(PARAM_FLOAT, 'The new grade for this user. Ignored if advanced grading used'),
1711                  'attemptnumber' => new external_value(PARAM_INT, 'The attempt number (-1 means latest attempt)'),
1712                  'addattempt' => new external_value(PARAM_BOOL, 'Allow another attempt if the attempt reopen method is manual'),
1713                  'workflowstate' => new external_value(PARAM_ALPHA, 'The next marking workflow state'),
1714                  'applytoall' => new external_value(PARAM_BOOL, 'If true, this grade will be applied ' .
1715                                                                 'to all members ' .
1716                                                                 'of the group (for group assignments).'),
1717                  'plugindata' => new external_single_structure($pluginfeedbackparams, 'plugin data', VALUE_DEFAULT, array()),
1718                  'advancedgradingdata' => new external_single_structure($advancedgradingdata, 'advanced grading data',
1719                                                                         VALUE_DEFAULT, array())
1720              )
1721          );
1722      }
1723  
1724      /**
1725       * Save a student grade for a single assignment.
1726       *
1727       * @param int $assignmentid The id of the assignment
1728       * @param int $userid The id of the user
1729       * @param float $grade The grade (ignored if the assignment uses advanced grading)
1730       * @param int $attemptnumber The attempt number
1731       * @param bool $addattempt Allow another attempt
1732       * @param string $workflowstate New workflow state
1733       * @param bool $applytoall Apply the grade to all members of the group
1734       * @param array $plugindata Custom data used by plugins
1735       * @param array $advancedgradingdata Advanced grading data
1736       * @return null
1737       * @since Moodle 2.6
1738       */
1739      public static function save_grade($assignmentid,
1740                                        $userid,
1741                                        $grade,
1742                                        $attemptnumber,
1743                                        $addattempt,
1744                                        $workflowstate,
1745                                        $applytoall,
1746                                        $plugindata = array(),
1747                                        $advancedgradingdata = array()) {
1748          global $CFG, $USER;
1749          require_once("$CFG->dirroot/mod/assign/locallib.php");
1750  
1751          $params = self::validate_parameters(self::save_grade_parameters(),
1752                                              array('assignmentid' => $assignmentid,
1753                                                    'userid' => $userid,
1754                                                    'grade' => $grade,
1755                                                    'attemptnumber' => $attemptnumber,
1756                                                    'workflowstate' => $workflowstate,
1757                                                    'addattempt' => $addattempt,
1758                                                    'applytoall' => $applytoall,
1759                                                    'plugindata' => $plugindata,
1760                                                    'advancedgradingdata' => $advancedgradingdata));
1761  
1762          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1763          $context = context_module::instance($cm->id);
1764          self::validate_context($context);
1765  
1766          $assignment = new assign($context, $cm, null);
1767  
1768          $gradedata = (object)$params['plugindata'];
1769  
1770          $gradedata->addattempt = $params['addattempt'];
1771          $gradedata->attemptnumber = $params['attemptnumber'];
1772          $gradedata->workflowstate = $params['workflowstate'];
1773          $gradedata->applytoall = $params['applytoall'];
1774          $gradedata->grade = $params['grade'];
1775  
1776          if (!empty($params['advancedgradingdata'])) {
1777              $advancedgrading = array();
1778              $criteria = reset($params['advancedgradingdata']);
1779              foreach ($criteria as $key => $criterion) {
1780                  $details = array();
1781                  foreach ($criterion as $value) {
1782                      foreach ($value['fillings'] as $filling) {
1783                          $details[$value['criterionid']] = $filling;
1784                      }
1785                  }
1786                  $advancedgrading[$key] = $details;
1787              }
1788              $gradedata->advancedgrading = $advancedgrading;
1789          }
1790  
1791          $assignment->save_grade($params['userid'], $gradedata);
1792  
1793          return null;
1794      }
1795  
1796      /**
1797       * Describes the return value for save_grade
1798       *
1799       * @return external_single_structure
1800       * @since Moodle 2.6
1801       */
1802      public static function save_grade_returns() {
1803          return null;
1804      }
1805  
1806      /**
1807       * Describes the parameters for save_grades
1808       * @return external_external_function_parameters
1809       * @since  Moodle 2.7
1810       */
1811      public static function save_grades_parameters() {
1812          global $CFG;
1813          require_once("$CFG->dirroot/mod/assign/locallib.php");
1814          require_once("$CFG->dirroot/grade/grading/lib.php");
1815          $instance = new assign(null, null, null);
1816          $pluginfeedbackparams = array();
1817  
1818          foreach ($instance->get_feedback_plugins() as $plugin) {
1819              $pluginparams = $plugin->get_external_parameters();
1820              if (!empty($pluginparams)) {
1821                  $pluginfeedbackparams = array_merge($pluginfeedbackparams, $pluginparams);
1822              }
1823          }
1824  
1825          $advancedgradingdata = array();
1826          $methods = array_keys(grading_manager::available_methods(false));
1827          foreach ($methods as $method) {
1828              require_once($CFG->dirroot.'/grade/grading/form/'.$method.'/lib.php');
1829              $details  = call_user_func('gradingform_'.$method.'_controller::get_external_instance_filling_details');
1830              if (!empty($details)) {
1831                  $items = array();
1832                  foreach ($details as $key => $value) {
1833                      $value->required = VALUE_OPTIONAL;
1834                      unset($value->content->keys['id']);
1835                      $items[$key] = new external_multiple_structure (new external_single_structure(
1836                          array(
1837                              'criterionid' => new external_value(PARAM_INT, 'criterion id'),
1838                              'fillings' => $value
1839                          )
1840                      ));
1841                  }
1842                  $advancedgradingdata[$method] = new external_single_structure($items, 'items', VALUE_OPTIONAL);
1843              }
1844          }
1845  
1846          return new external_function_parameters(
1847              array(
1848                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1849                  'applytoall' => new external_value(PARAM_BOOL, 'If true, this grade will be applied ' .
1850                                                                 'to all members ' .
1851                                                                 'of the group (for group assignments).'),
1852                  'grades' => new external_multiple_structure(
1853                      new external_single_structure(
1854                          array (
1855                              'userid' => new external_value(PARAM_INT, 'The student id to operate on'),
1856                              'grade' => new external_value(PARAM_FLOAT, 'The new grade for this user. '.
1857                                                                         'Ignored if advanced grading used'),
1858                              'attemptnumber' => new external_value(PARAM_INT, 'The attempt number (-1 means latest attempt)'),
1859                              'addattempt' => new external_value(PARAM_BOOL, 'Allow another attempt if manual attempt reopen method'),
1860                              'workflowstate' => new external_value(PARAM_ALPHA, 'The next marking workflow state'),
1861                              'plugindata' => new external_single_structure($pluginfeedbackparams, 'plugin data',
1862                                                                            VALUE_DEFAULT, array()),
1863                              'advancedgradingdata' => new external_single_structure($advancedgradingdata, 'advanced grading data',
1864                                                                                     VALUE_DEFAULT, array())
1865                          )
1866                      )
1867                  )
1868              )
1869          );
1870      }
1871  
1872      /**
1873       * Save multiple student grades for a single assignment.
1874       *
1875       * @param int $assignmentid The id of the assignment
1876       * @param boolean $applytoall If set to true and this is a team assignment,
1877       * apply the grade to all members of the group
1878       * @param array $grades grade data for one or more students that includes
1879       *                  userid - The id of the student being graded
1880       *                  grade - The grade (ignored if the assignment uses advanced grading)
1881       *                  attemptnumber - The attempt number
1882       *                  addattempt - Allow another attempt
1883       *                  workflowstate - New workflow state
1884       *                  plugindata - Custom data used by plugins
1885       *                  advancedgradingdata - Optional Advanced grading data
1886       * @throws invalid_parameter_exception if multiple grades are supplied for
1887       * a team assignment that has $applytoall set to true
1888       * @return null
1889       * @since Moodle 2.7
1890       */
1891      public static function save_grades($assignmentid, $applytoall = false, $grades) {
1892          global $CFG, $USER;
1893          require_once("$CFG->dirroot/mod/assign/locallib.php");
1894  
1895          $params = self::validate_parameters(self::save_grades_parameters(),
1896                                              array('assignmentid' => $assignmentid,
1897                                                    'applytoall' => $applytoall,
1898                                                    'grades' => $grades));
1899  
1900          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1901          $context = context_module::instance($cm->id);
1902          self::validate_context($context);
1903          $assignment = new assign($context, $cm, null);
1904  
1905          if ($assignment->get_instance()->teamsubmission && $params['applytoall']) {
1906              // Check that only 1 user per submission group is provided.
1907              $groupids = array();
1908              foreach ($params['grades'] as $gradeinfo) {
1909                  $group = $assignment->get_submission_group($gradeinfo['userid']);
1910                  if (in_array($group->id, $groupids)) {
1911                      throw new invalid_parameter_exception('Multiple grades for the same team have been supplied '
1912                                                            .' this is not permitted when the applytoall flag is set');
1913                  } else {
1914                      $groupids[] = $group->id;
1915                  }
1916              }
1917          }
1918  
1919          foreach ($params['grades'] as $gradeinfo) {
1920              $gradedata = (object)$gradeinfo['plugindata'];
1921              $gradedata->addattempt = $gradeinfo['addattempt'];
1922              $gradedata->attemptnumber = $gradeinfo['attemptnumber'];
1923              $gradedata->workflowstate = $gradeinfo['workflowstate'];
1924              $gradedata->applytoall = $params['applytoall'];
1925              $gradedata->grade = $gradeinfo['grade'];
1926  
1927              if (!empty($gradeinfo['advancedgradingdata'])) {
1928                  $advancedgrading = array();
1929                  $criteria = reset($gradeinfo['advancedgradingdata']);
1930                  foreach ($criteria as $key => $criterion) {
1931                      $details = array();
1932                      foreach ($criterion as $value) {
1933                          foreach ($value['fillings'] as $filling) {
1934                              $details[$value['criterionid']] = $filling;
1935                          }
1936                      }
1937                      $advancedgrading[$key] = $details;
1938                  }
1939                  $gradedata->advancedgrading = $advancedgrading;
1940              }
1941              $assignment->save_grade($gradeinfo['userid'], $gradedata);
1942          }
1943  
1944          return null;
1945      }
1946  
1947      /**
1948       * Describes the return value for save_grades
1949       *
1950       * @return external_single_structure
1951       * @since Moodle 2.7
1952       */
1953      public static function save_grades_returns() {
1954          return null;
1955      }
1956  
1957      /**
1958       * Describes the parameters for copy_previous_attempt
1959       * @return external_external_function_parameters
1960       * @since  Moodle 2.6
1961       */
1962      public static function copy_previous_attempt_parameters() {
1963          return new external_function_parameters(
1964              array(
1965                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1966              )
1967          );
1968      }
1969  
1970      /**
1971       * Copy a students previous attempt to a new attempt.
1972       *
1973       * @param int $assignmentid
1974       * @return array of warnings to indicate any errors.
1975       * @since Moodle 2.6
1976       */
1977      public static function copy_previous_attempt($assignmentid) {
1978          global $CFG, $USER;
1979          require_once("$CFG->dirroot/mod/assign/locallib.php");
1980  
1981          $params = self::validate_parameters(self::copy_previous_attempt_parameters(),
1982                                              array('assignmentid' => $assignmentid));
1983  
1984          $cm = get_coursemodule_from_instance('assign', $assignmentid, 0, false, MUST_EXIST);
1985          $context = context_module::instance($cm->id);
1986          self::validate_context($context);
1987  
1988          $assignment = new assign($context, $cm, null);
1989  
1990          $notices = array();
1991  
1992          $assignment->copy_previous_attempt($submissiondata, $notices);
1993  
1994          $warnings = array();
1995          foreach ($notices as $notice) {
1996              $warnings[] = self::generate_warning($assignmentid,
1997                                                   'couldnotcopyprevioussubmission',
1998                                                   $notice);
1999          }
2000  
2001          return $warnings;
2002      }
2003  
2004      /**
2005       * Describes the return value for save_submission
2006       *
2007       * @return external_single_structure
2008       * @since Moodle 2.6
2009       */
2010      public static function copy_previous_attempt_returns() {
2011          return new external_warnings();
2012      }
2013  }

Search This Site: