MDL-36804 Assignment - Make sure webservice only returns the last submission/grade.
[moodle.git] / mod / assign / externallib.php
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/>.
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  */
26 defined('MOODLE_INTERNAL') || die;
28 require_once("$CFG->libdir/externallib.php");
30 /**
31  * Assign functions
32  */
33 class mod_assign_external extends external_api {
35     /**
36      * Describes the parameters for get_grades
37      * @return external_external_function_parameters
38      * @since  Moodle 2.4
39      */
40     public static function get_grades_parameters() {
41         return new external_function_parameters(
42             array(
43                 'assignmentids' => new external_multiple_structure(
44                     new external_value(PARAM_INT, 'assignment id'),
45                     '1 or more assignment ids',
46                     VALUE_REQUIRED),
47                 'since' => new external_value(PARAM_INT,
48                           'timestamp, only return records where timemodified >= since',
49                           VALUE_DEFAULT, 0)
50             )
51         );
52     }
54     /**
55      * Returns grade information from assign_grades for the requested assignment ids
56      * @param array of ints $assignmentids
57      * @param int $since only return records with timemodified >= since
58      * @return array of grade records for each requested assignment
59      * @since  Moodle 2.4
60      */
61     public static function get_grades($assignmentids, $since = 0) {
62         global $DB;
63         $params = self::validate_parameters(self::get_grades_parameters(),
64                         array('assignmentids' => $assignmentids,
65                               'since' => $since));
67         $assignments = array();
68         $warnings = array();
69         $requestedassignmentids = $params['assignmentids'];
71         // Check the user is allowed to get the grades for the assignments requested.
72         $placeholders = array();
73         list($sqlassignmentids, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED);
74         $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module ".
75                "WHERE md.name = :modname AND cm.instance ".$sqlassignmentids;
76         $placeholders['modname'] = 'assign';
77         $cms = $DB->get_records_sql($sql, $placeholders);
78         foreach ($cms as $cm) {
79             try {
80                 $context = context_module::instance($cm->id);
81                 self::validate_context($context);
82                 require_capability('mod/assign:grade', $context);
83             } catch (Exception $e) {
84                 $requestedassignmentids = array_diff($requestedassignmentids, array($cm->instance));
85                 $warning = array();
86                 $warning['item'] = 'assignment';
87                 $warning['itemid'] = $cm->instance;
88                 $warning['warningcode'] = '1';
89                 $warning['message'] = 'No access rights in module context';
90                 $warnings[] = $warning;
91             }
92         }
94         // Create the query and populate an array of grade records from the recordset results.
95         if (count ($requestedassignmentids) > 0) {
96             $placeholders = array();
97             list($inorequalsql, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED);
98             list($inorequalsql2, $placeholders2) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED);
100             $grademaxattempt = 'SELECT mxg.userid, MAX(mxg.attemptnumber) AS maxattempt
101                                 FROM {assign_grades} mxg
102                                 WHERE mxg.assignment ' . $inorequalsql2 . ' GROUP BY mxg.userid';
104             $sql = "SELECT ag.id,ag.assignment,ag.userid,ag.timecreated,ag.timemodified,".
105                    "ag.grader,ag.grade ".
106                    "FROM {assign_grades} ag ".
107                    "JOIN ( " . $grademaxattempt . " ) gmx ON ag.userid = gmx.userid".
108                    " WHERE ag.assignment ".$inorequalsql.
109                    " AND ag.timemodified  >= :since".
110                    " AND ag.attemptnumber = gmx.maxattempt" .
111                    " ORDER BY ag.assignment, ag.id";
112             $placeholders['since'] = $params['since'];
113             // Combine the parameters.
114             $placeholders += $placeholders2;
115             $rs = $DB->get_recordset_sql($sql, $placeholders);
116             $currentassignmentid = null;
117             $assignment = null;
118             foreach ($rs as $rd) {
119                 $grade = array();
120                 $grade['id'] = $rd->id;
121                 $grade['userid'] = $rd->userid;
122                 $grade['timecreated'] = $rd->timecreated;
123                 $grade['timemodified'] = $rd->timemodified;
124                 $grade['grader'] = $rd->grader;
125                 $grade['grade'] = (string)$rd->grade;
127                 if (is_null($currentassignmentid) || ($rd->assignment != $currentassignmentid )) {
128                     if (!is_null($assignment)) {
129                         $assignments[] = $assignment;
130                     }
131                     $assignment = array();
132                     $assignment['assignmentid'] = $rd->assignment;
133                     $assignment['grades'] = array();
134                     $requestedassignmentids = array_diff($requestedassignmentids, array($rd->assignment));
135                 }
136                 $assignment['grades'][] = $grade;
138                 $currentassignmentid = $rd->assignment;
139             }
140             if (!is_null($assignment)) {
141                 $assignments[] = $assignment;
142             }
143             $rs->close();
144         }
145         foreach ($requestedassignmentids as $assignmentid) {
146             $warning = array();
147             $warning['item'] = 'assignment';
148             $warning['itemid'] = $assignmentid;
149             $warning['warningcode'] = '3';
150             $warning['message'] = 'No grades found';
151             $warnings[] = $warning;
152         }
154         $result = array();
155         $result['assignments'] = $assignments;
156         $result['warnings'] = $warnings;
157         return $result;
158     }
160     /**
161      * Creates an assign_grades external_single_structure
162      * @return external_single_structure
163      * @since  Moodle 2.4
164      */
165     private static function assign_grades() {
166         return new external_single_structure(
167             array (
168                 'assignmentid'    => new external_value(PARAM_INT, 'assignment id'),
169                 'grades'   => new external_multiple_structure(new external_single_structure(
170                         array(
171                             'id'            => new external_value(PARAM_INT, 'grade id'),
172                             'userid'        => new external_value(PARAM_INT, 'student id'),
173                             'timecreated'   => new external_value(PARAM_INT, 'grade creation time'),
174                             'timemodified'  => new external_value(PARAM_INT, 'grade last modified time'),
175                             'grader'        => new external_value(PARAM_INT, 'grader'),
176                             'grade'         => new external_value(PARAM_TEXT, 'grade')
177                         )
178                     )
179                 )
180             )
181         );
182     }
184     /**
185      * Describes the get_grades return value
186      * @return external_single_structure
187      * @since  Moodle 2.4
188      */
189     public static function get_grades_returns() {
190         return new external_single_structure(
191             array(
192                 'assignments' => new external_multiple_structure(self::assign_grades(), 'list of assignment grade information'),
193                 'warnings'      => new external_warnings('item is always \'assignment\'',
194                     'when errorcode is 3 then itemid is an assignment id. When errorcode is 1, itemid is a course module id',
195                     'errorcode can be 3 (no grades found) or 1 (no permission to get grades)')
196             )
197         );
198     }
200     /**
201      * Returns description of method parameters
202      *
203      * @return external_function_parameters
204      * @since  Moodle 2.4
205      */
206     public static function get_assignments_parameters() {
207         return new external_function_parameters(
208             array(
209                 'courseids' => new external_multiple_structure(
210                     new external_value(PARAM_INT, 'course id'),
211                     '0 or more course ids',
212                     VALUE_DEFAULT, array()
213                 ),
214                 'capabilities'  => new external_multiple_structure(
215                     new external_value(PARAM_CAPABILITY, 'capability'),
216                     'list of capabilities used to filter courses',
217                     VALUE_DEFAULT, array()
218                 )
219             )
220         );
221     }
223     /**
224      * Returns an array of courses the user is enrolled in, and for each course all of the assignments that the user can
225      * view within that course.
226      *
227      * @param array $courseids An optional array of course ids. If provided only assignments within the given course
228      * will be returned. If the user is not enrolled in a given course a warning will be generated and returned.
229      * @param array $capabilities An array of additional capability checks you wish to be made on the course context.
230      * @return An array of courses and warnings.
231      * @since  Moodle 2.4
232      */
233     public static function get_assignments($courseids = array(), $capabilities = array()) {
234         global $USER, $DB;
236         $params = self::validate_parameters(
237             self::get_assignments_parameters(),
238             array('courseids' => $courseids, 'capabilities' => $capabilities)
239         );
241         $warnings = array();
242         $fields = 'sortorder,shortname,fullname,timemodified';
243         $courses = enrol_get_users_courses($USER->id, true, $fields);
244         // Used to test for ids that have been requested but can't be returned.
245         if (count($params['courseids']) > 0) {
246             foreach ($params['courseids'] as $courseid) {
247                 if (!in_array($courseid, array_keys($courses))) {
248                     unset($courses[$courseid]);
249                     $warnings[] = array(
250                         'item' => 'course',
251                         'itemid' => $courseid,
252                         'warningcode' => '2',
253                         'message' => 'User is not enrolled or does not have requested capability'
254                     );
255                 }
256             }
257         }
258         foreach ($courses as $id => $course) {
259             if (count($params['courseids']) > 0 && !in_array($id, $params['courseids'])) {
260                 unset($courses[$id]);
261             }
262             $context = context_course::instance($id);
263             try {
264                 self::validate_context($context);
265             } catch (Exception $e) {
266                 unset($courses[$id]);
267                 $warnings[] = array(
268                     'item' => 'course',
269                     'itemid' => $id,
270                     'warningcode' => '1',
271                     'message' => 'No access rights in course context '.$e->getMessage().$e->getTraceAsString()
272                 );
273                 continue;
274             }
275             if (count($params['capabilities']) > 0 && !has_all_capabilities($params['capabilities'], $context)) {
276                 unset($courses[$id]);
277             }
278         }
279         $extrafields='m.id as assignmentid, m.course, m.nosubmissions, m.submissiondrafts, m.sendnotifications, '.
280                      'm.sendlatenotifications, m.duedate, m.allowsubmissionsfromdate, m.grade, m.timemodified, '.
281                      'm.completionsubmit, m.cutoffdate, m.teamsubmission, m.requireallteammemberssubmit, '.
282                      'm.teamsubmissiongroupingid, m.blindmarking, m.revealidentities, m.requiresubmissionstatement';
283         $coursearray = array();
284         foreach ($courses as $id => $course) {
285             $assignmentarray = array();
286             // Get a list of assignments for the course.
287             if ($modules = get_coursemodules_in_course('assign', $courses[$id]->id, $extrafields)) {
288                 foreach ($modules as $module) {
289                     $context = context_module::instance($module->id);
290                     try {
291                         self::validate_context($context);
292                         require_capability('mod/assign:view', $context);
293                     } catch (Exception $e) {
294                         $warnings[] = array(
295                             'item' => 'module',
296                             'itemid' => $module->id,
297                             'warningcode' => '1',
298                             'message' => 'No access rights in module context'
299                         );
300                         continue;
301                     }
302                     $configrecords = $DB->get_recordset('assign_plugin_config', array('assignment' => $module->assignmentid));
303                     $configarray = array();
304                     foreach ($configrecords as $configrecord) {
305                         $configarray[] = array(
306                             'id' => $configrecord->id,
307                             'assignment' => $configrecord->assignment,
308                             'plugin' => $configrecord->plugin,
309                             'subtype' => $configrecord->subtype,
310                             'name' => $configrecord->name,
311                             'value' => $configrecord->value
312                         );
313                     }
314                     $configrecords->close();
316                     $assignmentarray[]= array(
317                         'id' => $module->assignmentid,
318                         'cmid' => $module->id,
319                         'course' => $module->course,
320                         'name' => $module->name,
321                         'nosubmissions' => $module->nosubmissions,
322                         'submissiondrafts' => $module->submissiondrafts,
323                         'sendnotifications' => $module->sendnotifications,
324                         'sendlatenotifications' => $module->sendlatenotifications,
325                         'duedate' => $module->duedate,
326                         'allowsubmissionsfromdate' => $module->allowsubmissionsfromdate,
327                         'grade' => $module->grade,
328                         'timemodified' => $module->timemodified,
329                         'completionsubmit' => $module->completionsubmit,
330                         'cutoffdate' => $module->cutoffdate,
331                         'teamsubmission' => $module->teamsubmission,
332                         'requireallteammemberssubmit' => $module->requireallteammemberssubmit,
333                         'teamsubmissiongroupingid' => $module->teamsubmissiongroupingid,
334                         'blindmarking' => $module->blindmarking,
335                         'revealidentities' => $module->revealidentities,
336                         'requiresubmissionstatement' => $module->requiresubmissionstatement,
337                         'configs' => $configarray
338                     );
339                 }
340             }
341             $coursearray[]= array(
342                 'id' => $courses[$id]->id,
343                 'fullname' => $courses[$id]->fullname,
344                 'shortname' => $courses[$id]->shortname,
345                 'timemodified' => $courses[$id]->timemodified,
346                 'assignments' => $assignmentarray
347             );
348         }
350         $result = array(
351             'courses' => $coursearray,
352             'warnings' => $warnings
353         );
354         return $result;
355     }
357     /**
358      * Creates an assignment external_single_structure
359      *
360      * @return external_single_structure
361      * @since Moodle 2.4
362      */
363     private static function get_assignments_assignment_structure() {
364         return new external_single_structure(
365             array(
366                 'id' => new external_value(PARAM_INT, 'assignment id'),
367                 'course' => new external_value(PARAM_INT, 'course id'),
368                 'name' => new external_value(PARAM_TEXT, 'assignment name'),
369                 'nosubmissions' => new external_value(PARAM_INT, 'no submissions'),
370                 'submissiondrafts' => new external_value(PARAM_INT, 'submissions drafts'),
371                 'sendnotifications' => new external_value(PARAM_INT, 'send notifications'),
372                 'sendlatenotifications' => new external_value(PARAM_INT, 'send notifications'),
373                 'duedate' => new external_value(PARAM_INT, 'assignment due date'),
374                 'allowsubmissionsfromdate' => new external_value(PARAM_INT, 'allow submissions from date'),
375                 'grade' => new external_value(PARAM_INT, 'grade type'),
376                 'timemodified' => new external_value(PARAM_INT, 'last time assignment was modified'),
377                 'completionsubmit' => new external_value(PARAM_INT, 'if enabled, set activity as complete following submission'),
378                 'cutoffdate' => new external_value(PARAM_INT, 'date after which submission is not accepted without an extension'),
379                 'teamsubmission' => new external_value(PARAM_INT, 'if enabled, students submit as a team'),
380                 'requireallteammemberssubmit' => new external_value(PARAM_INT, 'if enabled, all team members must submit'),
381                 'teamsubmissiongroupingid' => new external_value(PARAM_INT, 'the grouping id for the team submission groups'),
382                 'blindmarking' => new external_value(PARAM_INT, 'if enabled, hide identities until reveal identities actioned'),
383                 'revealidentities' => new external_value(PARAM_INT, 'show identities for a blind marking assignment'),
384                 'requiresubmissionstatement' => new external_value(PARAM_INT, 'student must accept submission statement'),
385                 'configs' => new external_multiple_structure(self::get_assignments_config_structure(), 'configuration settings')
386             ), 'assignment information object');
387     }
389     /**
390      * Creates an assign_plugin_config external_single_structure
391      *
392      * @return external_single_structure
393      * @since Moodle 2.4
394      */
395     private static function get_assignments_config_structure() {
396         return new external_single_structure(
397             array(
398                 'id' => new external_value(PARAM_INT, 'assign_plugin_config id'),
399                 'assignment' => new external_value(PARAM_INT, 'assignment id'),
400                 'plugin' => new external_value(PARAM_TEXT, 'plugin'),
401                 'subtype' => new external_value(PARAM_TEXT, 'subtype'),
402                 'name' => new external_value(PARAM_TEXT, 'name'),
403                 'value' => new external_value(PARAM_TEXT, 'value')
404             ), 'assignment configuration object'
405         );
406     }
408     /**
409      * Creates a course external_single_structure
410      *
411      * @return external_single_structure
412      * @since Moodle 2.4
413      */
414     private static function get_assignments_course_structure() {
415         return new external_single_structure(
416             array(
417                 'id' => new external_value(PARAM_INT, 'course id'),
418                 'fullname' => new external_value(PARAM_TEXT, 'course full name'),
419                 'shortname' => new external_value(PARAM_TEXT, 'course short name'),
420                 'timemodified' => new external_value(PARAM_INT, 'last time modified'),
421                 'assignments' => new external_multiple_structure(self::get_assignments_assignment_structure(), 'assignment info')
422               ), 'course information object'
423         );
424     }
426     /**
427      * Describes the return value for get_assignments
428      *
429      * @return external_single_structure
430      * @since Moodle 2.4
431      */
432     public static function get_assignments_returns() {
433         return new external_single_structure(
434             array(
435                 'courses' => new external_multiple_structure(self::get_assignments_course_structure(), 'list of courses'),
436                 'warnings'  => new external_warnings('item can be \'course\' (errorcode 1 or 2) or \'module\' (errorcode 1)',
437                     'When item is a course then itemid is a course id. When the item is a module then itemid is a module id',
438                     'errorcode can be 1 (no access rights) or 2 (not enrolled or no permissions)')
439             )
440         );
441     }
443     /**
444      * Describes the parameters for get_submissions
445      *
446      * @return external_external_function_parameters
447      * @since Moodle 2.5
448      */
449     public static function get_submissions_parameters() {
450         return new external_function_parameters(
451             array(
452                 'assignmentids' => new external_multiple_structure(
453                     new external_value(PARAM_INT, 'assignment id'),
454                     '1 or more assignment ids',
455                     VALUE_REQUIRED),
456                 'status' => new external_value(PARAM_ALPHA, 'status', VALUE_DEFAULT, ''),
457                 'since' => new external_value(PARAM_INT, 'submitted since', VALUE_DEFAULT, 0),
458                 'before' => new external_value(PARAM_INT, 'submitted before', VALUE_DEFAULT, 0)
459             )
460         );
461     }
463     /**
464      * Returns submissions for the requested assignment ids
465      *
466      * @param array of ints $assignmentids
467      * @param string $status only return submissions with this status
468      * @param int $since only return submissions with timemodified >= since
469      * @param int $before only return submissions with timemodified <= before
470      * @return array of submissions for each requested assignment
471      * @since Moodle 2.5
472      */
473     public static function get_submissions($assignmentids, $status = '', $since = 0, $before = 0) {
474         global $DB, $CFG;
475         require_once("$CFG->dirroot/mod/assign/locallib.php");
476         $params = self::validate_parameters(self::get_submissions_parameters(),
477                         array('assignmentids' => $assignmentids,
478                               'status' => $status,
479                               'since' => $since,
480                               'before' => $before));
482         $warnings = array();
483         $assignments = array();
485         // Check the user is allowed to get the submissions for the assignments requested.
486         $placeholders = array();
487         list($inorequalsql, $placeholders) = $DB->get_in_or_equal($params['assignmentids'], SQL_PARAMS_NAMED);
488         $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module ".
489                "WHERE md.name = :modname AND cm.instance ".$inorequalsql;
490         $placeholders['modname'] = 'assign';
491         $cms = $DB->get_records_sql($sql, $placeholders);
492         $assigns = array();
493         foreach ($cms as $cm) {
494             try {
495                 $context = context_module::instance($cm->id);
496                 self::validate_context($context);
497                 require_capability('mod/assign:grade', $context);
498                 $assign = new assign($context, null, null);
499                 $assigns[] = $assign;
500             } catch (Exception $e) {
501                 $warnings[] = array(
502                     'item' => 'assignment',
503                     'itemid' => $cm->instance,
504                     'warningcode' => '1',
505                     'message' => 'No access rights in module context'
506                 );
507             }
508         }
510         foreach ($assigns as $assign) {
511             $submissions = array();
512             $submissionplugins = $assign->get_submission_plugins();
513             $placeholders = array('assignid1' => $assign->get_instance()->id,
514                                   'assignid2' => $assign->get_instance()->id);
516             $submissionmaxattempt = 'SELECT mxs.userid, MAX(mxs.attemptnumber) AS maxattempt
517                                      FROM {assign_submission} mxs
518                                      WHERE mxs.assignment = :assignid1 GROUP BY mxs.userid';
520             $sql = "SELECT mas.id, mas.assignment,mas.userid,".
521                    "mas.timecreated,mas.timemodified,mas.status,mas.groupid ".
522                    "FROM {assign_submission} mas ".
523                    "JOIN ( " . $submissionmaxattempt . " ) smx ON mas.userid = smx.userid ".
524                    "WHERE mas.assignment = :assignid2 AND mas.attemptnumber = smx.maxattempt";
526             if (!empty($params['status'])) {
527                 $placeholders['status'] = $params['status'];
528                 $sql = $sql." AND mas.status = :status";
529             }
530             if (!empty($params['before'])) {
531                 $placeholders['since'] = $params['since'];
532                 $placeholders['before'] = $params['before'];
533                 $sql = $sql." AND mas.timemodified BETWEEN :since AND :before";
534             } else {
535                 $placeholders['since'] = $params['since'];
536                 $sql = $sql." AND mas.timemodified >= :since";
537             }
539             $submissionrecords = $DB->get_records_sql($sql, $placeholders);
541             if (!empty($submissionrecords)) {
542                 $fs = get_file_storage();
543                 foreach ($submissionrecords as $submissionrecord) {
544                     $submission = array(
545                         'id' => $submissionrecord->id,
546                         'userid' => $submissionrecord->userid,
547                         'timecreated' => $submissionrecord->timecreated,
548                         'timemodified' => $submissionrecord->timemodified,
549                         'status' => $submissionrecord->status,
550                         'groupid' => $submissionrecord->groupid
551                     );
552                     foreach ($submissionplugins as $submissionplugin) {
553                         $plugin = array(
554                             'name' => $submissionplugin->get_name(),
555                             'type' => $submissionplugin->get_type()
556                         );
557                         // Subtype is 'assignsubmission', type is currently 'file' or 'onlinetext'.
558                         $component = $submissionplugin->get_subtype().'_'.$submissionplugin->get_type();
560                         $fileareas = $submissionplugin->get_file_areas();
561                         foreach ($fileareas as $filearea => $name) {
562                             $fileareainfo = array('area' => $filearea);
563                             $files = $fs->get_area_files(
564                                 $assign->get_context()->id,
565                                 $component,
566                                 $filearea,
567                                 $submissionrecord->id,
568                                 "timemodified",
569                                 false
570                             );
571                             foreach ($files as $file) {
572                                 $filepath = array('filepath' => $file->get_filepath().$file->get_filename());
573                                 $fileareainfo['files'][] = $filepath;
574                             }
575                             $plugin['fileareas'][] = $fileareainfo;
576                         }
578                         $editorfields = $submissionplugin->get_editor_fields();
579                         foreach ($editorfields as $name => $description) {
580                             $editorfieldinfo = array(
581                                 'name' => $name,
582                                 'description' => $description,
583                                 'text' => $submissionplugin->get_editor_text($name, $submissionrecord->id),
584                                 'format' => $submissionplugin->get_editor_format($name, $submissionrecord->id)
585                             );
586                             $plugin['editorfields'][] = $editorfieldinfo;
587                         }
589                         $submission['plugins'][] = $plugin;
590                     }
591                     $submissions[] = $submission;
592                 }
593             } else {
594                 $warnings[] = array(
595                     'item' => 'module',
596                     'itemid' => $assign->get_instance()->id,
597                     'warningcode' => '3',
598                     'message' => 'No submissions found'
599                 );
600             }
602             $assignments[] = array(
603                 'assignmentid' => $assign->get_instance()->id,
604                 'submissions' => $submissions
605             );
607         }
609         $result = array(
610             'assignments' => $assignments,
611             'warnings' => $warnings
612         );
613         return $result;
614     }
616     /**
617      * Creates an assign_submissions external_single_structure
618      *
619      * @return external_single_structure
620      * @since Moodle 2.5
621      */
622     private static function get_submissions_structure() {
623         return new external_single_structure(
624             array (
625                 'assignmentid' => new external_value(PARAM_INT, 'assignment id'),
626                 'submissions' => new external_multiple_structure(
627                     new external_single_structure(
628                         array(
629                             'id' => new external_value(PARAM_INT, 'submission id'),
630                             'userid' => new external_value(PARAM_INT, 'student id'),
631                             'timecreated' => new external_value(PARAM_INT, 'submission creation time'),
632                             'timemodified' => new external_value(PARAM_INT, 'submission last modified time'),
633                             'status' => new external_value(PARAM_TEXT, 'submission status'),
634                             'groupid' => new external_value(PARAM_INT, 'group id'),
635                             'plugins' => new external_multiple_structure(
636                                 new external_single_structure(
637                                     array(
638                                         'type' => new external_value(PARAM_TEXT, 'submission plugin type'),
639                                         'name' => new external_value(PARAM_TEXT, 'submission plugin name'),
640                                         'fileareas' => new external_multiple_structure(
641                                             new external_single_structure(
642                                                 array (
643                                                     'area' => new external_value (PARAM_TEXT, 'file area'),
644                                                     'files' => new external_multiple_structure(
645                                                         new external_single_structure(
646                                                             array (
647                                                                 'filepath' => new external_value (PARAM_TEXT, 'file path')
648                                                             )
649                                                         ), 'files', VALUE_OPTIONAL
650                                                     )
651                                                 )
652                                             ), 'fileareas', VALUE_OPTIONAL
653                                         ),
654                                         'editorfields' => new external_multiple_structure(
655                                             new external_single_structure(
656                                                 array(
657                                                     'name' => new external_value(PARAM_TEXT, 'field name'),
658                                                     'description' => new external_value(PARAM_TEXT, 'field description'),
659                                                     'text' => new external_value (PARAM_RAW, 'field value'),
660                                                     'format' => new external_format_value ('text')
661                                                 )
662                                             )
663                                             , 'editorfields', VALUE_OPTIONAL
664                                         )
665                                     )
666                                 )
667                                 , 'plugins', VALUE_OPTIONAL
668                             )
669                         )
670                     )
671                 )
672             )
673         );
674     }
676     /**
677      * Describes the get_submissions return value
678      *
679      * @return external_single_structure
680      * @since Moodle 2.5
681      */
682     public static function get_submissions_returns() {
683         return new external_single_structure(
684             array(
685                 'assignments' => new external_multiple_structure(self::get_submissions_structure(), 'assignment submissions'),
686                 'warnings' => new external_warnings()
687             )
688         );
689     }