Search moodle.org's
Developer Documentation


  • Bug fixes for general core bugs in 2.8.x ended 9 November 2015 (12 months).
  • Bug fixes for security issues in 2.8.x ended 9 May 2016 (18 months).
  • minimum PHP 5.4.4 (always use latest PHP 5.4.x or 5.5.x on Windows - http://windows.php.net/download/), PHP 7 is NOT supported
  • Differences Between: [Versions 28 and 29] [Versions 28 and 30] [Versions 28 and 31] [Versions 28 and 32] [Versions 28 and 33] [Versions 28 and 34] [Versions 28 and 35] [Versions 28 and 36] [Versions 28 and 37]

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

    Search This Site: