--- loncom/homework/grades.pm 2010/05/03 10:51:22 1.634
+++ loncom/homework/grades.pm 2017/12/21 23:20:48 1.747
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.634 2010/05/03 10:51:22 foxr Exp $
+# $Id: grades.pm,v 1.747 2017/12/21 23:20:48 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -40,10 +40,12 @@ 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::lonstathelpers;
+use Apache::lonquickgrades;
+use Apache::bridgetask();
use String::Similarity;
use LONCAPA;
@@ -52,6 +54,7 @@ use POSIX qw(floor);
my %perm=();
+my %old_essays=();
# These variables are used to recover from ssi errors
@@ -113,7 +116,11 @@ sub getpartlist {
my $res = $navmap->getBySymb($symb);
my $partlist = $res->parts();
my $url = $res->src();
- my @metakeys = split(/,/,&Apache::lonnet::metadata($url,'keys'));
+ my $toolsymb;
+ if ($url =~ /ext\.tool$/) {
+ $toolsymb = $symb;
+ }
+ my @metakeys = split(/,/,&Apache::lonnet::metadata($url,'keys',$toolsymb));
my @stores;
foreach my $part (@{ $partlist }) {
@@ -200,6 +207,7 @@ sub get_display_part {
sub reset_caches {
&reset_analyze_cache();
&reset_perm();
+ &reset_old_essays();
}
{
@@ -212,8 +220,13 @@ sub reset_caches {
}
sub get_analyze {
- my ($symb,$uname,$udom,$no_increment,$add_to_hash)=@_;
+ my ($symb,$uname,$udom,$no_increment,$add_to_hash,$type,$trial,$rndseed,$bubbles_per_row)=@_;
my $key = "$symb\0$uname\0$udom";
+ if ($type eq 'randomizetry') {
+ if ($trial ne '') {
+ $key .= "\0".$trial;
+ }
+ }
if (exists($analyze_cache{$key})) {
my $getupdate = 0;
if (ref($add_to_hash) eq 'HASH') {
@@ -241,9 +254,18 @@ sub reset_caches {
'grade_courseid' => $env{'request.course.id'},
'grade_username' => $uname,
'grade_noincrement' => $no_increment);
+ if ($bubbles_per_row ne '') {
+ $form{'bubbles_per_row'} = $bubbles_per_row;
+ }
+ if ($type eq 'randomizetry') {
+ $form{'grade_questiontype'} = $type;
+ if ($rndseed ne '') {
+ $form{'grade_rndseed'} = $rndseed;
+ }
+ }
if (ref($add_to_hash)) {
%form = (%form,%{$add_to_hash});
- }
+ }
my $subresult=&ssi_with_retries($url, $ssi_retries,%form);
(undef,$subresult)=split(/_HASH_REF__/,$subresult,2);
my %analyze=&Apache::lonnet::str2hash($subresult);
@@ -256,15 +278,15 @@ sub reset_caches {
}
sub get_order {
- my ($partid,$respid,$symb,$uname,$udom,$no_increment)=@_;
- my $analyze = &get_analyze($symb,$uname,$udom,$no_increment);
+ my ($partid,$respid,$symb,$uname,$udom,$no_increment,$type,$trial,$rndseed)=@_;
+ my $analyze = &get_analyze($symb,$uname,$udom,$no_increment,undef,$type,$trial,$rndseed);
return $analyze->{"$partid.$respid.shown"};
}
sub get_radiobutton_correct_foil {
- my ($partid,$respid,$symb,$uname,$udom)=@_;
- my $analyze = &get_analyze($symb,$uname,$udom);
- my $foils = &get_order($partid,$respid,$symb,$uname,$udom);
+ my ($partid,$respid,$symb,$uname,$udom,$type,$trial,$rndseed)=@_;
+ my $analyze = &get_analyze($symb,$uname,$udom,undef,undef,$type,$trial,$rndseed);
+ my $foils = &get_order($partid,$respid,$symb,$uname,$udom,undef,$type,$trial,$rndseed);
if (ref($foils) eq 'ARRAY') {
foreach my $foil (@{$foils}) {
if ($analyze->{"$partid.$respid.foil.value.$foil"} eq 'true') {
@@ -275,7 +297,7 @@ sub reset_caches {
}
sub scantron_partids_tograde {
- my ($resource,$cid,$uname,$udom,$check_for_randomlist) = @_;
+ my ($resource,$cid,$uname,$udom,$check_for_randomlist,$bubbles_per_row,$scancode) = @_;
my (%analysis,@parts);
if (ref($resource)) {
my $symb = $resource->symb();
@@ -283,7 +305,16 @@ sub reset_caches {
if ($check_for_randomlist) {
$add_to_form = { 'check_parts_withrandomlist' => 1,};
}
- my $analyze = &get_analyze($symb,$uname,$udom,undef,$add_to_form);
+ if ($scancode) {
+ if (ref($add_to_form) eq 'HASH') {
+ $add_to_form->{'code_for_randomlist'} = $scancode;
+ } else {
+ $add_to_form = { 'code_for_randomlist' => $scancode,};
+ }
+ }
+ my $analyze =
+ &get_analyze($symb,$uname,$udom,undef,$add_to_form,
+ undef,undef,undef,$bubbles_per_row);
if (ref($analyze) eq 'HASH') {
%analysis = %{$analyze};
}
@@ -306,10 +337,12 @@ sub reset_caches {
# response types only.
sub cleanRecord {
my ($answer,$response,$symb,$partid,$respid,$record,$order,$version,
- $uname,$udom) = @_;
+ $uname,$udom,$type,$trial,$rndseed) = @_;
my $grayFont = '';
if ($response =~ /^(option|rank)$/) {
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 ($toprow,$bottomrow);
foreach my $foil (@$order) {
@@ -323,9 +356,11 @@ sub cleanRecord {
return '
';
+ $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);
@@ -345,12 +380,14 @@ sub cleanRecord {
''.
'
'.
''.&mt('Answer').' '.$toprow.' '.''.$grayFont.&mt('Option ID').' '.
- $grayFont.$bottomrow.' '.
''.$grayFont.&mt('Item ID').' '.
$middlerow.' '.'';
+ $bottomrow.'';
} elsif ($response eq 'radiobutton') {
my %answer=&Apache::lonnet::str2hash($answer);
+ my @answer = %answer;
+ %answer = map {&HTML::Entities::encode($_, '"<>&')} @answer;
my ($toprow,$bottomrow);
my $correct =
- &get_radiobutton_correct_foil($partid,$respid,$symb,$uname,$udom);
+ &get_radiobutton_correct_foil($partid,$respid,$symb,$uname,$udom,$type,$trial,$rndseed);
foreach my $foil (@$order) {
if (exists($answer{$foil})) {
if ($foil eq $correct) {
@@ -366,7 +403,7 @@ sub cleanRecord {
return ''.$grayFont.&mt('Option ID').' '.
- $bottomrow.'
';
+ $bottomrow.'';
} elsif ($response eq 'essay') {
if (! exists ($env{'form.'.$symb})) {
my (%keyhash) = &Apache::lonnet::dump('nohist_handgrade',
@@ -380,10 +417,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').' '.
- $bottomrow.'
-g;
return ''.&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;
@@ -417,12 +455,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
@@ -663,7 +703,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
@@ -680,11 +724,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);
@@ -694,7 +738,7 @@ sub most_similar {
$sname=$tname;
$sdom=$tdom;
$scrsid=$tcrsid;
- $sessay=$old_essays->{$tkey};
+ $sessay=$old_essays{$symb}{$tkey};
}
}
if ($limit>0.6) {
@@ -712,7 +756,7 @@ sub most_similar {
sub initialverifyreceipt {
my ($request,$symb) = @_;
&commonJSfunctions($request);
- return ''."\n".
''.
''."\n".
+ $optiontext{'last'}.' '."\n".
''.
''."\n".
+ $optiontext{'datesub'}.''."\n".
''.
'';
- $gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('Submissions'))
+ $optiontext{'all'}.'';
+ my $viewtitle;
+ if ($is_tool) {
+ $viewtitle = &mt('View Transactions');
+ } else {
+ $viewtitle = &mt('View Submissions');
+ }
+ $gradeTable .= &Apache::lonhtmlcommon::row_title($viewtitle)
.$submission_options
.&Apache::lonhtmlcommon::row_closure();
+ my $closure;
+ if (($is_tool) && (exists($env{'form.Status'}))) {
+ $closure = 1;
+ }
$gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('Grading Increments'))
.''
- .&Apache::lonhtmlcommon::row_closure();
+ .&Apache::lonhtmlcommon::row_closure($closure);
$gradeTable .=
&build_section_inputs().
@@ -916,19 +990,30 @@ LISTJAVASCRIPT
if (exists($env{'form.Status'})) {
$gradeTable .= ''."\n";
} else {
+ if ($is_tool) {
+ $closure = 1;
+ }
$gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('Student Status'))
.&Apache::lonhtmlcommon::StatusOptions(
$saveStatus,undef,1,'javascript:reLoadList(this.form);')
- .&Apache::lonhtmlcommon::row_closure();
+ .&Apache::lonhtmlcommon::row_closure($closure);
}
- $gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('Check For Plagiarism'))
- .''
- .&Apache::lonhtmlcommon::row_closure(1)
- .&Apache::lonhtmlcommon::end_pick_box();
-
+ unless ($is_tool) {
+ $closure = 1;
+ $gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('Check For Plagiarism'))
+ .''
+ .&Apache::lonhtmlcommon::row_closure($closure);
+ }
+ $gradeTable .= &Apache::lonhtmlcommon::end_pick_box();
+ my $regrademsg;
+ if ($is_tool) {
+ $regrademsg =&mt("To view/grade/regrade, click on the check box(es) next to the student's name(s). Then click on the Next button.");
+ } else {
+ $regrademsg = &mt("To view/grade/regrade a submission or a group of submissions, click on the check box(es) next to the student's name(s). Then click on the Next button.");
+ }
$gradeTable .= '
' - .&mt("To view/grade/regrade a submission or a group of submissions, click on the check box(es) next to the student's name(s). Then click on the Next button.")."\n" + .$regrademsg."\n" .'' .'
'; @@ -1060,7 +1145,7 @@ LISTJAVASCRIPT if ($submitonly eq 'graded' ) { $submissions = 'ungraded submissions'; } if ($submitonly eq 'queued' ) { $submissions = 'queued submissions'; } $gradeTable='