[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/mod/assign/ -> externallib.php (source)

   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_multiple_structure(
1269             new external_warnings()
1270          );
1271      }
1272  
1273      /**
1274       * Describes the parameters for revert_submissions_to_draft
1275       * @return external_external_function_parameters
1276       * @since  Moodle 2.6
1277       */
1278      public static function revert_submissions_to_draft_parameters() {
1279          return new external_function_parameters(
1280              array(
1281                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1282                  'userids' => new external_multiple_structure(
1283                      new external_value(PARAM_INT, 'user id'),
1284                      '1 or more user ids',
1285                      VALUE_REQUIRED),
1286              )
1287          );
1288      }
1289  
1290      /**
1291       * Reverts a list of user submissions to draft for a single assignment.
1292       *
1293       * @param int $assignmentid The id of the assignment
1294       * @param array $userids Array of user ids to revert
1295       * @return array of warnings for each submission that could not be reverted.
1296       * @since Moodle 2.6
1297       */
1298      public static function revert_submissions_to_draft($assignmentid, $userids) {
1299          global $CFG;
1300          require_once("$CFG->dirroot/mod/assign/locallib.php");
1301  
1302          $params = self::validate_parameters(self::revert_submissions_to_draft_parameters(),
1303                          array('assignmentid' => $assignmentid,
1304                                'userids' => $userids));
1305  
1306          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1307          $context = context_module::instance($cm->id);
1308          self::validate_context($context);
1309  
1310          $assignment = new assign($context, $cm, null);
1311  
1312          $warnings = array();
1313          foreach ($params['userids'] as $userid) {
1314              if (!$assignment->revert_to_draft($userid)) {
1315                  $detail = 'User id: ' . $userid . ', Assignment id: ' . $params['assignmentid'];
1316                  $warnings[] = self::generate_warning($params['assignmentid'],
1317                                                       'couldnotrevert',
1318                                                       $detail);
1319              }
1320          }
1321  
1322          return $warnings;
1323      }
1324  
1325      /**
1326       * Describes the return value for revert_submissions_to_draft
1327       *
1328       * @return external_single_structure
1329       * @since Moodle 2.6
1330       */
1331      public static function revert_submissions_to_draft_returns() {
1332          return new external_multiple_structure(
1333             new external_warnings()
1334          );
1335      }
1336  
1337      /**
1338       * Describes the parameters for unlock_submissions
1339       * @return external_external_function_parameters
1340       * @since  Moodle 2.6
1341       */
1342      public static function unlock_submissions_parameters() {
1343          return new external_function_parameters(
1344              array(
1345                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1346                  'userids' => new external_multiple_structure(
1347                      new external_value(PARAM_INT, 'user id'),
1348                      '1 or more user ids',
1349                      VALUE_REQUIRED),
1350              )
1351          );
1352      }
1353  
1354      /**
1355       * Locks (prevent updates to) submissions in this assignment.
1356       *
1357       * @param int $assignmentid The id of the assignment
1358       * @param array $userids Array of user ids to lock
1359       * @return array of warnings for each submission that could not be locked.
1360       * @since Moodle 2.6
1361       */
1362      public static function unlock_submissions($assignmentid, $userids) {
1363          global $CFG;
1364          require_once("$CFG->dirroot/mod/assign/locallib.php");
1365  
1366          $params = self::validate_parameters(self::unlock_submissions_parameters(),
1367                          array('assignmentid' => $assignmentid,
1368                                'userids' => $userids));
1369  
1370          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1371          $context = context_module::instance($cm->id);
1372          self::validate_context($context);
1373  
1374          $assignment = new assign($context, $cm, null);
1375  
1376          $warnings = array();
1377          foreach ($params['userids'] as $userid) {
1378              if (!$assignment->unlock_submission($userid)) {
1379                  $detail = 'User id: ' . $userid . ', Assignment id: ' . $params['assignmentid'];
1380                  $warnings[] = self::generate_warning($params['assignmentid'],
1381                                                       'couldnotunlock',
1382                                                       $detail);
1383              }
1384          }
1385  
1386          return $warnings;
1387      }
1388  
1389      /**
1390       * Describes the return value for unlock_submissions
1391       *
1392       * @return external_single_structure
1393       * @since Moodle 2.6
1394       */
1395      public static function unlock_submissions_returns() {
1396          return new external_multiple_structure(
1397             new external_warnings()
1398          );
1399      }
1400  
1401      /**
1402       * Describes the parameters for submit_for_grading
1403       * @return external_external_function_parameters
1404       * @since  Moodle 2.6
1405       */
1406      public static function submit_for_grading_parameters() {
1407          return new external_function_parameters(
1408              array(
1409                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1410                  'acceptsubmissionstatement' => new external_value(PARAM_BOOL, 'Accept the assignment submission statement')
1411              )
1412          );
1413      }
1414  
1415      /**
1416       * Submit the logged in users assignment for grading.
1417       *
1418       * @param int $assignmentid The id of the assignment
1419       * @return array of warnings to indicate any errors.
1420       * @since Moodle 2.6
1421       */
1422      public static function submit_for_grading($assignmentid, $acceptsubmissionstatement) {
1423          global $CFG, $USER;
1424          require_once("$CFG->dirroot/mod/assign/locallib.php");
1425  
1426          $params = self::validate_parameters(self::submit_for_grading_parameters(),
1427                                              array('assignmentid' => $assignmentid,
1428                                                    'acceptsubmissionstatement' => $acceptsubmissionstatement));
1429  
1430          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1431          $context = context_module::instance($cm->id);
1432          self::validate_context($context);
1433  
1434          $assignment = new assign($context, $cm, null);
1435  
1436          $warnings = array();
1437          $data = new stdClass();
1438          $data->submissionstatement = $params['acceptsubmissionstatement'];
1439          $notices = array();
1440  
1441          if (!$assignment->submit_for_grading($data, $notices)) {
1442              $detail = 'User id: ' . $USER->id . ', Assignment id: ' . $params['assignmentid'] . ' Notices:' . implode(', ', $notices);
1443              $warnings[] = self::generate_warning($params['assignmentid'],
1444                                                   'couldnotsubmitforgrading',
1445                                                   $detail);
1446          }
1447  
1448          return $warnings;
1449      }
1450  
1451      /**
1452       * Describes the return value for submit_for_grading
1453       *
1454       * @return external_single_structure
1455       * @since Moodle 2.6
1456       */
1457      public static function submit_for_grading_returns() {
1458          return new external_multiple_structure(
1459             new external_warnings()
1460          );
1461      }
1462  
1463      /**
1464       * Describes the parameters for save_user_extensions
1465       * @return external_external_function_parameters
1466       * @since  Moodle 2.6
1467       */
1468      public static function save_user_extensions_parameters() {
1469          return new external_function_parameters(
1470              array(
1471                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1472                  'userids' => new external_multiple_structure(
1473                      new external_value(PARAM_INT, 'user id'),
1474                      '1 or more user ids',
1475                      VALUE_REQUIRED),
1476                  'dates' => new external_multiple_structure(
1477                      new external_value(PARAM_INT, 'dates'),
1478                      '1 or more extension dates (timestamp)',
1479                      VALUE_REQUIRED),
1480              )
1481          );
1482      }
1483  
1484      /**
1485       * Grant extension dates to students for an assignment.
1486       *
1487       * @param int $assignmentid The id of the assignment
1488       * @param array $userids Array of user ids to grant extensions to
1489       * @param array $dates Array of extension dates
1490       * @return array of warnings for each extension date that could not be granted
1491       * @since Moodle 2.6
1492       */
1493      public static function save_user_extensions($assignmentid, $userids, $dates) {
1494          global $CFG;
1495          require_once("$CFG->dirroot/mod/assign/locallib.php");
1496  
1497          $params = self::validate_parameters(self::save_user_extensions_parameters(),
1498                          array('assignmentid' => $assignmentid,
1499                                'userids' => $userids,
1500                                'dates' => $dates));
1501  
1502          if (count($params['userids']) != count($params['dates'])) {
1503              $detail = 'Length of userids and dates parameters differ.';
1504              $warnings[] = self::generate_warning($params['assignmentid'],
1505                                                   'invalidparameters',
1506                                                   $detail);
1507  
1508              return $warnings;
1509          }
1510  
1511          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1512          $context = context_module::instance($cm->id);
1513          self::validate_context($context);
1514  
1515          $assignment = new assign($context, $cm, null);
1516  
1517          $warnings = array();
1518          foreach ($params['userids'] as $idx => $userid) {
1519              $duedate = $params['dates'][$idx];
1520              if (!$assignment->save_user_extension($userid, $duedate)) {
1521                  $detail = 'User id: ' . $userid . ', Assignment id: ' . $params['assignmentid'] . ', Extension date: ' . $duedate;
1522                  $warnings[] = self::generate_warning($params['assignmentid'],
1523                                                       'couldnotgrantextensions',
1524                                                       $detail);
1525              }
1526          }
1527  
1528          return $warnings;
1529      }
1530  
1531      /**
1532       * Describes the return value for save_user_extensions
1533       *
1534       * @return external_single_structure
1535       * @since Moodle 2.6
1536       */
1537      public static function save_user_extensions_returns() {
1538          return new external_multiple_structure(
1539             new external_warnings()
1540          );
1541      }
1542  
1543      /**
1544       * Describes the parameters for reveal_identities
1545       * @return external_external_function_parameters
1546       * @since  Moodle 2.6
1547       */
1548      public static function reveal_identities_parameters() {
1549          return new external_function_parameters(
1550              array(
1551                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on')
1552              )
1553          );
1554      }
1555  
1556      /**
1557       * Reveal the identities of anonymous students to markers for a single assignment.
1558       *
1559       * @param int $assignmentid The id of the assignment
1560       * @return array of warnings to indicate any errors.
1561       * @since Moodle 2.6
1562       */
1563      public static function reveal_identities($assignmentid) {
1564          global $CFG, $USER;
1565          require_once("$CFG->dirroot/mod/assign/locallib.php");
1566  
1567          $params = self::validate_parameters(self::reveal_identities_parameters(),
1568                                              array('assignmentid' => $assignmentid));
1569  
1570          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1571          $context = context_module::instance($cm->id);
1572          self::validate_context($context);
1573  
1574          $assignment = new assign($context, $cm, null);
1575  
1576          $warnings = array();
1577          if (!$assignment->reveal_identities()) {
1578              $detail = 'User id: ' . $USER->id . ', Assignment id: ' . $params['assignmentid'];
1579              $warnings[] = self::generate_warning($params['assignmentid'],
1580                                                   'couldnotrevealidentities',
1581                                                   $detail);
1582          }
1583  
1584          return $warnings;
1585      }
1586  
1587      /**
1588       * Describes the return value for reveal_identities
1589       *
1590       * @return external_single_structure
1591       * @since Moodle 2.6
1592       */
1593      public static function reveal_identities_returns() {
1594          return new external_multiple_structure(
1595             new external_warnings()
1596          );
1597      }
1598  
1599      /**
1600       * Describes the parameters for save_submission
1601       * @return external_external_function_parameters
1602       * @since  Moodle 2.6
1603       */
1604      public static function save_submission_parameters() {
1605          global $CFG;
1606          require_once("$CFG->dirroot/mod/assign/locallib.php");
1607          $instance = new assign(null, null, null);
1608          $pluginsubmissionparams = array();
1609  
1610          foreach ($instance->get_submission_plugins() as $plugin) {
1611              $pluginparams = $plugin->get_external_parameters();
1612              if (!empty($pluginparams)) {
1613                  $pluginsubmissionparams = array_merge($pluginsubmissionparams, $pluginparams);
1614              }
1615          }
1616  
1617          return new external_function_parameters(
1618              array(
1619                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1620                  'plugindata' => new external_single_structure(
1621                      $pluginsubmissionparams
1622                  )
1623              )
1624          );
1625      }
1626  
1627      /**
1628       * Save a student submission for a single assignment
1629       *
1630       * @param int $assignmentid The id of the assignment
1631       * @param array $plugindata - The submitted data for plugins
1632       * @return array of warnings to indicate any errors
1633       * @since Moodle 2.6
1634       */
1635      public static function save_submission($assignmentid, $plugindata) {
1636          global $CFG, $USER;
1637          require_once("$CFG->dirroot/mod/assign/locallib.php");
1638  
1639          $params = self::validate_parameters(self::save_submission_parameters(),
1640                                              array('assignmentid' => $assignmentid,
1641                                                    'plugindata' => $plugindata));
1642  
1643          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1644          $context = context_module::instance($cm->id);
1645          self::validate_context($context);
1646  
1647          $assignment = new assign($context, $cm, null);
1648  
1649          $notices = array();
1650  
1651          $submissiondata = (object)$params['plugindata'];
1652  
1653          $assignment->save_submission($submissiondata, $notices);
1654  
1655          $warnings = array();
1656          foreach ($notices as $notice) {
1657              $warnings[] = self::generate_warning($params['assignmentid'],
1658                                                   'couldnotsavesubmission',
1659                                                   $notice);
1660          }
1661  
1662          return $warnings;
1663      }
1664  
1665      /**
1666       * Describes the return value for save_submission
1667       *
1668       * @return external_single_structure
1669       * @since Moodle 2.6
1670       */
1671      public static function save_submission_returns() {
1672          return new external_multiple_structure(
1673             new external_warnings()
1674          );
1675      }
1676  
1677      /**
1678       * Describes the parameters for save_grade
1679       * @return external_external_function_parameters
1680       * @since  Moodle 2.6
1681       */
1682      public static function save_grade_parameters() {
1683          global $CFG;
1684          require_once("$CFG->dirroot/mod/assign/locallib.php");
1685          require_once("$CFG->dirroot/grade/grading/lib.php");
1686          $instance = new assign(null, null, null);
1687          $pluginfeedbackparams = array();
1688  
1689          foreach ($instance->get_feedback_plugins() as $plugin) {
1690              $pluginparams = $plugin->get_external_parameters();
1691              if (!empty($pluginparams)) {
1692                  $pluginfeedbackparams = array_merge($pluginfeedbackparams, $pluginparams);
1693              }
1694          }
1695  
1696          $advancedgradingdata = array();
1697          $methods = array_keys(grading_manager::available_methods(false));
1698          foreach ($methods as $method) {
1699              require_once($CFG->dirroot.'/grade/grading/form/'.$method.'/lib.php');
1700              $details  = call_user_func('gradingform_'.$method.'_controller::get_external_instance_filling_details');
1701              if (!empty($details)) {
1702                  $items = array();
1703                  foreach ($details as $key => $value) {
1704                      $value->required = VALUE_OPTIONAL;
1705                      unset($value->content->keys['id']);
1706                      $items[$key] = new external_multiple_structure (new external_single_structure(
1707                          array(
1708                              'criterionid' => new external_value(PARAM_INT, 'criterion id'),
1709                              'fillings' => $value
1710                          )
1711                      ));
1712                  }
1713                  $advancedgradingdata[$method] = new external_single_structure($items, 'items', VALUE_OPTIONAL);
1714              }
1715          }
1716  
1717          return new external_function_parameters(
1718              array(
1719                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1720                  'userid' => new external_value(PARAM_INT, 'The student id to operate on'),
1721                  'grade' => new external_value(PARAM_FLOAT, 'The new grade for this user. Ignored if advanced grading used'),
1722                  'attemptnumber' => new external_value(PARAM_INT, 'The attempt number (-1 means latest attempt)'),
1723                  'addattempt' => new external_value(PARAM_BOOL, 'Allow another attempt if the attempt reopen method is manual'),
1724                  'workflowstate' => new external_value(PARAM_ALPHA, 'The next marking workflow state'),
1725                  'applytoall' => new external_value(PARAM_BOOL, 'If true, this grade will be applied ' .
1726                                                                 'to all members ' .
1727                                                                 'of the group (for group assignments).'),
1728                  'plugindata' => new external_single_structure($pluginfeedbackparams, 'plugin data', VALUE_DEFAULT, array()),
1729                  'advancedgradingdata' => new external_single_structure($advancedgradingdata, 'advanced grading data',
1730                                                                         VALUE_DEFAULT, array())
1731              )
1732          );
1733      }
1734  
1735      /**
1736       * Save a student grade for a single assignment.
1737       *
1738       * @param int $assignmentid The id of the assignment
1739       * @param int $userid The id of the user
1740       * @param float $grade The grade (ignored if the assignment uses advanced grading)
1741       * @param int $attemptnumber The attempt number
1742       * @param bool $addattempt Allow another attempt
1743       * @param string $workflowstate New workflow state
1744       * @param bool $applytoall Apply the grade to all members of the group
1745       * @param array $plugindata Custom data used by plugins
1746       * @param array $advancedgradingdata Advanced grading data
1747       * @return null
1748       * @since Moodle 2.6
1749       */
1750      public static function save_grade($assignmentid,
1751                                        $userid,
1752                                        $grade,
1753                                        $attemptnumber,
1754                                        $addattempt,
1755                                        $workflowstate,
1756                                        $applytoall,
1757                                        $plugindata = array(),
1758                                        $advancedgradingdata = array()) {
1759          global $CFG, $USER;
1760          require_once("$CFG->dirroot/mod/assign/locallib.php");
1761  
1762          $params = self::validate_parameters(self::save_grade_parameters(),
1763                                              array('assignmentid' => $assignmentid,
1764                                                    'userid' => $userid,
1765                                                    'grade' => $grade,
1766                                                    'attemptnumber' => $attemptnumber,
1767                                                    'workflowstate' => $workflowstate,
1768                                                    'addattempt' => $addattempt,
1769                                                    'applytoall' => $applytoall,
1770                                                    'plugindata' => $plugindata,
1771                                                    'advancedgradingdata' => $advancedgradingdata));
1772  
1773          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1774          $context = context_module::instance($cm->id);
1775          self::validate_context($context);
1776  
1777          $assignment = new assign($context, $cm, null);
1778  
1779          $gradedata = (object)$params['plugindata'];
1780  
1781          $gradedata->addattempt = $params['addattempt'];
1782          $gradedata->attemptnumber = $params['attemptnumber'];
1783          $gradedata->workflowstate = $params['workflowstate'];
1784          $gradedata->applytoall = $params['applytoall'];
1785          $gradedata->grade = $params['grade'];
1786  
1787          if (!empty($params['advancedgradingdata'])) {
1788              $advancedgrading = array();
1789              $criteria = reset($params['advancedgradingdata']);
1790              foreach ($criteria as $key => $criterion) {
1791                  $details = array();
1792                  foreach ($criterion as $value) {
1793                      foreach ($value['fillings'] as $filling) {
1794                          $details[$value['criterionid']] = $filling;
1795                      }
1796                  }
1797                  $advancedgrading[$key] = $details;
1798              }
1799              $gradedata->advancedgrading = $advancedgrading;
1800          }
1801  
1802          $assignment->save_grade($params['userid'], $gradedata);
1803  
1804          return null;
1805      }
1806  
1807      /**
1808       * Describes the return value for save_grade
1809       *
1810       * @return external_single_structure
1811       * @since Moodle 2.6
1812       */
1813      public static function save_grade_returns() {
1814          return null;
1815      }
1816  
1817      /**
1818       * Describes the parameters for save_grades
1819       * @return external_external_function_parameters
1820       * @since  Moodle 2.7
1821       */
1822      public static function save_grades_parameters() {
1823          global $CFG;
1824          require_once("$CFG->dirroot/mod/assign/locallib.php");
1825          require_once("$CFG->dirroot/grade/grading/lib.php");
1826          $instance = new assign(null, null, null);
1827          $pluginfeedbackparams = array();
1828  
1829          foreach ($instance->get_feedback_plugins() as $plugin) {
1830              $pluginparams = $plugin->get_external_parameters();
1831              if (!empty($pluginparams)) {
1832                  $pluginfeedbackparams = array_merge($pluginfeedbackparams, $pluginparams);
1833              }
1834          }
1835  
1836          $advancedgradingdata = array();
1837          $methods = array_keys(grading_manager::available_methods(false));
1838          foreach ($methods as $method) {
1839              require_once($CFG->dirroot.'/grade/grading/form/'.$method.'/lib.php');
1840              $details  = call_user_func('gradingform_'.$method.'_controller::get_external_instance_filling_details');
1841              if (!empty($details)) {
1842                  $items = array();
1843                  foreach ($details as $key => $value) {
1844                      $value->required = VALUE_OPTIONAL;
1845                      unset($value->content->keys['id']);
1846                      $items[$key] = new external_multiple_structure (new external_single_structure(
1847                          array(
1848                              'criterionid' => new external_value(PARAM_INT, 'criterion id'),
1849                              'fillings' => $value
1850                          )
1851                      ));
1852                  }
1853                  $advancedgradingdata[$method] = new external_single_structure($items, 'items', VALUE_OPTIONAL);
1854              }
1855          }
1856  
1857          return new external_function_parameters(
1858              array(
1859                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1860                  'applytoall' => new external_value(PARAM_BOOL, 'If true, this grade will be applied ' .
1861                                                                 'to all members ' .
1862                                                                 'of the group (for group assignments).'),
1863                  'grades' => new external_multiple_structure(
1864                      new external_single_structure(
1865                          array (
1866                              'userid' => new external_value(PARAM_INT, 'The student id to operate on'),
1867                              'grade' => new external_value(PARAM_FLOAT, 'The new grade for this user. '.
1868                                                                         'Ignored if advanced grading used'),
1869                              'attemptnumber' => new external_value(PARAM_INT, 'The attempt number (-1 means latest attempt)'),
1870                              'addattempt' => new external_value(PARAM_BOOL, 'Allow another attempt if manual attempt reopen method'),
1871                              'workflowstate' => new external_value(PARAM_ALPHA, 'The next marking workflow state'),
1872                              'plugindata' => new external_single_structure($pluginfeedbackparams, 'plugin data',
1873                                                                            VALUE_DEFAULT, array()),
1874                              'advancedgradingdata' => new external_single_structure($advancedgradingdata, 'advanced grading data',
1875                                                                                     VALUE_DEFAULT, array())
1876                          )
1877                      )
1878                  )
1879              )
1880          );
1881      }
1882  
1883      /**
1884       * Save multiple student grades for a single assignment.
1885       *
1886       * @param int $assignmentid The id of the assignment
1887       * @param boolean $applytoall If set to true and this is a team assignment,
1888       * apply the grade to all members of the group
1889       * @param array $grades grade data for one or more students that includes
1890       *                  userid - The id of the student being graded
1891       *                  grade - The grade (ignored if the assignment uses advanced grading)
1892       *                  attemptnumber - The attempt number
1893       *                  addattempt - Allow another attempt
1894       *                  workflowstate - New workflow state
1895       *                  plugindata - Custom data used by plugins
1896       *                  advancedgradingdata - Optional Advanced grading data
1897       * @throws invalid_parameter_exception if multiple grades are supplied for
1898       * a team assignment that has $applytoall set to true
1899       * @return null
1900       * @since Moodle 2.7
1901       */
1902      public static function save_grades($assignmentid, $applytoall = false, $grades) {
1903          global $CFG, $USER;
1904          require_once("$CFG->dirroot/mod/assign/locallib.php");
1905  
1906          $params = self::validate_parameters(self::save_grades_parameters(),
1907                                              array('assignmentid' => $assignmentid,
1908                                                    'applytoall' => $applytoall,
1909                                                    'grades' => $grades));
1910  
1911          $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST);
1912          $context = context_module::instance($cm->id);
1913          self::validate_context($context);
1914          $assignment = new assign($context, $cm, null);
1915  
1916          if ($assignment->get_instance()->teamsubmission && $params['applytoall']) {
1917              // Check that only 1 user per submission group is provided.
1918              $groupids = array();
1919              foreach ($params['grades'] as $gradeinfo) {
1920                  $group = $assignment->get_submission_group($gradeinfo['userid']);
1921                  if (in_array($group->id, $groupids)) {
1922                      throw new invalid_parameter_exception('Multiple grades for the same team have been supplied '
1923                                                            .' this is not permitted when the applytoall flag is set');
1924                  } else {
1925                      $groupids[] = $group->id;
1926                  }
1927              }
1928          }
1929  
1930          foreach ($params['grades'] as $gradeinfo) {
1931              $gradedata = (object)$gradeinfo['plugindata'];
1932              $gradedata->addattempt = $gradeinfo['addattempt'];
1933              $gradedata->attemptnumber = $gradeinfo['attemptnumber'];
1934              $gradedata->workflowstate = $gradeinfo['workflowstate'];
1935              $gradedata->applytoall = $params['applytoall'];
1936              $gradedata->grade = $gradeinfo['grade'];
1937  
1938              if (!empty($gradeinfo['advancedgradingdata'])) {
1939                  $advancedgrading = array();
1940                  $criteria = reset($gradeinfo['advancedgradingdata']);
1941                  foreach ($criteria as $key => $criterion) {
1942                      $details = array();
1943                      foreach ($criterion as $value) {
1944                          foreach ($value['fillings'] as $filling) {
1945                              $details[$value['criterionid']] = $filling;
1946                          }
1947                      }
1948                      $advancedgrading[$key] = $details;
1949                  }
1950                  $gradedata->advancedgrading = $advancedgrading;
1951              }
1952              $assignment->save_grade($gradeinfo['userid'], $gradedata);
1953          }
1954  
1955          return null;
1956      }
1957  
1958      /**
1959       * Describes the return value for save_grades
1960       *
1961       * @return external_single_structure
1962       * @since Moodle 2.7
1963       */
1964      public static function save_grades_returns() {
1965          return null;
1966      }
1967  
1968      /**
1969       * Describes the parameters for copy_previous_attempt
1970       * @return external_external_function_parameters
1971       * @since  Moodle 2.6
1972       */
1973      public static function copy_previous_attempt_parameters() {
1974          return new external_function_parameters(
1975              array(
1976                  'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
1977              )
1978          );
1979      }
1980  
1981      /**
1982       * Copy a students previous attempt to a new attempt.
1983       *
1984       * @param int $assignmentid
1985       * @return array of warnings to indicate any errors.
1986       * @since Moodle 2.6
1987       */
1988      public static function copy_previous_attempt($assignmentid) {
1989          global $CFG, $USER;
1990          require_once("$CFG->dirroot/mod/assign/locallib.php");
1991  
1992          $params = self::validate_parameters(self::copy_previous_attempt_parameters(),
1993                                              array('assignmentid' => $assignmentid));
1994  
1995          $cm = get_coursemodule_from_instance('assign', $assignmentid, 0, false, MUST_EXIST);
1996          $context = context_module::instance($cm->id);
1997          self::validate_context($context);
1998  
1999          $assignment = new assign($context, $cm, null);
2000  
2001          $notices = array();
2002  
2003          $assignment->copy_previous_attempt($submissiondata, $notices);
2004  
2005          $warnings = array();
2006          foreach ($notices as $notice) {
2007              $warnings[] = self::generate_warning($assignmentid,
2008                                                   'couldnotcopyprevioussubmission',
2009                                                   $notice);
2010          }
2011  
2012          return $warnings;
2013      }
2014  
2015      /**
2016       * Describes the return value for save_submission
2017       *
2018       * @return external_single_structure
2019       * @since Moodle 2.6
2020       */
2021      public static function copy_previous_attempt_returns() {
2022          return new external_multiple_structure(
2023             new external_warnings()
2024          );
2025      }
2026  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1