2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
22 * @copyright 2012 Paul Charsley
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') ||
die;
28 require_once("$CFG->libdir/externallib.php");
32 * @copyright 2012 Paul Charsley
33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 class mod_assign_external
extends external_api
{
38 * Generate a warning in a standard structure for a known failure.
40 * @param int $assignmentid - The assignment
41 * @param string $warningcode - The key for the warning message
42 * @param string $detail - A description of the error
43 * @return array - Warning structure containing item, itemid, warningcode, message
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.'
58 $message = $warningmessages[$warningcode];
59 if (empty($message)) {
60 $message = 'Unknown warning type.';
63 return array('item'=>$detail,
64 'itemid'=>$assignmentid,
65 'warningcode'=>$warningcode,
70 * Describes the parameters for get_grades
71 * @return external_external_function_parameters
74 public static function get_grades_parameters() {
75 return new external_function_parameters(
77 'assignmentids' => new external_multiple_structure(
78 new external_value(PARAM_INT
, 'assignment id'),
79 '1 or more assignment ids',
81 'since' => new external_value(PARAM_INT
,
82 'timestamp, only return records where timemodified >= since',
89 * Returns grade information from assign_grades for the requested assignment ids
90 * @param int[] $assignmentids
91 * @param int $since only return records with timemodified >= since
92 * @return array of grade records for each requested assignment
95 public static function get_grades($assignmentids, $since = 0) {
97 $params = self
::validate_parameters(self
::get_grades_parameters(),
98 array('assignmentids' => $assignmentids,
101 $assignments = array();
103 $requestedassignmentids = $params['assignmentids'];
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) {
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
));
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;
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
);
133 $sql = "SELECT ag.id,
141 FROM {assign_grades} ag, {assign_submission} s
142 WHERE s.assignment $inorequalsql
143 AND s.userid = ag.userid
145 AND s.attemptnumber = ag.attemptnumber
146 AND ag.timemodified >= :since
147 AND ag.assignment = s.assignment
148 ORDER BY ag.assignment, ag.id";
150 $placeholders['since'] = $params['since'];
151 $rs = $DB->get_recordset_sql($sql, $placeholders);
152 $currentassignmentid = null;
154 foreach ($rs as $rd) {
156 $grade['id'] = $rd->id
;
157 $grade['userid'] = $rd->userid
;
158 $grade['timecreated'] = $rd->timecreated
;
159 $grade['timemodified'] = $rd->timemodified
;
160 $grade['grader'] = $rd->grader
;
161 $grade['attemptnumber'] = $rd->attemptnumber
;
162 $grade['grade'] = (string)$rd->grade
;
164 if (is_null($currentassignmentid) ||
($rd->assignment
!= $currentassignmentid )) {
165 if (!is_null($assignment)) {
166 $assignments[] = $assignment;
168 $assignment = array();
169 $assignment['assignmentid'] = $rd->assignment
;
170 $assignment['grades'] = array();
171 $requestedassignmentids = array_diff($requestedassignmentids, array($rd->assignment
));
173 $assignment['grades'][] = $grade;
175 $currentassignmentid = $rd->assignment
;
177 if (!is_null($assignment)) {
178 $assignments[] = $assignment;
182 foreach ($requestedassignmentids as $assignmentid) {
184 $warning['item'] = 'assignment';
185 $warning['itemid'] = $assignmentid;
186 $warning['warningcode'] = '3';
187 $warning['message'] = 'No grades found';
188 $warnings[] = $warning;
192 $result['assignments'] = $assignments;
193 $result['warnings'] = $warnings;
198 * Creates an assign_grades external_single_structure
199 * @return external_single_structure
202 private static function assign_grades() {
203 return new external_single_structure(
205 'assignmentid' => new external_value(PARAM_INT
, 'assignment id'),
206 'grades' => new external_multiple_structure(new external_single_structure(
208 'id' => new external_value(PARAM_INT
, 'grade id'),
209 'userid' => new external_value(PARAM_INT
, 'student id'),
210 'attemptnumber' => new external_value(PARAM_INT
, 'attempt number'),
211 'timecreated' => new external_value(PARAM_INT
, 'grade creation time'),
212 'timemodified' => new external_value(PARAM_INT
, 'grade last modified time'),
213 'grader' => new external_value(PARAM_INT
, 'grader'),
214 'grade' => new external_value(PARAM_TEXT
, 'grade')
223 * Describes the get_grades return value
224 * @return external_single_structure
227 public static function get_grades_returns() {
228 return new external_single_structure(
230 'assignments' => new external_multiple_structure(self
::assign_grades(), 'list of assignment grade information'),
231 'warnings' => new external_warnings('item is always \'assignment\'',
232 'when errorcode is 3 then itemid is an assignment id. When errorcode is 1, itemid is a course module id',
233 'errorcode can be 3 (no grades found) or 1 (no permission to get grades)')
239 * Returns description of method parameters
241 * @return external_function_parameters
244 public static function get_assignments_parameters() {
245 return new external_function_parameters(
247 'courseids' => new external_multiple_structure(
248 new external_value(PARAM_INT
, 'course id'),
249 '0 or more course ids',
250 VALUE_DEFAULT
, array()
252 'capabilities' => new external_multiple_structure(
253 new external_value(PARAM_CAPABILITY
, 'capability'),
254 'list of capabilities used to filter courses',
255 VALUE_DEFAULT
, array()
262 * Returns an array of courses the user is enrolled in, and for each course all of the assignments that the user can
263 * view within that course.
265 * @param array $courseids An optional array of course ids. If provided only assignments within the given course
266 * will be returned. If the user is not enrolled in a given course a warning will be generated and returned.
267 * @param array $capabilities An array of additional capability checks you wish to be made on the course context.
268 * @return An array of courses and warnings.
271 public static function get_assignments($courseids = array(), $capabilities = array()) {
272 global $USER, $DB, $CFG;
273 require_once("$CFG->dirroot/mod/assign/locallib.php");
275 $params = self
::validate_parameters(
276 self
::get_assignments_parameters(),
277 array('courseids' => $courseids, 'capabilities' => $capabilities)
281 $fields = 'sortorder,shortname,fullname,timemodified';
282 $courses = enrol_get_users_courses($USER->id
, true, $fields);
283 // Used to test for ids that have been requested but can't be returned.
284 if (count($params['courseids']) > 0) {
285 foreach ($params['courseids'] as $courseid) {
286 if (!in_array($courseid, array_keys($courses))) {
287 unset($courses[$courseid]);
290 'itemid' => $courseid,
291 'warningcode' => '2',
292 'message' => 'User is not enrolled or does not have requested capability'
297 foreach ($courses as $id => $course) {
298 if (count($params['courseids']) > 0 && !in_array($id, $params['courseids'])) {
299 unset($courses[$id]);
301 $context = context_course
::instance($id);
303 self
::validate_context($context);
304 } catch (Exception
$e) {
305 unset($courses[$id]);
309 'warningcode' => '1',
310 'message' => 'No access rights in course context '.$e->getMessage().$e->getTraceAsString()
314 if (count($params['capabilities']) > 0 && !has_all_capabilities($params['capabilities'], $context)) {
315 unset($courses[$id]);
318 $extrafields='m.id as assignmentid, ' .
320 'm.nosubmissions, ' .
321 'm.submissiondrafts, ' .
322 'm.sendnotifications, '.
323 'm.sendlatenotifications, ' .
324 'm.sendstudentnotifications, ' .
326 'm.allowsubmissionsfromdate, '.
329 'm.completionsubmit, ' .
331 'm.teamsubmission, ' .
332 'm.requireallteammemberssubmit, '.
333 'm.teamsubmissiongroupingid, ' .
335 'm.revealidentities, ' .
336 'm.attemptreopenmethod, '.
338 'm.markingworkflow, ' .
339 'm.markingallocation, ' .
340 'm.requiresubmissionstatement, '.
343 $coursearray = array();
344 foreach ($courses as $id => $course) {
345 $assignmentarray = array();
346 // Get a list of assignments for the course.
347 if ($modules = get_coursemodules_in_course('assign', $courses[$id]->id
, $extrafields)) {
348 foreach ($modules as $module) {
349 $context = context_module
::instance($module->id
);
351 self
::validate_context($context);
352 require_capability('mod/assign:view', $context);
353 } catch (Exception
$e) {
356 'itemid' => $module->id
,
357 'warningcode' => '1',
358 'message' => 'No access rights in module context'
362 $configrecords = $DB->get_recordset('assign_plugin_config', array('assignment' => $module->assignmentid
));
363 $configarray = array();
364 foreach ($configrecords as $configrecord) {
365 $configarray[] = array(
366 'id' => $configrecord->id
,
367 'assignment' => $configrecord->assignment
,
368 'plugin' => $configrecord->plugin
,
369 'subtype' => $configrecord->subtype
,
370 'name' => $configrecord->name
,
371 'value' => $configrecord->value
374 $configrecords->close();
377 'id' => $module->assignmentid
,
378 'cmid' => $module->id
,
379 'course' => $module->course
,
380 'name' => $module->name
,
381 'nosubmissions' => $module->nosubmissions
,
382 'submissiondrafts' => $module->submissiondrafts
,
383 'sendnotifications' => $module->sendnotifications
,
384 'sendlatenotifications' => $module->sendlatenotifications
,
385 'sendstudentnotifications' => $module->sendstudentnotifications
,
386 'duedate' => $module->duedate
,
387 'allowsubmissionsfromdate' => $module->allowsubmissionsfromdate
,
388 'grade' => $module->grade
,
389 'timemodified' => $module->timemodified
,
390 'completionsubmit' => $module->completionsubmit
,
391 'cutoffdate' => $module->cutoffdate
,
392 'teamsubmission' => $module->teamsubmission
,
393 'requireallteammemberssubmit' => $module->requireallteammemberssubmit
,
394 'teamsubmissiongroupingid' => $module->teamsubmissiongroupingid
,
395 'blindmarking' => $module->blindmarking
,
396 'revealidentities' => $module->revealidentities
,
397 'attemptreopenmethod' => $module->attemptreopenmethod
,
398 'maxattempts' => $module->maxattempts
,
399 'markingworkflow' => $module->markingworkflow
,
400 'markingallocation' => $module->markingallocation
,
401 'requiresubmissionstatement' => $module->requiresubmissionstatement
,
402 'configs' => $configarray
405 // Return or not intro and file attachments depending on the plugin settings.
406 $assign = new assign($context, null, null);
408 if ($assign->show_intro()) {
410 list($assignment['intro'], $assignment['introformat']) = external_format_text($module->intro
,
411 $module->introformat
, $context->id
, 'mod_assign', ASSIGN_INTROATTACHMENT_FILEAREA
, 0);
413 $fs = get_file_storage();
414 if ($files = $fs->get_area_files($context->id
, 'mod_assign', ASSIGN_INTROATTACHMENT_FILEAREA
,
415 0, 'timemodified', false)) {
417 $assignment['introattachments'] = array();
418 foreach ($files as $file) {
419 $filename = $file->get_filename();
421 $assignment['introattachments'][] = array(
422 'filename' => $filename,
423 'mimetype' => $file->get_mimetype(),
424 'fileurl' => moodle_url
::make_webservice_pluginfile_url(
425 $context->id
, 'mod_assign', ASSIGN_INTROATTACHMENT_FILEAREA
, 0, '/', $filename)->out(false)
431 $assignmentarray[] = $assignment;
434 $coursearray[]= array(
435 'id' => $courses[$id]->id
,
436 'fullname' => $courses[$id]->fullname
,
437 'shortname' => $courses[$id]->shortname
,
438 'timemodified' => $courses[$id]->timemodified
,
439 'assignments' => $assignmentarray
444 'courses' => $coursearray,
445 'warnings' => $warnings
451 * Creates an assignment external_single_structure
453 * @return external_single_structure
456 private static function get_assignments_assignment_structure() {
457 return new external_single_structure(
459 'id' => new external_value(PARAM_INT
, 'assignment id'),
460 'cmid' => new external_value(PARAM_INT
, 'course module id'),
461 'course' => new external_value(PARAM_INT
, 'course id'),
462 'name' => new external_value(PARAM_TEXT
, 'assignment name'),
463 'nosubmissions' => new external_value(PARAM_INT
, 'no submissions'),
464 'submissiondrafts' => new external_value(PARAM_INT
, 'submissions drafts'),
465 'sendnotifications' => new external_value(PARAM_INT
, 'send notifications'),
466 'sendlatenotifications' => new external_value(PARAM_INT
, 'send notifications'),
467 'sendstudentnotifications' => new external_value(PARAM_INT
, 'send student notifications (default)'),
468 'duedate' => new external_value(PARAM_INT
, 'assignment due date'),
469 'allowsubmissionsfromdate' => new external_value(PARAM_INT
, 'allow submissions from date'),
470 'grade' => new external_value(PARAM_INT
, 'grade type'),
471 'timemodified' => new external_value(PARAM_INT
, 'last time assignment was modified'),
472 'completionsubmit' => new external_value(PARAM_INT
, 'if enabled, set activity as complete following submission'),
473 'cutoffdate' => new external_value(PARAM_INT
, 'date after which submission is not accepted without an extension'),
474 'teamsubmission' => new external_value(PARAM_INT
, 'if enabled, students submit as a team'),
475 'requireallteammemberssubmit' => new external_value(PARAM_INT
, 'if enabled, all team members must submit'),
476 'teamsubmissiongroupingid' => new external_value(PARAM_INT
, 'the grouping id for the team submission groups'),
477 'blindmarking' => new external_value(PARAM_INT
, 'if enabled, hide identities until reveal identities actioned'),
478 'revealidentities' => new external_value(PARAM_INT
, 'show identities for a blind marking assignment'),
479 'attemptreopenmethod' => new external_value(PARAM_TEXT
, 'method used to control opening new attempts'),
480 'maxattempts' => new external_value(PARAM_INT
, 'maximum number of attempts allowed'),
481 'markingworkflow' => new external_value(PARAM_INT
, 'enable marking workflow'),
482 'markingallocation' => new external_value(PARAM_INT
, 'enable marking allocation'),
483 'requiresubmissionstatement' => new external_value(PARAM_INT
, 'student must accept submission statement'),
484 'configs' => new external_multiple_structure(self
::get_assignments_config_structure(), 'configuration settings'),
485 'intro' => new external_value(PARAM_RAW
,
486 'assignment intro, not allways returned because it deppends on the activity configuration', VALUE_OPTIONAL
),
487 'introformat' => new external_format_value('intro', VALUE_OPTIONAL
),
488 'introattachments' => new external_multiple_structure(
489 new external_single_structure(
491 'filename' => new external_value(PARAM_FILE
, 'file name'),
492 'mimetype' => new external_value(PARAM_RAW
, 'mime type'),
493 'fileurl' => new external_value(PARAM_URL
, 'file download url')
495 ), 'intro attachments files', VALUE_OPTIONAL
497 ), 'assignment information object');
501 * Creates an assign_plugin_config external_single_structure
503 * @return external_single_structure
506 private static function get_assignments_config_structure() {
507 return new external_single_structure(
509 'id' => new external_value(PARAM_INT
, 'assign_plugin_config id'),
510 'assignment' => new external_value(PARAM_INT
, 'assignment id'),
511 'plugin' => new external_value(PARAM_TEXT
, 'plugin'),
512 'subtype' => new external_value(PARAM_TEXT
, 'subtype'),
513 'name' => new external_value(PARAM_TEXT
, 'name'),
514 'value' => new external_value(PARAM_TEXT
, 'value')
515 ), 'assignment configuration object'
520 * Creates a course external_single_structure
522 * @return external_single_structure
525 private static function get_assignments_course_structure() {
526 return new external_single_structure(
528 'id' => new external_value(PARAM_INT
, 'course id'),
529 'fullname' => new external_value(PARAM_TEXT
, 'course full name'),
530 'shortname' => new external_value(PARAM_TEXT
, 'course short name'),
531 'timemodified' => new external_value(PARAM_INT
, 'last time modified'),
532 'assignments' => new external_multiple_structure(self
::get_assignments_assignment_structure(), 'assignment info')
533 ), 'course information object'
538 * Describes the return value for get_assignments
540 * @return external_single_structure
543 public static function get_assignments_returns() {
544 return new external_single_structure(
546 'courses' => new external_multiple_structure(self
::get_assignments_course_structure(), 'list of courses'),
547 'warnings' => new external_warnings('item can be \'course\' (errorcode 1 or 2) or \'module\' (errorcode 1)',
548 'When item is a course then itemid is a course id. When the item is a module then itemid is a module id',
549 'errorcode can be 1 (no access rights) or 2 (not enrolled or no permissions)')
555 * Describes the parameters for get_submissions
557 * @return external_external_function_parameters
560 public static function get_submissions_parameters() {
561 return new external_function_parameters(
563 'assignmentids' => new external_multiple_structure(
564 new external_value(PARAM_INT
, 'assignment id'),
565 '1 or more assignment ids',
567 'status' => new external_value(PARAM_ALPHA
, 'status', VALUE_DEFAULT
, ''),
568 'since' => new external_value(PARAM_INT
, 'submitted since', VALUE_DEFAULT
, 0),
569 'before' => new external_value(PARAM_INT
, 'submitted before', VALUE_DEFAULT
, 0)
575 * Returns submissions for the requested assignment ids
577 * @param int[] $assignmentids
578 * @param string $status only return submissions with this status
579 * @param int $since only return submissions with timemodified >= since
580 * @param int $before only return submissions with timemodified <= before
581 * @return array of submissions for each requested assignment
584 public static function get_submissions($assignmentids, $status = '', $since = 0, $before = 0) {
586 require_once("$CFG->dirroot/mod/assign/locallib.php");
587 $params = self
::validate_parameters(self
::get_submissions_parameters(),
588 array('assignmentids' => $assignmentids,
591 'before' => $before));
594 $assignments = array();
596 // Check the user is allowed to get the submissions for the assignments requested.
597 $placeholders = array();
598 list($inorequalsql, $placeholders) = $DB->get_in_or_equal($params['assignmentids'], SQL_PARAMS_NAMED
);
599 $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module ".
600 "WHERE md.name = :modname AND cm.instance ".$inorequalsql;
601 $placeholders['modname'] = 'assign';
602 $cms = $DB->get_records_sql($sql, $placeholders);
604 foreach ($cms as $cm) {
606 $context = context_module
::instance($cm->id
);
607 self
::validate_context($context);
608 require_capability('mod/assign:grade', $context);
609 $assign = new assign($context, null, null);
610 $assigns[] = $assign;
611 } catch (Exception
$e) {
613 'item' => 'assignment',
614 'itemid' => $cm->instance
,
615 'warningcode' => '1',
616 'message' => 'No access rights in module context'
621 foreach ($assigns as $assign) {
622 $submissions = array();
623 $submissionplugins = $assign->get_submission_plugins();
624 $placeholders = array('assignid1' => $assign->get_instance()->id
,
625 'assignid2' => $assign->get_instance()->id
);
627 $submissionmaxattempt = 'SELECT mxs.userid, MAX(mxs.attemptnumber) AS maxattempt
628 FROM {assign_submission} mxs
629 WHERE mxs.assignment = :assignid1 GROUP BY mxs.userid';
631 $sql = "SELECT mas.id, mas.assignment,mas.userid,".
632 "mas.timecreated,mas.timemodified,mas.status,mas.groupid,mas.attemptnumber ".
633 "FROM {assign_submission} mas ".
634 "JOIN ( " . $submissionmaxattempt . " ) smx ON mas.userid = smx.userid ".
635 "WHERE mas.assignment = :assignid2 AND mas.attemptnumber = smx.maxattempt";
637 if (!empty($params['status'])) {
638 $placeholders['status'] = $params['status'];
639 $sql = $sql." AND mas.status = :status";
641 if (!empty($params['before'])) {
642 $placeholders['since'] = $params['since'];
643 $placeholders['before'] = $params['before'];
644 $sql = $sql." AND mas.timemodified BETWEEN :since AND :before";
646 $placeholders['since'] = $params['since'];
647 $sql = $sql." AND mas.timemodified >= :since";
650 $submissionrecords = $DB->get_records_sql($sql, $placeholders);
652 if (!empty($submissionrecords)) {
653 $fs = get_file_storage();
654 foreach ($submissionrecords as $submissionrecord) {
656 'id' => $submissionrecord->id
,
657 'userid' => $submissionrecord->userid
,
658 'timecreated' => $submissionrecord->timecreated
,
659 'timemodified' => $submissionrecord->timemodified
,
660 'status' => $submissionrecord->status
,
661 'attemptnumber' => $submissionrecord->attemptnumber
,
662 'groupid' => $submissionrecord->groupid
664 foreach ($submissionplugins as $submissionplugin) {
666 'name' => $submissionplugin->get_name(),
667 'type' => $submissionplugin->get_type()
669 // Subtype is 'assignsubmission', type is currently 'file' or 'onlinetext'.
670 $component = $submissionplugin->get_subtype().'_'.$submissionplugin->get_type();
672 $fileareas = $submissionplugin->get_file_areas();
673 foreach ($fileareas as $filearea => $name) {
674 $fileareainfo = array('area' => $filearea);
675 $files = $fs->get_area_files(
676 $assign->get_context()->id
,
679 $submissionrecord->id
,
683 foreach ($files as $file) {
684 $filepath = $file->get_filepath().$file->get_filename();
685 $fileurl = file_encode_url($CFG->wwwroot
. '/webservice/pluginfile.php', '/' . $assign->get_context()->id
.
686 '/' . $component. '/'. $filearea . '/' . $submissionrecord->id
. $filepath);
688 'filepath' => $filepath,
689 'fileurl' => $fileurl
691 $fileareainfo['files'][] = $fileinfo;
693 $plugin['fileareas'][] = $fileareainfo;
696 $editorfields = $submissionplugin->get_editor_fields();
697 foreach ($editorfields as $name => $description) {
698 $editorfieldinfo = array(
700 'description' => $description,
701 'text' => $submissionplugin->get_editor_text($name, $submissionrecord->id
),
702 'format' => $submissionplugin->get_editor_format($name, $submissionrecord->id
)
704 $plugin['editorfields'][] = $editorfieldinfo;
707 $submission['plugins'][] = $plugin;
709 $submissions[] = $submission;
714 'itemid' => $assign->get_instance()->id
,
715 'warningcode' => '3',
716 'message' => 'No submissions found'
720 $assignments[] = array(
721 'assignmentid' => $assign->get_instance()->id
,
722 'submissions' => $submissions
728 'assignments' => $assignments,
729 'warnings' => $warnings
735 * Creates an assign_submissions external_single_structure
737 * @return external_single_structure
740 private static function get_submissions_structure() {
741 return new external_single_structure(
743 'assignmentid' => new external_value(PARAM_INT
, 'assignment id'),
744 'submissions' => new external_multiple_structure(
745 new external_single_structure(
747 'id' => new external_value(PARAM_INT
, 'submission id'),
748 'userid' => new external_value(PARAM_INT
, 'student id'),
749 'attemptnumber' => new external_value(PARAM_INT
, 'attempt number'),
750 'timecreated' => new external_value(PARAM_INT
, 'submission creation time'),
751 'timemodified' => new external_value(PARAM_INT
, 'submission last modified time'),
752 'status' => new external_value(PARAM_TEXT
, 'submission status'),
753 'groupid' => new external_value(PARAM_INT
, 'group id'),
754 'plugins' => new external_multiple_structure(
755 new external_single_structure(
757 'type' => new external_value(PARAM_TEXT
, 'submission plugin type'),
758 'name' => new external_value(PARAM_TEXT
, 'submission plugin name'),
759 'fileareas' => new external_multiple_structure(
760 new external_single_structure(
762 'area' => new external_value (PARAM_TEXT
, 'file area'),
763 'files' => new external_multiple_structure(
764 new external_single_structure(
766 'filepath' => new external_value (PARAM_TEXT
, 'file path'),
767 'fileurl' => new external_value (PARAM_URL
, 'file download url',
770 ), 'files', VALUE_OPTIONAL
773 ), 'fileareas', VALUE_OPTIONAL
775 'editorfields' => new external_multiple_structure(
776 new external_single_structure(
778 'name' => new external_value(PARAM_TEXT
, 'field name'),
779 'description' => new external_value(PARAM_TEXT
, 'field description'),
780 'text' => new external_value (PARAM_RAW
, 'field value'),
781 'format' => new external_format_value ('text')
784 , 'editorfields', VALUE_OPTIONAL
788 , 'plugins', VALUE_OPTIONAL
798 * Describes the get_submissions return value
800 * @return external_single_structure
803 public static function get_submissions_returns() {
804 return new external_single_structure(
806 'assignments' => new external_multiple_structure(self
::get_submissions_structure(), 'assignment submissions'),
807 'warnings' => new external_warnings()
813 * Describes the parameters for set_user_flags
814 * @return external_function_parameters
817 public static function set_user_flags_parameters() {
818 return new external_function_parameters(
820 'assignmentid' => new external_value(PARAM_INT
, 'assignment id'),
821 'userflags' => new external_multiple_structure(
822 new external_single_structure(
824 'userid' => new external_value(PARAM_INT
, 'student id'),
825 'locked' => new external_value(PARAM_INT
, 'locked', VALUE_OPTIONAL
),
826 'mailed' => new external_value(PARAM_INT
, 'mailed', VALUE_OPTIONAL
),
827 'extensionduedate' => new external_value(PARAM_INT
, 'extension due date', VALUE_OPTIONAL
),
828 'workflowstate' => new external_value(PARAM_TEXT
, 'marking workflow state', VALUE_OPTIONAL
),
829 'allocatedmarker' => new external_value(PARAM_INT
, 'allocated marker', VALUE_OPTIONAL
)
838 * Create or update user_flags records
840 * @param int $assignmentid the assignment for which the userflags are created or updated
841 * @param array $userflags An array of userflags to create or update
842 * @return array containing success or failure information for each record
845 public static function set_user_flags($assignmentid, $userflags = array()) {
847 require_once($CFG->dirroot
. "/mod/assign/locallib.php");
849 $params = self
::validate_parameters(self
::set_user_flags_parameters(),
850 array('assignmentid' => $assignmentid,
851 'userflags' => $userflags));
853 // Load assignment if it exists and if the user has the capability.
854 $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST
);
855 $context = context_module
::instance($cm->id
);
856 self
::validate_context($context);
857 require_capability('mod/assign:grade', $context);
858 $assign = new assign($context, null, null);
861 foreach ($params['userflags'] as $userflag) {
865 $record = $assign->get_user_flags($userflag['userid'], false);
867 if (isset($userflag['locked'])) {
868 $record->locked
= $userflag['locked'];
870 if (isset($userflag['mailed'])) {
871 $record->mailed
= $userflag['mailed'];
873 if (isset($userflag['extensionduedate'])) {
874 $record->extensionduedate
= $userflag['extensionduedate'];
876 if (isset($userflag['workflowstate'])) {
877 $record->workflowstate
= $userflag['workflowstate'];
879 if (isset($userflag['allocatedmarker'])) {
880 $record->allocatedmarker
= $userflag['allocatedmarker'];
882 if ($assign->update_user_flags($record)) {
883 $result['id'] = $record->id
;
884 $result['userid'] = $userflag['userid'];
886 $result['id'] = $record->id
;
887 $result['userid'] = $userflag['userid'];
888 $result['errormessage'] = 'Record created but values could not be set';
891 $record = $assign->get_user_flags($userflag['userid'], true);
892 $setfields = isset($userflag['locked'])
893 ||
isset($userflag['mailed'])
894 ||
isset($userflag['extensionduedate'])
895 ||
isset($userflag['workflowstate'])
896 ||
isset($userflag['allocatedmarker']);
899 if (isset($userflag['locked'])) {
900 $record->locked
= $userflag['locked'];
902 if (isset($userflag['mailed'])) {
903 $record->mailed
= $userflag['mailed'];
905 if (isset($userflag['extensionduedate'])) {
906 $record->extensionduedate
= $userflag['extensionduedate'];
908 if (isset($userflag['workflowstate'])) {
909 $record->workflowstate
= $userflag['workflowstate'];
911 if (isset($userflag['allocatedmarker'])) {
912 $record->allocatedmarker
= $userflag['allocatedmarker'];
914 if ($assign->update_user_flags($record)) {
915 $result['id'] = $record->id
;
916 $result['userid'] = $userflag['userid'];
918 $result['id'] = $record->id
;
919 $result['userid'] = $userflag['userid'];
920 $result['errormessage'] = 'Record created but values could not be set';
923 $result['id'] = $record->id
;
924 $result['userid'] = $userflag['userid'];
928 $result['userid'] = $userflag['userid'];
929 $result['errormessage'] = 'Record could not be created';
933 $results[] = $result;
939 * Describes the set_user_flags return value
940 * @return external_multiple_structure
943 public static function set_user_flags_returns() {
944 return new external_multiple_structure(
945 new external_single_structure(
947 'id' => new external_value(PARAM_INT
, 'id of record if successful, -1 for failure'),
948 'userid' => new external_value(PARAM_INT
, 'userid of record'),
949 'errormessage' => new external_value(PARAM_TEXT
, 'Failure error message', VALUE_OPTIONAL
)
956 * Describes the parameters for get_user_flags
957 * @return external_function_parameters
960 public static function get_user_flags_parameters() {
961 return new external_function_parameters(
963 'assignmentids' => new external_multiple_structure(
964 new external_value(PARAM_INT
, 'assignment id'),
965 '1 or more assignment ids',
972 * Returns user flag information from assign_user_flags for the requested assignment ids
973 * @param int[] $assignmentids
974 * @return array of user flag records for each requested assignment
977 public static function get_user_flags($assignmentids) {
979 $params = self
::validate_parameters(self
::get_user_flags_parameters(),
980 array('assignmentids' => $assignmentids));
982 $assignments = array();
984 $requestedassignmentids = $params['assignmentids'];
986 // Check the user is allowed to get the user flags for the assignments requested.
987 $placeholders = array();
988 list($sqlassignmentids, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED
);
989 $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module ".
990 "WHERE md.name = :modname AND cm.instance ".$sqlassignmentids;
991 $placeholders['modname'] = 'assign';
992 $cms = $DB->get_records_sql($sql, $placeholders);
993 foreach ($cms as $cm) {
995 $context = context_module
::instance($cm->id
);
996 self
::validate_context($context);
997 require_capability('mod/assign:grade', $context);
998 } catch (Exception
$e) {
999 $requestedassignmentids = array_diff($requestedassignmentids, array($cm->instance
));
1001 $warning['item'] = 'assignment';
1002 $warning['itemid'] = $cm->instance
;
1003 $warning['warningcode'] = '1';
1004 $warning['message'] = 'No access rights in module context';
1005 $warnings[] = $warning;
1009 // Create the query and populate an array of assign_user_flags records from the recordset results.
1010 if (count ($requestedassignmentids) > 0) {
1011 $placeholders = array();
1012 list($inorequalsql, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED
);
1014 $sql = "SELECT auf.id,auf.assignment,auf.userid,auf.locked,auf.mailed,".
1015 "auf.extensionduedate,auf.workflowstate,auf.allocatedmarker ".
1016 "FROM {assign_user_flags} auf ".
1017 "WHERE auf.assignment ".$inorequalsql.
1018 " ORDER BY auf.assignment, auf.id";
1020 $rs = $DB->get_recordset_sql($sql, $placeholders);
1021 $currentassignmentid = null;
1023 foreach ($rs as $rd) {
1024 $userflag = array();
1025 $userflag['id'] = $rd->id
;
1026 $userflag['userid'] = $rd->userid
;
1027 $userflag['locked'] = $rd->locked
;
1028 $userflag['mailed'] = $rd->mailed
;
1029 $userflag['extensionduedate'] = $rd->extensionduedate
;
1030 $userflag['workflowstate'] = $rd->workflowstate
;
1031 $userflag['allocatedmarker'] = $rd->allocatedmarker
;
1033 if (is_null($currentassignmentid) ||
($rd->assignment
!= $currentassignmentid )) {
1034 if (!is_null($assignment)) {
1035 $assignments[] = $assignment;
1037 $assignment = array();
1038 $assignment['assignmentid'] = $rd->assignment
;
1039 $assignment['userflags'] = array();
1040 $requestedassignmentids = array_diff($requestedassignmentids, array($rd->assignment
));
1042 $assignment['userflags'][] = $userflag;
1044 $currentassignmentid = $rd->assignment
;
1046 if (!is_null($assignment)) {
1047 $assignments[] = $assignment;
1053 foreach ($requestedassignmentids as $assignmentid) {
1055 $warning['item'] = 'assignment';
1056 $warning['itemid'] = $assignmentid;
1057 $warning['warningcode'] = '3';
1058 $warning['message'] = 'No user flags found';
1059 $warnings[] = $warning;
1063 $result['assignments'] = $assignments;
1064 $result['warnings'] = $warnings;
1069 * Creates an assign_user_flags external_single_structure
1070 * @return external_single_structure
1073 private static function assign_user_flags() {
1074 return new external_single_structure(
1076 'assignmentid' => new external_value(PARAM_INT
, 'assignment id'),
1077 'userflags' => new external_multiple_structure(new external_single_structure(
1079 'id' => new external_value(PARAM_INT
, 'user flag id'),
1080 'userid' => new external_value(PARAM_INT
, 'student id'),
1081 'locked' => new external_value(PARAM_INT
, 'locked'),
1082 'mailed' => new external_value(PARAM_INT
, 'mailed'),
1083 'extensionduedate' => new external_value(PARAM_INT
, 'extension due date'),
1084 'workflowstate' => new external_value(PARAM_TEXT
, 'marking workflow state', VALUE_OPTIONAL
),
1085 'allocatedmarker' => new external_value(PARAM_INT
, 'allocated marker')
1094 * Describes the get_user_flags return value
1095 * @return external_single_structure
1098 public static function get_user_flags_returns() {
1099 return new external_single_structure(
1101 'assignments' => new external_multiple_structure(self
::assign_user_flags(), 'list of assign user flag information'),
1102 'warnings' => new external_warnings('item is always \'assignment\'',
1103 'when errorcode is 3 then itemid is an assignment id. When errorcode is 1, itemid is a course module id',
1104 'errorcode can be 3 (no user flags found) or 1 (no permission to get user flags)')
1110 * Describes the parameters for get_user_mappings
1111 * @return external_function_parameters
1114 public static function get_user_mappings_parameters() {
1115 return new external_function_parameters(
1117 'assignmentids' => new external_multiple_structure(
1118 new external_value(PARAM_INT
, 'assignment id'),
1119 '1 or more assignment ids',
1126 * Returns user mapping information from assign_user_mapping for the requested assignment ids
1127 * @param int[] $assignmentids
1128 * @return array of user mapping records for each requested assignment
1131 public static function get_user_mappings($assignmentids) {
1133 $params = self
::validate_parameters(self
::get_user_mappings_parameters(),
1134 array('assignmentids' => $assignmentids));
1136 $assignments = array();
1137 $warnings = array();
1138 $requestedassignmentids = $params['assignmentids'];
1140 // Check the user is allowed to get the mappings for the assignments requested.
1141 $placeholders = array();
1142 list($sqlassignmentids, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED
);
1143 $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module ".
1144 "WHERE md.name = :modname AND cm.instance ".$sqlassignmentids;
1145 $placeholders['modname'] = 'assign';
1146 $cms = $DB->get_records_sql($sql, $placeholders);
1147 foreach ($cms as $cm) {
1149 $context = context_module
::instance($cm->id
);
1150 self
::validate_context($context);
1151 require_capability('mod/assign:revealidentities', $context);
1152 } catch (Exception
$e) {
1153 $requestedassignmentids = array_diff($requestedassignmentids, array($cm->instance
));
1155 $warning['item'] = 'assignment';
1156 $warning['itemid'] = $cm->instance
;
1157 $warning['warningcode'] = '1';
1158 $warning['message'] = 'No access rights in module context';
1159 $warnings[] = $warning;
1163 // Create the query and populate an array of assign_user_mapping records from the recordset results.
1164 if (count ($requestedassignmentids) > 0) {
1165 $placeholders = array();
1166 list($inorequalsql, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED
);
1168 $sql = "SELECT aum.id,aum.assignment,aum.userid ".
1169 "FROM {assign_user_mapping} aum ".
1170 "WHERE aum.assignment ".$inorequalsql.
1171 " ORDER BY aum.assignment, aum.id";
1173 $rs = $DB->get_recordset_sql($sql, $placeholders);
1174 $currentassignmentid = null;
1176 foreach ($rs as $rd) {
1178 $mapping['id'] = $rd->id
;
1179 $mapping['userid'] = $rd->userid
;
1181 if (is_null($currentassignmentid) ||
($rd->assignment
!= $currentassignmentid )) {
1182 if (!is_null($assignment)) {
1183 $assignments[] = $assignment;
1185 $assignment = array();
1186 $assignment['assignmentid'] = $rd->assignment
;
1187 $assignment['mappings'] = array();
1188 $requestedassignmentids = array_diff($requestedassignmentids, array($rd->assignment
));
1190 $assignment['mappings'][] = $mapping;
1192 $currentassignmentid = $rd->assignment
;
1194 if (!is_null($assignment)) {
1195 $assignments[] = $assignment;
1201 foreach ($requestedassignmentids as $assignmentid) {
1203 $warning['item'] = 'assignment';
1204 $warning['itemid'] = $assignmentid;
1205 $warning['warningcode'] = '3';
1206 $warning['message'] = 'No mappings found';
1207 $warnings[] = $warning;
1211 $result['assignments'] = $assignments;
1212 $result['warnings'] = $warnings;
1217 * Creates an assign_user_mappings external_single_structure
1218 * @return external_single_structure
1221 private static function assign_user_mappings() {
1222 return new external_single_structure(
1224 'assignmentid' => new external_value(PARAM_INT
, 'assignment id'),
1225 'mappings' => new external_multiple_structure(new external_single_structure(
1227 'id' => new external_value(PARAM_INT
, 'user mapping id'),
1228 'userid' => new external_value(PARAM_INT
, 'student id')
1237 * Describes the get_user_mappings return value
1238 * @return external_single_structure
1241 public static function get_user_mappings_returns() {
1242 return new external_single_structure(
1244 'assignments' => new external_multiple_structure(self
::assign_user_mappings(), 'list of assign user mapping data'),
1245 'warnings' => new external_warnings('item is always \'assignment\'',
1246 'when errorcode is 3 then itemid is an assignment id. When errorcode is 1, itemid is a course module id',
1247 'errorcode can be 3 (no user mappings found) or 1 (no permission to get user mappings)')
1253 * Describes the parameters for lock_submissions
1254 * @return external_external_function_parameters
1257 public static function lock_submissions_parameters() {
1258 return new external_function_parameters(
1260 'assignmentid' => new external_value(PARAM_INT
, 'The assignment id to operate on'),
1261 'userids' => new external_multiple_structure(
1262 new external_value(PARAM_INT
, 'user id'),
1263 '1 or more user ids',
1270 * Locks (prevent updates to) submissions in this assignment.
1272 * @param int $assignmentid The id of the assignment
1273 * @param array $userids Array of user ids to lock
1274 * @return array of warnings for each submission that could not be locked.
1277 public static function lock_submissions($assignmentid, $userids) {
1279 require_once("$CFG->dirroot/mod/assign/locallib.php");
1281 $params = self
::validate_parameters(self
::lock_submissions_parameters(),
1282 array('assignmentid' => $assignmentid,
1283 'userids' => $userids));
1285 $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST
);
1286 $context = context_module
::instance($cm->id
);
1287 self
::validate_context($context);
1289 $assignment = new assign($context, $cm, null);
1291 $warnings = array();
1292 foreach ($params['userids'] as $userid) {
1293 if (!$assignment->lock_submission($userid)) {
1294 $detail = 'User id: ' . $userid . ', Assignment id: ' . $params['assignmentid'];
1295 $warnings[] = self
::generate_warning($params['assignmentid'],
1305 * Describes the return value for lock_submissions
1307 * @return external_single_structure
1310 public static function lock_submissions_returns() {
1311 return new external_warnings();
1315 * Describes the parameters for revert_submissions_to_draft
1316 * @return external_external_function_parameters
1319 public static function revert_submissions_to_draft_parameters() {
1320 return new external_function_parameters(
1322 'assignmentid' => new external_value(PARAM_INT
, 'The assignment id to operate on'),
1323 'userids' => new external_multiple_structure(
1324 new external_value(PARAM_INT
, 'user id'),
1325 '1 or more user ids',
1332 * Reverts a list of user submissions to draft for a single assignment.
1334 * @param int $assignmentid The id of the assignment
1335 * @param array $userids Array of user ids to revert
1336 * @return array of warnings for each submission that could not be reverted.
1339 public static function revert_submissions_to_draft($assignmentid, $userids) {
1341 require_once("$CFG->dirroot/mod/assign/locallib.php");
1343 $params = self
::validate_parameters(self
::revert_submissions_to_draft_parameters(),
1344 array('assignmentid' => $assignmentid,
1345 'userids' => $userids));
1347 $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST
);
1348 $context = context_module
::instance($cm->id
);
1349 self
::validate_context($context);
1351 $assignment = new assign($context, $cm, null);
1353 $warnings = array();
1354 foreach ($params['userids'] as $userid) {
1355 if (!$assignment->revert_to_draft($userid)) {
1356 $detail = 'User id: ' . $userid . ', Assignment id: ' . $params['assignmentid'];
1357 $warnings[] = self
::generate_warning($params['assignmentid'],
1367 * Describes the return value for revert_submissions_to_draft
1369 * @return external_single_structure
1372 public static function revert_submissions_to_draft_returns() {
1373 return new external_warnings();
1377 * Describes the parameters for unlock_submissions
1378 * @return external_external_function_parameters
1381 public static function unlock_submissions_parameters() {
1382 return new external_function_parameters(
1384 'assignmentid' => new external_value(PARAM_INT
, 'The assignment id to operate on'),
1385 'userids' => new external_multiple_structure(
1386 new external_value(PARAM_INT
, 'user id'),
1387 '1 or more user ids',
1394 * Locks (prevent updates to) submissions in this assignment.
1396 * @param int $assignmentid The id of the assignment
1397 * @param array $userids Array of user ids to lock
1398 * @return array of warnings for each submission that could not be locked.
1401 public static function unlock_submissions($assignmentid, $userids) {
1403 require_once("$CFG->dirroot/mod/assign/locallib.php");
1405 $params = self
::validate_parameters(self
::unlock_submissions_parameters(),
1406 array('assignmentid' => $assignmentid,
1407 'userids' => $userids));
1409 $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST
);
1410 $context = context_module
::instance($cm->id
);
1411 self
::validate_context($context);
1413 $assignment = new assign($context, $cm, null);
1415 $warnings = array();
1416 foreach ($params['userids'] as $userid) {
1417 if (!$assignment->unlock_submission($userid)) {
1418 $detail = 'User id: ' . $userid . ', Assignment id: ' . $params['assignmentid'];
1419 $warnings[] = self
::generate_warning($params['assignmentid'],
1429 * Describes the return value for unlock_submissions
1431 * @return external_single_structure
1434 public static function unlock_submissions_returns() {
1435 return new external_warnings();
1439 * Describes the parameters for submit_for_grading
1440 * @return external_external_function_parameters
1443 public static function submit_for_grading_parameters() {
1444 return new external_function_parameters(
1446 'assignmentid' => new external_value(PARAM_INT
, 'The assignment id to operate on'),
1447 'acceptsubmissionstatement' => new external_value(PARAM_BOOL
, 'Accept the assignment submission statement')
1453 * Submit the logged in users assignment for grading.
1455 * @param int $assignmentid The id of the assignment
1456 * @return array of warnings to indicate any errors.
1459 public static function submit_for_grading($assignmentid, $acceptsubmissionstatement) {
1461 require_once("$CFG->dirroot/mod/assign/locallib.php");
1463 $params = self
::validate_parameters(self
::submit_for_grading_parameters(),
1464 array('assignmentid' => $assignmentid,
1465 'acceptsubmissionstatement' => $acceptsubmissionstatement));
1467 $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST
);
1468 $context = context_module
::instance($cm->id
);
1469 self
::validate_context($context);
1471 $assignment = new assign($context, $cm, null);
1473 $warnings = array();
1474 $data = new stdClass();
1475 $data->submissionstatement
= $params['acceptsubmissionstatement'];
1478 if (!$assignment->submit_for_grading($data, $notices)) {
1479 $detail = 'User id: ' . $USER->id
. ', Assignment id: ' . $params['assignmentid'] . ' Notices:' . implode(', ', $notices);
1480 $warnings[] = self
::generate_warning($params['assignmentid'],
1481 'couldnotsubmitforgrading',
1489 * Describes the return value for submit_for_grading
1491 * @return external_single_structure
1494 public static function submit_for_grading_returns() {
1495 return new external_warnings();
1499 * Describes the parameters for save_user_extensions
1500 * @return external_external_function_parameters
1503 public static function save_user_extensions_parameters() {
1504 return new external_function_parameters(
1506 'assignmentid' => new external_value(PARAM_INT
, 'The assignment id to operate on'),
1507 'userids' => new external_multiple_structure(
1508 new external_value(PARAM_INT
, 'user id'),
1509 '1 or more user ids',
1511 'dates' => new external_multiple_structure(
1512 new external_value(PARAM_INT
, 'dates'),
1513 '1 or more extension dates (timestamp)',
1520 * Grant extension dates to students for an assignment.
1522 * @param int $assignmentid The id of the assignment
1523 * @param array $userids Array of user ids to grant extensions to
1524 * @param array $dates Array of extension dates
1525 * @return array of warnings for each extension date that could not be granted
1528 public static function save_user_extensions($assignmentid, $userids, $dates) {
1530 require_once("$CFG->dirroot/mod/assign/locallib.php");
1532 $params = self
::validate_parameters(self
::save_user_extensions_parameters(),
1533 array('assignmentid' => $assignmentid,
1534 'userids' => $userids,
1535 'dates' => $dates));
1537 if (count($params['userids']) != count($params['dates'])) {
1538 $detail = 'Length of userids and dates parameters differ.';
1539 $warnings[] = self
::generate_warning($params['assignmentid'],
1540 'invalidparameters',
1546 $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST
);
1547 $context = context_module
::instance($cm->id
);
1548 self
::validate_context($context);
1550 $assignment = new assign($context, $cm, null);
1552 $warnings = array();
1553 foreach ($params['userids'] as $idx => $userid) {
1554 $duedate = $params['dates'][$idx];
1555 if (!$assignment->save_user_extension($userid, $duedate)) {
1556 $detail = 'User id: ' . $userid . ', Assignment id: ' . $params['assignmentid'] . ', Extension date: ' . $duedate;
1557 $warnings[] = self
::generate_warning($params['assignmentid'],
1558 'couldnotgrantextensions',
1567 * Describes the return value for save_user_extensions
1569 * @return external_single_structure
1572 public static function save_user_extensions_returns() {
1573 return new external_warnings();
1577 * Describes the parameters for reveal_identities
1578 * @return external_external_function_parameters
1581 public static function reveal_identities_parameters() {
1582 return new external_function_parameters(
1584 'assignmentid' => new external_value(PARAM_INT
, 'The assignment id to operate on')
1590 * Reveal the identities of anonymous students to markers for a single assignment.
1592 * @param int $assignmentid The id of the assignment
1593 * @return array of warnings to indicate any errors.
1596 public static function reveal_identities($assignmentid) {
1598 require_once("$CFG->dirroot/mod/assign/locallib.php");
1600 $params = self
::validate_parameters(self
::reveal_identities_parameters(),
1601 array('assignmentid' => $assignmentid));
1603 $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST
);
1604 $context = context_module
::instance($cm->id
);
1605 self
::validate_context($context);
1607 $assignment = new assign($context, $cm, null);
1609 $warnings = array();
1610 if (!$assignment->reveal_identities()) {
1611 $detail = 'User id: ' . $USER->id
. ', Assignment id: ' . $params['assignmentid'];
1612 $warnings[] = self
::generate_warning($params['assignmentid'],
1613 'couldnotrevealidentities',
1621 * Describes the return value for reveal_identities
1623 * @return external_single_structure
1626 public static function reveal_identities_returns() {
1627 return new external_warnings();
1631 * Describes the parameters for save_submission
1632 * @return external_external_function_parameters
1635 public static function save_submission_parameters() {
1637 require_once("$CFG->dirroot/mod/assign/locallib.php");
1638 $instance = new assign(null, null, null);
1639 $pluginsubmissionparams = array();
1641 foreach ($instance->get_submission_plugins() as $plugin) {
1642 $pluginparams = $plugin->get_external_parameters();
1643 if (!empty($pluginparams)) {
1644 $pluginsubmissionparams = array_merge($pluginsubmissionparams, $pluginparams);
1648 return new external_function_parameters(
1650 'assignmentid' => new external_value(PARAM_INT
, 'The assignment id to operate on'),
1651 'plugindata' => new external_single_structure(
1652 $pluginsubmissionparams
1659 * Save a student submission for a single assignment
1661 * @param int $assignmentid The id of the assignment
1662 * @param array $plugindata - The submitted data for plugins
1663 * @return array of warnings to indicate any errors
1666 public static function save_submission($assignmentid, $plugindata) {
1668 require_once("$CFG->dirroot/mod/assign/locallib.php");
1670 $params = self
::validate_parameters(self
::save_submission_parameters(),
1671 array('assignmentid' => $assignmentid,
1672 'plugindata' => $plugindata));
1674 $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST
);
1675 $context = context_module
::instance($cm->id
);
1676 self
::validate_context($context);
1678 $assignment = new assign($context, $cm, null);
1682 $submissiondata = (object)$params['plugindata'];
1684 $assignment->save_submission($submissiondata, $notices);
1686 $warnings = array();
1687 foreach ($notices as $notice) {
1688 $warnings[] = self
::generate_warning($params['assignmentid'],
1689 'couldnotsavesubmission',
1697 * Describes the return value for save_submission
1699 * @return external_single_structure
1702 public static function save_submission_returns() {
1703 return new external_warnings();
1707 * Describes the parameters for save_grade
1708 * @return external_external_function_parameters
1711 public static function save_grade_parameters() {
1713 require_once("$CFG->dirroot/mod/assign/locallib.php");
1714 require_once("$CFG->dirroot/grade/grading/lib.php");
1715 $instance = new assign(null, null, null);
1716 $pluginfeedbackparams = array();
1718 foreach ($instance->get_feedback_plugins() as $plugin) {
1719 $pluginparams = $plugin->get_external_parameters();
1720 if (!empty($pluginparams)) {
1721 $pluginfeedbackparams = array_merge($pluginfeedbackparams, $pluginparams);
1725 $advancedgradingdata = array();
1726 $methods = array_keys(grading_manager
::available_methods(false));
1727 foreach ($methods as $method) {
1728 require_once($CFG->dirroot
.'/grade/grading/form/'.$method.'/lib.php');
1729 $details = call_user_func('gradingform_'.$method.'_controller::get_external_instance_filling_details');
1730 if (!empty($details)) {
1732 foreach ($details as $key => $value) {
1733 $value->required
= VALUE_OPTIONAL
;
1734 unset($value->content
->keys
['id']);
1735 $items[$key] = new external_multiple_structure (new external_single_structure(
1737 'criterionid' => new external_value(PARAM_INT
, 'criterion id'),
1738 'fillings' => $value
1742 $advancedgradingdata[$method] = new external_single_structure($items, 'items', VALUE_OPTIONAL
);
1746 return new external_function_parameters(
1748 'assignmentid' => new external_value(PARAM_INT
, 'The assignment id to operate on'),
1749 'userid' => new external_value(PARAM_INT
, 'The student id to operate on'),
1750 'grade' => new external_value(PARAM_FLOAT
, 'The new grade for this user. Ignored if advanced grading used'),
1751 'attemptnumber' => new external_value(PARAM_INT
, 'The attempt number (-1 means latest attempt)'),
1752 'addattempt' => new external_value(PARAM_BOOL
, 'Allow another attempt if the attempt reopen method is manual'),
1753 'workflowstate' => new external_value(PARAM_ALPHA
, 'The next marking workflow state'),
1754 'applytoall' => new external_value(PARAM_BOOL
, 'If true, this grade will be applied ' .
1756 'of the group (for group assignments).'),
1757 'plugindata' => new external_single_structure($pluginfeedbackparams, 'plugin data', VALUE_DEFAULT
, array()),
1758 'advancedgradingdata' => new external_single_structure($advancedgradingdata, 'advanced grading data',
1759 VALUE_DEFAULT
, array())
1765 * Save a student grade for a single assignment.
1767 * @param int $assignmentid The id of the assignment
1768 * @param int $userid The id of the user
1769 * @param float $grade The grade (ignored if the assignment uses advanced grading)
1770 * @param int $attemptnumber The attempt number
1771 * @param bool $addattempt Allow another attempt
1772 * @param string $workflowstate New workflow state
1773 * @param bool $applytoall Apply the grade to all members of the group
1774 * @param array $plugindata Custom data used by plugins
1775 * @param array $advancedgradingdata Advanced grading data
1779 public static function save_grade($assignmentid,
1786 $plugindata = array(),
1787 $advancedgradingdata = array()) {
1789 require_once("$CFG->dirroot/mod/assign/locallib.php");
1791 $params = self
::validate_parameters(self
::save_grade_parameters(),
1792 array('assignmentid' => $assignmentid,
1793 'userid' => $userid,
1795 'attemptnumber' => $attemptnumber,
1796 'workflowstate' => $workflowstate,
1797 'addattempt' => $addattempt,
1798 'applytoall' => $applytoall,
1799 'plugindata' => $plugindata,
1800 'advancedgradingdata' => $advancedgradingdata));
1802 $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST
);
1803 $context = context_module
::instance($cm->id
);
1804 self
::validate_context($context);
1806 $assignment = new assign($context, $cm, null);
1808 $gradedata = (object)$params['plugindata'];
1810 $gradedata->addattempt
= $params['addattempt'];
1811 $gradedata->attemptnumber
= $params['attemptnumber'];
1812 $gradedata->workflowstate
= $params['workflowstate'];
1813 $gradedata->applytoall
= $params['applytoall'];
1814 $gradedata->grade
= $params['grade'];
1816 if (!empty($params['advancedgradingdata'])) {
1817 $advancedgrading = array();
1818 $criteria = reset($params['advancedgradingdata']);
1819 foreach ($criteria as $key => $criterion) {
1821 foreach ($criterion as $value) {
1822 foreach ($value['fillings'] as $filling) {
1823 $details[$value['criterionid']] = $filling;
1826 $advancedgrading[$key] = $details;
1828 $gradedata->advancedgrading
= $advancedgrading;
1831 $assignment->save_grade($params['userid'], $gradedata);
1837 * Describes the return value for save_grade
1839 * @return external_single_structure
1842 public static function save_grade_returns() {
1847 * Describes the parameters for save_grades
1848 * @return external_external_function_parameters
1851 public static function save_grades_parameters() {
1853 require_once("$CFG->dirroot/mod/assign/locallib.php");
1854 require_once("$CFG->dirroot/grade/grading/lib.php");
1855 $instance = new assign(null, null, null);
1856 $pluginfeedbackparams = array();
1858 foreach ($instance->get_feedback_plugins() as $plugin) {
1859 $pluginparams = $plugin->get_external_parameters();
1860 if (!empty($pluginparams)) {
1861 $pluginfeedbackparams = array_merge($pluginfeedbackparams, $pluginparams);
1865 $advancedgradingdata = array();
1866 $methods = array_keys(grading_manager
::available_methods(false));
1867 foreach ($methods as $method) {
1868 require_once($CFG->dirroot
.'/grade/grading/form/'.$method.'/lib.php');
1869 $details = call_user_func('gradingform_'.$method.'_controller::get_external_instance_filling_details');
1870 if (!empty($details)) {
1872 foreach ($details as $key => $value) {
1873 $value->required
= VALUE_OPTIONAL
;
1874 unset($value->content
->keys
['id']);
1875 $items[$key] = new external_multiple_structure (new external_single_structure(
1877 'criterionid' => new external_value(PARAM_INT
, 'criterion id'),
1878 'fillings' => $value
1882 $advancedgradingdata[$method] = new external_single_structure($items, 'items', VALUE_OPTIONAL
);
1886 return new external_function_parameters(
1888 'assignmentid' => new external_value(PARAM_INT
, 'The assignment id to operate on'),
1889 'applytoall' => new external_value(PARAM_BOOL
, 'If true, this grade will be applied ' .
1891 'of the group (for group assignments).'),
1892 'grades' => new external_multiple_structure(
1893 new external_single_structure(
1895 'userid' => new external_value(PARAM_INT
, 'The student id to operate on'),
1896 'grade' => new external_value(PARAM_FLOAT
, 'The new grade for this user. '.
1897 'Ignored if advanced grading used'),
1898 'attemptnumber' => new external_value(PARAM_INT
, 'The attempt number (-1 means latest attempt)'),
1899 'addattempt' => new external_value(PARAM_BOOL
, 'Allow another attempt if manual attempt reopen method'),
1900 'workflowstate' => new external_value(PARAM_ALPHA
, 'The next marking workflow state'),
1901 'plugindata' => new external_single_structure($pluginfeedbackparams, 'plugin data',
1902 VALUE_DEFAULT
, array()),
1903 'advancedgradingdata' => new external_single_structure($advancedgradingdata, 'advanced grading data',
1904 VALUE_DEFAULT
, array())
1913 * Save multiple student grades for a single assignment.
1915 * @param int $assignmentid The id of the assignment
1916 * @param boolean $applytoall If set to true and this is a team assignment,
1917 * apply the grade to all members of the group
1918 * @param array $grades grade data for one or more students that includes
1919 * userid - The id of the student being graded
1920 * grade - The grade (ignored if the assignment uses advanced grading)
1921 * attemptnumber - The attempt number
1922 * addattempt - Allow another attempt
1923 * workflowstate - New workflow state
1924 * plugindata - Custom data used by plugins
1925 * advancedgradingdata - Optional Advanced grading data
1926 * @throws invalid_parameter_exception if multiple grades are supplied for
1927 * a team assignment that has $applytoall set to true
1931 public static function save_grades($assignmentid, $applytoall = false, $grades) {
1933 require_once("$CFG->dirroot/mod/assign/locallib.php");
1935 $params = self
::validate_parameters(self
::save_grades_parameters(),
1936 array('assignmentid' => $assignmentid,
1937 'applytoall' => $applytoall,
1938 'grades' => $grades));
1940 $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST
);
1941 $context = context_module
::instance($cm->id
);
1942 self
::validate_context($context);
1943 $assignment = new assign($context, $cm, null);
1945 if ($assignment->get_instance()->teamsubmission
&& $params['applytoall']) {
1946 // Check that only 1 user per submission group is provided.
1947 $groupids = array();
1948 foreach ($params['grades'] as $gradeinfo) {
1949 $group = $assignment->get_submission_group($gradeinfo['userid']);
1950 if (in_array($group->id
, $groupids)) {
1951 throw new invalid_parameter_exception('Multiple grades for the same team have been supplied '
1952 .' this is not permitted when the applytoall flag is set');
1954 $groupids[] = $group->id
;
1959 foreach ($params['grades'] as $gradeinfo) {
1960 $gradedata = (object)$gradeinfo['plugindata'];
1961 $gradedata->addattempt
= $gradeinfo['addattempt'];
1962 $gradedata->attemptnumber
= $gradeinfo['attemptnumber'];
1963 $gradedata->workflowstate
= $gradeinfo['workflowstate'];
1964 $gradedata->applytoall
= $params['applytoall'];
1965 $gradedata->grade
= $gradeinfo['grade'];
1967 if (!empty($gradeinfo['advancedgradingdata'])) {
1968 $advancedgrading = array();
1969 $criteria = reset($gradeinfo['advancedgradingdata']);
1970 foreach ($criteria as $key => $criterion) {
1972 foreach ($criterion as $value) {
1973 foreach ($value['fillings'] as $filling) {
1974 $details[$value['criterionid']] = $filling;
1977 $advancedgrading[$key] = $details;
1979 $gradedata->advancedgrading
= $advancedgrading;
1981 $assignment->save_grade($gradeinfo['userid'], $gradedata);
1988 * Describes the return value for save_grades
1990 * @return external_single_structure
1993 public static function save_grades_returns() {
1998 * Describes the parameters for copy_previous_attempt
1999 * @return external_external_function_parameters
2002 public static function copy_previous_attempt_parameters() {
2003 return new external_function_parameters(
2005 'assignmentid' => new external_value(PARAM_INT
, 'The assignment id to operate on'),
2011 * Copy a students previous attempt to a new attempt.
2013 * @param int $assignmentid
2014 * @return array of warnings to indicate any errors.
2017 public static function copy_previous_attempt($assignmentid) {
2019 require_once("$CFG->dirroot/mod/assign/locallib.php");
2021 $params = self
::validate_parameters(self
::copy_previous_attempt_parameters(),
2022 array('assignmentid' => $assignmentid));
2024 $cm = get_coursemodule_from_instance('assign', $assignmentid, 0, false, MUST_EXIST
);
2025 $context = context_module
::instance($cm->id
);
2026 self
::validate_context($context);
2028 $assignment = new assign($context, $cm, null);
2032 $assignment->copy_previous_attempt($submissiondata, $notices);
2034 $warnings = array();
2035 foreach ($notices as $notice) {
2036 $warnings[] = self
::generate_warning($assignmentid,
2037 'couldnotcopyprevioussubmission',
2045 * Describes the return value for save_submission
2047 * @return external_single_structure
2050 public static function copy_previous_attempt_returns() {
2051 return new external_warnings();
2055 * Returns description of method parameters
2057 * @return external_function_parameters
2060 public static function view_grading_table_parameters() {
2061 return new external_function_parameters(
2063 'assignid' => new external_value(PARAM_INT
, 'assign instance id')
2069 * Trigger the grading_table_viewed event.
2071 * @param int $assignid the assign instance id
2072 * @return array of warnings and status result
2074 * @throws moodle_exception
2076 public static function view_grading_table($assignid) {
2078 require_once($CFG->dirroot
. "/mod/assign/locallib.php");
2080 $params = self
::validate_parameters(self
::view_grading_table_parameters(),
2082 'assignid' => $assignid
2084 $warnings = array();
2086 // Request and permission validation.
2087 $assign = $DB->get_record('assign', array('id' => $params['assignid']), 'id', MUST_EXIST
);
2088 list($course, $cm) = get_course_and_cm_from_instance($assign, 'assign');
2090 $context = context_module
::instance($cm->id
);
2091 self
::validate_context($context);
2093 require_capability('mod/assign:view', $context);
2095 $assign = new assign($context, null, null);
2096 $assign->require_view_grades();
2097 \mod_assign\event\grading_table_viewed
::create_from_assign($assign)->trigger();
2100 $result['status'] = true;
2101 $result['warnings'] = $warnings;
2106 * Returns description of method result value
2108 * @return external_description
2111 public static function view_grading_table_returns() {
2112 return new external_single_structure(
2114 'status' => new external_value(PARAM_BOOL
, 'status: true if success'),
2115 'warnings' => new external_warnings()