--- loncom/homework/grades.pm 2008/02/06 00:39:11 1.509
+++ loncom/homework/grades.pm 2008/03/04 11:23:12 1.513
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.509 2008/02/06 00:39:11 raeburn Exp $
+# $Id: grades.pm,v 1.513 2008/03/04 11:23:12 foxr Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -47,8 +47,82 @@ use LONCAPA;
use POSIX qw(floor);
+
my %perm=();
+# These variables are used to recover from ssi errors
+
+my $ssi_retries = 5;
+my $ssi_error;
+my $ssi_error_resource;
+my $ssi_error_message;
+
+
+# Do an ssi with retries:
+# While I'd love to factor out this with the vesrion in lonprintout,
+# that would either require a data coupling between modules, which I refuse to perpetuate
+# (there's quite enough of that already), or would require the invention of another infrastructure
+# I'm not quite ready to invent (e.g. an ssi_with_retry object).
+#
+# At least the logic that drives this has been pulled out into loncommon.
+
+
+#
+# ssi_with_retries - Does the server side include of a resource.
+# if the ssi call returns an error we'll retry it up to
+# the number of times requested by the caller.
+# If we still have a proble, no text is appended to the
+# output and we set some global variables.
+# to indicate to the caller an SSI error occured.
+# All of this is supposed to deal with the issues described
+# in LonCAPA BZ 5631 see:
+# http://bugs.lon-capa.org/show_bug.cgi?id=5631
+# by informing the user that this happened.
+#
+# Parameters:
+# resource - The resource to include. This is passed directly, without
+# interpretation to lonnet::ssi.
+# form - The form hash parameters that guide the interpretation of the resource
+#
+# retries - Number of retries allowed before giving up completely.
+# Returns:
+# On success, returns the rendered resource identified by the resource parameter.
+# Side Effects:
+# The following global variables can be set:
+# ssi_error - If an unrecoverable error occured this becomes true.
+# It is up to the caller to initialize this to false
+# if desired.
+# ssi_last_error_resource - If an unrecoverable error occured, this is the value
+# of the resource that could not be rendered by the ssi
+# call.
+# ssi_last_error - The error string fetched from the ssi response
+# in the event of an error.
+#
+sub ssi_with_retries {
+ my ($resource, $retries, %form) = @_;
+ my ($content, $response) = &Apache::loncommon::ssi_with_retries($resource, $retries, %form);
+ if ($response->is_error) {
+ $ssi_error = 1;
+ $ssi_error_resource = $resource;
+ $ssi_error_message = $response->code . " " . $response->message;
+ }
+
+ return $content;
+
+}
+#
+# Prodcuces an ssi retry failure error message to the user:
+#
+
+sub ssi_print_error {
+ my ($r) = @_;
+ $r->print('
Unrecoverable network error
');
+ $r->print('
Unable to perform a resource fetch from a server: ');
+ $r->print("Resource: $ssi_error_resource ");
+ $r->print("Error: $ssi_error_message Try again later.");
+ $r->print('If errors persist, contact LonCAPA support for assistance
');
+}
+
#
# --- Retrieve the parts from the metadata file.---
sub getpartlist {
@@ -201,7 +275,7 @@ sub reset_caches {
my (undef,undef,$url)=&Apache::lonnet::decode_symb($symb);
$url=&Apache::lonnet::clutter($url);
- my $subresult=&Apache::lonnet::ssi($url,
+ my $subresult=&ssi_with_retries($url, $ssi_retries,
('grade_target' => 'analyze'),
('grade_domain' => $udom),
('grade_symb' => $symb),
@@ -4881,6 +4955,8 @@ sub scantron_selectphase {
my $CODE_unique=&scantron_CODEunique();
my $result;
+ $ssi_error = 0;
+
# Chunk of form to prompt for a file to grade and how:
$result.= '
@@ -5458,7 +5534,10 @@ sub scantron_validator_lettnum {
my $occurrences = 0;
if (($responsetype_per_response{$questnum-1} eq 'essayresponse') ||
($responsetype_per_response{$questnum-1} eq 'formularesponse') ||
- ($responsetype_per_response{$questnum-1} eq 'stringresponse')) {
+ ($responsetype_per_response{$questnum-1} eq 'stringresponse') ||
+ ($responsetype_per_response{$questnum-1} eq 'imageresponse') ||
+ ($responsetype_per_response{$questnum-1} eq 'reactionresponse') ||
+ ($responsetype_per_response{$questnum-1} eq 'organicresponse')) {
my @singlelines = split('',$currquest);
foreach my $entry (@singlelines) {
$occurrences = &occurence_count($entry,$matchon);
@@ -5557,7 +5636,10 @@ sub scantron_validator_positional {
#
if (($responsetype_per_response{$questnum-1} eq 'essayresponse') ||
($responsetype_per_response{$questnum-1} eq 'formularesponse') ||
- ($responsetype_per_response{$questnum-1} eq 'stringresponse')) {
+ ($responsetype_per_response{$questnum-1} eq 'stringresponse') ||
+ ($responsetype_per_response{$questnum-1} eq 'imageresponse') ||
+ ($responsetype_per_response{$questnum-1} eq 'reactionresponse') ||
+ ($responsetype_per_response{$questnum-1} eq 'organicresponse')) {
my $doubleerror = 0;
while (($currquest >= $$scantron_config{'Qlength'}) &&
(!$doubleerror)) {
@@ -6031,8 +6113,7 @@ sub scantron_validate_file {
}
if (!$stop) {
my $warning=&scantron_warning_screen('Start Grading');
- $r->print('
-'.&mt('Validation process complete.').'
+ $r->print(&mt('Validation process complete.').'
'.$warning.'
@@ -6798,8 +6879,9 @@ for multi and missing bubble cases).
in exam mode. This hash contains a
comma-separated list of the lines per
sub-question.
- %responsetype_per_response - essayresponse, forumalaresponse, and
- stringresponse type problem parts can have
+ %responsetype_per_response - essayresponse, formularesponse,
+ stringresponse, imageresponse, reactionresponse,
+ and organicresponse type problem parts can have
multiple lines per response if the weight
assigned exceeds 10. In this case, only
one bubble per line is permitted, but more
@@ -6833,7 +6915,10 @@ sub prompt_for_corrections {
$r->print(&mt('The group of bubble lines below responds to a single question.').' ');
if (($responsetype_per_response{$question-1} eq 'essayresponse') ||
($responsetype_per_response{$question-1} eq 'formularesponse') ||
- ($responsetype_per_response{$question-1} eq 'stringresponse')) {
+ ($responsetype_per_response{$question-1} eq 'stringresponse') ||
+ ($responsetype_per_response{$question-1} eq 'imageresponse') ||
+ ($responsetype_per_response{$question-1} eq 'reactionresponse') ||
+ ($responsetype_per_response{$question-1} eq 'organicresponse')) {
$r->print(&mt("Although this particular question type requires handgrading, the instructions for this question in the exam directed students to leave [quant,_1,line] blank on their scantron sheets.",$lines).'
'.&mt('A non-zero score can be assigned to the student during scantron grading by selecting a bubble in at least one line.').' '.&mt('The score for this question will be a sum of the numeric values for the selected bubbles from each line, where A=1 point, B=2 points etc.').' '.&mt("To assign a score of zero for this question, mark all lines as 'No bubble'.").'
');
} else {
$r->print(&mt("Select at most one bubble in a single line and select 'No Bubble' in all the other lines. ")." ");
@@ -7146,8 +7231,9 @@ sub scantron_get_maxbubble {
my $response_number = 0;
my $bubble_line = 0;
foreach my $resource (@resources) {
- # Need to retrieve part IDs and response IDs because essayresponse
- # items are not included in $analysis{'parts'} from lonnet::ssi.
+ # Need to retrieve part IDs and response IDs because essayresponse,
+ # reactionresponse and organicresponse items are not included in
+ # $analysis{'parts'} from lonnet::ssi.
my %possible_part_ids;
if (ref($resource->parts()) eq 'ARRAY') {
foreach my $part (@{$resource->parts()}) {
@@ -7157,7 +7243,7 @@ sub scantron_get_maxbubble {
}
}
}
- my $result=&Apache::lonnet::ssi($resource->src(),
+ my $result=&ssi_with_retries($resource->src(), $ssi_retries,
('symb' => $resource->symb()),
('grade_target' => 'analyze'),
('grade_courseid' => $cid),
@@ -7175,7 +7261,9 @@ sub scantron_get_maxbubble {
}
# Add part_ids for any essayresponse items.
foreach my $part_id (keys(%possible_part_ids)) {
- if ($analysis{$part_id.'.type'} eq 'essayresponse') {
+ if (($analysis{$part_id.'.type'} eq 'essayresponse') ||
+ ($analysis{$part_id.'.type'} eq 'reactionresponse') ||
+ ($analysis{$part_id.'.type'} eq 'organicresponse')) {
if (!grep(/^\Q$part_id\E$/,@parts)) {
push (@parts,$part_id);
}
@@ -7329,9 +7417,12 @@ sub scantron_validate_missingbubbles {
sub scantron_process_students {
my ($r) = @_;
+
my (undef,undef,$sequence)=&Apache::lonnet::decode_symb($env{'form.selectpage'});
my ($symb)=&get_symb($r);
- if (!$symb) {return '';}
+ if (!$symb) {
+ return '';
+ }
my $default_form_data=&defaultFormData($symb);
my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
@@ -7363,6 +7454,17 @@ SCANTRONFORM
my ($uname,$udom,$started);
&scantron_get_maxbubble(); # Need the bubble lines array to parse.
+
+
+ # If an ssi failed in scantron_get_maxbubble, put an error message out to
+ # the user and return.
+
+ if ($ssi_error) {
+ $r->print("");
+ &ssi_print_error($r);
+ $r->print(&show_grading_menu_form($symb));
+ return ''; # Dunno why the other returns return '' rather than just returning.
+ }
while ($i<$scanlines->{'count'}) {
($uname,$udom)=('','');
@@ -7411,10 +7513,16 @@ SCANTRONFORM
$form{'CODE'}=$scan_record->{'scantron.CODE'};
} else {
$form{'CODE'}='';
+ }
+ my $result=&ssi_with_retries($resource->src(), $ssi_retries, %form);
+ if ($ssi_error) {
+ $ssi_error = 0; # So end of handler error message does not trigger.
+ $r->print("");
+ &ssi_print_error($r);
+ $r->print(&show_grading_menu_form($symb));
+ return ''; # Why return ''? Beats me.
}
- my $result=&Apache::lonnet::ssi($resource->src(),%form);
- if ($result ne '') {
- }
+
if (&Apache::loncommon::connection_aborted($r)) { last; }
}
$completedstudents{$uname}={'line'=>$line};
@@ -7716,14 +7824,12 @@ sub grading_menu {
$menudata->{'url'}.'" >'.
$menudata->{'name'}."\n";
} else {
- $Str .='