Merge branch 'MDL-37148-master' of git://github.com/damyon/moodle

This commit is contained in:
Sam Hemelryk
2013-09-17 08:50:38 +12:00
24 changed files with 1913 additions and 347 deletions
+9 -1
View File
@@ -627,5 +627,13 @@ abstract class assign_plugin {
return true;
}
/**
* If this plugin can participate in a webservice (save_submission or save_grade),
* return a list of external_params to be included in the definition of that webservice.
*
* @return external_description|null
*/
public function get_external_parameters() {
return null;
}
}
+65
View File
@@ -63,5 +63,70 @@ $functions = array(
'classpath' => 'mod/assign/externallib.php',
'description' => 'Returns the blind marking mappings for assignments',
'type' => 'read'
),
'mod_assign_revert_submissions_to_draft' => array(
'classname' => 'mod_assign_external',
'methodname' => 'revert_submissions_to_draft',
'classpath' => 'mod/assign/externallib.php',
'description' => 'Reverts the list of submissions to draft status',
'type' => 'write'
),
'mod_assign_lock_submissions' => array(
'classname' => 'mod_assign_external',
'methodname' => 'lock_submissions',
'classpath' => 'mod/assign/externallib.php',
'description' => 'Prevent students from making changes to a list of submissions',
'type' => 'write'
),
'mod_assign_unlock_submissions' => array(
'classname' => 'mod_assign_external',
'methodname' => 'unlock_submissions',
'classpath' => 'mod/assign/externallib.php',
'description' => 'Allow students to make changes to a list of submissions',
'type' => 'write'
),
'mod_assign_save_submission' => array(
'classname' => 'mod_assign_external',
'methodname' => 'save_submission',
'classpath' => 'mod/assign/externallib.php',
'description' => 'Update the current students submission',
'type' => 'write'
),
'mod_assign_submit_for_grading' => array(
'classname' => 'mod_assign_external',
'methodname' => 'submit_for_grading',
'classpath' => 'mod/assign/externallib.php',
'description' => 'Submit the current students assignment for grading',
'type' => 'write'
),
'mod_assign_save_grade' => array(
'classname' => 'mod_assign_external',
'methodname' => 'save_grade',
'classpath' => 'mod/assign/externallib.php',
'description' => 'Save a grade update for a single student.',
'type' => 'write'
),
'mod_assign_save_user_extensions' => array(
'classname' => 'mod_assign_external',
'methodname' => 'save_user_extensions',
'classpath' => 'mod/assign/externallib.php',
'description' => 'Save a list of assignment extensions',
'type' => 'write'
),
'mod_assign_reveal_identities' => array(
'classname' => 'mod_assign_external',
'methodname' => 'reveal_identities',
'classpath' => 'mod/assign/externallib.php',
'description' => 'Reveal the identities for a blind marking assignment',
'type' => 'write'
)
);
+660 -6
View File
@@ -29,9 +29,43 @@ require_once("$CFG->libdir/externallib.php");
/**
* Assign functions
* @copyright 2012 Paul Charsley
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_assign_external extends external_api {
/**
* Generate a warning in a standard structure for a known failure.
*
* @param int $assignmentid - The assignment
* @param string $warningcode - The key for the warning message
* @param string $detail - A description of the error
* @return array - Warning structure containing item, itemid, warningcode, message
*/
private static function generate_warning($assignmentid, $warningcode, $detail) {
$warningmessages = array(
'couldnotlock'=>'Could not lock the submission for this user.',
'couldnotunlock'=>'Could not unlock the submission for this user.',
'couldnotsubmitforgrading'=>'Could not submit assignment for grading.',
'couldnotrevealidentities'=>'Could not reveal identities.',
'couldnotgrantextensions'=>'Could not grant submission date extensions.',
'couldnotrevert'=>'Could not revert submission to draft.',
'invalidparameters'=>'Invalid parameters.',
'couldnotsavesubmission'=>'Could not save submission.',
'couldnotsavegrade'=>'Could not save grade.'
);
$message = $warningmessages[$warningcode];
if (empty($message)) {
$message = 'Unknown warning type.';
}
return array('item'=>$detail,
'itemid'=>$assignmentid,
'warningcode'=>$warningcode,
'message'=>$message);
}
/**
* Describes the parameters for get_grades
* @return external_external_function_parameters
@@ -53,7 +87,7 @@ class mod_assign_external extends external_api {
/**
* Returns grade information from assign_grades for the requested assignment ids
* @param array of ints $assignmentids
* @param int[] $assignmentids
* @param int $since only return records with timemodified >= since
* @return array of grade records for each requested assignment
* @since Moodle 2.4
@@ -102,7 +136,7 @@ class mod_assign_external extends external_api {
WHERE mxg.assignment ' . $inorequalsql2 . ' GROUP BY mxg.userid';
$sql = "SELECT ag.id,ag.assignment,ag.userid,ag.timecreated,ag.timemodified,".
"ag.grader,ag.grade ".
"ag.grader,ag.grade,ag.attemptnumber ".
"FROM {assign_grades} ag ".
"JOIN ( " . $grademaxattempt . " ) gmx ON ag.userid = gmx.userid".
" WHERE ag.assignment ".$inorequalsql.
@@ -122,6 +156,7 @@ class mod_assign_external extends external_api {
$grade['timecreated'] = $rd->timecreated;
$grade['timemodified'] = $rd->timemodified;
$grade['grader'] = $rd->grader;
$grade['attemptnumber'] = $rd->attemptnumber;
$grade['grade'] = (string)$rd->grade;
if (is_null($currentassignmentid) || ($rd->assignment != $currentassignmentid )) {
@@ -170,6 +205,7 @@ class mod_assign_external extends external_api {
array(
'id' => new external_value(PARAM_INT, 'grade id'),
'userid' => new external_value(PARAM_INT, 'student id'),
'attemptnumber' => new external_value(PARAM_INT, 'attempt number'),
'timecreated' => new external_value(PARAM_INT, 'grade creation time'),
'timemodified' => new external_value(PARAM_INT, 'grade last modified time'),
'grader' => new external_value(PARAM_INT, 'grader'),
@@ -473,7 +509,7 @@ class mod_assign_external extends external_api {
/**
* Returns submissions for the requested assignment ids
*
* @param array of ints $assignmentids
* @param int[] $assignmentids
* @param string $status only return submissions with this status
* @param int $since only return submissions with timemodified >= since
* @param int $before only return submissions with timemodified <= before
@@ -528,7 +564,7 @@ class mod_assign_external extends external_api {
WHERE mxs.assignment = :assignid1 GROUP BY mxs.userid';
$sql = "SELECT mas.id, mas.assignment,mas.userid,".
"mas.timecreated,mas.timemodified,mas.status,mas.groupid ".
"mas.timecreated,mas.timemodified,mas.status,mas.groupid,mas.attemptnumber ".
"FROM {assign_submission} mas ".
"JOIN ( " . $submissionmaxattempt . " ) smx ON mas.userid = smx.userid ".
"WHERE mas.assignment = :assignid2 AND mas.attemptnumber = smx.maxattempt";
@@ -557,6 +593,7 @@ class mod_assign_external extends external_api {
'timecreated' => $submissionrecord->timecreated,
'timemodified' => $submissionrecord->timemodified,
'status' => $submissionrecord->status,
'attemptnumber' => $submissionrecord->attemptnumber,
'groupid' => $submissionrecord->groupid
);
foreach ($submissionplugins as $submissionplugin) {
@@ -638,6 +675,7 @@ class mod_assign_external extends external_api {
array(
'id' => new external_value(PARAM_INT, 'submission id'),
'userid' => new external_value(PARAM_INT, 'student id'),
'attemptnumber' => new external_value(PARAM_INT, 'attempt number'),
'timecreated' => new external_value(PARAM_INT, 'submission creation time'),
'timemodified' => new external_value(PARAM_INT, 'submission last modified time'),
'status' => new external_value(PARAM_TEXT, 'submission status'),
@@ -716,7 +754,7 @@ class mod_assign_external extends external_api {
/**
* Returns user flag information from assign_user_flags for the requested assignment ids
* @param array of ints $assignmentids
* @param int[] $assignmentids
* @return array of user flag records for each requested assignment
* @since Moodle 2.6
*/
@@ -870,7 +908,7 @@ class mod_assign_external extends external_api {
/**
* Returns user mapping information from assign_user_mapping for the requested assignment ids
* @param array of ints $assignmentids
* @param int[] $assignmentids
* @return array of user mapping records for each requested assignment
* @since Moodle 2.6
*/
@@ -995,4 +1033,620 @@ class mod_assign_external extends external_api {
);
}
/**
* Describes the parameters for lock_submissions
* @return external_external_function_parameters
* @since Moodle 2.6
*/
public static function lock_submissions_parameters() {
return new external_function_parameters(
array(
'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
'userids' => new external_multiple_structure(
new external_value(PARAM_INT, 'user id'),
'1 or more user ids',
VALUE_REQUIRED),
)
);
}
/**
* Locks (prevent updates to) submissions in this assignment.
*
* @param int $assignmentid The id of the assignment
* @param array $userids Array of user ids to lock
* @return array of warnings for each submission that could not be locked.
* @since Moodle 2.6
*/
public static function lock_submissions($assignmentid, $userids) {
global $CFG;
require_once("$CFG->dirroot/mod/assign/locallib.php");
$params = self::validate_parameters(self::lock_submissions_parameters(),
array('assignmentid' => $assignmentid,
'userids' => $userids));
$cm = get_coursemodule_from_instance('assign', $assignmentid, 0, false, MUST_EXIST);
$context = context_module::instance($cm->id);
$assignment = new assign($context, $cm, null);
$warnings = array();
foreach ($userids as $userid) {
if (!$assignment->lock_submission($userid)) {
$detail = 'User id: ' . $userid . ', Assignment id: ' . $assignmentid;
$warnings[] = self::generate_warning($assignmentid,
'couldnotlock',
$detail);
}
}
return $warnings;
}
/**
* Describes the return value for lock_submissions
*
* @return external_single_structure
* @since Moodle 2.6
*/
public static function lock_submissions_returns() {
return new external_multiple_structure(
new external_warnings()
);
}
/**
* Describes the parameters for revert_submissions_to_draft
* @return external_external_function_parameters
* @since Moodle 2.6
*/
public static function revert_submissions_to_draft_parameters() {
return new external_function_parameters(
array(
'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
'userids' => new external_multiple_structure(
new external_value(PARAM_INT, 'user id'),
'1 or more user ids',
VALUE_REQUIRED),
)
);
}
/**
* Reverts a list of user submissions to draft for a single assignment.
*
* @param int $assignmentid The id of the assignment
* @param array $userids Array of user ids to revert
* @return array of warnings for each submission that could not be reverted.
* @since Moodle 2.6
*/
public static function revert_submissions_to_draft($assignmentid, $userids) {
global $CFG;
require_once("$CFG->dirroot/mod/assign/locallib.php");
$params = self::validate_parameters(self::revert_submissions_to_draft_parameters(),
array('assignmentid' => $assignmentid,
'userids' => $userids));
$cm = get_coursemodule_from_instance('assign', $assignmentid, 0, false, MUST_EXIST);
$context = context_module::instance($cm->id);
$assignment = new assign($context, $cm, null);
$warnings = array();
foreach ($userids as $userid) {
if (!$assignment->revert_to_draft($userid)) {
$detail = 'User id: ' . $userid . ', Assignment id: ' . $assignmentid;
$warnings[] = self::generate_warning($assignmentid,
'couldnotrevert',
$detail);
}
}
return $warnings;
}
/**
* Describes the return value for revert_submissions_to_draft
*
* @return external_single_structure
* @since Moodle 2.6
*/
public static function revert_submissions_to_draft_returns() {
return new external_multiple_structure(
new external_warnings()
);
}
/**
* Describes the parameters for unlock_submissions
* @return external_external_function_parameters
* @since Moodle 2.6
*/
public static function unlock_submissions_parameters() {
return new external_function_parameters(
array(
'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
'userids' => new external_multiple_structure(
new external_value(PARAM_INT, 'user id'),
'1 or more user ids',
VALUE_REQUIRED),
)
);
}
/**
* Locks (prevent updates to) submissions in this assignment.
*
* @param int $assignmentid The id of the assignment
* @param array $userids Array of user ids to lock
* @return array of warnings for each submission that could not be locked.
* @since Moodle 2.6
*/
public static function unlock_submissions($assignmentid, $userids) {
global $CFG;
require_once("$CFG->dirroot/mod/assign/locallib.php");
$params = self::validate_parameters(self::unlock_submissions_parameters(),
array('assignmentid' => $assignmentid,
'userids' => $userids));
$cm = get_coursemodule_from_instance('assign', $assignmentid, 0, false, MUST_EXIST);
$context = context_module::instance($cm->id);
$assignment = new assign($context, $cm, null);
$warnings = array();
foreach ($userids as $userid) {
if (!$assignment->unlock_submission($userid)) {
$detail = 'User id: ' . $userid . ', Assignment id: ' . $assignmentid;
$warnings[] = self::generate_warning($assignmentid,
'couldnotunlock',
$detail);
}
}
return $warnings;
}
/**
* Describes the return value for unlock_submissions
*
* @return external_single_structure
* @since Moodle 2.6
*/
public static function unlock_submissions_returns() {
return new external_multiple_structure(
new external_warnings()
);
}
/**
* Describes the parameters for submit_for_grading
* @return external_external_function_parameters
* @since Moodle 2.6
*/
public static function submit_for_grading_parameters() {
return new external_function_parameters(
array(
'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
'acceptsubmissionstatement' => new external_value(PARAM_BOOL, 'Accept the assignment submission statement')
)
);
}
/**
* Submit the logged in users assignment for grading.
*
* @param int $assignmentid The id of the assignment
* @return array of warnings to indicate any errors.
* @since Moodle 2.6
*/
public static function submit_for_grading($assignmentid, $acceptsubmissionstatement) {
global $CFG, $USER;
require_once("$CFG->dirroot/mod/assign/locallib.php");
$params = self::validate_parameters(self::submit_for_grading_parameters(),
array('assignmentid' => $assignmentid,
'acceptsubmissionstatement' => $acceptsubmissionstatement));
$cm = get_coursemodule_from_instance('assign', $assignmentid, 0, false, MUST_EXIST);
$context = context_module::instance($cm->id);
$assignment = new assign($context, $cm, null);
$warnings = array();
$data = new stdClass();
$data->submissionstatement = $acceptsubmissionstatement;
if (!$assignment->submit_for_grading($data)) {
$detail = 'User id: ' . $USER->id . ', Assignment id: ' . $assignmentid;
$warnings[] = self::generate_warning($assignmentid,
'couldnotsubmitforgrading',
$detail);
}
return $warnings;
}
/**
* Describes the return value for submit_for_grading
*
* @return external_single_structure
* @since Moodle 2.6
*/
public static function submit_for_grading_returns() {
return new external_multiple_structure(
new external_warnings()
);
}
/**
* Describes the parameters for save_user_extensions
* @return external_external_function_parameters
* @since Moodle 2.6
*/
public static function save_user_extensions_parameters() {
return new external_function_parameters(
array(
'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
'userids' => new external_multiple_structure(
new external_value(PARAM_INT, 'user id'),
'1 or more user ids',
VALUE_REQUIRED),
'dates' => new external_multiple_structure(
new external_value(PARAM_INT, 'dates'),
'1 or more extension dates (timestamp)',
VALUE_REQUIRED),
)
);
}
/**
* Grant extension dates to students for an assignment.
*
* @param int $assignmentid The id of the assignment
* @param array $userids Array of user ids to grant extensions to
* @param array $dates Array of extension dates
* @return array of warnings for each extension date that could not be granted
* @since Moodle 2.6
*/
public static function save_user_extensions($assignmentid, $userids, $dates) {
global $CFG;
require_once("$CFG->dirroot/mod/assign/locallib.php");
$params = self::validate_parameters(self::save_user_extensions_parameters(),
array('assignmentid' => $assignmentid,
'userids' => $userids,
'dates' => $dates));
if (count($userids) != count($dates)) {
$detail = 'Length of userids and dates parameters differ.';
$warnings[] = self::generate_warning($assignmentid,
'invalidparameters',
$detail);
return $warnings;
}
$cm = get_coursemodule_from_instance('assign', $assignmentid, 0, false, MUST_EXIST);
$context = context_module::instance($cm->id);
$assignment = new assign($context, $cm, null);
$warnings = array();
foreach ($userids as $idx => $userid) {
$duedate = $dates[$idx];
if (!$assignment->save_user_extension($userid, $duedate)) {
$detail = 'User id: ' . $userid . ', Assignment id: ' . $assignmentid . ', Extension date: ' . $duedate;
$warnings[] = self::generate_warning($assignmentid,
'couldnotgrantextensions',
$detail);
}
}
return $warnings;
}
/**
* Describes the return value for save_user_extensions
*
* @return external_single_structure
* @since Moodle 2.6
*/
public static function save_user_extensions_returns() {
return new external_multiple_structure(
new external_warnings()
);
}
/**
* Describes the parameters for reveal_identities
* @return external_external_function_parameters
* @since Moodle 2.6
*/
public static function reveal_identities_parameters() {
return new external_function_parameters(
array(
'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on')
)
);
}
/**
* Reveal the identities of anonymous students to markers for a single assignment.
*
* @param int $assignmentid The id of the assignment
* @return array of warnings to indicate any errors.
* @since Moodle 2.6
*/
public static function reveal_identities($assignmentid) {
global $CFG, $USER;
require_once("$CFG->dirroot/mod/assign/locallib.php");
$params = self::validate_parameters(self::reveal_identities_parameters(),
array('assignmentid' => $assignmentid));
$cm = get_coursemodule_from_instance('assign', $assignmentid, 0, false, MUST_EXIST);
$context = context_module::instance($cm->id);
$assignment = new assign($context, $cm, null);
$warnings = array();
if (!$assignment->reveal_identities()) {
$detail = 'User id: ' . $USER->id . ', Assignment id: ' . $assignmentid;
$warnings[] = self::generate_warning($assignmentid,
'couldnotrevealidentities',
$detail);
}
return $warnings;
}
/**
* Describes the return value for reveal_identities
*
* @return external_single_structure
* @since Moodle 2.6
*/
public static function reveal_identities_returns() {
return new external_multiple_structure(
new external_warnings()
);
}
/**
* Describes the parameters for save_submission
* @return external_external_function_parameters
* @since Moodle 2.6
*/
public static function save_submission_parameters() {
global $CFG;
require_once("$CFG->dirroot/mod/assign/locallib.php");
$instance = new assign(null, null, null);
$pluginsubmissionparams = array();
foreach ($instance->get_submission_plugins() as $plugin) {
$pluginparams = $plugin->get_external_parameters();
if (!empty($pluginparams)) {
$pluginsubmissionparams = array_merge($pluginsubmissionparams, $pluginparams);
}
}
return new external_function_parameters(
array(
'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
'plugindata' => new external_single_structure(
$pluginsubmissionparams
)
)
);
}
/**
* Save a student submission for a single assignment
*
* @param int $assignmentid The id of the assignment
* @param array $plugindata - The submitted data for plugins
* @return array of warnings to indicate any errors
* @since Moodle 2.6
*/
public static function save_submission($assignmentid, $plugindata) {
global $CFG, $USER;
require_once("$CFG->dirroot/mod/assign/locallib.php");
$params = self::validate_parameters(self::save_submission_parameters(),
array('assignmentid' => $assignmentid,
'plugindata' => $plugindata));
$cm = get_coursemodule_from_instance('assign', $assignmentid, 0, false, MUST_EXIST);
$context = context_module::instance($cm->id);
$assignment = new assign($context, $cm, null);
$notices = array();
$submissiondata = (object)$plugindata;
$assignment->save_submission($submissiondata, $notices);
$warnings = array();
foreach ($notices as $notice) {
$warnings[] = self::generate_warning($assignmentid,
'couldnotsavesubmission',
$notice);
}
return $warnings;
}
/**
* Describes the return value for save_submission
*
* @return external_single_structure
* @since Moodle 2.6
*/
public static function save_submission_returns() {
return new external_multiple_structure(
new external_warnings()
);
}
/**
* Describes the parameters for save_grade
* @return external_external_function_parameters
* @since Moodle 2.6
*/
public static function save_grade_parameters() {
global $CFG;
require_once("$CFG->dirroot/mod/assign/locallib.php");
$instance = new assign(null, null, null);
$pluginfeedbackparams = array();
foreach ($instance->get_feedback_plugins() as $plugin) {
$pluginparams = $plugin->get_external_parameters();
if (!empty($pluginparams)) {
$pluginfeedbackparams = array_merge($pluginfeedbackparams, $pluginparams);
}
}
return new external_function_parameters(
array(
'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
'userid' => new external_value(PARAM_INT, 'The student id to operate on'),
'grade' => new external_value(PARAM_FLOAT, 'The new grade for this user'),
'attemptnumber' => new external_value(PARAM_INT, 'The attempt number (-1 means latest attempt)'),
'addattempt' => new external_value(PARAM_BOOL, 'Allow another attempt if the attempt reopen method is manual'),
'workflowstate' => new external_value(PARAM_ALPHA, 'The next marking workflow state'),
'applytoall' => new external_value(PARAM_BOOL, 'If true, this grade will be applied ' .
'to all members ' .
'of the group (for group assignments).'),
'plugindata' => new external_single_structure(
$pluginfeedbackparams
)
)
);
}
/**
* Save a student grade for a single assignment.
*
* @param int $assignmentid The id of the assignment
* @param int $userid The id of the user
* @param float $grade The grade
* @param int $attemptnumber The attempt number
* @param bool $addattempt Allow another attempt
* @param string $workflowstate New workflow state
* @param bool $applytoall Apply the grade to all members of the group
* @param array $plugindata Custom data used by plugins
* @return null
* @since Moodle 2.6
*/
public static function save_grade($assignmentid,
$userid,
$grade,
$attemptnumber,
$addattempt,
$workflowstate,
$applytoall,
$plugindata) {
global $CFG, $USER;
require_once("$CFG->dirroot/mod/assign/locallib.php");
$params = self::validate_parameters(self::save_grade_parameters(),
array('assignmentid' => $assignmentid,
'userid' => $userid,
'grade' => $grade,
'attemptnumber' => $attemptnumber,
'workflowstate' => $workflowstate,
'addattempt' => $addattempt,
'applytoall' => $applytoall,
'plugindata' => $plugindata));
$cm = get_coursemodule_from_instance('assign', $assignmentid, 0, false, MUST_EXIST);
$context = context_module::instance($cm->id);
$assignment = new assign($context, $cm, null);
$gradedata = (object)$plugindata;
$gradedata->addattempt = $addattempt;
$gradedata->attemptnumber = $attemptnumber;
$gradedata->workflowstate = $workflowstate;
$gradedata->applytoall = $applytoall;
$gradedata->grade = $grade;
$assignment->save_grade($userid, $gradedata);
return null;
}
/**
* Describes the return value for save_grade
*
* @return external_single_structure
* @since Moodle 2.6
*/
public static function save_grade_returns() {
return null;
}
/**
* Describes the parameters for copy_previous_attempt
* @return external_external_function_parameters
* @since Moodle 2.6
*/
public static function copy_previous_attempt_parameters() {
return new external_function_parameters(
array(
'assignmentid' => new external_value(PARAM_INT, 'The assignment id to operate on'),
)
);
}
/**
* Copy a students previous attempt to a new attempt.
*
* @param int $assignmentid
* @return array of warnings to indicate any errors.
* @since Moodle 2.6
*/
public static function copy_previous_attempt($assignmentid) {
global $CFG, $USER;
require_once("$CFG->dirroot/mod/assign/locallib.php");
$params = self::validate_parameters(self::copy_previous_attempt_parameters(),
array('assignmentid' => $assignmentid));
$cm = get_coursemodule_from_instance('assign', $assignmentid, 0, false, MUST_EXIST);
$context = context_module::instance($cm->id);
$assignment = new assign($context, $cm, null);
$notices = array();
$assignment->copy_previous_attempt($submissiondata, $notices);
$warnings = array();
foreach ($notices as $notice) {
$warnings[] = self::generate_warning($assignmentid,
'couldnotcopyprevioussubmission',
$notice);
}
return $warnings;
}
/**
* Describes the return value for save_submission
*
* @return external_single_structure
* @since Moodle 2.6
*/
public static function copy_previous_attempt_returns() {
return new external_multiple_structure(
new external_warnings()
);
}
}
@@ -15,7 +15,9 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Restore subplugin class that provides the necessary information needed to restore
* Restore subplugin class.
*
* Provides the necessary information needed to restore
* one assign_submission subplugin.
*
* @package assignfeedback_comments
@@ -26,7 +28,9 @@
defined('MOODLE_INTERNAL') || die();
/**
* Restore subplugin class that provides the necessary information needed to restore
* Restore subplugin class.
*
* Provides the necessary information needed to restore
* one assignfeedback subplugin.
*
* @package assignfeedback_comments
+12
View File
@@ -390,4 +390,16 @@ class assign_feedback_comments extends assign_feedback_plugin {
return $this->view($grade) == '';
}
/**
* Return a description of external params suitable for uploading an feedback comment from a webservice.
*
* @return external_description|null
*/
public function get_external_parameters() {
$editorparams = array('text' => new external_value(PARAM_TEXT, 'The text for this feedback.'),
'format' => new external_value(PARAM_INT, 'The format for this feedback'));
$editorstructure = new external_single_structure($editorparams);
return array('assignfeedbackcomments_editor' => $editorstructure);
}
}
+1 -1
View File
@@ -17,7 +17,7 @@
/**
* This file defines the admin settings for this plugin
*
* @package assignsubmission_comments
* @package assignfeedback_comments
* @copyright 2012 NetSpot {@link http://www.netspot.com.au}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
@@ -24,7 +24,9 @@
defined('MOODLE_INTERNAL') || die();
/**
* Restore subplugin class that provides the necessary information needed
* Restore subplugin class.
*
* Provides the necessary information needed
* to restore one assign_feedback subplugin.
*
* @package assignfeedback_file
+16 -1
View File
@@ -36,7 +36,7 @@ define('ASSIGNFEEDBACK_FILE_MAXFILEUNZIPTIME', 120);
/**
* Library class for file feedback plugin extending feedback plugin base class.
*
* @package asignfeedback_file
* @package assignfeedback_file
* @copyright 2012 NetSpot {@link http://www.netspot.com.au}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
@@ -609,4 +609,19 @@ class assign_feedback_file extends assign_feedback_plugin {
public function get_grading_actions() {
return array('uploadzip'=>get_string('uploadzip', 'assignfeedback_file'));
}
/**
* Return a description of external params suitable for uploading a feedback file from a webservice.
*
* @return external_description|null
*/
public function get_external_parameters() {
return array(
'files_filemanager' => new external_value(
PARAM_INT,
'The id of a draft area containing files for this feedback.'
)
);
}
}
+1 -1
View File
@@ -17,7 +17,7 @@
/**
* This file defines the admin settings for this plugin
*
* @package assignsubmission_onlinetext
* @package assignfeedback_file
* @copyright 2012 NetSpot {@link http://www.netspot.com.au}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
+4 -2
View File
@@ -71,6 +71,7 @@ class assign_grading_table extends table_sql implements renderable {
* @param string $filter The current filter
* @param int $rowoffset For showing a subsequent page of results
* @param bool $quickgrading Is this table wrapped in a quickgrading form?
* @param string $downloadfilename
*/
public function __construct(assign $assignment,
$perpage,
@@ -435,6 +436,7 @@ class assign_grading_table extends table_sql implements renderable {
/**
* Add a column with an ID that uniquely identifies this user in this assignment.
*
* @param stdClass $row
* @return string
*/
public function col_recordid(stdClass $row) {
@@ -621,8 +623,8 @@ class assign_grading_table extends table_sql implements renderable {
* Use a static cache to try and reduce DB calls.
*
* @param int $userid The user id for this submission
* @param int $groupid The groupid (returned)
* @param mixed $submission The stdClass submission or false (returned)
* @param int $group The groupid (returned)
* @param stdClass|false $submission The stdClass submission or false (returned)
* @param int $attemptnumber Return a specific attempt number (-1 for latest)
*/
protected function get_group_and_submission($userid, &$group, &$submission, $attemptnumber) {
+12 -10
View File
@@ -16,6 +16,7 @@
/**
* This file contains the moodle hooks for the assign module.
*
* It delegates most functions to the assignment class.
*
* @package mod_assign
@@ -59,8 +60,9 @@ function assign_delete_instance($id) {
* This function is used by the reset_course_userdata function in moodlelib.
* This function will remove all assignment submissions and feedbacks in the database
* and clean up any related data.
* @param $data the data submitted from the reset course.
* @return array status array
*
* @param stdClass $data the data submitted from the reset course.
* @return array
*/
function assign_reset_userdata($data) {
global $CFG, $DB;
@@ -109,7 +111,7 @@ function assign_reset_gradebook($courseid, $type='') {
/**
* Implementation of the function for printing the form elements that control
* whether the course reset functionality affects the assignment.
* @param $mform form passed by reference
* @param moodleform $mform form passed by reference
*/
function assign_reset_course_form_definition(&$mform) {
$mform->addElement('header', 'assignheader', get_string('modulenameplural', 'assign'));
@@ -131,7 +133,7 @@ function assign_reset_course_form_defaults($course) {
*
* This is done by calling the update_instance() method of the assignment type class
* @param stdClass $data
* @param $form
* @param stdClass $form - unused
* @return object
*/
function assign_update_instance(stdClass $data, $form) {
@@ -280,11 +282,11 @@ function assign_get_coursemodule_info($coursemodule) {
* @param stdClass $currentcontext Current context of block
*/
function assign_page_type_list($pagetype, $parentcontext, $currentcontext) {
$module_pagetype = array(
$modulepagetype = array(
'mod-assign-*' => get_string('page-mod-assign-x', 'assign'),
'mod-assign-view' => get_string('page-mod-assign-view', 'assign'),
);
return $module_pagetype;
return $modulepagetype;
}
/**
@@ -656,10 +658,10 @@ function assign_get_recent_mod_activity(&$activities,
}
$groupmode = groups_get_activity_groupmode($cm, $course);
$cm_context = context_module::instance($cm->id);
$grader = has_capability('moodle/grade:viewall', $cm_context);
$accessallgroups = has_capability('moodle/site:accessallgroups', $cm_context);
$viewfullnames = has_capability('moodle/site:viewfullnames', $cm_context);
$cmcontext = context_module::instance($cm->id);
$grader = has_capability('moodle/grade:viewall', $cmcontext);
$accessallgroups = has_capability('moodle/site:accessallgroups', $cmcontext);
$viewfullnames = has_capability('moodle/site:viewfullnames', $cmcontext);
if (is_null($modinfo->get_groups())) {
// Load all my groups and cache it in modinfo.
+424 -270
View File
@@ -389,7 +389,7 @@ class assign {
$nextpageparams['action'] = 'editsubmission';
}
} else if ($action == 'lock') {
$this->process_lock();
$this->process_lock_submission();
$action = 'redirect';
$nextpageparams['action'] = 'grading';
} else if ($action == 'addattempt') {
@@ -401,7 +401,7 @@ class assign {
$action = 'redirect';
$nextpageparams['action'] = 'grading';
} else if ($action == 'unlock') {
$this->process_unlock();
$this->process_unlock_submission();
$action = 'redirect';
$nextpageparams['action'] = 'grading';
} else if ($action == 'setbatchmarkingworkflowstate') {
@@ -674,7 +674,7 @@ class assign {
* Actual implementation of the reset course functionality, delete all the
* assignment submissions for course $data->courseid.
*
* @param $data the data submitted from the reset course.
* @param stdClass $data the data submitted from the reset course.
* @return array status array
*/
public function reset_userdata($data) {
@@ -2012,10 +2012,10 @@ class assign {
$submitted = get_string('submissionstatus_', 'assign');
}
}
$grading_info = grade_get_grades($course->id, 'mod', 'assign', $cm->instance, $USER->id);
if (isset($grading_info->items[0]->grades[$USER->id]) &&
!$grading_info->items[0]->grades[$USER->id]->hidden ) {
$grade = $grading_info->items[0]->grades[$USER->id]->str_grade;
$gradinginfo = grade_get_grades($course->id, 'mod', 'assign', $cm->instance, $USER->id);
if (isset($gradinginfo->items[0]->grades[$USER->id]) &&
!$gradinginfo->items[0]->grades[$USER->id]->hidden ) {
$grade = $gradinginfo->items[0]->grades[$USER->id]->str_grade;
} else {
$grade = '-';
}
@@ -2151,6 +2151,7 @@ class assign {
/**
* Rewrite plugin file urls so they resolve correctly in an exported zip.
*
* @param string $text - The replacement text
* @param stdClass $user - The user record
* @param assign_plugin $plugin - The assignment plugin
*/
@@ -2240,6 +2241,7 @@ class assign {
/**
* Display a continue page.
*
* @param string $message - The message to display
* @return string
*/
protected function view_savegrading_result($message) {
@@ -3246,6 +3248,7 @@ class assign {
/**
* Allows the plugin to show a batch grading operation page.
*
* @param moodleform $mform
* @return none
*/
protected function view_plugin_grading_batch_operation($mform) {
@@ -3323,9 +3326,9 @@ class assign {
foreach ($userlist as $userid) {
if ($data->operation == 'lock') {
$this->process_lock($userid);
$this->process_lock_submission($userid);
} else if ($data->operation == 'unlock') {
$this->process_unlock($userid);
$this->process_unlock_submission($userid);
} else if ($data->operation == 'reverttodraft') {
$this->process_revert_to_draft($userid);
} else if ($data->operation == 'addattempt') {
@@ -3462,7 +3465,7 @@ class assign {
/**
* Ask the user to confirm they want to submit their work for grading.
*
* @param $mform moodleform - null unless form validation has failed
* @param moodleform $mform - null unless form validation has failed
* @return string
*/
protected function check_submit_for_grading($mform) {
@@ -3660,7 +3663,8 @@ class assign {
// Only show the grade if it is not hidden in gradebook.
if (!empty($gradebookgrade->grade) && ($cangrade || !$gradebookgrade->hidden)) {
if ($controller = $gradingmanager->get_active_controller()) {
$controller->set_grade_range(make_grades_menu($this->get_instance()->grade), $this->get_instance()->grade > 0);
$menu = make_grades_menu($this->get_instance()->grade);
$controller->set_grade_range($menu, $this->get_instance()->grade > 0);
$gradefordisplay = $controller->render_grade($PAGE,
$grade->id,
$gradingitem,
@@ -4250,7 +4254,6 @@ class assign {
* @param string $modulename
* @param stdClass $coursemodule
* @param string $assignmentname
* @param stdClass $info
*/
protected static function format_notification_message_html($messagetype,
$info,
@@ -4290,6 +4293,8 @@ class assign {
* @param stdClass $course
* @param string $modulename
* @param string $assignmentname
* @param bool $blindmarking
* @param int $uniqueidforuser
* @return void
*/
public static function send_assignment_notification($userfrom,
@@ -4471,18 +4476,85 @@ class assign {
}
}
/**
* Submit a submission for grading.
*
* @return bool Return false if the submission was not submitted.
*/
public function submit_for_grading($data) {
global $USER;
// Need submit permission to submit an assignment.
require_capability('mod/assign:submit', $this->context);
$instance = $this->get_instance();
if ($instance->teamsubmission) {
$submission = $this->get_group_submission($USER->id, 0, true);
} else {
$submission = $this->get_user_submission($USER->id, true);
}
if (!$this->submissions_open($USER->id)) {
return false;
}
if ($instance->requiresubmissionstatement && !$data->submissionstatement) {
return false;
}
if ($submission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
// Give each submission plugin a chance to process the submission.
$plugins = $this->get_submission_plugins();
foreach ($plugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
$plugin->submit_for_grading($submission);
}
}
$submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
$this->update_submission($submission, $USER->id, true, $instance->teamsubmission);
$completion = new completion_info($this->get_course());
if ($completion->is_enabled($this->get_course_module()) && $instance->completionsubmit) {
$completion->update_state($this->get_course_module(), COMPLETION_COMPLETE, $USER->id);
}
if (!empty($data->submissionstatement)) {
$logmessage = get_string('submissionstatementacceptedlog',
'mod_assign',
fullname($USER));
$this->add_to_log('submission statement accepted', $logmessage);
}
$logdata = $this->add_to_log('submit for grading', $this->format_submission_for_log($submission), '', true);
$this->notify_graders($submission);
$this->notify_student_submission_receipt($submission);
// Trigger assessable_submitted event on submission.
$params = array(
'context' => context_module::instance($this->get_course_module()->id),
'objectid' => $submission->id,
'other' => array(
'submission_editable' => false
)
);
$event = \mod_assign\event\assessable_submitted::create($params);
$event->set_legacy_logdata($logdata);
$event->trigger();
return true;
}
return false;
}
/**
* Assignment submission is processed before grading.
*
* @param $mform If validation failed when submitting this form - this is the moodleform.
* @param moodleform|null $mform If validation failed when submitting this form - this is the moodleform.
* It can be null.
* @return bool Return false if the validation fails. This affects which page is displayed next.
*/
protected function process_submit_for_grading($mform) {
global $USER, $CFG;
// Need submit permission to submit an assignment.
require_capability('mod/assign:submit', $this->context);
require_once($CFG->dirroot . '/mod/assign/submissionconfirmform.php');
require_sesskey();
@@ -4512,57 +4584,7 @@ class assign {
if ($mform->get_data() == false) {
return false;
}
if ($instance->teamsubmission) {
$submission = $this->get_group_submission($USER->id, 0, true);
} else {
$submission = $this->get_user_submission($USER->id, true);
}
if ($submission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
// Give each submission plugin a chance to process the submission.
$plugins = $this->get_submission_plugins();
foreach ($plugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
$plugin->submit_for_grading($submission);
}
}
$submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
$this->update_submission($submission, $USER->id, true, $instance->teamsubmission);
$completion = new completion_info($this->get_course());
if ($completion->is_enabled($this->get_course_module()) && $instance->completionsubmit) {
$completion->update_state($this->get_course_module(), COMPLETION_COMPLETE, $USER->id);
}
if (isset($data->submissionstatement)) {
$logmessage = get_string('submissionstatementacceptedlog',
'mod_assign',
fullname($USER));
$addtolog = $this->add_to_log('submission statement accepted', $logmessage, '', true);
$params = array(
'context' => $this->context,
'objectid' => $submission->id
);
$event = \mod_assign\event\statement_accepted::create($params);
$event->set_legacy_logdata($addtolog);
$event->trigger();
}
$logdata = $this->add_to_log('submit for grading', $this->format_submission_for_log($submission), '', true);
$this->notify_graders($submission);
$this->notify_student_submission_receipt($submission);
// Trigger assessable_submitted event on submission.
$params = array(
'context' => context_module::instance($this->get_course_module()->id),
'objectid' => $submission->id,
'other' => array(
'submission_editable' => false
)
);
$event = \mod_assign\event\assessable_submitted::create($params);
$event->set_legacy_logdata($logdata);
$event->trigger();
}
return $this->submit_for_grading($data);
}
return true;
}
@@ -4574,9 +4596,30 @@ class assign {
* @param mixed $extensionduedate Either an integer date or null
* @return boolean
*/
protected function save_user_extension($userid, $extensionduedate) {
public function save_user_extension($userid, $extensionduedate) {
global $DB;
// Need submit permission to submit an assignment.
require_capability('mod/assign:grantextension', $this->context);
if (!is_enrolled($this->get_course_context(), $userid)) {
return false;
}
if (!has_capability('mod/assign:submit', $this->context, $userid)) {
return false;
}
if ($this->get_instance()->duedate && $extensionduedate) {
if ($this->get_instance()->duedate > $extensionduedate) {
return false;
}
}
if ($this->get_instance()->allowsubmissionsfromdate && $extensionduedate) {
if ($this->get_instance()->allowsubmissionsfromdate > $extensionduedate) {
return false;
}
}
$flags = $this->get_user_flags($userid, true);
$flags->extensionduedate = $extensionduedate;
@@ -4608,9 +4651,6 @@ class assign {
// Include extension form.
require_once($CFG->dirroot . '/mod/assign/extensionform.php');
// Need submit permission to submit an assignment.
require_capability('mod/assign:grantextension', $this->context);
$batchusers = optional_param('selectedusers', '', PARAM_SEQUENCE);
$userid = 0;
if (!$batchusers) {
@@ -4843,11 +4883,12 @@ class assign {
*
* @return void
*/
protected function process_reveal_identities() {
global $DB, $CFG;
public function reveal_identities() {
global $DB;
require_capability('mod/assign:revealidentities', $this->context);
if (!confirm_sesskey()) {
if ($this->get_instance()->revealidentities || empty($this->get_instance()->blindmarking)) {
return false;
}
@@ -4891,6 +4932,20 @@ class assign {
$event->trigger();
}
/**
* Reveal student identities to markers (and the gradebook).
*
* @return void
*/
protected function process_reveal_identities() {
if (!confirm_sesskey()) {
return false;
}
return $this->reveal_identities();
}
/**
* Save grading options.
@@ -5018,15 +5073,30 @@ class assign {
}
/**
* Copy the current assignment submission from the last submitted attempt.
* Require a valid sess key and then call copy_previous_attempt.
*
* @param array $notices Any error messages that should be shown
* to the user at the top of the edit submission form.
* @return bool
*/
protected function process_copy_previous_attempt(&$notices) {
require_sesskey();
return copy_previous_attempt($notices);
}
/**
* Copy the current assignment submission from the last submitted attempt.
*
* @param array $notices Any error messages that should be shown
* to the user at the top of the edit submission form.
* @return bool
*/
public function copy_previous_attempt(&$notices) {
global $USER, $CFG;
require_capability('mod/assign:submit', $this->context);
$instance = $this->get_instance();
if ($instance->teamsubmission) {
$submission = $this->get_group_submission($USER->id, 0, true);
@@ -5136,6 +5206,108 @@ class assign {
return $allempty;
}
/**
* Save assignment submission for the current user.
*
* @param stdClass $data
* @param array $notices Any error messages that should be shown
* to the user.
* @return bool
*/
public function save_submission(stdClass $data, & $notices) {
global $CFG, $USER;
require_capability('mod/assign:submit', $this->context);
$instance = $this->get_instance();
if ($instance->teamsubmission) {
$submission = $this->get_group_submission($USER->id, 0, true);
} else {
$submission = $this->get_user_submission($USER->id, true);
}
if ($instance->submissiondrafts) {
$submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
} else {
$submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
}
$flags = $this->get_user_flags($USER->id, false);
// Get the flags to check if it is locked.
if ($flags && $flags->locked) {
print_error('submissionslocked', 'assign');
return true;
}
$pluginerror = false;
foreach ($this->submissionplugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
if (!$plugin->save($submission, $data)) {
$notices[] = $plugin->get_error();
$pluginerror = true;
}
}
}
$allempty = $this->submission_empty($submission);
if ($pluginerror || $allempty) {
if ($allempty) {
$notices[] = get_string('submissionempty', 'mod_assign');
}
return false;
}
$this->update_submission($submission, $USER->id, true, $instance->teamsubmission);
// Logging.
if (isset($data->submissionstatement)) {
$logmessage = get_string('submissionstatementacceptedlog',
'mod_assign',
fullname($USER));
$this->add_to_log('submission statement accepted', $logmessage);
$addtolog = $this->add_to_log('submission statement accepted', $logmessage, '', true);
$params = array(
'context' => $this->context,
'objectid' => $submission->id
);
$event = \mod_assign\event\statement_accepted::create($params);
$event->set_legacy_logdata($addtolog);
$event->trigger();
}
$addtolog = $this->add_to_log('submit', $this->format_submission_for_log($submission), '', true);
$params = array(
'context' => $this->context,
'objectid' => $submission->id
);
$event = \mod_assign\event\submission_updated::create($params);
$event->set_legacy_logdata($addtolog);
$event->trigger();
$complete = COMPLETION_INCOMPLETE;
if ($submission->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
$complete = COMPLETION_COMPLETE;
}
$completion = new completion_info($this->get_course());
if ($completion->is_enabled($this->get_course_module()) && $instance->completionsubmit) {
$completion->update_state($this->get_course_module(), $complete, $USER->id);
}
if (!$instance->submissiondrafts) {
$this->notify_student_submission_receipt($submission);
$this->notify_graders($submission);
// Trigger assessable_submitted event on submission.
$params = array(
'context' => context_module::instance($this->get_course_module()->id),
'objectid' => $submission->id,
'other' => array(
'submission_editable' => true
)
);
$event = \mod_assign\event\assessable_submitted::create($params);
$event->trigger();
}
return true;
}
/**
* Save assignment submission.
*
@@ -5145,13 +5317,12 @@ class assign {
* @return bool
*/
protected function process_save_submission(&$mform, &$notices) {
global $USER, $CFG;
global $CFG;
// Include submission form.
require_once($CFG->dirroot . '/mod/assign/submission_form.php');
// Need submit permission to submit an assignment.
require_capability('mod/assign:submit', $this->context);
require_sesskey();
if (!$this->submissions_open()) {
$notices[] = get_string('duedatereached', 'assign');
@@ -5165,92 +5336,7 @@ class assign {
return true;
}
if ($data = $mform->get_data()) {
if ($instance->teamsubmission) {
$submission = $this->get_group_submission($USER->id, 0, true);
} else {
$submission = $this->get_user_submission($USER->id, true);
}
if ($instance->submissiondrafts) {
$submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
} else {
$submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
}
$flags = $this->get_user_flags($USER->id, false);
// Get the flags to check if it is locked.
if ($flags && $flags->locked) {
print_error('submissionslocked', 'assign');
return true;
}
$pluginerror = false;
foreach ($this->submissionplugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
if (!$plugin->save($submission, $data)) {
$notices[] = $plugin->get_error();
$pluginerror = true;
}
}
}
$allempty = $this->submission_empty($submission);
if ($pluginerror || $allempty) {
if ($allempty) {
$notices[] = get_string('submissionempty', 'mod_assign');
}
return false;
}
$this->update_submission($submission, $USER->id, true, $instance->teamsubmission);
// Logging.
if (isset($data->submissionstatement)) {
$logmessage = get_string('submissionstatementacceptedlog',
'mod_assign',
fullname($USER));
$addtolog = $this->add_to_log('submission statement accepted', $logmessage, '', true);
$params = array(
'context' => $this->context,
'objectid' => $submission->id
);
$event = \mod_assign\event\statement_accepted::create($params);
$event->set_legacy_logdata($addtolog);
$event->trigger();
}
$addtolog = $this->add_to_log('submit', $this->format_submission_for_log($submission), '', true);
$params = array(
'context' => $this->context,
'objectid' => $submission->id
);
$event = \mod_assign\event\submission_updated::create($params);
$event->set_legacy_logdata($addtolog);
$event->trigger();
$complete = COMPLETION_INCOMPLETE;
if ($submission->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
$complete = COMPLETION_COMPLETE;
}
$completion = new completion_info($this->get_course());
if ($completion->is_enabled($this->get_course_module()) && $instance->completionsubmit) {
$completion->update_state($this->get_course_module(), $complete, $USER->id);
}
if (!$instance->submissiondrafts) {
$this->notify_student_submission_receipt($submission);
$this->notify_graders($submission);
// Trigger assessable_submitted event on submission.
$params = array(
'context' => context_module::instance($this->get_course_module()->id),
'objectid' => $submission->id,
'other' => array(
'submission_editable' => true
)
);
$event = \mod_assign\event\assessable_submitted::create($params);
$event->trigger();
}
return true;
return $this->save_submission($data, $notices);
}
return false;
}
@@ -5295,6 +5381,7 @@ class assign {
* This is specific to the assignment, marker and student.
*
* @param int $userid - The student userid
* @param stdClass|false $grade - The grade record
* @param bool $gradingdisabled
* @return mixed gradingform_instance|null $gradinginstance
*/
@@ -5686,21 +5773,15 @@ class assign {
/**
* Revert to draft.
* Uses url parameter userid
*
* @param int $userid
* @return void
* @return boolean
*/
protected function process_revert_to_draft($userid = 0) {
public function revert_to_draft($userid) {
global $DB, $USER;
// Need grade permission.
require_capability('mod/assign:grade', $this->context);
require_sesskey();
if (!$userid) {
$userid = required_param('userid', PARAM_INT);
}
if ($this->get_instance()->teamsubmission) {
$submission = $this->get_group_submission($userid, 0, false);
@@ -5709,7 +5790,7 @@ class assign {
}
if (!$submission) {
return;
return false;
}
$submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
$this->update_submission($submission, $userid, true, $this->get_instance()->teamsubmission);
@@ -5748,39 +5829,51 @@ class assign {
$event = \mod_assign\event\submission_status_updated::create($params);
$event->set_legacy_logdata($addtolog);
$event->trigger();
return true;
}
/**
* Lock the process.
* Uses url parameter userid
* Revert to draft.
* Uses url parameter userid if userid not supplied as a parameter.
*
* @param int $userid
* @return void
* @return boolean
*/
protected function process_lock($userid = 0) {
global $USER, $DB;
// Need grade permission.
require_capability('mod/assign:grade', $this->context);
protected function process_revert_to_draft($userid = 0) {
require_sesskey();
if (!$userid) {
$userid = required_param('userid', PARAM_INT);
}
return $this->revert_to_draft($userid);
}
/**
* Prevent student updates to this submission
*
* @param int $userid
* @return bool
*/
public function lock_submission($userid) {
global $USER, $DB;
// Need grade permission.
require_capability('mod/assign:grade', $this->context);
// Give each submission plugin a chance to process the locking.
$plugins = $this->get_submission_plugins();
$submission = $this->get_user_submission($userid, false);
foreach ($plugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
$plugin->lock($submission);
}
}
$flags = $this->get_user_flags($userid, true);
$flags->locked = 1;
$this->update_user_flags($flags);
foreach ($plugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
$plugin->lock($submission, $flags);
}
}
$user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST);
$logmessage = get_string('locksubmissionforstudent',
@@ -5795,6 +5888,7 @@ class assign {
$event = \mod_assign\event\submission_locked::create($params);
$event->set_legacy_logdata($addtolog);
$event->trigger();
return true;
}
@@ -5905,34 +5999,49 @@ class assign {
/**
* Unlock the process.
* Prevent student updates to this submission.
* Uses url parameter userid.
*
* @param int $userid
* @return void
*/
protected function process_unlock($userid = 0) {
global $USER, $DB;
protected function process_lock_submission($userid = 0) {
// Need grade permission.
require_capability('mod/assign:grade', $this->context);
require_sesskey();
if (!$userid) {
$userid = required_param('userid', PARAM_INT);
}
return $this->lock_submission($userid);
}
/**
* Unlock the student submission.
*
* @param int $userid
* @return bool
*/
public function unlock_submission($userid) {
global $USER, $DB;
// Need grade permission.
require_capability('mod/assign:grade', $this->context);
// Give each submission plugin a chance to process the unlocking.
$plugins = $this->get_submission_plugins();
$submission = $this->get_user_submission($userid, false);
foreach ($plugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
$plugin->unlock($submission);
}
}
$flags = $this->get_user_flags($userid, true);
$flags->locked = 0;
$this->update_user_flags($flags);
foreach ($plugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
$plugin->unlock($submission, $flags);
}
}
$user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST);
$logmessage = get_string('unlocksubmissionforstudent',
@@ -5947,6 +6056,25 @@ class assign {
$event = \mod_assign\event\submission_unlocked::create($params);
$event->set_legacy_logdata($addtolog);
$event->trigger();
return true;
}
/**
* Unlock the student submission.
* Uses url parameter userid.
*
* @param int $userid
* @return bool
*/
protected function process_unlock_submission($userid = 0) {
require_sesskey();
if (!$userid) {
$userid = required_param('userid', PARAM_INT);
}
return $this->unlock_submission($userid);
}
/**
@@ -5954,7 +6082,7 @@ class assign {
*
* @param stdClass $formdata - the data from the form
* @param int $userid - the user to apply the grade to
* @param int attemptnumber - The attempt number to apply the grade to.
* @param int $attemptnumber - The attempt number to apply the grade to.
* @return void
*/
protected function apply_grade_to_user($formdata, $userid, $attemptnumber) {
@@ -6060,6 +6188,92 @@ class assign {
}
/**
* Save grade update.
*
* @param int $userid
* @param stdClass $data
* @return bool - was the grade saved
*/
public function save_grade($userid, $data) {
// Need grade permission.
require_capability('mod/assign:grade', $this->context);
$instance = $this->get_instance();
$submission = null;
if ($instance->teamsubmission) {
$submission = $this->get_group_submission($userid, 0, false, $data->attemptnumber);
} else {
$submission = $this->get_user_submission($userid, false, $data->attemptnumber);
}
if ($instance->teamsubmission && $data->applytoall) {
$groupid = 0;
if ($this->get_submission_group($userid)) {
$group = $this->get_submission_group($userid);
if ($group) {
$groupid = $group->id;
}
}
$members = $this->get_submission_group_members($groupid, true);
foreach ($members as $member) {
// User may exist in multple groups (which should put them in the default group).
$this->apply_grade_to_user($data, $member->id, $data->attemptnumber);
$this->process_outcomes($member->id, $data);
}
} else {
$this->apply_grade_to_user($data, $userid, $data->attemptnumber);
$this->process_outcomes($userid, $data);
}
$maxattemptsreached = !empty($submission) &&
$submission->attemptnumber >= ($instance->maxattempts - 1) &&
$instance->maxattempts != ASSIGN_UNLIMITED_ATTEMPTS;
$shouldreopen = false;
if ($instance->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_UNTILPASS) {
// Check the gradetopass from the gradebook.
$gradinginfo = grade_get_grades($this->get_course()->id,
'mod',
'assign',
$instance->id,
$userid);
// What do we do if the grade has not been added to the gradebook (e.g. blind marking)?
$gradingitem = null;
$gradebookgrade = null;
if (isset($gradinginfo->items[0])) {
$gradingitem = $gradinginfo->items[0];
$gradebookgrade = $gradingitem->grades[$userid];
}
if ($gradebookgrade) {
// TODO: This code should call grade_grade->is_passed().
$shouldreopen = true;
if (is_null($gradebookgrade->grade)) {
$shouldreopen = false;
}
if (empty($gradingitem->gradepass) || $gradingitem->gradepass == $gradingitem->grademin) {
$shouldreopen = false;
}
if ($gradebookgrade->grade >= $gradingitem->gradepass) {
$shouldreopen = false;
}
}
}
if ($instance->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL &&
!empty($data->addattempt)) {
$shouldreopen = true;
}
// Never reopen if we are editing a previous attempt.
if ($data->attemptnumber != -1) {
$shouldreopen = false;
}
if ($shouldreopen && !$maxattemptsreached) {
$this->add_attempt($userid);
}
return true;
}
/**
* Save grade.
*
@@ -6071,8 +6285,6 @@ class assign {
// Include grade form.
require_once($CFG->dirroot . '/mod/assign/gradeform.php');
// Need submit permission to submit an assignment.
require_capability('mod/assign:grade', $this->context);
require_sesskey();
$instance = $this->get_instance();
@@ -6111,80 +6323,10 @@ class assign {
array('class'=>'gradeform'));
if ($formdata = $mform->get_data()) {
$submission = null;
if ($instance->teamsubmission) {
$submission = $this->get_group_submission($userid, 0, false, $attemptnumber);
} else {
$submission = $this->get_user_submission($userid, false, $attemptnumber);
}
if ($instance->teamsubmission && $formdata->applytoall) {
$groupid = 0;
if ($this->get_submission_group($userid)) {
$group = $this->get_submission_group($userid);
if ($group) {
$groupid = $group->id;
}
}
$members = $this->get_submission_group_members($groupid, true);
foreach ($members as $member) {
// User may exist in multple groups (which should put them in the default group).
$this->apply_grade_to_user($formdata, $member->id, $attemptnumber);
$this->process_outcomes($member->id, $formdata);
}
} else {
$this->apply_grade_to_user($formdata, $userid, $attemptnumber);
$this->process_outcomes($userid, $formdata);
}
$maxattemptsreached = !empty($submission) &&
$submission->attemptnumber >= ($instance->maxattempts - 1) &&
$instance->maxattempts != ASSIGN_UNLIMITED_ATTEMPTS;
$shouldreopen = false;
if ($instance->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_UNTILPASS) {
// Check the gradetopass from the gradebook.
$gradinginfo = grade_get_grades($this->get_course()->id,
'mod',
'assign',
$instance->id,
$userid);
// What do we do if the grade has not been added to the gradebook (e.g. blind marking)?
$gradingitem = null;
$gradebookgrade = null;
if (isset($gradinginfo->items[0])) {
$gradingitem = $gradinginfo->items[0];
$gradebookgrade = $gradingitem->grades[$userid];
}
if ($gradebookgrade) {
// TODO: This code should call grade_grade->is_passed().
$shouldreopen = true;
if (is_null($gradebookgrade->grade)) {
$shouldreopen = false;
}
if (empty($gradingitem->gradepass) || $gradingitem->gradepass == $gradingitem->grademin) {
$shouldreopen = false;
}
if ($gradebookgrade->grade >= $gradingitem->gradepass) {
$shouldreopen = false;
}
}
}
if ($instance->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL &&
!empty($formdata->addattempt)) {
$shouldreopen = true;
}
// Never reopen if we are editing a previous attempt.
if ($attemptnumber != -1) {
$shouldreopen = false;
}
if ($shouldreopen && !$maxattemptsreached) {
$this->process_add_attempt($userid);
}
return $this->save_grade($userid, $formdata);
} else {
return false;
}
return true;
}
/**
@@ -6297,15 +6439,26 @@ class assign {
}
/**
* Add a new attempt for a user.
* Check for a sess key and then call add_attempt.
*
* @param int $userid int The user to add the attempt for
* @return bool - true if successful.
*/
protected function process_add_attempt($userid) {
require_capability('mod/assign:grade', $this->context);
require_sesskey();
return $this->add_attempt($userid);
}
/**
* Add a new attempt for a user.
*
* @param int $userid int The user to add the attempt for
* @return bool - true if successful.
*/
protected function add_attempt($userid) {
require_capability('mod/assign:grade', $this->context);
if ($this->get_instance()->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_NONE) {
return false;
}
@@ -6466,6 +6619,7 @@ class assign {
/**
* Lookup this user id and return the unique id for this assignment.
*
* @param int $assignid The assignment id
* @param int $userid The userid to lookup
* @return int The unique id
*/
+11
View File
@@ -265,6 +265,11 @@ class mod_assign_mod_form extends moodleform_mod {
$assignment->plugin_data_preprocessing($defaultvalues);
}
/**
* Add any custom completion rules to the form.
*
* @return array Contains the names of the added form elements
*/
public function add_completion_rules() {
$mform =& $this->_form;
@@ -272,6 +277,12 @@ class mod_assign_mod_form extends moodleform_mod {
return array('completionsubmit');
}
/**
* Determines if completion is enabled for this module.
*
* @param array $data
* @return bool
*/
public function completion_rule_enabled($data) {
return !empty($data['completionsubmit']);
}
+13 -10
View File
@@ -42,6 +42,7 @@ class assign_submit_for_grading_page implements renderable {
* Constructor
* @param string $notifications - Any mesages to display
* @param int $coursemoduleid
* @param moodleform $confirmform
*/
public function __construct($notifications, $coursemoduleid, $confirmform) {
$this->notifications = $notifications;
@@ -69,6 +70,7 @@ class assign_gradingmessage implements renderable {
* Constructor
* @param string $heading This is the heading to display
* @param string $message This is the message to display
* @param int $coursemoduleid
*/
public function __construct($heading, $message, $coursemoduleid) {
$this->heading = $heading;
@@ -404,6 +406,7 @@ class assign_submission_status implements renderable {
* @param int $extensionduedate - Any extension to the due date granted for this user
* @param context $context - Any extension to the due date granted for this user
* @param bool $blindmarking - Should we hide student identities from graders?
* @param string $gradingcontrollerpreview
* @param string $attemptreopenmethod - The method of reopening student attempts.
* @param int $maxattempts - How many attempts can a student make?
*/
@@ -493,14 +496,14 @@ class assign_attempt_history implements renderable {
/**
* Constructor
*
* @param $submissions
* @param $grades
* @param $submissionplugins
* @param $feedbackplugins
* @param $coursemoduleid
* @param $returnaction
* @param $returnparams
* @param $cangrade
* @param array $submissions
* @param array $grades
* @param array $submissionplugins
* @param array $feedbackplugins
* @param int $coursemoduleid
* @param string $returnaction
* @param array $returnparams
* @param bool $cangrade
*/
public function __construct($submissions,
$grades,
@@ -648,8 +651,8 @@ class assign_course_index_summary implements renderable {
/**
* constructor
*
* @param $usesections boolean - True if this course format uses sections
* @param $courseformatname string - The id of this course format
* @param boolean $usesections - True if this course format uses sections
* @param string $courseformatname - The id of this course format
*/
public function __construct($usesections, $courseformatname) {
$this->usesections = $usesections;
@@ -23,7 +23,9 @@
*/
/**
* restore subplugin class that provides the necessary information
* Restore subplugin class.
*
* Provides the necessary information
* needed to restore one assign_submission subplugin.
*
* @package assignsubmission_file
+15
View File
@@ -249,6 +249,7 @@ class assign_submission_file extends assign_submission_plugin {
* Produce a list of files suitable for export that represent this feedback or submission
*
* @param stdClass $submission The submission
* @param stdClass $user The user record - unused
* @return array - return an array of files indexed by filename
*/
public function get_files(stdClass $submission, stdClass $user) {
@@ -477,4 +478,18 @@ class assign_submission_file extends assign_submission_plugin {
}
return true;
}
/**
* Return a description of external params suitable for uploading a file submission from a webservice.
*
* @return external_description|null
*/
public function get_external_parameters() {
return array(
'files_filemanager' => new external_value(
PARAM_INT,
'The id of a draft area containing files for this submission.'
)
);
}
}
@@ -23,7 +23,9 @@
*/
/**
* restore subplugin class that provides the necessary information needed to restore
* Restore subplugin class.
*
* Provides the necessary information needed to restore
* one assign_submission subplugin.
*
* @package assignsubmission_onlinetext
@@ -495,6 +495,20 @@ class assign_submission_onlinetext extends assign_submission_plugin {
}
return true;
}
/**
* Return a description of external params suitable for uploading an onlinetext submission from a webservice.
*
* @return external_description|null
*/
public function get_external_parameters() {
$editorparams = array('text' => new external_value(PARAM_TEXT, 'The text for this submission.'),
'format' => new external_value(PARAM_INT, 'The format for this submission'),
'itemid' => new external_value(PARAM_INT, 'The draft area id for files attached to the submission'));
$editorstructure = new external_single_structure($editorparams);
return array('onlinetext_editor' => $editorstructure);
}
}
+9 -5
View File
@@ -79,28 +79,32 @@ abstract class assign_submission_plugin extends assign_plugin {
/**
* Copy the plugin specific submission data to a new submission record.
*
* @param stdClass $oldsubmission - Old submission record
* @param stdClass $submission - New submission record
* @return bool
*/
public function copy_submission( stdClass $oldsubmission, stdClass $submission) {
return true;
}
/*
/**
* Carry out any extra processing required when the work is locked.
*
* @param stdClass $submission - assign_submission data
* @param stdClass|false $submission - assign_submission data if any
* @param stdClass $flags - User flags record
* @return void
*/
public function lock(stdClass $submission) {
public function lock($submission, stdClass $flags) {
}
/**
* Carry out any extra processing required when the work is unlocked.
*
* @param stdClass $submission - assign_submission data
* @param stdClass|false $submission - assign_submission data if any
* @param stdClass $flags - User flags record
* @return void
*/
public function unlock(stdClass $submission) {
public function unlock($submission, stdClass $flags) {
}
/**
-20
View File
@@ -223,10 +223,6 @@ class mod_assign_base_testcase extends advanced_testcase {
*/
class testable_assign extends assign {
public function testable_process_reveal_identities() {
return parent::process_reveal_identities();
}
public function testable_show_intro() {
return parent::show_intro();
}
@@ -259,10 +255,6 @@ class testable_assign extends assign {
return parent::process_add_attempt($userid);
}
public function testable_process_lock($userid = 0) {
return parent::process_lock($userid);
}
public function testable_process_save_quick_grades($postdata) {
// Ugly hack to get something into the method.
global $_POST;
@@ -270,18 +262,6 @@ class testable_assign extends assign {
return parent::process_save_quick_grades();
}
public function testable_process_unlock($userid = 0) {
return parent::process_unlock($userid);
}
public function testable_process_copy_previous_attempt(&$notices) {
return parent::process_copy_previous_attempt($notices);
}
public function testable_process_revert_to_draft($userid = 0) {
return parent::process_revert_to_draft($userid);
}
public function testable_process_set_batch_marking_allocation($selectedusers, $markerid) {
// Ugly hack to get something into the method.
global $_POST;
+612 -5
View File
@@ -41,7 +41,7 @@ class mod_assign_external_testcase extends externallib_advanced_testcase {
/**
* Test get_grades
*/
public function test_get_grades () {
public function test_get_grades() {
global $DB, $USER;
$this->resetAfterTest(true);
@@ -118,7 +118,7 @@ class mod_assign_external_testcase extends externallib_advanced_testcase {
/**
* Test get_assignments
*/
public function test_get_assignments () {
public function test_get_assignments() {
global $DB, $USER;
$this->resetAfterTest(true);
@@ -218,7 +218,7 @@ class mod_assign_external_testcase extends externallib_advanced_testcase {
/**
* Test get_submissions
*/
public function test_get_submissions () {
public function test_get_submissions() {
global $DB, $USER;
$this->resetAfterTest(true);
@@ -307,7 +307,7 @@ class mod_assign_external_testcase extends externallib_advanced_testcase {
/**
* Test get_user_flags
*/
public function test_get_user_flags () {
public function test_get_user_flags() {
global $DB, $USER;
$this->resetAfterTest(true);
@@ -378,7 +378,7 @@ class mod_assign_external_testcase extends externallib_advanced_testcase {
/**
* Test get_user_mappings
*/
public function test_get_user_mappings () {
public function test_get_user_mappings() {
global $DB, $USER;
$this->resetAfterTest(true);
@@ -436,4 +436,611 @@ class mod_assign_external_testcase extends externallib_advanced_testcase {
$this->assertEquals($student->id, $mapping['userid']);
}
/**
* Test lock_submissions
*/
public function test_lock_submissions() {
global $DB, $USER;
$this->resetAfterTest(true);
// Create a course and assignment and users.
$course = self::getDataGenerator()->create_course();
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
$params['course'] = $course->id;
$params['assignsubmission_onlinetext_enabled'] = 1;
$instance = $generator->create_instance($params);
$cm = get_coursemodule_from_instance('assign', $instance->id);
$context = context_module::instance($cm->id);
$assign = new assign($context, $cm, $course);
$student1 = self::getDataGenerator()->create_user();
$student2 = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname'=>'student'));
$this->getDataGenerator()->enrol_user($student1->id,
$course->id,
$studentrole->id);
$this->getDataGenerator()->enrol_user($student2->id,
$course->id,
$studentrole->id);
$teacher = self::getDataGenerator()->create_user();
$teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
$this->getDataGenerator()->enrol_user($teacher->id,
$course->id,
$teacherrole->id);
// Create a student1 with an online text submission.
// Simulate a submission.
$this->setUser($student1);
$submission = $assign->get_user_submission($student1->id, true);
$data = new stdClass();
$data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
'text'=>'Submission text',
'format'=>FORMAT_MOODLE);
$plugin = $assign->get_submission_plugin_by_type('onlinetext');
$plugin->save($submission, $data);
// Ready to test.
$this->setUser($teacher);
$students = array($student1->id, $student2->id);
$result = mod_assign_external::lock_submissions($instance->id, $students);
// Check for 0 warnings.
$this->assertEquals(0, count($result));
$this->setUser($student2);
$submission = $assign->get_user_submission($student2->id, true);
$data = new stdClass();
$data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
'text'=>'Submission text',
'format'=>FORMAT_MOODLE);
$notices = array();
$this->setExpectedException('moodle_exception');
$assign->save_submission($data, $notices);
}
/**
* Test unlock_submissions
*/
public function test_unlock_submissions() {
global $DB, $USER;
$this->resetAfterTest(true);
// Create a course and assignment and users.
$course = self::getDataGenerator()->create_course();
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
$params['course'] = $course->id;
$params['assignsubmission_onlinetext_enabled'] = 1;
$instance = $generator->create_instance($params);
$cm = get_coursemodule_from_instance('assign', $instance->id);
$context = context_module::instance($cm->id);
$assign = new assign($context, $cm, $course);
$student1 = self::getDataGenerator()->create_user();
$student2 = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname'=>'student'));
$this->getDataGenerator()->enrol_user($student1->id,
$course->id,
$studentrole->id);
$this->getDataGenerator()->enrol_user($student2->id,
$course->id,
$studentrole->id);
$teacher = self::getDataGenerator()->create_user();
$teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
$this->getDataGenerator()->enrol_user($teacher->id,
$course->id,
$teacherrole->id);
// Create a student1 with an online text submission.
// Simulate a submission.
$this->setUser($student1);
$submission = $assign->get_user_submission($student1->id, true);
$data = new stdClass();
$data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
'text'=>'Submission text',
'format'=>FORMAT_MOODLE);
$plugin = $assign->get_submission_plugin_by_type('onlinetext');
$plugin->save($submission, $data);
// Ready to test.
$this->setUser($teacher);
$students = array($student1->id, $student2->id);
$result = mod_assign_external::lock_submissions($instance->id, $students);
// Check for 0 warnings.
$this->assertEquals(0, count($result));
$result = mod_assign_external::unlock_submissions($instance->id, $students);
// Check for 0 warnings.
$this->assertEquals(0, count($result));
$this->setUser($student2);
$submission = $assign->get_user_submission($student2->id, true);
$data = new stdClass();
$data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
'text'=>'Submission text',
'format'=>FORMAT_MOODLE);
$notices = array();
$assign->save_submission($data, $notices);
}
/**
* Test submit_for_grading
*/
public function test_submit_for_grading() {
global $DB, $USER;
$this->resetAfterTest(true);
// Create a course and assignment and users.
$course = self::getDataGenerator()->create_course();
set_config('submissionreceipts', 0, 'assign');
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
$params['course'] = $course->id;
$params['assignsubmission_onlinetext_enabled'] = 1;
$params['submissiondrafts'] = 1;
$params['sendnotifications'] = 0;
$params['requiresubmissionstatement'] = 1;
$instance = $generator->create_instance($params);
$cm = get_coursemodule_from_instance('assign', $instance->id);
$context = context_module::instance($cm->id);
$assign = new assign($context, $cm, $course);
$student1 = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname'=>'student'));
$this->getDataGenerator()->enrol_user($student1->id,
$course->id,
$studentrole->id);
// Create a student1 with an online text submission.
// Simulate a submission.
$this->setUser($student1);
$submission = $assign->get_user_submission($student1->id, true);
$data = new stdClass();
$data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
'text'=>'Submission text',
'format'=>FORMAT_MOODLE);
$plugin = $assign->get_submission_plugin_by_type('onlinetext');
$plugin->save($submission, $data);
$result = mod_assign_external::submit_for_grading($instance->id, false);
// Should be 1 fail because the submission statement was not aceptted.
$this->assertEquals(1, count($result));
$result = mod_assign_external::submit_for_grading($instance->id, true);
// Check for 0 warnings.
$this->assertEquals(0, count($result));
$submission = $assign->get_user_submission($student1->id, false);
$this->assertEquals(ASSIGN_SUBMISSION_STATUS_SUBMITTED, $submission->status);
}
/**
* Test save_user_extensions
*/
public function test_save_user_extensions() {
global $DB, $USER;
$this->resetAfterTest(true);
// Create a course and assignment and users.
$course = self::getDataGenerator()->create_course();
$teacher = self::getDataGenerator()->create_user();
$teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
$this->getDataGenerator()->enrol_user($teacher->id,
$course->id,
$teacherrole->id);
$this->setUser($teacher);
$now = time();
$yesterday = $now - 24*60*60;
$tomorrow = $now + 24*60*60;
set_config('submissionreceipts', 0, 'assign');
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
$params['course'] = $course->id;
$params['submissiondrafts'] = 1;
$params['sendnotifications'] = 0;
$params['duedate'] = $yesterday;
$params['cutoffdate'] = $now - 10;
$instance = $generator->create_instance($params);
$cm = get_coursemodule_from_instance('assign', $instance->id);
$context = context_module::instance($cm->id);
$assign = new assign($context, $cm, $course);
$student1 = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname'=>'student'));
$this->getDataGenerator()->enrol_user($student1->id,
$course->id,
$studentrole->id);
$this->setUser($student1);
$result = mod_assign_external::submit_for_grading($instance->id, true);
// Check for 0 warnings.
$this->assertEquals(1, count($result));
$this->setUser($teacher);
$result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($now, $tomorrow));
$this->assertEquals(1, count($result));
$this->setUser($teacher);
$result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($yesterday - 10));
$this->assertEquals(1, count($result));
$this->setUser($teacher);
$result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($tomorrow));
$this->assertEquals(0, count($result));
$this->setUser($student1);
$result = mod_assign_external::submit_for_grading($instance->id, true);
$this->assertEquals(0, count($result));
$this->setUser($student1);
$result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($now, $tomorrow));
}
/**
* Test reveal_identities
*/
public function test_reveal_identities() {
global $DB, $USER;
$this->resetAfterTest(true);
// Create a course and assignment and users.
$course = self::getDataGenerator()->create_course();
$teacher = self::getDataGenerator()->create_user();
$teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
$this->getDataGenerator()->enrol_user($teacher->id,
$course->id,
$teacherrole->id);
$this->setUser($teacher);
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
$params['course'] = $course->id;
$params['submissiondrafts'] = 1;
$params['sendnotifications'] = 0;
$params['blindmarking'] = 1;
$instance = $generator->create_instance($params);
$cm = get_coursemodule_from_instance('assign', $instance->id);
$context = context_module::instance($cm->id);
$assign = new assign($context, $cm, $course);
$student1 = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname'=>'student'));
$this->getDataGenerator()->enrol_user($student1->id,
$course->id,
$studentrole->id);
$this->setUser($student1);
$this->setExpectedException('required_capability_exception');
$result = mod_assign_external::reveal_identities($instance->id);
$this->assertEquals(1, count($result));
$this->assertEquals(true, $assign->is_blind_marking());
$this->setUser($teacher);
$result = mod_assign_external::reveal_identities($instance->id);
$this->assertEquals(0, count($result));
$this->assertEquals(false, $assign->is_blind_marking());
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
$params['course'] = $course->id;
$params['submissiondrafts'] = 1;
$params['sendnotifications'] = 0;
$params['blindmarking'] = 0;
$instance = $generator->create_instance($params);
$cm = get_coursemodule_from_instance('assign', $instance->id);
$context = context_module::instance($cm->id);
$assign = new assign($context, $cm, $course);
$result = mod_assign_external::reveal_identities($instance->id);
$this->assertEquals(1, count($result));
$this->assertEquals(false, $assign->is_blind_marking());
}
/**
* Test revert_submissions_to_draft
*/
public function test_revert_submissions_to_draft() {
global $DB, $USER;
$this->resetAfterTest(true);
set_config('submissionreceipts', 0, 'assign');
// Create a course and assignment and users.
$course = self::getDataGenerator()->create_course();
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
$params['course'] = $course->id;
$params['sendnotifications'] = 0;
$params['submissiondrafts'] = 1;
$instance = $generator->create_instance($params);
$cm = get_coursemodule_from_instance('assign', $instance->id);
$context = context_module::instance($cm->id);
$assign = new assign($context, $cm, $course);
$student1 = self::getDataGenerator()->create_user();
$student2 = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname'=>'student'));
$this->getDataGenerator()->enrol_user($student1->id,
$course->id,
$studentrole->id);
$this->getDataGenerator()->enrol_user($student2->id,
$course->id,
$studentrole->id);
$teacher = self::getDataGenerator()->create_user();
$teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
$this->getDataGenerator()->enrol_user($teacher->id,
$course->id,
$teacherrole->id);
// Create a student1 with an online text submission.
// Simulate a submission.
$this->setUser($student1);
$result = mod_assign_external::submit_for_grading($instance->id, true);
$this->assertEquals(0, count($result));
// Ready to test.
$this->setUser($teacher);
$students = array($student1->id, $student2->id);
$result = mod_assign_external::revert_submissions_to_draft($instance->id, array($student1->id));
// Check for 0 warnings.
$this->assertEquals(0, count($result));
}
/**
* Test save_submission
*/
public function test_save_submission() {
global $DB, $USER;
$this->resetAfterTest(true);
// Create a course and assignment and users.
$course = self::getDataGenerator()->create_course();
$teacher = self::getDataGenerator()->create_user();
$teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
$this->getDataGenerator()->enrol_user($teacher->id,
$course->id,
$teacherrole->id);
$this->setUser($teacher);
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
$params['course'] = $course->id;
$params['assignsubmission_onlinetext_enabled'] = 1;
$params['assignsubmission_file_enabled'] = 1;
$params['assignsubmission_file_maxfiles'] = 5;
$params['assignsubmission_file_maxsizebytes'] = 1024*1024;
$instance = $generator->create_instance($params);
$cm = get_coursemodule_from_instance('assign', $instance->id);
$context = context_module::instance($cm->id);
$assign = new assign($context, $cm, $course);
$student1 = self::getDataGenerator()->create_user();
$student2 = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname'=>'student'));
$this->getDataGenerator()->enrol_user($student1->id,
$course->id,
$studentrole->id);
$this->getDataGenerator()->enrol_user($student2->id,
$course->id,
$studentrole->id);
// Create a student1 with an online text submission.
// Simulate a submission.
$this->setUser($student1);
// Create a file in a draft area.
$draftidfile = file_get_unused_draft_itemid();
$usercontext = context_user::instance($student1->id);
$filerecord = array(
'contextid' => $usercontext->id,
'component' => 'user',
'filearea' => 'draft',
'itemid' => $draftidfile,
'filepath' => '/',
'filename' => 'testtext.txt',
);
$fs = get_file_storage();
$fs->create_file_from_string($filerecord, 'text contents');
// Create another file in a different draft area.
$draftidonlinetext = file_get_unused_draft_itemid();
$filerecord = array(
'contextid' => $usercontext->id,
'component' => 'user',
'filearea' => 'draft',
'itemid' => $draftidonlinetext,
'filepath' => '/',
'filename' => 'shouldbeanimage.txt',
);
$fs->create_file_from_string($filerecord, 'image contents (not really)');
// Now try a submission.
$submissionpluginparams = array();
$submissionpluginparams['files_filemanager'] = $draftidfile;
$onlinetexteditorparams = array('text'=>'Yeeha!',
'format'=>1,
'itemid'=>$draftidonlinetext);
$submissionpluginparams['onlinetext_editor'] = $onlinetexteditorparams;
$result = mod_assign_external::save_submission($instance->id, $submissionpluginparams);
$this->assertEquals(0, count($result));
}
/**
* Test save_grade
*/
public function test_save_grade() {
global $DB, $USER;
$this->resetAfterTest(true);
// Create a course and assignment and users.
$course = self::getDataGenerator()->create_course();
$teacher = self::getDataGenerator()->create_user();
$teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
$this->getDataGenerator()->enrol_user($teacher->id,
$course->id,
$teacherrole->id);
$this->setUser($teacher);
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
$params['course'] = $course->id;
$params['assignfeedback_file_enabled'] = 1;
$params['assignfeedback_comments_enabled'] = 1;
$instance = $generator->create_instance($params);
$cm = get_coursemodule_from_instance('assign', $instance->id);
$context = context_module::instance($cm->id);
$assign = new assign($context, $cm, $course);
$student1 = self::getDataGenerator()->create_user();
$student2 = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname'=>'student'));
$this->getDataGenerator()->enrol_user($student1->id,
$course->id,
$studentrole->id);
$this->getDataGenerator()->enrol_user($student2->id,
$course->id,
$studentrole->id);
// Simulate a grade.
$this->setUser($teacher);
// Create a file in a draft area.
$draftidfile = file_get_unused_draft_itemid();
$usercontext = context_user::instance($teacher->id);
$filerecord = array(
'contextid' => $usercontext->id,
'component' => 'user',
'filearea' => 'draft',
'itemid' => $draftidfile,
'filepath' => '/',
'filename' => 'testtext.txt',
);
$fs = get_file_storage();
$fs->create_file_from_string($filerecord, 'text contents');
// Now try a grade.
$feedbackpluginparams = array();
$feedbackpluginparams['files_filemanager'] = $draftidfile;
$feedbackeditorparams = array('text'=>'Yeeha!',
'format'=>1);
$feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
$result = mod_assign_external::save_grade($instance->id,
$student1->id,
50.0,
-1,
true,
'released',
false,
$feedbackpluginparams);
// No warnings.
$this->assertEquals(0, count($result));
$result = mod_assign_external::get_grades(array($instance->id));
$this->assertEquals($result['assignments'][0]['grades'][0]['grade'], '50.0');
}
/**
* Test copy_previous_attempt
*/
public function test_copy_previous_attempt() {
global $DB, $USER;
$this->resetAfterTest(true);
// Create a course and assignment and users.
$course = self::getDataGenerator()->create_course();
$teacher = self::getDataGenerator()->create_user();
$teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
$this->getDataGenerator()->enrol_user($teacher->id,
$course->id,
$teacherrole->id);
$this->setUser($teacher);
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
$params['course'] = $course->id;
$params['assignsubmission_onlinetext_enabled'] = 1;
$params['assignsubmission_file_enabled'] = 0;
$params['assignfeedback_file_enabled'] = 0;
$params['attemptreopenmethod'] = 'manual';
$params['maxattempts'] = 5;
$instance = $generator->create_instance($params);
$cm = get_coursemodule_from_instance('assign', $instance->id);
$context = context_module::instance($cm->id);
$assign = new assign($context, $cm, $course);
$student1 = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname'=>'student'));
$this->getDataGenerator()->enrol_user($student1->id,
$course->id,
$studentrole->id);
// Now try a submission.
$this->setUser($student1);
$draftidonlinetext = file_get_unused_draft_itemid();
$submissionpluginparams = array();
$onlinetexteditorparams = array('text'=>'Yeeha!',
'format'=>1,
'itemid'=>$draftidonlinetext);
$submissionpluginparams['onlinetext_editor'] = $onlinetexteditorparams;
$submissionpluginparams['files_filemanager'] = file_get_unused_draft_itemid();
$result = mod_assign_external::save_submission($instance->id, $submissionpluginparams);
$this->setUser($teacher);
// Add a grade and reopen the attempt.
// Now try a grade.
$feedbackpluginparams = array();
$feedbackpluginparams['files_filemanager'] = file_get_unused_draft_itemid();
$feedbackeditorparams = array('text'=>'Yeeha!',
'format'=>1);
$feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
$result = mod_assign_external::save_grade($instance->id,
$student1->id,
50.0,
-1,
true,
'released',
false,
$feedbackpluginparams);
$this->setUser($student1);
// Now copy the previous attempt.
$result = mod_assign_external::copy_previous_attempt($instance->id);
// No warnings.
$this->assertEquals(0, count($result));
$this->setUser($teacher);
$result = mod_assign_external::get_submissions(array($instance->id));
// Check we are now on the second attempt.
$this->assertEquals($result['assignments'][0]['submissions'][0]['attemptnumber'], 1);
// Check the plugins data is not empty.
$this->assertNotEmpty($result['assignments'][0]['submissions'][0]['plugins']);
}
}
+14 -9
View File
@@ -83,26 +83,31 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
// Test students cannot reveal identities.
$nopermission = false;
$this->students[0]->ignoresesskey = true;
$this->setUser($this->students[0]);
$this->setExpectedException('required_capability_exception');
$assign->testable_process_reveal_identities();
$assign->reveal_identities();
$this->students[0]->ignoresesskey = false;
// Test teachers cannot reveal identities.
$nopermission = false;
$this->teachers[0]->ignoresesskey = true;
$this->setUser($this->teachers[0]);
$this->setExpectedException('required_capability_exception');
$assign->testable_process_reveal_identities();
$assign->reveal_identities();
$this->teachers[0]->ignoresesskey = false;
// Test sesskey is required.
$this->setUser($this->editingteachers[0]);
$this->setExpectedException('moodle_exception');
$assign->testable_process_reveal_identities();
$assign->reveal_identities();
// Test editingteacher can reveal identities if sesskey is ignored.
$this->editingteachers[0]->ignoresesskey = true;
$this->setUser($this->editingteachers[0]);
$assign->testable_process_reveal_identities();
$assign->reveal_identities();
$this->assertEquals(false, $assign->is_blind_marking());
$this->editingteachers[0]->ignoresesskey = false;
// Test student names are visible.
$gradingtable = new assign_grading_table($assign, 1, '', 0, true);
@@ -1038,7 +1043,7 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
$assign = $this->create_instance();
$sink = $this->redirectEvents();
$assign->testable_process_lock($this->students[0]->id);
$assign->lock_submission($this->students[0]->id);
$events = $sink->get_events();
$this->assertCount(1, $events);
@@ -1071,7 +1076,7 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
$assign = $this->create_instance(array('blindmarking'=>1));
$sink = $this->redirectEvents();
$assign->testable_process_reveal_identities();
$assign->reveal_identities();
$events = $sink->get_events();
$this->assertCount(1, $events);
@@ -1105,7 +1110,7 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
$assign->testable_update_submission($submission, $this->students[0]->id, true, false);
$sink = $this->redirectEvents();
$assign->testable_process_revert_to_draft($this->students[0]->id);
$assign->revert_to_draft($this->students[0]->id);
$events = $sink->get_events();
$this->assertCount(1, $events);
@@ -1213,7 +1218,7 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
$sink = $this->redirectEvents();
$notices = null;
$assign->testable_process_copy_previous_attempt($notices);
$assign->copy_previous_attempt($notices);
$events = $sink->get_events();
$this->assertCount(1, $events);
@@ -1243,7 +1248,7 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
$assign = $this->create_instance();
$sink = $this->redirectEvents();
$assign->testable_process_unlock($this->students[0]->id);
$assign->unlock_submission($this->students[0]->id);
$events = $sink->get_events();
$this->assertCount(1, $events);
+5
View File
@@ -3,6 +3,11 @@ This files describes API changes in the assign code.
=== 2.6 ===
* To see submission/grades of inactive users, user should have moodle/course:viewsuspendedusers capability.
* count_* functions will return only active participants.
* assign_submission_plugin->lock and unlock methods have an additional parameter for user flags. A user will not
always have a submission record when the submission is locked/unlocked.
* Submission and feedback plugins can now participate in webservices. The plugin must implement get_external_parameters()
to describe the parameters it is expecting from the mod_assign_save_grade or mod_assign_save_submission functions. The
plugin will then handle the webservice via it's normal save() method with the extra data supplied in the $data argument.
=== 2.5 ===
+1 -1
View File
@@ -25,7 +25,7 @@
defined('MOODLE_INTERNAL') || die();
$module->component = 'mod_assign'; // Full name of the plugin (used for diagnostics).
$module->version = 2013070902; // The current module version (Date: YYYYMMDDXX).
$module->version = 2013080800; // The current module version (Date: YYYYMMDDXX).
$module->requires = 2013050100; // Requires this Moodle version.
$module->cron = 60;