MDL-80743 mod_assign: Add automatic attempt reopening option
This commit is contained in:
@@ -90,9 +90,12 @@ $string['attempthistory'] = 'Previous attempts';
|
||||
$string['attemptnumber'] = 'Attempt number';
|
||||
$string['attemptsettings'] = 'Attempt settings';
|
||||
$string['attemptreopenmethod'] = 'Grant attempts';
|
||||
$string['attemptreopenmethod_automatic'] = 'Automatically';
|
||||
$string['attemptreopenmethod_automatic_help'] = 'After each attempt, the next is granted automatically.';
|
||||
$string['attemptreopenmethod_help'] = 'This setting controls how students are granted attempts for this assignment. For each attempt, the grade and feedback are saved, and can be viewed by the teacher and the student. The available options are:
|
||||
|
||||
* Manually - After each attempt, you can grant the next one through the Submissions page or the Grader page.
|
||||
* Automatically - After each attempt, the next is granted automatically.
|
||||
* Automatically until pass - After each attempt, the next will be granted automatically, until the student achieves the passing grade.';
|
||||
$string['attemptreopenmethod_manual'] = 'Manually';
|
||||
$string['attemptreopenmethod_manual_help'] = 'After each attempt, you can grant the next one through the Submissions page or the Grader page.';
|
||||
|
||||
+19
-12
@@ -53,6 +53,7 @@ define('ASSIGN_MARKER_FILTER_NO_MARKER', -1);
|
||||
*/
|
||||
define('ASSIGN_ATTEMPT_REOPEN_METHOD_NONE', 'none');
|
||||
define('ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL', 'manual');
|
||||
define('ASSIGN_ATTEMPT_REOPEN_METHOD_AUTOMATIC', 'automatic');
|
||||
define('ASSIGN_ATTEMPT_REOPEN_METHOD_UNTILPASS', 'untilpass');
|
||||
|
||||
// Special value means allow unlimited attempts.
|
||||
@@ -8699,21 +8700,27 @@ class assign {
|
||||
$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.
|
||||
$gradeitem = $this->get_grade_item();
|
||||
if ($gradeitem) {
|
||||
$gradegrade = grade_grade::fetch(array('userid' => $userid, 'itemid' => $gradeitem->id));
|
||||
switch ($instance->attemptreopenmethod) {
|
||||
case ASSIGN_ATTEMPT_REOPEN_METHOD_AUTOMATIC:
|
||||
$shouldreopen = true;
|
||||
break;
|
||||
case ASSIGN_ATTEMPT_REOPEN_METHOD_UNTILPASS:
|
||||
// Check the gradetopass from the gradebook.
|
||||
$gradeitem = $this->get_grade_item();
|
||||
if ($gradeitem) {
|
||||
$gradegrade = grade_grade::fetch(['userid' => $userid, 'itemid' => $gradeitem->id]);
|
||||
|
||||
// Do not reopen if is_passed returns null, e.g. if there is no pass criterion set.
|
||||
if ($gradegrade && ($gradegrade->is_passed() === false)) {
|
||||
// Do not reopen if is_passed returns null, e.g. if there is no pass criterion set.
|
||||
if ($gradegrade && ($gradegrade->is_passed() === false)) {
|
||||
$shouldreopen = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL:
|
||||
if (!empty($addattempt)) {
|
||||
$shouldreopen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($instance->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL &&
|
||||
!empty($addattempt)) {
|
||||
$shouldreopen = true;
|
||||
break;
|
||||
}
|
||||
if ($shouldreopen && !$maxattemptsreached) {
|
||||
$this->add_attempt($userid);
|
||||
|
||||
@@ -150,6 +150,11 @@ class mod_assign_mod_form extends moodleform_mod {
|
||||
name: get_string('attemptreopenmethod_manual', 'mod_assign'),
|
||||
definition: ['description' => get_string('attemptreopenmethod_manual_help', 'mod_assign')]
|
||||
);
|
||||
$choice->add_option(
|
||||
value: ASSIGN_ATTEMPT_REOPEN_METHOD_AUTOMATIC,
|
||||
name: get_string('attemptreopenmethod_automatic', 'mod_assign'),
|
||||
definition: ['description' => get_string('attemptreopenmethod_automatic_help', 'mod_assign')]
|
||||
);
|
||||
$choice->add_option(
|
||||
value: ASSIGN_ATTEMPT_REOPEN_METHOD_UNTILPASS,
|
||||
name: get_string('attemptreopenmethod_untilpass', 'mod_assign'),
|
||||
|
||||
@@ -2758,6 +2758,66 @@ class locallib_test extends \advanced_testcase {
|
||||
$this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test reopen behavior when in "Automatic" mode.
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
public function test_attempt_reopen_method_automatic(): void {
|
||||
global $PAGE;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
|
||||
|
||||
$assign = $this->create_instance($course, [
|
||||
'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_AUTOMATIC,
|
||||
'maxattempts' => 3,
|
||||
'submissiondrafts' => 1,
|
||||
'assignsubmission_onlinetext_enabled' => 1,
|
||||
]);
|
||||
$PAGE->set_url(new \moodle_url('/mod/assign/view.php', ['id' => $assign->get_course_module()->id]));
|
||||
|
||||
// Set grade to pass to 80.
|
||||
$gradeitem = $assign->get_grade_item();
|
||||
$gradeitem->gradepass = '80.0';
|
||||
$gradeitem->update();
|
||||
|
||||
// Student should be able to see an add submission button.
|
||||
$this->setUser($student);
|
||||
$output = $assign->view_submission_action_bar($assign->get_instance(), $student);
|
||||
$this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
|
||||
|
||||
// Add a submission as a student.
|
||||
$this->add_submission($student, $assign);
|
||||
$this->submit_for_grading($student, $assign);
|
||||
|
||||
// Verify the student cannot make a new attempt.
|
||||
$output = $assign->view_student_summary($student, true);
|
||||
$this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
|
||||
|
||||
// Mark the submission as non-passing.
|
||||
$this->mark_submission($teacher, $assign, $student, 50.0);
|
||||
|
||||
// Check the student now has a button for Add a new attempt.
|
||||
$this->setUser($student);
|
||||
$output = $assign->view_submission_action_bar($assign->get_instance(), $student);
|
||||
$this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
|
||||
|
||||
// Add a second submission.
|
||||
$this->add_submission($student, $assign);
|
||||
$this->submit_for_grading($student, $assign);
|
||||
|
||||
// Mark the submission as passing.
|
||||
$this->mark_submission($teacher, $assign, $student, 80.0, [], 1);
|
||||
|
||||
// Check the student now has a button for Add a new attempt.
|
||||
$this->setUser($student);
|
||||
$output = $assign->view_submission_action_bar($assign->get_instance(), $student);
|
||||
$this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test student visibility for each stage of the marking workflow.
|
||||
*/
|
||||
|
||||
@@ -25,5 +25,5 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'mod_assign'; // Full name of the plugin (used for diagnostics).
|
||||
$plugin->version = 2024042202; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2024053100; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2024041600; // Requires this Moodle version.
|
||||
|
||||
Reference in New Issue
Block a user