Skip to content

Commit 40dd5d5

Browse files
committed
Rework error handling when a problem fails to render in a test.
First, fix a general issue when a problem fails to render that results in a message that has no relation to the actual problem. The issue is that the `create_ans_str_from_responses` method of the `WeBWorK::Utils::ProblemProcessing` module is called with a `$pg` hash that doesn't contain the right things, and the method is not safe guarded against that. This fixes issue #2829. Second, rework how error handling is done in tests. Instead of just rendering the errors for problems that failed to render, still render all problems on the page. Show the errors for the problems that failed, but still render all of the problems that didn't fail. This means, that the problem navigation is still shown. In fact the entire page renders normally, but the error message is shown for the problems that fail to render. So the student can at least continue to work the rest of the test normally. The student can even grade the test on a page for which a problem fails to render. Note that the "request information" is no longer shown for these messages when in a test. A special `briefErrorOutput` stash value can be set when the `templates/ContentGenerator/Base/error_output.html.ep` template is rendered to skip that. Although, I really thing that information should never be shown in the page for any exception that occurs. I don't think that the time, method, uri, and HTTP headers of the request, ever help with these exceptions.
1 parent a00a004 commit 40dd5d5

File tree

6 files changed

+26
-46
lines changed

6 files changed

+26
-46
lines changed

lib/WeBWorK/AchievementEvaluator.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use WeBWorK::WWSafe;
1616

1717
our @EXPORT_OK = qw(checkForAchievements);
1818

19-
sub checkForAchievements ($problem_in, $pg, $c, %options) {
19+
sub checkForAchievements ($problem_in, $c, %options) {
2020
my $db = $c->db;
2121
my $ce = $c->ce;
2222

lib/WeBWorK/ContentGenerator/GatewayQuiz.pm

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -887,9 +887,6 @@ async sub pre_header_initialize ($c) {
887887
my @problems;
888888
my @pg_results;
889889

890-
# pg errors are stored here.
891-
$c->{errors} = [];
892-
893890
# Process the problems as needed.
894891
my @mergedProblems;
895892
if ($setID eq 'Undefined_Set') {
@@ -1511,17 +1508,6 @@ async sub getProblemHTML ($c, $effectiveUser, $set, $formFields, $mergedProblem)
15111508
# So rewarn them and let the global warning handler take care of it.
15121509
warn $pg->{warnings} if $pg->{warnings};
15131510

1514-
if ($pg->{flags}{error_flag}) {
1515-
push @{ $c->{errors} },
1516-
{
1517-
set => $set->set_id . ',v' . $set->version_id,
1518-
problem => $mergedProblem->problem_id,
1519-
message => $pg->{errors},
1520-
context => $pg->{body_text},
1521-
};
1522-
$pg->{body_text} = undef;
1523-
}
1524-
15251511
# If the user can check answers and either this is not an answer submission or the problem_data form
15261512
# parameter was previously set, then set or update the problem_data form parameter.
15271513
$c->param('problem_data_' . $mergedProblem->problem_id => encode_json($pg->{PERSISTENCE_HASH} || '{}'))

lib/WeBWorK/ContentGenerator/Problem.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,7 @@ sub output_achievement_message ($c) {
15491549
&& $c->{submitAnswers}
15501550
&& $c->{problem}->set_id ne 'Undefined_Set')
15511551
{
1552-
return checkForAchievements($c->{problem}, $c->{pg}, $c);
1552+
return checkForAchievements($c->{problem}, $c);
15531553
}
15541554

15551555
return '';

lib/WeBWorK/Utils/ProblemProcessing.pm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ sub create_ans_str_from_responses ($formFields, $pg, $needed_grading = 0) {
298298
my @past_answers_order;
299299
my @last_answer_order;
300300

301-
my %pg_answers_hash = %{ $pg->{PG_ANSWERS_HASH} };
301+
my %pg_answers_hash = %{ $pg->{PG_ANSWERS_HASH} // {} };
302302
for my $ans_id (@{ $pg->{flags}{ANSWER_ENTRY_ORDER} // [] }) {
303303
$scores_string .= ($pg_answers_hash{$ans_id}{rh_ans}{score} // 0) >= 1 ? '1' : '0';
304304
push @answerTypes, $pg_answers_hash{$ans_id}{rh_ans}{type} // '';
@@ -326,7 +326,7 @@ sub create_ans_str_from_responses ($formFields, $pg, $needed_grading = 0) {
326326
# KEPT_EXTRA_ANSWERS needs to be stored in last_answer in order to preserve persistence items.
327327
# The persistence items do not need to be stored in past_answers_string.
328328
# Don't add _ext_data items. Those are stored elsewhere.
329-
for my $entry_id (@{ $pg->{flags}{KEPT_EXTRA_ANSWERS} }) {
329+
for my $entry_id (@{ $pg->{flags}{KEPT_EXTRA_ANSWERS} // [] }) {
330330
next if exists($answers_to_store{$entry_id}) || $entry_id =~ /^_ext_data/;
331331
$answers_to_store{$entry_id} = $formFields->{$entry_id};
332332
push @last_answer_order, $entry_id;

templates/ContentGenerator/Base/error_output.html.ep

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
% use Date::Format;
22
%
3-
<h2><%= maketext('WeBWorK Error') %></h2>
3+
% unless (stash->{briefErrorOutput}) {
4+
<h2><%= maketext('WeBWorK Error') %></h2>
5+
% }
46
<p>
57
<%= maketext(
68
'WeBWorK has encountered a software error while attempting to process this problem. It is likely that '
@@ -15,6 +17,7 @@
1517
<div class="error-output">
1618
<%== ref $details =~ /SCALAR/i ? $$details : ref $details =~ /ARRAY/i ? join('', @$details) : $details %>
1719
</div>
20+
% last if stash->{briefErrorOutput};
1821
<h3><%= maketext('Request information') %></h3>
1922
<table class="table-bordered mb-2">
2023
<tr>

templates/ContentGenerator/GatewayQuiz.html.ep

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -108,25 +108,6 @@
108108
% last;
109109
% }
110110
%
111-
% # If there were translation errors, then show those and exit.
112-
% if (@{ $c->{errors} }) {
113-
% my $errorNum = 1;
114-
% my ($message, $context) = (c, c);
115-
% for (@{ $c->{errors} }) {
116-
% push(@$message, "$errorNum. ") if (@{ $c->{errors} } > 1);
117-
% push(@$message, $_->{message}, tag('br'));
118-
%
119-
% my $line = begin
120-
<p><%= (@{ $c->{errors} } > 1 ? "$errorNum." : '') %><%== $_->{context} %></p>
121-
<div class="gwDivider"></div>
122-
% end
123-
% push @$context, $line->();
124-
% }
125-
<%= include 'ContentGenerator/Base/error_output', error => $message->join(''), details => $context->join('') =%>
126-
%
127-
% last;
128-
% }
129-
%
130111
% my $setID = $c->{set}->set_id;
131112
% my $setVersionID = $c->{set}->version_id;
132113
% my $numProbPerPage = $c->{set}->problems_per_page;
@@ -405,7 +386,7 @@
405386
% # Problems can be shown, so output the main form and the problems.
406387
% my $startTime = param('startTime') || time;
407388
%
408-
<%= form_for $action, name => 'gwquiz', method => 'POST', class => 'problem-main-form', begin =%>
389+
<%= form_for $action, name => 'gwquiz', method => 'POST', class => 'problem-main-form mt-0', begin =%>
409390
<%= $c->hidden_authen_fields =%>
410391
%
411392
% # Hacks to use a javascript link to trigger previews and jump to subsequent pages of a multipage test.
@@ -603,11 +584,21 @@
603584
</div>
604585
% }
605586
%
606-
<div class="problem-content col-lg-10" <%== get_problem_lang_and_dir(
607-
$pg->{flags}, $ce->{perProblemLangAndDirSettingMode}, $ce->{language}
608-
) %>>
609-
<%== $pg->{body_text} =%>
610-
</div>
587+
% # If there were translation errors, then show those instead of the problem.
588+
% if ($pg->{flags}{error_flag}) {
589+
% stash->{briefErrorOutput} = 1;
590+
<%= include 'ContentGenerator/Base/error_output',
591+
error => $pg->{errors},
592+
details => $pg->{body_text} =%>
593+
%
594+
% delete stash->{briefErrorOutput};
595+
% } else {
596+
<div class="problem-content col-lg-10" <%== get_problem_lang_and_dir(
597+
$pg->{flags}, $ce->{perProblemLangAndDirSettingMode}, $ce->{language}
598+
) %>>
599+
<%== $pg->{body_text} =%>
600+
</div>
601+
% }
611602
% if ($pg->{result}{msg}) {
612603
<div class="mb-2"><b><%== maketext('Note: [_1]', tag('i', $pg->{result}{msg})) %></b></div>
613604
% }
@@ -651,7 +642,7 @@
651642
% }
652643
%
653644
% # Initialize the problem graders for the problem.
654-
% if ($c->{will}{showProblemGrader}) {
645+
% if ($c->{will}{showProblemGrader} && !$pg->{flags}{error_flag}) {
655646
<%= WeBWorK::HTML::SingleProblemGrader->new($c, $pg, $problems->[ $probOrder->[$i] ])
656647
->insertGrader =%>
657648
% }
@@ -785,5 +776,5 @@
785776
% # If achievements enabled, check to see if there are new ones and output them. Use the first
786777
% # problem to seed the data. However, all of the problems will be provided to the achievement evaluator.
787778
% if ($ce->{achievementsEnabled} && $c->{will}{recordAnswers} && $c->{submitAnswers} && $setID ne 'Undefined_Set') {
788-
<%= checkForAchievements($problems->[0], $pg_results->[0], $c, setVersion => $setVersionID) =%>
779+
<%= checkForAchievements($problems->[0], $c, setVersion => $setVersionID) =%>
789780
% }

0 commit comments

Comments
 (0)