diff --git a/htdocs/js/GatewayQuiz/gateway.js b/htdocs/js/GatewayQuiz/gateway.js index 4aecb3f37e..365389560c 100644 --- a/htdocs/js/GatewayQuiz/gateway.js +++ b/htdocs/js/GatewayQuiz/gateway.js @@ -158,22 +158,20 @@ const remainingTime = serverDueTime - browserTime + timeDelta; - if (!timerDiv.dataset.acting) { - if (remainingTime <= 10 - gracePeriod) { - if (sessionStorage.getItem('gatewayAlertStatus')) { - sessionStorage.removeItem('gatewayAlertStatus'); - - // Submit the test if time is expired and near the end of grace period. - actuallySubmit = true; - submitAnswers.click(); - } - } else { - // Set the timer text and check alerts at page load. - updateTimer(); + if (!timerDiv.dataset.acting && remainingTime <= 10 - gracePeriod) { + if (sessionStorage.getItem('gatewayAlertStatus')) { + sessionStorage.removeItem('gatewayAlertStatus'); - // Start the timer. - setInterval(updateTimer, 1000); + // Submit the test if time is expired and near the end of grace period. + actuallySubmit = true; + submitAnswers.click(); } + } else { + // Set the timer text and check alerts at page load. + updateTimer(); + + // Start the timer. + setInterval(updateTimer, 1000); } } diff --git a/lib/WeBWorK/ConfigValues.pm b/lib/WeBWorK/ConfigValues.pm index 24cb77116c..19f3172f38 100644 --- a/lib/WeBWorK/ConfigValues.pm +++ b/lib/WeBWorK/ConfigValues.pm @@ -529,7 +529,14 @@ sub getConfigValues ($ce) { var => 'permissionLevels{record_answers_when_acting_as_student}', doc => x('Can submit answers for a student'), doc2 => x( - 'When acting as a student, this permission level and higher can submit answers for that student.'), + 'When acting as a student, this permission level and higher can submit answers for that student, ' + . 'which includes starting and grading test versions. This permission should only be turned ' + . 'on temporarily and set back to "nobody" after you are done submitting answers for a ' + . 'student, as it can interfere with tests. If you have this permission and are viewing a ' + . 'test version for a student that is also working on that version, your answers will be ' + . 'saved for that student when moving between pages, which could reset or change the answers ' + . 'entered in by the student.' + ), type => 'permission' }, { diff --git a/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm b/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm index cfd6b4ab85..8d09e610e0 100644 --- a/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm +++ b/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm @@ -142,9 +142,12 @@ sub can_recordAnswers ($c, $user, $permissionLevel, $effectiveUser, $set, $probl if ($user->user_id ne $effectiveUser->user_id) { # If the user is not allowed to record answers as another user, return that permission. If the user is allowed - # to record only set version answers, then allow that between the open and close dates, and so drop out of this - # conditional to the usual one. - return 1 if $authz->hasPermissions($user->user_id, 'record_answers_when_acting_as_student'); + # to record an unsubmitted test, allow that. If the user is allowed to record only set version answers, then + # allow that between the open and close dates, and so drop out of this conditional to the usual one. + return 1 + if $authz->hasPermissions($user->user_id, 'record_answers_when_acting_as_student') + || $c->can_gradeUnsubmittedTest($user, $permissionLevel, $effectiveUser, $set, $problem, $tmplSet, + $submitAnswers); return 0 if !$authz->hasPermissions($user->user_id, 'record_set_version_answers_when_acting_as_student'); } @@ -225,6 +228,15 @@ sub can_checkAnswers ($c, $user, $permissionLevel, $effectiveUser, $set, $proble return 0; } +# If user can use the problem grader, and the test is past due and has not been submitted, allow them to submit. +sub can_gradeUnsubmittedTest ($c, $user, $permissionLevel, $effectiveUser, $set, $problem, $tmplSet, $submitAnswers = 0) +{ + return + !$submitAnswers + && $c->can_showProblemGrader($user, $permissionLevel, $effectiveUser, $set, $problem, $tmplSet) + && (after($set->due_date + $c->ce->{gatewayGracePeriod}) && !$set->version_last_attempt_time); +} + sub can_showScore ($c, $user, $permissionLevel, $effectiveUser, $set, $problem, $tmplSet) { return $c->authz->hasPermissions($user->user_id, 'view_hidden_work') @@ -642,7 +654,8 @@ async sub pre_header_initialize ($c) { if ( ($currentNumAttempts < $maxAttemptsPerVersion) && ($effectiveUserID eq $userID - || $authz->hasPermissions($userID, 'record_set_version_answers_when_acting_as_student')) + || $authz->hasPermissions($userID, 'record_set_version_answers_when_acting_as_student') + || $authz->hasPermissions($userID, 'record_answers_when_acting_as_student')) ) { if (between($set->open_date(), $set->due_date() + $ce->{gatewayGracePeriod}, $c->submitTime)) { @@ -741,6 +754,7 @@ async sub pre_header_initialize ($c) { checkAnswers => $c->can_checkAnswers(@args), recordAnswersNextTime => $c->can_recordAnswers(@args, $c->{submitAnswers}), checkAnswersNextTime => $c->can_checkAnswers(@args, $c->{submitAnswers}), + gradeUnsubmittedTest => $c->can_gradeUnsubmittedTest(@args, $c->{submitAnswers}), showScore => $c->can_showScore(@args), showProblemScores => $c->can_showProblemScores(@args), showWork => $c->can_showWork(@args), @@ -755,6 +769,11 @@ async sub pre_header_initialize ($c) { $c->{can} = \%can; $c->{will} = \%will; + # Issue a warning if a test has not been submitted, but can still be graded by the instructor. + $c->addbadmessage( + 'This test version is past due, but has not been graded. You can still grade the test for this user.') + if $can{gradeUnsubmittedTest} && $userID ne $effectiveUserID; + # Set up problem numbering and multipage variables. my @problemNumbers; diff --git a/templates/ContentGenerator/GatewayQuiz.html.ep b/templates/ContentGenerator/GatewayQuiz.html.ep index ce8719b0fb..414dd4e6f8 100644 --- a/templates/ContentGenerator/GatewayQuiz.html.ep +++ b/templates/ContentGenerator/GatewayQuiz.html.ep @@ -235,7 +235,7 @@ % # Remaining output of test headers. % # Display timer or information about elapsed time, output link, and information about any recorded score if not % # submitAnswers or checkAnswers. -% if ($c->{can}{recordAnswersNextTime}) { +% if ($c->{can}{recordAnswersNextTime} || $c->{can}{gradeUnsubmittedTest}) { % my $timeLeft = $c->{set}->due_date - int($submitTime); # This is in seconds % % # Print the timer if there is less than 24 hours left. @@ -269,11 +269,13 @@ ) =%> % } % - % if ($timeLeft < 60 && $timeLeft > 0 && !$authz->hasPermissions($userID, 'record_answers_when_acting_as_student')) { + % if ($timeLeft < 60 && $timeLeft > 0 && !$c->{can}{gradeUnsubmittedTest} + % && !$authz->hasPermissions($userID, 'record_answers_when_acting_as_student')) {
<%= maketext('You have less than 1 minute to complete this test.') %>
- % } elsif ($timeLeft <= 0 && !$authz->hasPermissions($userID, 'record_answers_when_acting_as_student')) { + % } elsif ($timeLeft <= 0 && !$c->{can}{gradeUnsubmittedTest} && + % !$authz->hasPermissions($userID, 'record_answers_when_acting_as_student')) {
<%= maketext('You are out of time!') @@ -653,11 +655,16 @@ %
<%= submit_button maketext('Preview Test'), name => 'previewAnswers', class => 'btn btn-primary mb-1' =%> - % if ($c->{can}{recordAnswersNextTime}) { + % if ($c->{can}{checkAnswersNextTime} + % && (!$c->{can}{recordAnswersNextTime} || $c->{can}{showProblemGrader})) { + <%= submit_button maketext('Check Test'), name => 'checkAnswers', class => 'btn btn-primary mb-1' =%> + % } + % if ($c->{can}{recordAnswersNextTime} || $c->{can}{gradeUnsubmittedTest}) { <%= tag('input', type => 'submit', name => 'submitAnswers', - value => maketext('Grade Test'), + value => $effectiveUserID ne $userID + ? maketext('Grade Test for [_1]', $effectiveUserID) : maketext('Grade Test'), class => 'btn btn-primary mb-1', $c->{set}->attempts_per_version ? ( @@ -687,9 +694,6 @@ : () ) =%> % } - % if ($c->{can}{checkAnswersNextTime} && !$c->{can}{recordAnswersNextTime}) { - <%= submit_button maketext('Check Test'), name => 'checkAnswers', class => 'btn btn-primary mb-1' =%> - % }
% if ($numProbPerPage && $numPages > 1 && $c->{can}{recordAnswersNextTime}) {

<%= maketext('Note: grading the test grades all problems, not just those on this page.') %>