MDL-28448 Assign: Add a new capability that lets teachers mess with student submissions.
authorDamyon Wiese <damyon@moodle.com>
Wed, 11 Dec 2013 08:59:23 +0000 (16:59 +0800)
committerDamyon Wiese <damyon@moodle.com>
Wed, 15 Jan 2014 04:52:08 +0000 (12:52 +0800)
mod/assign/db/access.php
mod/assign/externallib.php
mod/assign/gradingtable.php
mod/assign/lang/en/assign.php
mod/assign/locallib.php
mod/assign/tests/locallib_test.php
mod/assign/version.php

index e68af3a..89815ab 100644 (file)
@@ -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,
index fd28223..dc6e06a 100644 (file)
@@ -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);
index 5c96c3c..fe5f1e6 100644 (file)
@@ -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);
index b677b20..1f09a49 100644 (file)
@@ -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
+\'<i>{$a->assignment}</i>\' has been submitted.<br /><br />
+You can see the status of your <a href="{$a->url}">assignment submission</a>.';
+$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}';
index 404b695..fc62b56 100644 (file)
@@ -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') .
-                 '. <br>';
+        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) . ' <br>';
 
         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);
     }
index a1ca542..758f295 100644 (file)
@@ -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:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
         $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));
+
+    }
 }
 
index a2e1f9a..46acd8a 100644 (file)
@@ -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;