From bdd47c60ac97538b5076f9ce95054612dd4bed57 Mon Sep 17 00:00:00 2001 From: Jaimos Skriletz Date: Tue, 26 Nov 2024 14:26:33 -0700 Subject: [PATCH] Updates to grading tests for other users. When able to grade a test of another user, change the "Grade Test" button to "Grade Test for UserID" to make it clear the test is being graded for another user. Show the "Check Test" button along side the "Grade Test" button for instructor who can use the problem grader but also have the permission to submit the past due test. Allow instructors who can use the problem grader to grade unsubmitted tests for that user without needing the permission to submit test versions or answers for another user. This way if for some reason a student's test doesn't get submitted correctly (such as a user closing their browser without grading the test or after reaching a grade proctor screen), it can still be graded with their saved answers. Update the timer when acting as another user if it is being shown, just only suppress warnings about running out of time in this case. Update description of record_answers_when_acting_as_student to state that it can also start and grade test versions. Also include a warning about that permission should be disabled (set back to "nobody") after using it as it can interfere with tests, and should probably only be used temporarily. --- htdocs/js/GatewayQuiz/gateway.js | 26 ++++++++--------- lib/WeBWorK/ConfigValues.pm | 9 +++++- lib/WeBWorK/ContentGenerator/GatewayQuiz.pm | 28 ++++++++++++++++--- .../ContentGenerator/GatewayQuiz.html.ep | 20 +++++++------ 4 files changed, 56 insertions(+), 27 deletions(-) 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..727196956d 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,12 @@ 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( + $c->maketext( + '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.') %>