Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove the checkboxes for showing correct answers and solutions. #2275

Merged
merged 6 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions conf/defaults.config
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,20 @@ $pg{options}{periodicRandomizationPeriod} = 5;
# and before a new version is requested.
$pg{options}{showCorrectOnRandomize} = 0;

###############################################################################
# answer feedback options
################################################################################

# If set to 1, then answer feedback is automatically shown when returning to an
# answered problem or after answers are available for the assignment. This is
# present in problems when a student opens the problem without the student
# needing to click the "Check Answers" button.
$pg{options}{automaticAnswerFeedback} = 1;

# If set to 1, then a "Reveal" button must be clicked to reveal correct answers
# even after the answer date.
$pg{options}{correctRevealBtnAlways} = 0;

################################################################################
# Single Problem Grader
################################################################################
Expand Down Expand Up @@ -2076,6 +2090,27 @@ $ConfigValues = [
),
type => 'popuplist',
values => ['preview', 'submit', 'conservative']
},
{
var => 'pg{options}{automaticAnswerFeedback}',
doc => x('Show automatic answer feedback'),
doc2 => x(
'Answer feedback will be available in problems when returning to a previously worked problem and '
. 'after answers are available. Students will not need to click "Submit Answers" to make this '
. 'feedback appear. Furthermore, the $showPartialCorrectAnswers variable set in some problems '
. 'that prevents showing which of the answers are correct is ignored after the answer date.'
),
type => 'boolean'
},
{
var => 'pg{options}{correctRevealBtnAlways}',
doc => x('Show correct answer "Reveal" button always'),
doc2 => x(
'A "Reveal" button must be clicked to make a correct answer visible any time that correct answers for '
. ' a problem are shown. Note that this is always the case for instructors before answers are '
. ' available to students, and in "Show Me Another" problems.'
),
type => 'boolean'
}
],
[
Expand Down
2 changes: 0 additions & 2 deletions htdocs/js/ProblemSetDetail/problemsetdetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,6 @@
}, { passive: true });

// Send a request to the webwork webservice and render a problem.
const basicWebserviceURL = `${webworkConfig?.webwork_url ?? '/webwork2'}/render_rpc`;

const render = (id) => new Promise((resolve) => {
const renderArea = document.getElementById(`psr_render_area_${id}`);

Expand Down
138 changes: 74 additions & 64 deletions lib/WeBWorK/ContentGenerator/GatewayQuiz.pm
Original file line number Diff line number Diff line change
Expand Up @@ -74,23 +74,41 @@ sub can_showCorrectAnswers ($c, $user, $permissionLevel, $effectiveUser, $set, $
my $attemptsPerVersion = $set->attempts_per_version || 0;
my $attemptsUsed = $problem->num_correct + $problem->num_incorrect + ($c->{submitAnswers} ? 1 : 0);

# This is complicated by trying to address hiding scores by problem. That is, if $set->hide_score_by_problem and
# $set->hide_score are both set, then we should allow scores to be shown, but not show the score on any individual
# problem. To deal with this, we make can_showCorrectAnswers give the least restrictive view of hiding, and then
# filter scores for the problems themselves later.
return (
(
(
after($set->answer_date, $c->submitTime) || ($attemptsUsed >= $attemptsPerVersion
&& $attemptsPerVersion != 0
&& $set->due_date == $set->answer_date)
)
|| $authz->hasPermissions($user->user_id, 'show_correct_answers_before_answer_date')
$authz->hasPermissions($user->user_id, 'show_correct_answers_before_answer_date')
|| (
after($set->answer_date, $c->submitTime)
|| ($attemptsUsed >= $attemptsPerVersion
&& $attemptsPerVersion != 0
&& $set->due_date == $set->answer_date)
)
)
&& $c->can_showProblemScores($user, $permissionLevel, $effectiveUser, $set, $problem, $tmplSet)
);
}

# This version is the same as the above version except that it ignores elevated permisions. So it will be true if this
# set is in the state that anyone can show correct answers regardless of if they have the
# show_correct_answers_before_answer_date or view_hidden_work permissions. In this case, feedback is shown even without
# a form submission, and correct answers are shown in the feedback, if the $pg{options}{automaticAnswerFeedback} option
# is set in the course configuration.
sub can_showCorrectAnswersForAll ($c, $set, $problem, $tmplSet) {
my $attemptsPerVersion = $set->attempts_per_version || 0;
my $attemptsUsed = $problem->num_correct + $problem->num_incorrect + ($c->{submitAnswers} ? 1 : 0);

return (
(
after($set->answer_date, $c->submitTime) || ($attemptsUsed >= $attemptsPerVersion
&& $attemptsPerVersion != 0
&& $set->due_date == $set->answer_date)
)
&& (
$authz->hasPermissions($user->user_id, 'view_hidden_work')
|| $set->hide_score_by_problem eq 'N' && ($set->hide_score eq 'N'
|| ($set->hide_score eq 'BeforeAnswerDate' && after($tmplSet->answer_date, $c->submitTime)))
(
$set->hide_score eq 'N'
|| ($set->hide_score eq 'BeforeAnswerDate' && after($tmplSet->answer_date, $c->submitTime))
)
&& $set->hide_score_by_problem eq 'N'
)
);
}
Expand All @@ -108,10 +126,7 @@ sub can_showHints ($c) { return 1; }

sub can_showSolutions ($c, $user, $permissionLevel, $effectiveUser, $set, $problem, $tmplSet) {
my $authz = $c->authz;

return 1 if $authz->hasPermissions($user->user_id, 'always_show_solution');

# This is the same as can_showCorrectAnswers.
return $c->can_showCorrectAnswers($user, $permissionLevel, $effectiveUser, $set, $problem, $tmplSet);
}

Expand Down Expand Up @@ -684,36 +699,15 @@ async sub pre_header_initialize ($c) {

# What does the user want to do?
my %want = (
showOldAnswers => $user->showOldAnswers ne '' ? $user->showOldAnswers : $ce->{pg}{options}{showOldAnswers},
# showProblemGrader implies showCorrectAnswers. This is a convenience for grading.
showCorrectAnswers => ($c->param('showProblemGrader') || 0)
|| ($c->param('showCorrectAnswers') && ($c->{submitAnswers} || $c->{checkAnswers}))
|| 0,
showProblemGrader => $c->param('showProblemGrader')
|| 0,
# Hints are not yet implemented in gateway quzzes.
showHints => 0,
# showProblemGrader implies showSolutions. Another convenience for grading.
showSolutions => $c->param('showProblemGrader')
|| ($c->param('showSolutions') && ($c->{submitAnswers} || $c->{checkAnswers})),
recordAnswers => $c->{submitAnswers} && !$authz->hasPermissions($userID, 'avoid_recording_answers'),
# we also want to check answers if we were checking answers and are switching between pages
checkAnswers => $c->{checkAnswers},
useMathView => $user->useMathView ne '' ? $user->useMathView : $ce->{pg}{options}{useMathView},
useMathQuill => $user->useMathQuill ne '' ? $user->useMathQuill : $ce->{pg}{options}{useMathQuill},
);

# Are certain options enforced?
my %must = (
showOldAnswers => 0,
showCorrectAnswers => 0,
showProblemGrader => 0,
showHints => 0,
showSolutions => 0,
recordAnswers => 0,
checkAnswers => 0,
useMathView => 0,
useMathQuill => 0,
showOldAnswers => $user->showOldAnswers ne '' ? $user->showOldAnswers : $ce->{pg}{options}{showOldAnswers},
showCorrectAnswers => 1,
showProblemGrader => $c->param('showProblemGrader') || 0,
showHints => 0, # Hints are not yet implemented in gateway quzzes.
showSolutions => 1,
recordAnswers => $c->{submitAnswers} && !$authz->hasPermissions($userID, 'avoid_recording_answers'),
checkAnswers => $c->{checkAnswers},
useMathView => $user->useMathView ne '' ? $user->useMathView : $ce->{pg}{options}{useMathView},
useMathQuill => $user->useMathQuill ne '' ? $user->useMathQuill : $ce->{pg}{options}{useMathQuill},
);

# Does the user have permission to use certain options?
Expand All @@ -736,10 +730,9 @@ async sub pre_header_initialize ($c) {
);

# Final values for options
my %will = map { $_ => $can{$_} && ($must{$_} || $want{$_}) } keys %must;
my %will = map { $_ => $can{$_} && $want{$_} } keys %can;

$c->{want} = \%want;
$c->{must} = \%must;
$c->{can} = \%can;
$c->{will} = \%will;

Expand Down Expand Up @@ -1453,6 +1446,13 @@ sub warningMessage ($c) {
# hash of parameters from the input form that need to be passed to the translator, and $mergedProblem
# is what we'd expect.
async sub getProblemHTML ($c, $effectiveUser, $set, $formFields, $mergedProblem) {
my $showReturningFeedback =
!($c->{submitAnswers} || $c->{previewAnswers} || $c->{checkAnswers})
&& $c->{will}{showOldAnswers}
&& $c->ce->{pg}{options}{automaticAnswerFeedback}
&& $c->{can}{showProblemScores}
&& $mergedProblem->num_correct + $mergedProblem->num_incorrect > 0;

my $pg = await renderPG(
$c,
$effectiveUser,
Expand All @@ -1461,25 +1461,35 @@ async sub getProblemHTML ($c, $effectiveUser, $set, $formFields, $mergedProblem)
$set->psvn,
$formFields,
{
displayMode => $c->{displayMode},
showHints => $c->{will}{showHints},
showSolutions => $c->{will}{showSolutions},
refreshMath2img => $c->{will}{showHints} || $c->{will}{showSolutions},
processAnswers => 1,
QUIZ_PREFIX => 'Q' . sprintf('%04d', $mergedProblem->problem_id) . '_',
useMathQuill => $c->{will}{useMathQuill},
useMathView => $c->{will}{useMathView},
forceScaffoldsOpen => 1,
isInstructor => $c->authz->hasPermissions($c->{userID}, 'view_answers'),
showFeedback => $c->{submitAnswers} || $c->{previewAnswers} || $c->{will}{checkAnswers},
displayMode => $c->{displayMode},
showHints => $c->{will}{showHints},
showSolutions => $c->{will}{showSolutions},
refreshMath2img => $c->{will}{showHints} || $c->{will}{showSolutions},
processAnswers => 1,
QUIZ_PREFIX => 'Q' . sprintf('%04d', $mergedProblem->problem_id) . '_',
useMathQuill => $c->{will}{useMathQuill},
useMathView => $c->{will}{useMathView},
forceScaffoldsOpen => 1,
isInstructor => $c->authz->hasPermissions($c->{userID}, 'view_answers'),
showFeedback => $c->{submitAnswers}
|| $c->{previewAnswers}
|| $c->{will}{checkAnswers}
|| $showReturningFeedback,
showAttemptAnswers => $c->ce->{pg}{options}{showEvaluatedAnswers},
showAttemptPreviews => 1,
showAttemptResults => !$c->{previewAnswers} && $c->{can}{showProblemScores},
forceShowAttemptResults => $c->{will}{showProblemGrader},
showMessages => 1,
showCorrectAnswers => ($c->{submitAnswers} || $c->{will}{checkAnswers} || $c->{will}{showProblemGrader})
? $c->{will}{showCorrectAnswers}
: 0,
forceShowAttemptResults => $c->{will}{showProblemGrader}
|| ($c->ce->{pg}{options}{automaticAnswerFeedback}
&& !$c->{previewAnswers}
&& $c->can_showCorrectAnswersForAll($set, $c->{problem}, $c->{tmplSet})),
showMessages => 1,
showCorrectAnswers => (
$c->{will}{showProblemGrader} ? 2
: !$c->{previewAnswers} && $c->can_showCorrectAnswersForAll($set, $c->{problem}, $c->{tmplSet})
? ($c->ce->{pg}{options}{correctRevealBtnAlways} ? 1 : 2)
: !$c->{previewAnswers} && $c->{will}{showCorrectAnswers} ? 1
: 0
),
debuggingOptions => getTranslatorDebuggingOptions($c->authz, $c->{userID})
},
);
Expand Down
73 changes: 32 additions & 41 deletions lib/WeBWorK/ContentGenerator/Problem.pm
Original file line number Diff line number Diff line change
Expand Up @@ -449,49 +449,29 @@ async sub pre_header_initialize ($c) {
$showMeAnother{Count} = 0 unless $showMeAnother{Count} =~ /^[+-]?\d+$/;

# Store the showMeAnother hash for the check to see if the button can be used
# (this hash is updated and re-stored after the can, must, will hashes)
# (this hash is updated and re-stored after the can and will hashes)
$c->{showMeAnother} = \%showMeAnother;

# Permissions

# What does the user want to do?
my %want = (
showOldAnswers => $user->showOldAnswers ne '' ? $user->showOldAnswers : $ce->{pg}{options}{showOldAnswers},
# showProblemGrader implies showCorrectAnswers. This is a convenience for grading.
showCorrectAnswers => $c->param('showCorrectAnswers') || $c->param('showProblemGrader') || 0,
showProblemGrader => $c->param('showProblemGrader') || 0,
showAnsGroupInfo => $c->param('showAnsGroupInfo') || $ce->{pg}{options}{showAnsGroupInfo},
showAnsHashInfo => $c->param('showAnsHashInfo') || $ce->{pg}{options}{showAnsHashInfo},
showPGInfo => $c->param('showPGInfo') || $ce->{pg}{options}{showPGInfo},
showResourceInfo => $c->param('showResourceInfo') || $ce->{pg}{options}{showResourceInfo},
showOldAnswers => $user->showOldAnswers ne '' ? $user->showOldAnswers : $ce->{pg}{options}{showOldAnswers},
showCorrectAnswers => 1,
showProblemGrader => $c->param('showProblemGrader') || 0,
showAnsGroupInfo => $c->param('showAnsGroupInfo') || $ce->{pg}{options}{showAnsGroupInfo},
showAnsHashInfo => $c->param('showAnsHashInfo') || $ce->{pg}{options}{showAnsHashInfo},
showPGInfo => $c->param('showPGInfo') || $ce->{pg}{options}{showPGInfo},
showResourceInfo => $c->param('showResourceInfo') || $ce->{pg}{options}{showResourceInfo},
showHints => 1,
showSolutions => 1,
useMathView => $user->useMathView ne '' ? $user->useMathView : $ce->{pg}{options}{useMathView},
useMathQuill => $user->useMathQuill ne '' ? $user->useMathQuill : $ce->{pg}{options}{useMathQuill},
recordAnswers => $c->{submitAnswers},
recordAnswers => $c->{submitAnswers} && !$authz->hasPermissions($userID, 'avoid_recording_answers'),
checkAnswers => $checkAnswers,
getSubmitButton => 1,
);

# Are certain options enforced?
my %must = (
showOldAnswers => 0,
showCorrectAnswers => 0,
showProblemGrader => 0,
showAnsGroupInfo => 0,
showAnsHashInfo => 0,
showPGInfo => 0,
showResourceInfo => 0,
showHints => 0,
showSolutions => 0,
recordAnswers => !$authz->hasPermissions($userID, 'avoid_recording_answers'),
checkAnswers => 0,
showMeAnother => 0,
getSubmitButton => 0,
useMathView => 0,
useMathQuill => 0,
);

# Does the user have permission to use certain options?
my @args = ($user, $effectiveUser, $c->{set}, $problem);

Expand Down Expand Up @@ -548,11 +528,10 @@ async sub pre_header_initialize ($c) {
}

# Final values for options
my %will = map { $_ => $can{$_} && ($want{$_} || $must{$_}) } keys %must;
my %will = map { $_ => $can{$_} && $want{$_} } keys %can;

if ($prEnabled && $problem->{prCount} >= $rerandomizePeriod && !after($c->{set}->due_date, $c->submitTime)) {
$showMeAnother{active} = 0;
$must{requestNewSeed} = 1;
$can{requestNewSeed} = 1;
$want{requestNewSeed} = 1;
$will{requestNewSeed} = 1;
Expand All @@ -561,13 +540,16 @@ async sub pre_header_initialize ($c) {
# being recorded and the number of attempts from being increased.
if ($problem->{prCount} > $rerandomizePeriod) {
$c->{resubmitDetected} = 1;
$must{recordAnswers} = 0;
$can{recordAnswers} = 0;
$want{recordAnswers} = 0;
$will{recordAnswers} = 0;
}
}

# If this is set to 1 below, then feedback is shown when a student returns to a previously worked problem without
# requiring another answer submission.
my $showReturningFeedback = 0;

# Sticky answers
if (!($c->{submitAnswers} || $previewAnswers || $checkAnswers) && $will{showOldAnswers}) {
my %oldAnswers = decodeAnswers($problem->last_answer);
Expand All @@ -576,7 +558,9 @@ async sub pre_header_initialize ($c) {
# Clear answers if this is a new problem version
delete $formFields->{$_} for keys %oldAnswers;
} else {
$formFields->{$_} = $oldAnswers{$_} for keys %oldAnswers;
$formFields->{$_} = $oldAnswers{$_} for (keys %oldAnswers);
$showReturningFeedback = 1
if $ce->{pg}{options}{automaticAnswerFeedback} && $problem->num_correct + $problem->num_incorrect > 0;
}
}

Expand All @@ -602,15 +586,23 @@ async sub pre_header_initialize ($c) {
useMathView => $will{useMathView},
forceScaffoldsOpen => 0,
isInstructor => $authz->hasPermissions($userID, 'view_answers'),
showFeedback => $c->{submitAnswers} || $c->{previewAnswers},
showFeedback => $c->{submitAnswers} || $c->{previewAnswers} || $showReturningFeedback,
showAttemptAnswers => $ce->{pg}{options}{showEvaluatedAnswers},
showAttemptPreviews => 1,
showAttemptResults => $c->{submitAnswers},
forceShowAttemptResults => $will{checkAnswers} || $will{showProblemGrader},
showMessages => 1,
showCorrectAnswers => $c->{submitAnswers} ? ($c->{showCorrectOnRandomize} // $will{showCorrectAnswers})
: $will{checkAnswers} || $will{showProblemGrader} ? $will{showCorrectAnswers}
: 0,
showAttemptResults => $c->{submitAnswers} || $showReturningFeedback,
forceShowAttemptResults => $will{checkAnswers}
|| $will{showProblemGrader}
|| ($ce->{pg}{options}{automaticAnswerFeedback}
&& !$c->{previewAnswers}
&& after($c->{set}->answer_date, $c->submitTime)),
showMessages => 1,
showCorrectAnswers => (
$will{showProblemGrader} || ($c->{submitAnswers} && $c->{showCorrectOnRandomize}) ? 2
: !$c->{previewAnswers} && after($c->{set}->answer_date, $c->submitTime)
? ($ce->{pg}{options}{correctRevealBtnAlways} ? 1 : 2)
: !$c->{previewAnswers} && $will{showCorrectAnswers} ? 1
: 0
),
debuggingOptions => getTranslatorDebuggingOptions($authz, $userID)
}
);
Expand Down Expand Up @@ -646,7 +638,6 @@ async sub pre_header_initialize ($c) {

# Store fields
$c->{want} = \%want;
$c->{must} = \%must;
$c->{can} = \%can;
$c->{will} = \%will;
$c->{pg} = $pg;
Expand Down
Loading
Loading