mirror of
https://github.com/moodle/moodle.git
synced 2025-08-03 16:13:28 +02:00
quiz delays MDL-20956 don't let overdue attempts + delays block students.
Suppose a quiz has a 60 min time limit, and an enforced delay of 60 mins between attempts. Suppose a sudent starts an attempt, and then closes their browser, and then comes back 2 hours later. When they try to restart the quiz, it is submitted immediately by the timer. Now they are blocked out for the next hour. After this change, they would no longer be blocked, becuse if their attemtp had been submitted at the end of the first hour, then they would already have waited an hour. That is, we compare the current time with both $lastattempt->timefinish + $delay and $lastattempt->timestart + $timelimit + $delay.
This commit is contained in:
parent
afba32ddd5
commit
207d145dda
2 changed files with 93 additions and 13 deletions
|
@ -106,7 +106,8 @@ class quiz_access_manager {
|
|||
* should be blocked. If access is OK, return false.
|
||||
*
|
||||
* @param integer $numattempts the number of previous attempts this user has made.
|
||||
* @param object $lastattempt information about the user's last completed attempt.
|
||||
* @param object|false $lastattempt information about the user's last completed attempt.
|
||||
* if there is not a previous attempt, the false is passed.
|
||||
* @return mixed An array of reason why access is not allowed, or an empty array
|
||||
* (== false) if access should be allowed.
|
||||
*/
|
||||
|
@ -561,12 +562,7 @@ class inter_attempt_delay_access_rule extends quiz_access_rule_base {
|
|||
/// No more attempts allowed anyway.
|
||||
return false;
|
||||
}
|
||||
$nextstarttime = 0;
|
||||
if ($numprevattempts == 1 && $this->_quiz->delay1) {
|
||||
$nextstarttime = $lastattempt->timefinish + $this->_quiz->delay1;
|
||||
} else if ($numprevattempts > 1 && $this->_quiz->delay2) {
|
||||
$nextstarttime = $lastattempt->timefinish + $this->_quiz->delay2;
|
||||
}
|
||||
$nextstarttime = $this->compute_next_start_time($numprevattempts, $lastattempt);
|
||||
if ($this->_timenow < $nextstarttime) {
|
||||
if ($this->_quiz->timeclose == 0 || $nextstarttime <= $this->_quiz->timeclose) {
|
||||
return get_string('youmustwait', 'quiz', userdate($nextstarttime));
|
||||
|
@ -576,13 +572,35 @@ class inter_attempt_delay_access_rule extends quiz_access_rule_base {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
public function is_finished($numprevattempts, $lastattempt) {
|
||||
$nextstarttime = 0;
|
||||
if ($numprevattempts == 1 && $this->_quiz->delay1) {
|
||||
$nextstarttime = $lastattempt->timefinish + $this->_quiz->delay1;
|
||||
} else if ($numprevattempts > 1 && $this->_quiz->delay2) {
|
||||
$nextstarttime = $lastattempt->timefinish + $this->_quiz->delay2;
|
||||
|
||||
/**
|
||||
* Compute the next time a student would be allowed to start an attempt,
|
||||
* according to this rule.
|
||||
* @param integer $numprevattempts number of previous attempts.
|
||||
* @param object $lastattempt information about the previous attempt.
|
||||
* @return number the time.
|
||||
*/
|
||||
protected function compute_next_start_time($numprevattempts, $lastattempt) {
|
||||
if ($numprevattempts == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$lastattemptfinish = $lastattempt->timefinish;
|
||||
if ($this->_quiz->timelimit > 0){
|
||||
$lastattemptfinish = min($lastattemptfinish,
|
||||
$lastattempt->timestart + $this->_quiz->timelimit);
|
||||
}
|
||||
|
||||
if ($numprevattempts == 1 && $this->_quiz->delay1) {
|
||||
return $lastattemptfinish + $this->_quiz->delay1;
|
||||
} else if ($numprevattempts > 1 && $this->_quiz->delay2) {
|
||||
return $lastattemptfinish + $this->_quiz->delay2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function is_finished($numprevattempts, $lastattempt) {
|
||||
$nextstarttime = $this->compute_next_start_time($numprevattempts, $lastattempt);
|
||||
return $this->_timenow <= $nextstarttime &&
|
||||
$this->_quiz->timeclose != 0 && $nextstarttime >= $this->_quiz->timeclose;
|
||||
}
|
||||
|
|
|
@ -230,6 +230,7 @@ class inter_attempt_delay_access_rule_test extends UnitTestCase {
|
|||
function test_just_first_delay() {
|
||||
$quiz = new stdClass;
|
||||
$quiz->attempts = 3;
|
||||
$quiz->timelimit = 0;
|
||||
$quiz->delay1 = 1000;
|
||||
$quiz->delay2 = 0;
|
||||
$quiz->timeclose = 0;
|
||||
|
@ -261,6 +262,7 @@ class inter_attempt_delay_access_rule_test extends UnitTestCase {
|
|||
function test_just_second_delay() {
|
||||
$quiz = new stdClass;
|
||||
$quiz->attempts = 5;
|
||||
$quiz->timelimit = 0;
|
||||
$quiz->delay1 = 0;
|
||||
$quiz->delay2 = 1000;
|
||||
$quiz->timeclose = 0;
|
||||
|
@ -295,6 +297,7 @@ class inter_attempt_delay_access_rule_test extends UnitTestCase {
|
|||
function test_just_both_delays() {
|
||||
$quiz = new stdClass;
|
||||
$quiz->attempts = 5;
|
||||
$quiz->timelimit = 0;
|
||||
$quiz->delay1 = 2000;
|
||||
$quiz->delay2 = 1000;
|
||||
$quiz->timeclose = 0;
|
||||
|
@ -337,6 +340,7 @@ class inter_attempt_delay_access_rule_test extends UnitTestCase {
|
|||
function test_with_close_date() {
|
||||
$quiz = new stdClass;
|
||||
$quiz->attempts = 5;
|
||||
$quiz->timelimit = 0;
|
||||
$quiz->delay1 = 2000;
|
||||
$quiz->delay2 = 1000;
|
||||
$quiz->timeclose = 15000;
|
||||
|
@ -382,6 +386,64 @@ class inter_attempt_delay_access_rule_test extends UnitTestCase {
|
|||
$attempt->timefinish = 14001;
|
||||
$this->assertFalse($rule->prevent_new_attempt(2, $attempt));
|
||||
}
|
||||
|
||||
function test_time_limit_and_overdue() {
|
||||
$quiz = new stdClass;
|
||||
$quiz->attempts = 5;
|
||||
$quiz->timelimit = 100;
|
||||
$quiz->delay1 = 2000;
|
||||
$quiz->delay2 = 1000;
|
||||
$quiz->timeclose = 0;
|
||||
$quiz->questions = '';
|
||||
$cm = new stdClass;
|
||||
$cm->id = 0;
|
||||
$quizobj = new quiz($quiz, $cm, null);
|
||||
$attempt = new stdClass;
|
||||
$attempt->timestart = 9900;
|
||||
$attempt->timefinish = 10100;
|
||||
|
||||
$rule = new inter_attempt_delay_access_rule($quizobj, 10000);
|
||||
$this->assertFalse($rule->description());
|
||||
$this->assertFalse($rule->prevent_access());
|
||||
$this->assertFalse($rule->is_finished(0, $attempt));
|
||||
$this->assertFalse($rule->time_left($attempt, 0));
|
||||
|
||||
$this->assertFalse($rule->prevent_new_attempt(0, $attempt));
|
||||
$this->assertFalse($rule->prevent_new_attempt(5, $attempt));
|
||||
$this->assertEqual($rule->prevent_new_attempt(1, $attempt), get_string('youmustwait', 'quiz', userdate(12000)));
|
||||
$this->assertEqual($rule->prevent_new_attempt(2, $attempt), get_string('youmustwait', 'quiz', userdate(11000)));
|
||||
$this->assertEqual($rule->prevent_new_attempt(3, $attempt), get_string('youmustwait', 'quiz', userdate(11000)));
|
||||
$attempt->timestart = 7950;
|
||||
$attempt->timefinish = 8000;
|
||||
$this->assertFalse($rule->prevent_new_attempt(1, $attempt));
|
||||
$this->assertFalse($rule->prevent_new_attempt(2, $attempt));
|
||||
$this->assertFalse($rule->prevent_new_attempt(3, $attempt));
|
||||
$attempt->timestart = 7950;
|
||||
$attempt->timefinish = 8001;
|
||||
$this->assertEqual($rule->prevent_new_attempt(1, $attempt), get_string('youmustwait', 'quiz', userdate(10001)));
|
||||
$this->assertFalse($rule->prevent_new_attempt(2, $attempt));
|
||||
$this->assertFalse($rule->prevent_new_attempt(4, $attempt));
|
||||
$attempt->timestart = 8950;
|
||||
$attempt->timefinish = 9000;
|
||||
$this->assertEqual($rule->prevent_new_attempt(1, $attempt), get_string('youmustwait', 'quiz', userdate(11000)));
|
||||
$this->assertFalse($rule->prevent_new_attempt(2, $attempt));
|
||||
$this->assertFalse($rule->prevent_new_attempt(3, $attempt));
|
||||
$attempt->timestart = 8950;
|
||||
$attempt->timefinish = 9001;
|
||||
$this->assertEqual($rule->prevent_new_attempt(1, $attempt), get_string('youmustwait', 'quiz', userdate(11001)));
|
||||
$this->assertEqual($rule->prevent_new_attempt(2, $attempt), get_string('youmustwait', 'quiz', userdate(10001)));
|
||||
$this->assertEqual($rule->prevent_new_attempt(4, $attempt), get_string('youmustwait', 'quiz', userdate(10001)));
|
||||
$attempt->timestart = 8900;
|
||||
$attempt->timefinish = 9100;
|
||||
$this->assertEqual($rule->prevent_new_attempt(1, $attempt), get_string('youmustwait', 'quiz', userdate(11000)));
|
||||
$this->assertFalse($rule->prevent_new_attempt(2, $attempt));
|
||||
$this->assertFalse($rule->prevent_new_attempt(3, $attempt));
|
||||
$attempt->timestart = 8901;
|
||||
$attempt->timefinish = 9100;
|
||||
$this->assertEqual($rule->prevent_new_attempt(1, $attempt), get_string('youmustwait', 'quiz', userdate(11001)));
|
||||
$this->assertEqual($rule->prevent_new_attempt(2, $attempt), get_string('youmustwait', 'quiz', userdate(10001)));
|
||||
$this->assertEqual($rule->prevent_new_attempt(4, $attempt), get_string('youmustwait', 'quiz', userdate(10001)));
|
||||
}
|
||||
}
|
||||
|
||||
class password_access_rule_test extends UnitTestCase {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue