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