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