--- loncom/homework/grades.pm 2008/02/06 00:39:11 1.509
+++ loncom/homework/grades.pm 2019/02/23 15:50:44 1.596.2.12.2.47
@@ -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.596.2.12.2.47 2019/02/23 15:50:44 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -26,6 +26,8 @@
# http://www.lon-capa.org/
#
+
+
package Apache::grades;
use strict;
use Apache::style;
@@ -38,23 +40,77 @@ use Apache::lonhomework;
use Apache::lonpickcode;
use Apache::loncoursedata;
use Apache::lonmsg();
-use Apache::Constants qw(:common);
+use Apache::Constants qw(:common :http);
use Apache::lonlocal;
use Apache::lonenc;
+use Apache::bridgetask();
+use Apache::lontexconvert();
+use HTML::Parser();
+use File::MMagic;
use String::Similarity;
use LONCAPA;
use POSIX qw(floor);
+
my %perm=();
+my %old_essays=();
+
+# These variables are used to recover from ssi errors
+
+my $ssi_retries = 5;
+my $ssi_error;
+my $ssi_error_resource;
+my $ssi_error_message;
+
+
+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) = @_;
+ my $helpurl = &Apache::loncommon::top_nav_help('Helpdesk');
+ $r->print('
+
+
+'.&mt('Unable to retrieve a resource from a server:').'
+'.&mt('Resource:').' '.$ssi_error_resource.'
+'.&mt('Error:').' '.$ssi_error_message.'
+
'.
+&mt('It is recommended that you try again later, as this error may mean the server was just temporarily unavailable, or is down for maintenance.').'
'.
+&mt('If the error persists, please contact the [_1] for assistance.',$helpurl).
+'
'; + } + $result.=' | '.&mt('Problem Part').' | ' + .''.&mt('Res. ID').' | ' + .''.&mt('Type').' | ' + .&Apache::loncommon::end_data_table_header_row(); my %resptype = (); my $hdgrade='no'; my %partsseen; - foreach my $partID (sort keys(%$responseType)) { - foreach my $resID (sort keys(%{ $responseType->{$partID} })) { - my $handgrade=$$handgrade{$partID.'_'.$resID}; - my $responsetype = $responseType->{$partID}->{$resID}; - $hdgrade = $handgrade if ($handgrade eq 'yes'); - $result.='
---|---|---|---|
"; - } else { - $result.=" | "; - } - $partsseen{$partID}=1; - } - my $display_part=&get_display_part($partID,$symb); - $result.=' | '.&mt('Part: [_1]',$display_part).' '. - $resID.' | '. - ''.&mt('Type: [_1]',$responsetype).' | '.&mt('Handgrade: [_1]',$handgrade).' | '; - } + foreach my $partID (sort(keys(%$responseType))) { + foreach my $resID (sort(keys(%{ $responseType->{$partID} }))) { + my $handgrade=$$handgrade{$partID.'_'.$resID}; + my $responsetype = $responseType->{$partID}->{$resID}; + $hdgrade = $handgrade if ($handgrade eq 'yes'); + $result.=&Apache::loncommon::start_data_table_row(); + if ($checkboxes) { + if (exists($partsseen{$partID})) { + $result.=""; + } else { + $result.=" | "; + } + $partsseen{$partID}=1; + } + my $display_part=&get_display_part($partID,$symb); + $result.=' | '.$display_part.' | ' + .''.''.$resID.' | ' + .''.&mt($responsetype).' | ' +# .''.&mt('Handgrade: [_1]',$handgrade).' | ' + .&Apache::loncommon::end_data_table_row(); + } } - $result.='
'; + $bottomrow.''; } elsif ($response eq 'match') { my %answer=&Apache::lonnet::str2hash($answer); + my @answer = %answer; + %answer = map {&HTML::Entities::encode($_, '"<>&')} @answer; my %grading=&Apache::lonnet::str2hash($record->{$version."resource.$partid.$respid.submissiongrading"}); my @items=&Apache::lonnet::str2array($record->{$version."resource.$partid.$respid.submissionitems"}); my ($toprow,$middlerow,$bottomrow); @@ -274,12 +440,12 @@ sub cleanRecord { ''. '
'. ' '.&mt('Answer').' '.$toprow.''.' '.$grayFont.&mt('Option ID').' '. - $grayFont.$bottomrow.'
'; + $bottomrow.''; } elsif ($response eq 'essay') { if (! exists ($env{'form.'.$symb})) { my (%keyhash) = &Apache::lonnet::dump('nohist_handgrade', @@ -309,10 +475,11 @@ sub cleanRecord { $env{'form.kwstyle'} = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : ''; $env{'form.'.$symb} = 1; # so that we don't have to read it from disk for multiple sub of the same prob. } - $answer =~ s-\n-'. '
'. ' '.&mt('Answer').' '.$toprow.''.' '.$grayFont.&mt('Option ID').' '. - $grayFont.$bottomrow.'
'.&keywords_highlight($answer).''; } elsif ( $response eq 'organic') { - my $result='Smile representation: "'.$answer.'"'; + my $result=&mt('Smile representation: [_1]', + '"'.&HTML::Entities::encode($answer, '"<>&').'"'); my $jme=$record->{$version."resource.$partid.$respid.molecule"}; $result.=&Apache::chemresponse::jme_img($jme,$answer,400); return $result; @@ -346,12 +513,14 @@ sub cleanRecord { $result.=''; return $result; } - } elsif ( $response =~ m/(?:numerical|formula)/) { + } elsif ( $response =~ m/(?:numerical|formula|custom)/) { + # Respect multiple input fields, see Bug #5409 $answer = &Apache::loncommon::format_previous_attempt_value('submission', $answer); + return $answer; } - return $answer; + return &HTML::Entities::encode($answer, '"<>&'); } #-- A couple of common js functions @@ -596,7 +765,11 @@ sub compute_points { # sub most_similar { - my ($uname,$udom,$uessay,$old_essays)=@_; + my ($uname,$udom,$symb,$uessay)=@_; + + unless ($symb) { return ''; } + + unless (ref($old_essays{$symb}) eq 'HASH') { return ''; } # ignore spaces and punctuation @@ -604,7 +777,7 @@ sub most_similar { # ignore empty submissions (occuring when only files are sent) - unless ($uessay=~/\w+/) { return ''; } + unless ($uessay=~/\w+/s) { return ''; } # these will be returned. Do not care if not at least 50 percent similar my $limit=0.6; @@ -613,11 +786,11 @@ sub most_similar { my $scrsid=''; my $sessay=''; # go through all essays ... - foreach my $tkey (keys(%$old_essays)) { + foreach my $tkey (keys(%{$old_essays{$symb}})) { my ($tname,$tdom,$tcrsid)=map {&unescape($_)} (split(/\./,$tkey)); # ... except the same student next if (($tname eq $uname) && ($tdom eq $udom)); - my $tessay=$old_essays->{$tkey}; + my $tessay=$old_essays{$symb}{$tkey}; $tessay=~s/\W+/ /gs; # String similarity gives up if not even limit my $tsimilar=&String::Similarity::similarity($uessay,$tessay,$limit); @@ -627,7 +800,7 @@ sub most_similar { $sname=$tname; $sdom=$tdom; $scrsid=$tcrsid; - $sessay=$old_essays->{$tkey}; + $sessay=$old_essays{$symb}{$tkey}; } } if ($limit>0.6) { @@ -653,9 +826,9 @@ sub verifyreceipt { my $title.= '
' + .&mt('No match found for the above receipt number.') + .'
'; } else { $string = &jscriptNform($symb).$title. ''. - &mt('The above receipt matches the following [numerate,_1,student].',$matches). + &mt('The above receipt number matches the following [quant,_1,student].',$matches). '
'. $header. $contents. @@ -737,18 +919,17 @@ sub listStudents { $env{'form.probTitle'} = $env{'form.probTitle'} eq '' ? &Apache::lonnet::gettitle($symb) : $env{'form.probTitle'}; - my $result='