diff --git a/mod/assign/db/access.php b/mod/assign/db/access.php
index e68af3a811e..89815ab52f0 100644
--- a/mod/assign/db/access.php
+++ b/mod/assign/db/access.php
@@ -82,6 +82,12 @@ $capabilities = array(
'clonepermissionsfrom' => 'moodle/course:manageactivities'
),
+ 'mod/assign:editothersubmission' => array(
+ 'riskbitmask' => RISK_MANAGETRUST|RISK_DATALOSS|RISK_PERSONAL,
+ 'captype' => 'write',
+ 'contextlevel' => CONTEXT_MODULE
+ ),
+
'mod/assign:grantextension' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
diff --git a/mod/assign/externallib.php b/mod/assign/externallib.php
index fd28223c4cc..dc6e06ab646 100644
--- a/mod/assign/externallib.php
+++ b/mod/assign/externallib.php
@@ -1422,9 +1422,10 @@ class mod_assign_external extends external_api {
$warnings = array();
$data = new stdClass();
$data->submissionstatement = $acceptsubmissionstatement;
+ $notices = array();
- if (!$assignment->submit_for_grading($data)) {
- $detail = 'User id: ' . $USER->id . ', Assignment id: ' . $assignmentid;
+ if (!$assignment->submit_for_grading($data, $notices)) {
+ $detail = 'User id: ' . $USER->id . ', Assignment id: ' . $assignmentid . ' Notices:' . implode(', ', $notices);
$warnings[] = self::generate_warning($assignmentid,
'couldnotsubmitforgrading',
$detail);
diff --git a/mod/assign/gradingtable.php b/mod/assign/gradingtable.php
index 5c96c3cb190..fe5f1e66ce8 100644
--- a/mod/assign/gradingtable.php
+++ b/mod/assign/gradingtable.php
@@ -962,6 +962,8 @@ class assign_grading_table extends table_sql implements renderable {
* @return string
*/
public function col_userid(stdClass $row) {
+ global $USER;
+
$edit = '';
$actions = array();
@@ -978,6 +980,9 @@ class assign_grading_table extends table_sql implements renderable {
}
$actions[$url->out(false)] = $description;
+ $submissionsopen = $this->assignment->submissions_open($row->id);
+ $caneditsubmission = $this->assignment->can_edit_submission($row->id, $USER->id);
+
// Hide for offline assignments.
if ($this->assignment->is_any_submission_plugin_enabled()) {
if (!$row->status ||
@@ -1018,6 +1023,18 @@ class assign_grading_table extends table_sql implements renderable {
$description = get_string('grantextension', 'assign');
$actions[$url->out(false)] = $description;
}
+ if ($submissionsopen &&
+ $USER->id != $row->id &&
+ $caneditsubmission) {
+ $urlparams = array('id' => $this->assignment->get_course_module()->id,
+ 'userid'=>$row->id,
+ 'action'=>'editsubmission',
+ 'sesskey'=>sesskey(),
+ 'page'=>$this->currpage);
+ $url = new moodle_url('/mod/assign/view.php', $urlparams);
+ $description = get_string('editsubmission', 'assign');
+ $actions[$url->out(false)] = $description;
+ }
}
if ($row->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED &&
$this->assignment->get_instance()->submissiondrafts) {
@@ -1030,6 +1047,20 @@ class assign_grading_table extends table_sql implements renderable {
$description = get_string('reverttodraftshort', 'assign');
$actions[$url->out(false)] = $description;
}
+ if ($row->status == ASSIGN_SUBMISSION_STATUS_DRAFT &&
+ $this->assignment->get_instance()->submissiondrafts &&
+ $caneditsubmission &&
+ $submissionsopen &&
+ $row->id != $USER->id) {
+ $urlparams = array('id' => $this->assignment->get_course_module()->id,
+ 'userid'=>$row->id,
+ 'action'=>'submitotherforgrading',
+ 'sesskey'=>sesskey(),
+ 'page'=>$this->currpage);
+ $url = new moodle_url('/mod/assign/view.php', $urlparams);
+ $description = get_string('submitforgrading', 'assign');
+ $actions[$url->out(false)] = $description;
+ }
$ismanual = $this->assignment->get_instance()->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL;
$hassubmission = !empty($row->status);
diff --git a/mod/assign/lang/en/assign.php b/mod/assign/lang/en/assign.php
index b677b200bf1..1f09a49401f 100644
--- a/mod/assign/lang/en/assign.php
+++ b/mod/assign/lang/en/assign.php
@@ -42,6 +42,7 @@ $string['alwaysshowdescription_help'] = 'If disabled, the Assignment Description
$string['applytoteam'] = 'Apply grades and feedback to entire group';
$string['assign:addinstance'] = 'Add a new assignment';
$string['assign:exportownsubmission'] = 'Export own submission';
+$string['assign:editothersubmission'] = 'Edit another students submission';
$string['assign:grade'] = 'Grade assignment';
$string['assign:grantextension'] = 'Grant extension';
$string['assign:manageallocations'] = 'Manage markers allocated to submissions';
@@ -135,6 +136,7 @@ $string['duedatevalidation'] = 'Due date must be after the allow submissions fro
$string['editattemptfeedback'] = 'Edit the grade and feedback for attempt number {$a}.';
$string['editingpreviousfeedbackwarning'] = 'You are editing the feedback for a previous attempt. This is attempt {$a->attemptnumber} out of {$a->totalattempts}.';
$string['editsubmission'] = 'Edit submission';
+$string['editsubmissionother'] = 'Edit submission for {$a}';
$string['editsubmission_help'] = 'Make changes to your submission';
$string['editingstatus'] = 'Editing status';
$string['editaction'] = 'Actions...';
@@ -350,6 +352,16 @@ $string['submissionnoteditable'] = 'Student cannot edit this submission';
$string['submissionnotready'] = 'This assignment is not ready to submit:';
$string['submissionplugins'] = 'Submission plugins';
$string['submissionreceipts'] = 'Send submission receipts';
+$string['submissionreceiptothertext'] = 'Your assignment submission for
+\'{$a->assignment}\' has been submitted.
+
+You can see the status of your assignment submission:
+
+ {$a->url}';
+$string['submissionreceiptotherhtml'] = 'Your assignment submission for
+\'{$a->assignment}\' has been submitted.
+You can see the status of your assignment submission.';
+$string['submissionreceiptothersmall'] = 'Your assignment submission for {$a->assignment} has been submitted.';
$string['submissionreceipttext'] = 'You have submitted an
assignment submission for \'{$a->assignment}\'
@@ -381,6 +393,7 @@ $string['submissionsummary'] = '{$a->status}. Last modified on {$a->timemodified
$string['submissionteam'] = 'Group';
$string['submission'] = 'Submission';
$string['submitaction'] = 'Submit';
+$string['submitforgrading'] = 'Submit for grading';
$string['submitassignment_help'] = 'Once this assignment is submitted you will not be able to make any more changes.';
$string['submitassignment'] = 'Submit assignment';
$string['submittedearly'] = 'Assignment was submitted {$a} early';
@@ -426,3 +439,4 @@ $string['workflowfilter'] = 'Workflow filter';
$string['submissiontypes'] = 'Submission types';
$string['feedbacktypes'] = 'Feedback types';
$string['groupsubmissionsettings'] = 'Group submission settings';
+$string['submissionlog'] = 'Student: {$a->fullname}, Status: {$a->status}';
diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index 404b6956ea3..fc62b564e74 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -417,9 +417,18 @@ class assign {
$nextpageparams['action'] = 'grading';
} else if ($action == 'confirmsubmit') {
$action = 'submit';
- if ($this->process_submit_for_grading($mform)) {
+ if ($this->process_submit_for_grading($mform, $notices)) {
$action = 'redirect';
$nextpageparams['action'] = 'view';
+ } else if ($notices) {
+ $action = 'viewsubmitforgradingerror';
+ }
+ } else if ($action == 'submitotherforgrading') {
+ if ($this->process_submit_other_for_grading($mform, $notices)) {
+ $action = 'redirect';
+ $nextpageparams['action'] = 'grading';
+ } else {
+ $action = 'viewsubmitforgradingerror';
}
} else if ($action == 'gradingbatchoperation') {
$action = $this->process_grading_batch_operation($mform);
@@ -521,6 +530,8 @@ class assign {
$o .= $this->view_batch_set_workflow_state($mform);
} else if ($action == 'viewbatchmarkingallocation') {
$o .= $this->view_batch_markingallocation($mform);
+ } else if ($action == 'viewsubmitforgradingerror') {
+ $o .= $this->view_error_page(get_string('submitforgrading', 'assign'), $notices);
} else {
$o .= $this->view_submission_page();
}
@@ -3187,28 +3198,47 @@ class assign {
/**
* Message for students when assignment submissions have been closed.
*
+ * @param string $title The page title
+ * @param array $notices The array of notices to show.
* @return string
*/
- protected function view_student_error_message() {
+ protected function view_notices($title, $notices) {
global $CFG;
$o = '';
- // Need submit permission to submit an assignment.
- require_capability('mod/assign:submit', $this->context);
$header = new assign_header($this->get_instance(),
$this->get_context(),
$this->show_intro(),
$this->get_course_module()->id,
- get_string('editsubmission', 'assign'));
+ $title);
$o .= $this->get_renderer()->render($header);
- $o .= $this->get_renderer()->notification(get_string('submissionsclosed', 'assign'));
+ foreach ($notices as $notice) {
+ $o .= $this->get_renderer()->notification($notice);
+ }
+
+ $url = new moodle_url('/mod/assign/view.php', array('id'=>$this->get_course_module()->id, 'action'=>'view'));
+ $o .= $this->get_renderer()->continue_button($url);
$o .= $this->view_footer();
return $o;
+ }
+ /**
+ * Get the name for a user - hiding their real name if blind marking is on.
+ *
+ * @param stdClass $user The user record as required by fullname()
+ * @return string The name.
+ */
+ protected function fullname($user) {
+ if ($this->is_blind_marking()) {
+ $uniqueid = $this->get_uniqueid_for_user($userid);
+ return get_string('participant', 'assign') . ' ' . $uniqueid;
+ } else {
+ return fullname($user);
+ }
}
/**
@@ -3220,24 +3250,44 @@ class assign {
* @return string The page output.
*/
protected function view_edit_submission_page($mform, $notices) {
- global $CFG;
+ global $CFG, $USER, $DB;
$o = '';
require_once($CFG->dirroot . '/mod/assign/submission_form.php');
// Need submit permission to submit an assignment.
- require_capability('mod/assign:submit', $this->context);
+ $userid = optional_param('userid', $USER->id, PARAM_INT);
+ $user = clone($USER);
+ if ($userid == $USER->id) {
+ // User is editing their own submission.
+ require_capability('mod/assign:submit', $this->context);
+ $title = get_string('editsubmission', 'assign');
+ } else {
+ // User is editing another user's submission.
+ if (!$this->can_edit_submission($userid, $USER->id)) {
+ print_error('nopermission');
+ }
- if (!$this->submissions_open()) {
- return $this->view_student_error_message();
+ $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
+ $name = $this->fullname($user);
+ $title = get_string('editsubmissionother', 'assign', $name);
}
+
+ if (!$this->submissions_open($userid)) {
+ $message = array(get_string('submissionsclosed', 'assign'));
+ return $this->view_notices($title, $message);
+ }
+
$o .= $this->get_renderer()->render(new assign_header($this->get_instance(),
$this->get_context(),
$this->show_intro(),
$this->get_course_module()->id,
- get_string('editsubmission', 'assign')));
- $o .= $this->plagiarism_print_disclosure();
+ $title));
+ if ($userid == $USER->id) {
+ // We only show this if it their submission.
+ $o .= $this->plagiarism_print_disclosure();
+ }
$data = new stdClass();
-
+ $data->userid = $userid;
if (!$mform) {
$mform = new mod_assign_submission_form(null, array($this, $data));
}
@@ -3249,7 +3299,7 @@ class assign {
$o .= $this->get_renderer()->render(new assign_form('editsubmissionform', $mform));
$o .= $this->view_footer();
- $this->add_to_log('view submit assignment form', get_string('viewownsubmissionform', 'assign'));
+ $this->add_to_log('view submit assignment form', $title);
return $o;
}
@@ -4265,6 +4315,42 @@ class assign {
}
+ /**
+ * Capability check to make sure this grader can edit this submission.
+ *
+ * @param int $userid - The user whose submission is to be edited
+ * @param int $graderid (optional) - The user who will do the editing (default to $USER->id).
+ * @return bool
+ */
+ public function can_edit_submission($userid, $graderid = 0) {
+ global $USER;
+
+ if (empty($graderid)) {
+ $graderid = $USER->id;
+ }
+
+ if ($userid == $graderid &&
+ $this->submissions_open($userid) &&
+ has_capability('mod/assign:submit', $this->context, $graderid)) {
+ // User can edit their own submission.
+ return true;
+ }
+
+ if (!has_capability('mod/assign:editothersubmission', $this->context, $graderid)) {
+ return false;
+ }
+
+ $cm = $this->get_course_module();
+ if (groups_get_activity_groupmode($cm) == SEPARATEGROUPS) {
+ // These arrays are indexed by groupid.
+ $studentgroups = array_keys(groups_get_activity_allowed_groups($cm, $userid));
+ $gradergroups = array_keys(groups_get_activity_allowed_groups($cm, $graderid));
+
+ return count(array_intersect($studentgroups, $gradergroups)) > 0;
+ }
+ return true;
+ }
+
/**
* Returns a list of teachers that should be grading given submission.
*
@@ -4536,11 +4622,19 @@ class assign {
} else {
$user = $USER;
}
- $this->send_notification($user,
- $user,
- 'submissionreceipt',
- 'assign_notification',
- $submission->timemodified);
+ if ($submission->userid == $USER->id) {
+ $this->send_notification(core_user::get_noreply_user(),
+ $user,
+ 'submissionreceipt',
+ 'assign_notification',
+ $submission->timemodified);
+ } else {
+ $this->send_notification($USER,
+ $user,
+ 'submissionreceiptother',
+ 'assign_notification',
+ $submission->timemodified);
+ }
}
/**
@@ -4580,27 +4674,40 @@ class assign {
/**
* Submit a submission for grading.
*
+ * @param stdClass $data - The form data
+ * @param array $notices - List of error messages to display on an error condition.
* @return bool Return false if the submission was not submitted.
*/
- public function submit_for_grading($data) {
+ public function submit_for_grading($data, $notices) {
global $USER;
+ $userid = $USER->id;
+ if (!empty($data->userid)) {
+ $userid = $data->userid;
+ }
// Need submit permission to submit an assignment.
- require_capability('mod/assign:submit', $this->context);
+ if ($userid == $USER->id) {
+ require_capability('mod/assign:submit', $this->context);
+ } else {
+ if (!$this->can_edit_submission($userid, $USER->id)) {
+ print_error('nopermission');
+ }
+ }
$instance = $this->get_instance();
if ($instance->teamsubmission) {
- $submission = $this->get_group_submission($USER->id, 0, true);
+ $submission = $this->get_group_submission($userid, 0, true);
} else {
- $submission = $this->get_user_submission($USER->id, true);
+ $submission = $this->get_user_submission($userid, true);
}
- if (!$this->submissions_open($USER->id)) {
+ if (!$this->submissions_open($userid)) {
+ $notices[] = get_string('submissionsclosed', 'assign');
return false;
}
- if ($instance->requiresubmissionstatement && !$data->submissionstatement) {
+ if ($instance->requiresubmissionstatement && empty($data->submissionstatement) && $USER->id == $userid) {
return false;
}
@@ -4614,13 +4721,13 @@ class assign {
}
$submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
- $this->update_submission($submission, $USER->id, true, $instance->teamsubmission);
+ $this->update_submission($submission, $userid, 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);
+ $completion->update_state($this->get_course_module(), COMPLETION_COMPLETE, $userid);
}
- if (!empty($data->submissionstatement)) {
+ if (!empty($data->submissionstatement) && $USER->id == $userid) {
$logmessage = get_string('submissionstatementacceptedlog',
'mod_assign',
fullname($USER));
@@ -4643,9 +4750,31 @@ class assign {
$event->trigger();
return true;
}
+ $notices[] = get_string('submissionsclosed', 'assign');
return false;
}
+ /**
+ * A students submission is submitted for grading by a teacher.
+ *
+ * @return bool
+ */
+ protected function process_submit_other_for_grading($mform, $notices) {
+ global $USER, $CFG;
+
+ require_sesskey();
+
+ $userid = optional_param('userid', $USER->id, PARAM_INT);
+
+ if (!$this->submissions_open($userid)) {
+ $notices[] = get_string('submissionsclosed', 'assign');
+ return false;
+ }
+ $data = new stdClass();
+ $data->userid = $userid;
+ return $this->submit_for_grading($data, $notices);
+ }
+
/**
* Assignment submission is processed before grading.
*
@@ -4653,14 +4782,15 @@ class assign {
* 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;
+ protected function process_submit_for_grading($mform, $notices) {
+ global $CFG;
require_once($CFG->dirroot . '/mod/assign/submissionconfirmform.php');
require_sesskey();
if (!$this->submissions_open()) {
- return $this->view_student_error_message();
+ $notices[] = get_string('submissionsclosed', 'assign');
+ return false;
}
$instance = $this->get_instance();
$data = new stdClass();
@@ -4685,7 +4815,7 @@ class assign {
if ($mform->get_data() == false) {
return false;
}
- return $this->submit_for_grading($data);
+ return $this->submit_for_grading($data, $notices);
}
return true;
}
@@ -5161,11 +5291,19 @@ class assign {
* @return string
*/
protected function format_submission_for_log(stdClass $submission) {
+ global $DB;
+
$info = '';
- $info .= get_string('submissionstatus', 'assign') .
- ': ' .
- get_string('submissionstatus_' . $submission->status, 'assign') .
- '.
';
+ if ($submission->userid) {
+ $user = $DB->get_record('user', array('id' => $submission->userid), '*', MUST_EXIST);
+ $name = fullname($user);
+ } else {
+ $group = $DB->get_record('groups', array('id' => $submission->groupid), '*', MUST_EXIST);
+ $name = $group->name;
+ }
+ $status = get_string('submissionstatus_' . $submission->status, 'assign');
+ $params = array('id'=>$submission->userid, 'fullname'=>$name, 'status'=>$status);
+ $info .= get_string('submissionlog', 'assign', $params) . '
';
foreach ($this->submissionplugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
@@ -5319,15 +5457,28 @@ class assign {
* @return bool
*/
public function save_submission(stdClass $data, & $notices) {
- global $CFG, $USER;
+ global $CFG, $USER, $DB;
- require_capability('mod/assign:submit', $this->context);
+ $userid = $USER->id;
+ if (!empty($data->userid)) {
+ $userid = $data->userid;
+ }
+
+ $user = clone($USER);
+ if ($userid == $USER->id) {
+ require_capability('mod/assign:submit', $this->context);
+ } else {
+ $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
+ if (!$this->can_edit_submission($userid, $USER->id)) {
+ print_error('nopermission');
+ }
+ }
$instance = $this->get_instance();
if ($instance->teamsubmission) {
- $submission = $this->get_group_submission($USER->id, 0, true);
+ $submission = $this->get_group_submission($userid, 0, true);
} else {
- $submission = $this->get_user_submission($USER->id, true);
+ $submission = $this->get_user_submission($userid, true);
}
if ($instance->submissiondrafts) {
$submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
@@ -5335,7 +5486,7 @@ class assign {
$submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
}
- $flags = $this->get_user_flags($USER->id, false);
+ $flags = $this->get_user_flags($userid, false);
// Get the flags to check if it is locked.
if ($flags && $flags->locked) {
@@ -5360,10 +5511,10 @@ class assign {
return false;
}
- $this->update_submission($submission, $USER->id, true, $instance->teamsubmission);
+ $this->update_submission($submission, $userid, true, $instance->teamsubmission);
// Logging.
- if (isset($data->submissionstatement)) {
+ if (isset($data->submissionstatement) && ($userid == $USER->id)) {
$logmessage = get_string('submissionstatementacceptedlog',
'mod_assign',
fullname($USER));
@@ -5392,7 +5543,7 @@ class assign {
}
$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);
+ $completion->update_state($this->get_course_module(), $complete, $userid);
}
if (!$instance->submissiondrafts) {
@@ -5421,20 +5572,22 @@ class assign {
* @return bool
*/
protected function process_save_submission(&$mform, &$notices) {
- global $CFG;
+ global $CFG, $USER;
// Include submission form.
require_once($CFG->dirroot . '/mod/assign/submission_form.php');
+ $userid = optional_param('userid', $USER->id, PARAM_INT);
// Need submit permission to submit an assignment.
require_sesskey();
- if (!$this->submissions_open()) {
+ if (!$this->submissions_open($userid)) {
$notices[] = get_string('duedatereached', 'assign');
return false;
}
$instance = $this->get_instance();
$data = new stdClass();
+ $data->userid = $userid;
$mform = new mod_assign_submission_form(null, array($this, $data));
if ($mform->is_cancelled()) {
return true;
@@ -5839,11 +5992,12 @@ class assign {
public function add_submission_form_elements(MoodleQuickForm $mform, stdClass $data) {
global $USER;
+ $userid = $data->userid;
// Team submissions.
if ($this->get_instance()->teamsubmission) {
- $submission = $this->get_group_submission($USER->id, 0, false);
+ $submission = $this->get_group_submission($userid, 0, false);
} else {
- $submission = $this->get_user_submission($USER->id, false);
+ $submission = $this->get_user_submission($userid, false);
}
// Submission statement.
@@ -5854,7 +6008,8 @@ class assign {
$draftsenabled = $this->get_instance()->submissiondrafts;
- if ($requiresubmissionstatement && !$draftsenabled) {
+ // Only show submission statement if we are editing our own submission.
+ if ($requiresubmissionstatement && !$draftsenabled && $userid == $USER->id) {
$submissionstatement = '';
if (!empty($adminconfig->submissionstatement)) {
@@ -5864,12 +6019,15 @@ class assign {
$mform->addRule('submissionstatement', get_string('required'), 'required', null, 'client');
}
- $this->add_plugin_submission_elements($submission, $mform, $data, $USER->id);
+ $this->add_plugin_submission_elements($submission, $mform, $data, $userid);
// Hidden params.
$mform->addElement('hidden', 'id', $this->get_course_module()->id);
$mform->setType('id', PARAM_INT);
+ $mform->addElement('hidden', 'userid', $userid);
+ $mform->setType('userid', PARAM_INT);
+
$mform->addElement('hidden', 'action', 'savesubmission');
$mform->setType('action', PARAM_TEXT);
}
diff --git a/mod/assign/tests/locallib_test.php b/mod/assign/tests/locallib_test.php
index a1ca542b740..758f29506b9 100644
--- a/mod/assign/tests/locallib_test.php
+++ b/mod/assign/tests/locallib_test.php
@@ -1278,6 +1278,90 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
$this->editingteachers[0]->ignoresesskey = false;
}
+ public function test_teacher_submit_for_student() {
+ global $PAGE;
+
+ $this->preventResetByRollback();
+ $sink = $this->redirectMessages();
+
+ $this->setUser($this->editingteachers[0]);
+
+ $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1, 'submissiondrafts'=>1));
+ $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
+
+ $this->setUser($this->students[0]);
+ // Simulate a submission.
+ $data = new stdClass();
+ $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
+ 'text'=>'Student submission text',
+ 'format'=>FORMAT_MOODLE);
+
+ $notices = array();
+ $assign->save_submission($data, $notices);
+
+ // Check that the submission text was saved.
+ $output = $assign->view_student_summary($this->students[0], true);
+ $this->assertContains('Student submission text', $output, 'Contains student submission text');
+
+ // Check that a teacher teacher with the extra capability can edit a students submission.
+ $this->setUser($this->teachers[0]);
+ $data = new stdClass();
+ $data->userid = $this->students[0]->id;
+ $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
+ 'text'=>'Teacher edited submission text',
+ 'format'=>FORMAT_MOODLE);
+
+ // Add the required capability.
+ $roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
+ assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
+ role_assign($roleid, $this->teachers[0]->id, $assign->get_context()->id);
+ accesslib_clear_all_caches_for_unit_testing();
+
+ // Try to save the submission.
+ $notices = array();
+ $assign->save_submission($data, $notices);
+
+ // Check that the teacher can submit the students work.
+ $data = new stdClass();
+ $data->userid = $this->students[0]->id;
+ $notices = array();
+ $assign->submit_for_grading($data, $notices);
+
+ // Revert to draft so the student can edit it.
+ $assign->revert_to_draft($this->students[0]->id);
+
+ $this->setUser($this->students[0]);
+
+ // Check that the submission text was saved.
+ $output = $assign->view_student_summary($this->students[0], true);
+ $this->assertContains('Teacher edited submission text', $output, 'Contains student submission text');
+
+ // Check that the student can submit their work.
+ $data = new stdClass();
+ $assign->submit_for_grading($data, $notices);
+
+ $output = $assign->view_student_summary($this->students[0], true);
+ $this->assertNotContains(get_string('addsubmission', 'assign'), $output);
+
+ // Set to a default editing teacher who should not be able to edit this submission.
+ $this->setUser($this->editingteachers[1]);
+
+ // Revert to draft so the submission is editable.
+ $assign->revert_to_draft($this->students[0]->id);
+
+ $data = new stdClass();
+ $data->userid = $this->students[0]->id;
+ $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
+ 'text'=>'Teacher 2 edited submission text',
+ 'format'=>FORMAT_MOODLE);
+
+ $notices = array();
+ $this->setExpectedException('moodle_exception');
+ $assign->save_submission($data, $notices);
+
+ $sink->close();
+ }
+
public function test_marker_updated_event() {
$this->editingteachers[0]->ignoresesskey = true;
$this->setUser($this->editingteachers[0]);
@@ -1669,5 +1753,55 @@ Anchor link 2:Link text
$plugin = $assign->get_feedback_plugin_by_type($gradebookplugintype);
$this->assertEquals(0, $plugin->is_enabled('enabled'));
}
+
+ /**
+ * Testing can_edit_submission
+ */
+ public function test_can_edit_submission() {
+ global $PAGE, $DB;
+ $this->create_extra_users();
+
+ $this->setAdminUser();
+ // Create assignment (onlinetext).
+ $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1, 'submissiondrafts'=>1));
+ $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
+
+ // Check student can edit their own submission.
+ $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->students[0]->id));
+ // Check student cannot edit others submission.
+ $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->students[1]->id));
+
+ // Check teacher cannot (by default) edit a students submission.
+ $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->teachers[0]->id));
+
+ // Add the required capability to edit a student submission.
+ $roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
+ assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
+ role_assign($roleid, $this->teachers[0]->id, $assign->get_context()->id);
+ accesslib_clear_all_caches_for_unit_testing();
+ // Retest - should now have access.
+ $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->teachers[0]->id));
+
+ // Force create an assignment with SEPARATEGROUPS.
+ $data = new stdClass();
+ $data->courseid = $this->course->id;
+ $data->name = 'Grouping';
+ $groupingid = groups_create_grouping($data);
+ groups_assign_grouping($groupingid, $this->groups[0]->id);
+ groups_assign_grouping($groupingid, $this->groups[1]->id);
+ $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
+
+ // Add the capability to the new assignment for extra students 0 and 1.
+ assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
+ role_assign($roleid, $this->extrastudents[0]->id, $assign->get_context()->id);
+ role_assign($roleid, $this->extrastudents[1]->id, $assign->get_context()->id);
+ accesslib_clear_all_caches_for_unit_testing();
+
+ // Verify the extra student does not have the capability to edit a submission not in their group.
+ $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->extrastudents[1]->id));
+ // Verify the extra student does have the capability to edit a submission in their group.
+ $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->extrastudents[0]->id));
+
+ }
}
diff --git a/mod/assign/version.php b/mod/assign/version.php
index a2e1f9a730a..46acd8a567a 100644
--- a/mod/assign/version.php
+++ b/mod/assign/version.php
@@ -25,7 +25,7 @@
defined('MOODLE_INTERNAL') || die();
$module->component = 'mod_assign'; // Full name of the plugin (used for diagnostics).
-$module->version = 2014010801; // The current module version (Date: YYYYMMDDXX).
+$module->version = 2014011500; // The current module version (Date: YYYYMMDDXX).
$module->requires = 2013110500; // Requires this Moodle version.
$module->cron = 60;