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