From 81dc61b4ea8235f4003a1e08fc5ae74dc81ee29c Mon Sep 17 00:00:00 2001 From: Glenn Rice Date: Mon, 29 Dec 2025 21:15:09 -0600 Subject: [PATCH] Make the problem graders also save the sub_status when needed. Basically, anytime that reduced scoring is not enabled or if it is but it is before the reduced scoring period, then the sub_status needs to also be set to the same thing as the status. Otherwise the "unreduced" score will not be computed correctly. So the problem graders now take this into account. This fixes issue #2873. --- .../js/ProblemGrader/singleproblemgrader.js | 1 + .../Instructor/ProblemGrader.pm | 21 ++++++++++++++++++- lib/WeBWorK/ContentGenerator/Problem.pm | 2 +- lib/WeBWorK/HTML/SingleProblemGrader.pm | 10 +++++++-- lib/WebworkWebservice.pm | 4 ++-- lib/WebworkWebservice/ProblemActions.pm | 14 +++++++------ .../ContentGenerator/GatewayQuiz.html.ep | 2 +- .../HTML/SingleProblemGrader/grader.html.ep | 3 ++- 8 files changed, 43 insertions(+), 14 deletions(-) diff --git a/htdocs/js/ProblemGrader/singleproblemgrader.js b/htdocs/js/ProblemGrader/singleproblemgrader.js index 002c5b7f0d..8518c43586 100644 --- a/htdocs/js/ProblemGrader/singleproblemgrader.js +++ b/htdocs/js/ProblemGrader/singleproblemgrader.js @@ -125,6 +125,7 @@ version_id: saveData.versionId, problem_id: saveData.problemId, status: parseInt(scoreInput.value) / 100, + ...(saveData.saveSubStatus === '1' ? { sub_status: parseInt(scoreInput.value) / 100 } : {}), mark_graded: true }), signal: controller.signal diff --git a/lib/WeBWorK/ContentGenerator/Instructor/ProblemGrader.pm b/lib/WeBWorK/ContentGenerator/Instructor/ProblemGrader.pm index 7bf2c9ed78..dae595e356 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/ProblemGrader.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/ProblemGrader.pm @@ -13,6 +13,7 @@ use HTML::Entities; use WeBWorK::Utils::JITAR qw(jitar_id_to_seq); use WeBWorK::Utils::Rendering qw(renderPG); use WeBWorK::Utils::Sets qw(get_test_problem_position format_set_name_display); +use WeBWorK::Utils::DateTime qw(before); async sub initialize ($c) { my $authz = $c->authz; @@ -96,6 +97,17 @@ async sub initialize ($c) { if ($c->param('assignGrades')) { $c->addgoodmessage($c->maketext('Grades have been saved for all current users.')); + # Get all of the merged user sets for this set. These are needed to determine if the problem sub_status also + # needs to be set. The sub_status must be set if reduced scoring is not enabled for the course or set or if it + # is before the reduced scoring date. + my %mergedSets; + if ($c->stash->{set}->assignment_type =~ /gateway/) { + $mergedSets{ $_->user_id }{ $_->version_id } = $_ + for $db->getMergedSetVersionsWhere({ set_id => { like => "$setID,v\%" } }); + } else { + %mergedSets = map { $_->user_id => { 0 => $_ } } $db->getMergedSetsWhere({ set_id => $setID }); + } + for my $user (@{ $c->stash->{users} }) { my $userID = $user->user_id; for (@{ $user->{data} }) { @@ -115,9 +127,16 @@ async sub initialize ($c) { $_->{problem}{flags} =~ s/:needs_grading$//; if ($c->param("$userID.$versionID.mark_correct")) { $_->{problem}->status(1); + $_->{problem}->sub_status(1); } elsif (defined $c->param("$userID.$versionID.score")) { my $newscore = $c->param("$userID.$versionID.score") / 100; - if ($newscore != $_->{problem}->status) { $_->{problem}->status($newscore); } + if ($newscore != $_->{problem}->status) { + $_->{problem}->status($newscore); + $_->{problem}->sub_status($newscore) + if !$ce->{pg}{ansEvalDefaults}{enableReducedScoring} + || !$mergedSets{$userID}{$versionID}->enable_reduced_scoring + || before($mergedSets{$userID}{$versionID}->reduced_scoring_date); + } } if ($versionID) { $db->putProblemVersion($_->{problem}); } diff --git a/lib/WeBWorK/ContentGenerator/Problem.pm b/lib/WeBWorK/ContentGenerator/Problem.pm index af44e7afab..4d163e4692 100644 --- a/lib/WeBWorK/ContentGenerator/Problem.pm +++ b/lib/WeBWorK/ContentGenerator/Problem.pm @@ -1134,7 +1134,7 @@ sub output_message ($c) { # Output the problem grader if the user has permissions to grade problems sub output_grader ($c) { if ($c->{will}{showProblemGrader}) { - return WeBWorK::HTML::SingleProblemGrader->new($c, $c->{pg}, $c->{problem})->insertGrader; + return WeBWorK::HTML::SingleProblemGrader->new($c, $c->{pg}, $c->{problem}, $c->{set})->insertGrader; } return ''; diff --git a/lib/WeBWorK/HTML/SingleProblemGrader.pm b/lib/WeBWorK/HTML/SingleProblemGrader.pm index d10de75633..fa7bd24304 100644 --- a/lib/WeBWorK/HTML/SingleProblemGrader.pm +++ b/lib/WeBWorK/HTML/SingleProblemGrader.pm @@ -11,8 +11,9 @@ as a student. use WeBWorK::Localize; use WeBWorK::Utils 'wwRound'; +use WeBWorK::Utils::DateTime qw(before); -sub new ($class, $c, $pg, $userProblem) { +sub new ($class, $c, $pg, $userProblem, $mergedSet) { $class = ref($class) || $class; my $db = $c->db; @@ -43,7 +44,12 @@ sub new ($class, $c, $pg, $userProblem) { recorded_score => $recordedScore, past_answer_id => $userPastAnswerID // 0, comment_string => $comment, - c => $c + c => $c, + # The grader needs to also save the sub_status if reduced scoring is not enabled, + # or if it is but it is before the reduced scoring date. + save_sub_status => !$c->ce->{pg}{ansEvalDefaults}{enableReducedScoring} + || !$mergedSet->enable_reduced_scoring + || before($mergedSet->reduced_scoring_date) }; bless $self, $class; diff --git a/lib/WebworkWebservice.pm b/lib/WebworkWebservice.pm index b4715a48c8..ef4f03f29d 100644 --- a/lib/WebworkWebservice.pm +++ b/lib/WebworkWebservice.pm @@ -248,8 +248,8 @@ sub command_permission { # WebworkWebservice::ProblemActions getUserProblem => 'access_instructor_tools', - # Note: The modify_student_data permission is checked in the following three methods and only the status and - # comment_string can actually be modified by users with the problem_grader permission only. + # Note: The modify_student_data permission is checked in the following three methods and only the status, + # sub_status, and comment_string can actually be modified by users with the problem_grader permission only. putUserProblem => 'problem_grader', putProblemVersion => 'problem_grader', putPastAnswer => 'problem_grader', diff --git a/lib/WebworkWebservice/ProblemActions.pm b/lib/WebworkWebservice/ProblemActions.pm index 3305176361..a93babdf56 100644 --- a/lib/WebworkWebservice/ProblemActions.pm +++ b/lib/WebworkWebservice/ProblemActions.pm @@ -38,16 +38,17 @@ sub putUserProblem { 'source_file', 'value', 'max_attempts', 'showMeAnother', 'showMeAnotherCount', 'prPeriod', 'prCount', 'problem_seed', 'attempted', 'last_answer', 'num_correct', 'num_incorrect', - 'att_to_open_children', 'counts_parent_grade', 'sub_status', 'flags' + 'att_to_open_children', 'counts_parent_grade', 'flags' ) { $userProblem->{$_} = $params->{$_} if defined $params->{$_}; } } - # The status is the only thing that users with the problem_grader permission can change. + # The status and sub_status are the only things that users with the problem_grader permission can change. # This method cannot be called without the problem_grader permission. - $userProblem->{status} = $params->{status} if defined $params->{status}; + $userProblem->{status} = $params->{status} if defined $params->{status}; + $userProblem->{sub_status} = $params->{sub_status} if defined $params->{sub_status}; # Remove the needs_grading flag if the mark_graded parameter is set. $userProblem->{flags} =~ s/:needs_grading$// if $params->{mark_graded}; @@ -77,16 +78,17 @@ sub putProblemVersion { 'source_file', 'value', 'max_attempts', 'showMeAnother', 'showMeAnotherCount', 'prPeriod', 'prCount', 'problem_seed', 'attempted', 'last_answer', 'num_correct', 'num_incorrect', - 'att_to_open_children', 'counts_parent_grade', 'sub_status', 'flags' + 'att_to_open_children', 'counts_parent_grade', 'flags' ) { $problemVersion->{$_} = $params->{$_} if defined($params->{$_}); } } - # The status is the only thing that users with the problem_grader permission can change. + # The status and sub_status are the only things that users with the problem_grader permission can change. # This method cannot be called without the problem_grader permission. - $problemVersion->{status} = $params->{status} if defined $params->{status}; + $problemVersion->{status} = $params->{status} if defined $params->{status}; + $problemVersion->{sub_status} = $params->{sub_status} if defined $params->{sub_status}; # Remove the needs_grading flag if the mark_graded parameter is set. $problemVersion->{flags} =~ s/:needs_grading$// if $params->{mark_graded}; diff --git a/templates/ContentGenerator/GatewayQuiz.html.ep b/templates/ContentGenerator/GatewayQuiz.html.ep index 1b4b7c7c72..5cd878c230 100644 --- a/templates/ContentGenerator/GatewayQuiz.html.ep +++ b/templates/ContentGenerator/GatewayQuiz.html.ep @@ -643,7 +643,7 @@ % % # Initialize the problem graders for the problem. % if ($c->{will}{showProblemGrader} && !$pg->{flags}{error_flag}) { - <%= WeBWorK::HTML::SingleProblemGrader->new($c, $pg, $problems->[ $probOrder->[$i] ]) + <%= WeBWorK::HTML::SingleProblemGrader->new($c, $pg, $problems->[ $probOrder->[$i] ], $c->{set}) ->insertGrader =%> % } diff --git a/templates/HTML/SingleProblemGrader/grader.html.ep b/templates/HTML/SingleProblemGrader/grader.html.ep index b5caad01ba..8930cdffd7 100644 --- a/templates/HTML/SingleProblemGrader/grader.html.ep +++ b/templates/HTML/SingleProblemGrader/grader.html.ep @@ -271,7 +271,8 @@ data-set-id="<%= $grader->{set_id} %>" data-version-id="<%= $grader->{version_id} %>" data-problem-id="<%= $grader->{problem_id} %>" - data-past-answer-id="<%= $grader->{past_answer_id} %>"> + data-past-answer-id="<%= $grader->{past_answer_id} %>" + data-save-sub-status="<%= $grader->{save_sub_status} %>"> <%= maketext('Save') =%>