From 33a604fb16f1272e79ad0aff4e2eaba4afdc3e02 Mon Sep 17 00:00:00 2001 From: Glenn Rice Date: Sun, 8 Nov 2026 11:09:00 -0600 Subject: [PATCH] Prevent instructors acting as a student from changing the student's problem data. When acting as a student, using "Show Me Another" incremented the student's `showMeAnotherCount`. It is now only incremented for the user's own problem. With periodic re-randomization enabled, the student's problem seed and `prCount` were saved on every page load, and the "Request New Version" button (also triggered by the enter key) was shown to instructors acting as a student, re-randomizing the student's problem. Now these are only saved and a new version can only be requested when acting as a student if the user has the `record_answers_when_acting_as_student` permission. In that case a "Request New Version for [student]" button is shown with the other buttons, and otherwise it is not shown. In either case the "Check Answers" button is available. On the "Show Me Another" page, the "Request New Version" button is no longer shown since it would re-randomize the original problem. The "Show Past Answers" and "Email Instructor" buttons are also no longer shown since past answers are for the original problem, and the emailed link can not go to the version of the problem shown on that page. Co-Authored-By: Claude Opus 5.5 --- lib/WeBWorK/ContentGenerator/Problem.pm | 20 ++++++++++++------ lib/WeBWorK/ContentGenerator/ShowMeAnother.pm | 21 ++++++++++++++----- .../Problem/submit_buttons.html.ep | 9 +++++++- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/lib/WeBWorK/ContentGenerator/Problem.pm b/lib/WeBWorK/ContentGenerator/Problem.pm index 9e733acbdb..489e4bab8b 100644 --- a/lib/WeBWorK/ContentGenerator/Problem.pm +++ b/lib/WeBWorK/ContentGenerator/Problem.pm @@ -480,14 +480,20 @@ async sub initialize ($c) { if (defined $problem->{prPeriod} && $problem->{prPeriod} > -1); $prEnabled = 0 if ($rerandomizePeriod < 1 || $c->{editMode}); + + my $canUpdateProblemRandomization = $userID eq $effectiveUserID + || $authz->hasPermissions($userID, 'record_answers_when_acting_as_student'); + if ($prEnabled) { $problem->{prCount} = 0 if !defined $problem->{prCount} || $problem->{prCount} =~ /^\s*$/; - $problem->{prCount} += $c->{submitAnswers} ? 1 : 0; + $problem->{prCount} += $c->{submitAnswers} && $canUpdateProblemRandomization ? 1 : 0; $requestNewSeed = 0 - if ($problem->{prCount} < $rerandomizePeriod || after($c->{set}->due_date, $c->submitTime)); + if (!$canUpdateProblemRandomization + || $problem->{prCount} < $rerandomizePeriod + || after($c->{set}->due_date, $c->submitTime)); if ($requestNewSeed) { # obtain new random seed to hopefully change the problem @@ -495,7 +501,7 @@ async sub initialize ($c) { ($problem->{problem_seed} + $problem->num_correct + $problem->num_incorrect) % 10000; $problem->{prCount} = 0; } - if ($problem->{prCount} > -1) { + if ($canUpdateProblemRandomization && $problem->{prCount} > -1) { my $pureProblem = $db->getUserProblem($problem->user_id, $problem->set_id, $problem->problem_id); $pureProblem->problem_seed($problem->{problem_seed}); $pureProblem->prCount($problem->{prCount}); @@ -507,9 +513,11 @@ async sub initialize ($c) { my %will = map { $_ => $can{$_} && $want{$_} } keys %can; if ($prEnabled && $problem->{prCount} >= $rerandomizePeriod && !after($c->{set}->due_date, $c->submitTime)) { - $can{requestNewSeed} = 1; + $c->{newVersionRequired} = 1; + $can{requestNewSeed} = $canUpdateProblemRandomization; $want{requestNewSeed} = 1; - $will{requestNewSeed} = 1; + $will{requestNewSeed} = $canUpdateProblemRandomization; + $can{getSubmitButton} = 0; $c->{showCorrectOnRandomize} = $ce->{pg}{options}{showCorrectOnRandomize}; # If this happens, it means that the page was refreshed. So prevent the answers from # being recorded and the number of attempts from being increased. @@ -1015,7 +1023,7 @@ sub output_score_summary ($c) { my $prMessage = ''; if ($prEnabled) { - my $attempts_before_rr = $c->{will}{requestNewSeed} ? 0 : ($rerandomizePeriod - $problem->{prCount}); + my $attempts_before_rr = $c->{newVersionRequired} ? 0 : ($rerandomizePeriod - $problem->{prCount}); $prMessage = ' ' . $c->maketext('You have [quant,_1,attempt,attempts] left before new version will be requested.', diff --git a/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm b/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm index 7cee78452c..b729d8075f 100644 --- a/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm +++ b/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm @@ -130,11 +130,13 @@ async sub initialize ($c) { || have_different_answers($showMeAnotherNewPG, $showMeAnotherOriginalPG)) { # Increment the counter detailing the number of times showMeAnother has been used, - # and update the database. - my $userProblem = - $db->getUserProblem($c->{effectiveUserID}, $c->stash('setID'), $c->stash('problemID')); - $userProblem->{showMeAnotherCount} = ++$c->{showMeAnother}{Count}; - $db->putUserProblem($userProblem); + # and update the database unless acting as another user. + if ($c->{userID} eq $c->{effectiveUserID}) { + my $userProblem = + $db->getUserProblem($c->{effectiveUserID}, $c->stash('setID'), $c->stash('problemID')); + $userProblem->{showMeAnotherCount} = ++$c->{showMeAnother}{Count}; + $db->putUserProblem($userProblem); + } # Save the problem seed from ShowMeAnother so that it can be used when the page reloads. $c->authen->session->{showMeAnother}{problemSeed} = $newProblemSeed; @@ -158,6 +160,8 @@ async sub initialize ($c) { $c->{can}{recordAnswers} = 0; $c->{can}{checkAnswers} = 0; # This is turned on if the showMeAnother conditions are met below. $c->{can}{getSubmitButton} = 0; + $c->{can}{requestNewSeed} = 0; + $c->{newVersionRequired} = 0; if ($c->stash->{isPossible}) { $c->{can}{showCorrectAnswers} = @@ -287,6 +291,13 @@ sub output_comments ($c) { return '' } sub output_grader ($c) { return '' } sub nav ($c, $args) { return '' } +# Past answers are for the original problem, not this version. +sub output_past_answer_button ($c) { return '' } + +# The problem seed for this version is only stored in the user's session, so a link in a +# feedback email can not take the instructor to this version of the problem. +sub output_email_instructor ($c) { return '' } + # Outputs the summary of the questions that the student has answered for the # current problem, along with available information about correctness. sub output_summary ($c) { diff --git a/templates/ContentGenerator/Problem/submit_buttons.html.ep b/templates/ContentGenerator/Problem/submit_buttons.html.ep index ae4e007fdd..e676234e42 100644 --- a/templates/ContentGenerator/Problem/submit_buttons.html.ep +++ b/templates/ContentGenerator/Problem/submit_buttons.html.ep @@ -3,7 +3,7 @@ % my %can = %{ $c->{can} }; % my %will = %{ $c->{will} }; % my $effectiveUser = param('effectiveUser'); -% if ($will{requestNewSeed}) { +% if ($will{requestNewSeed} && $authen->{user_id} eq $effectiveUser) { <%= submit_button maketext('Request New Version'), id => 'enter_key_submit', name => 'requestNewSeed', @@ -59,6 +59,13 @@ class => 'btn btn-primary mb-1' =%> % } % + % if ($will{requestNewSeed}) { + <%= submit_button maketext('Request New Version for [_1]', $effectiveUser), + id => 'submitAnswers_id', + name => 'requestNewSeed', + class => 'btn btn-primary mb-1' =%> + % } + % % if ($can{getSubmitButton}) { % if ($authen->{user_id} ne $effectiveUser) { % # If acting as a student, make it clear that answer submissions will