--- loncom/homework/grades.pm 2003/10/21 21:46:15 1.144
+++ loncom/homework/grades.pm 2003/11/07 18:05:33 1.149
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.144 2003/10/21 21:46:15 albertel Exp $
+# $Id: grades.pm,v 1.149 2003/11/07 18:05:33 albertel Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -55,17 +55,35 @@ my %perm=();
# ----- These first few routines are general use routines.----
#
-# --- Retrieve the parts that matches stores_\d+ from the metadata file.---
+# --- Retrieve the parts from the metadata file.---
sub getpartlist {
- my ($url) = @_;
- my @parts =();
- my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));
- foreach my $key (@metakeys) {
- if ( $key =~ m/stores_(\w+)_.*/) {
- push(@parts,$key);
+ my ($url,$symb) = @_;
+ my $partorder = &Apache::lonnet::metadata($url, 'partorder');
+ my @parts;
+ if ($partorder) {
+ for my $part (split (/,/,$partorder)) {
+ if (!&Apache::loncommon::check_if_partid_hidden($part,$symb)) {
+ push(@parts, $part);
+ }
+ }
+ } else {
+ my $metadata = &Apache::lonnet::metadata($url, 'packages');
+ foreach (split(/\,/,$metadata)) {
+ if ($_ =~ /^part_(.*)$/) {
+ if (!&Apache::loncommon::check_if_partid_hidden($1,$symb)) {
+ push(@parts, $1);
+ }
+ }
}
}
- return @parts;
+ my @stores;
+ foreach my $part (@parts) {
+ my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));
+ foreach my $key (@metakeys) {
+ if ($key =~ m/^stores_\Q$part\E_/) { push(@stores,$key); }
+ }
+ }
+ return @stores;
}
# --- Get the symbolic name of a problem and the url
@@ -115,20 +133,25 @@ sub response_type {
$symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url))) if ($symb eq '');
my $allkeys = &Apache::lonnet::metadata($url,'keys');
my %seen = ();
- my (@partlist,%handgrade);
+ my (@partlist,%handgrade,%responseType);
foreach (split(/,/,&Apache::lonnet::metadata($url,'packages'))) {
- if (/^\w+response_\w+.*/) {
+ if (/^\w+response_.*/) {
my ($responsetype,$part) = split(/_/,$_,2);
my ($partid,$respid) = split(/_/,$part);
+ if (&Apache::loncommon::check_if_partid_hidden($partid,$symb)) {
+ next;
+ }
$responsetype =~ s/response$//; # make it compatible w/ navmaps - should move to that!!
my ($value) = &Apache::lonnet::EXT('resource.'.$part.'.handgrade',$symb);
- $handgrade{$part} = $responsetype.':'.($value eq 'yes' ? 'yes' : 'no');
+ $handgrade{$part} = ($value eq 'yes' ? 'yes' : 'no');
+ if (!exists($responseType{$partid})) { $responseType{$partid}={}; }
+ $responseType{$partid}->{$respid}=$responsetype;
next if ($seen{$partid} > 0);
$seen{$partid}++;
push @partlist,$partid;
}
}
- return \@partlist,\%handgrade;
+ return \@partlist,\%handgrade,\%responseType;
}
#--- Show resource title
@@ -137,42 +160,104 @@ sub showResourceInfo {
my ($url,$probTitle) = @_;
my $result ='
'.
'
Current Resource: '.$probTitle.'
'."\n";
- my ($partlist,$handgrade) = &response_type($url);
+ my ($partlist,$handgrade,$responseType) = &response_type($url);
my %resptype = ();
my $hdgrade='no';
- for (sort keys(%$handgrade)) {
- my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
- my $partID = (split(/_/))[0];
- $resptype{$partID} = $responsetype;
+ for my $part_resID (sort keys(%$handgrade)) {
+ my $handgrade=$$handgrade{$part_resID};
+ my ($partID,$resID) = split(/_/,$part_resID);
+ my $responsetype = $responseType->{$partID}->{$resID};
$hdgrade = $handgrade if ($handgrade eq 'yes');
- $result.='
Part '.$partID.'
'.
+ $result.='
Part '.$partID.' '.
+ $resID.'
'.
'
Type: '.$responsetype.'
';
# '
Handgrade: '.$handgrade.'
';
}
$result.='
'."\n";
- return $result,\%resptype,$hdgrade,$partlist,$handgrade;
+ return $result,$responseType,$hdgrade,$partlist,$handgrade;
}
+
+sub get_order {
+ my ($partid,$respid,$symb,$uname,$udom)=@_;
+ my (undef,undef,$url)=&Apache::lonnet::decode_symb($symb);
+ $url=&Apache::lonnet::clutter($url);
+ my $subresult=&Apache::lonnet::ssi($url,
+ ('grade_target' => 'analyze'),
+ ('grade_domain' => $udom),
+ ('grade_symb' => $symb),
+ ('grade_courseid' =>
+ $ENV{'request.course.id'}),
+ ('grade_username' => $uname));
+ (undef,$subresult)=split(/_HASH_REF__/,$subresult,2);
+ my %analyze=&Apache::lonnet::str2hash($subresult);
+ return ($analyze{"$partid.$respid.shown"});
+}
#--- Clean response type for display
-#--- Currently filters option response type only.
+#--- Currently filters option/rank/radiobutton/match/essay response types only.
sub cleanRecord {
- my ($answer,$response,$symb) = @_;
- if ($response eq 'option') {
- my (@IDs,@ans);
- foreach (split(/\&/,&Apache::lonnet::unescape($answer))) {
- my ($optionID,$ans) = split(/=/);
- push @IDs,$optionID.'';
- push @ans,$ans;
+ my ($answer,$response,$symb,$partid,$respid,$record,$order,$version) = @_;
+ my $grayFont = '';
+ if ($response =~ /^(option|rank)$/) {
+ my %answer=&Apache::lonnet::str2hash($answer);
+ my %grading=&Apache::lonnet::str2hash($record->{$version."resource.$partid.$respid.submissiongrading"});
+ my ($toprow,$bottomrow);
+ foreach my $foil (@$order) {
+ if ($grading{$foil} == 1) {
+ $toprow.='
'.$answer{$foil}.'
';
+ } else {
+ $toprow.='
'.$answer{$foil}.'
';
+ }
+ $bottomrow.='
'.$grayFont.$foil.'
';
}
- my $grayFont = '';
return '
'.
- '
Answer
'.
- (join '
',@ans).'
'.
- '
'.$grayFont.'Option ID
'.$grayFont.
- (join '
'.$grayFont,@IDs).'
'.
- '
';
- }
- if ($response eq 'essay') {
+ '
Answer
'.$toprow.'
'.
+ '
'.$grayFont.'Option ID
'.
+ $grayFont.$bottomrow.'
'.'';
+ } elsif ($response eq 'match') {
+ my %answer=&Apache::lonnet::str2hash($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);
+ foreach my $foil (@$order) {
+ my $item=shift(@items);
+ if ($grading{$foil} == 1) {
+ $toprow.='
'.$item.'
';
+ $middlerow.='
'.$grayFont.$answer{$foil}.'
';
+ } else {
+ $toprow.='
'.$item.'
';
+ $middlerow.='
'.$grayFont.$answer{$foil}.'
';
+ }
+ $bottomrow.='
'.$grayFont.$foil.'
';
+ }
+ return '
'.
+ '
Answer
'.$toprow.'
'.
+ '
'.$grayFont.'Item ID
'.
+ $middlerow.'
'.
+ '
'.$grayFont.'Option ID
'.
+ $bottomrow.'
'.'
';
+ } elsif ($response eq 'radiobutton') {
+ my %answer=&Apache::lonnet::str2hash($answer);
+ my ($toprow,$bottomrow);
+ my $correct=($order->[0])+1;
+ for (my $i=1;$i<=$#$order;$i++) {
+ my $foil=$order->[$i];
+ if (exists($answer{$foil})) {
+ if ($i == $correct) {
+ $toprow.='
true
';
+ } else {
+ $toprow.='
true
';
+ }
+ } else {
+ $toprow.='
false
';
+ }
+ $bottomrow.='
'.$grayFont.$foil.'
';
+ }
+ return '
'.
+ '
Answer
'.$toprow.'
'.
+ '
'.$grayFont.'Option ID
'.
+ $grayFont.$bottomrow.'
'.'
';
+ } elsif ($response eq 'essay') {
if (! exists ($ENV{'form.'.$symb})) {
my (%keyhash) = &Apache::lonnet::dump('nohist_handgrade',
$ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
@@ -572,18 +657,21 @@ LISTJAVASCRIPT
my %status = ();
if ($ENV{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {
(%status) =&student_gradeStatus($url,$symb,$udom,$uname,$partlist);
- my $statusflg = '';
+ my $submitted = 0;
+ my $graded = 1;
foreach (keys(%status)) {
- $statusflg = 1 if ($status{$_} ne 'nothing');
+ $submitted = 1 if ($status{$_} ne 'nothing');
+ $graded = 0 if ($status{$_} =~ /^correct/);
my ($foo,$partid,$foo1) = split(/\./,$_);
if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
- $statusflg = '';
+ $submitted = 0;
$gradeTable.='';
}
}
- next if ($statusflg eq '' && $submitonly eq 'yes');
+ next if (!$submitted && ($submitonly eq 'yes' || $submitonly eq 'graded'));
+ next if (!$graded && $submitonly eq 'graded');
}
$ctr++;
@@ -625,7 +713,7 @@ LISTJAVASCRIPT
} else {
$gradeTable=' '.
'No submissions found for this resource for any students. ('.$num_students.
- ' checked for submissions ';
+ ' checked for submissions) ';
}
} elsif ($ctr == 1) {
$gradeTable =~ s/type=checkbox/type=checkbox checked/;
@@ -1397,7 +1485,7 @@ KEYWORDS
my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
- my ($partlist,$handgrade) = &response_type($url,$symb);
+ my ($partlist,$handgrade,$responseType) = &response_type($url,$symb);
# Display student info
$request->print(($counter == 0 ? '' : ' '));
@@ -1480,7 +1568,7 @@ KEYWORDS
$$fullname{$ENV{'form.'.$uname.':'.$udom.':submitted_by'}}.'';
$request->print($submitby);
} else {
- my ($string,$timestamp)= &get_last_submission (\%record);
+ my ($string,$timestamp)= &get_last_submission(\%record);
my $lastsubonly=''.
($$timestamp eq '' ? '' : 'Date Submitted: '.
$$timestamp)."\n";
@@ -1488,8 +1576,8 @@ KEYWORDS
$lastsubonly.='
'.$$string[0];
} else {
for my $part (sort keys(%$handgrade)) {
- my ($responsetype,$foo) = split(/:/,$$handgrade{$part});
my ($partid,$respid) = split(/_/,$part);
+ my $responsetype = $responseType->{$partid}->{$respid};
if (!exists($record{'resource.'.$partid.'.'.$respid.'.submission'})) {
$lastsubonly.='
Part '.
$partid.' ( ID '.$respid.
@@ -1497,7 +1585,7 @@ KEYWORDS
'Nothing submitted - no attempts
';
} else {
foreach (@$string) {
- my ($partid,$respid) = /^resource\.(\w+)\.(\w+)\.submission/;
+ my ($partid,$respid) = /^resource\.([^\.]*)\.([^\.]*)\.submission/;
if ($part eq ($partid.'_'.$respid)) {
my ($ressub,$subval) = split(/:/,$_,2);
# Similarity check
@@ -1517,6 +1605,7 @@ KEYWORDS
&keywords_highlight($oessay).'';
}
}
+ my $order=&get_order($partid,$respid,$symb,$uname,$udom);
$lastsubonly.='
Part '.
$partid.' ( ID '.$respid.
' ) '.
@@ -1527,11 +1616,11 @@ KEYWORDS
'Like all files provided by users, '.
'this file may contain virusses ':'').
'Submitted Answer: '.
- &cleanRecord($subval,$responsetype,$symb).
+ &cleanRecord($subval,$responsetype,$symb,$partid,$respid,\%record,$order).
'
'.$similar."\n"
if ($ENV{'form.lastSub'} eq 'lastonly' ||
($ENV{'form.lastSub'} eq 'hdgrade' &&
- $$handgrade{$part} =~ /:yes$/));
+ $$handgrade{$part} eq 'yes'));
}
}
}
@@ -1542,7 +1631,7 @@ KEYWORDS
}
} elsif ($ENV{'form.lastSub'} eq 'datesub') {
my (undef,$responseType,undef,$parts) = &showResourceInfo($url);
- $request->print(&displaySubByDates(\$symb,\%record,$parts,$responseType,$checkIcon));
+ $request->print(&displaySubByDates($symb,\%record,$parts,$responseType,$checkIcon,$uname,$udom));
} elsif ($ENV{'form.lastSub'} =~ /^(last|all)$/) {
$request->print(&Apache::loncommon::get_previous_attempt($symb,$uname,$udom,
$ENV{'request.course.id'},
@@ -1830,15 +1919,25 @@ sub processHandGrade {
}
$ctr = 0;
@parsedlist = reverse @parsedlist if ($button eq 'Previous');
+ my ($partlist) = &response_type($url);
foreach my $student (@parsedlist) {
+ my $submitonly=$ENV{'form.submitonly'};
my ($uname,$udom) = split(/:/,$student);
- if ($ENV{'form.submitonly'} eq 'yes') {
- my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
- my $statusflg = '';
- foreach (split(/:/,$ENV{'form.gradePartRespid'})){
- $statusflg = 1 if (exists ($record{'resource.'.$_.'.submission'}));
+ if ($submitonly =~ /^(yes|graded)$/) {
+# my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
+ my %status=&student_gradeStatus($url,$symb,$udom,$uname,$partlist);
+ my $submitted = 0;
+ my $graded = 1;
+ foreach (keys(%status)) {
+ $submitted = 1 if ($status{$_} ne 'nothing');
+ $graded = 0 if ($status{$_} =~ /^correct/);
+ my ($foo,$partid,$foo1) = split(/\./,$_);
+ if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
+ $submitted = 0;
+ }
}
- next if ($statusflg eq '');
+ next if (!$submitted && ($submitonly eq 'yes' || $submitonly eq 'graded'));
+ next if (!$graded && $submitonly eq 'graded');
}
push @nextlist,$student if ($ctr < $ntstu);
last if ($ctr == $ntstu);
@@ -2138,7 +2237,7 @@ sub viewgrades {
my ($partid,$respid) = split (/_/,$_,2);
next if $seen{$partid};
$seen{$partid}++;
- my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
+ my $handgrade=$$handgrade{$_};
my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb);
$weight{$partid} = $wgt eq '' ? '1' : $wgt;
@@ -2180,7 +2279,7 @@ sub viewgrades {
$result.= '
'."\n".
'
No.
'.
'
'.&nameUserString('header')."
\n";
- my (@parts) = sort(&getpartlist($url));
+ my (@parts) = sort(&getpartlist($url,$symb));
foreach my $part (@parts) {
my $display=&Apache::lonnet::metadata($url,$part.'.display');
$display =~ s|^Number of Attempts|Tries |; # makes the column narrower
@@ -2297,7 +2396,7 @@ sub editgrades {
my %columns = ();
my ($i,$ctr,$count,$rec_update) = (0,0,0,0);
- my (@parts) = sort(&getpartlist($url));
+ my (@parts) = sort(&getpartlist($url,$symb));
my $header;
while ($ctr < $ENV{'form.totalparts'}) {
my $partid = $ENV{'form.partid_'.$ctr};
@@ -2562,8 +2661,8 @@ ENDPICK
}
sub csvupload_fields {
- my ($url) = @_;
- my (@parts) = &getpartlist($url);
+ my ($url,$symb) = @_;
+ my (@parts) = &getpartlist($url,$symb);
my @fields=(['username','Student Username'],['domain','Student Domain']);
foreach my $part (sort(@parts)) {
my @datum;
@@ -2646,7 +2745,7 @@ sub csvuploadmap {
&csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);
my ($i,$keyfields);
if (@records) {
- my @fields=&csvupload_fields($url);
+ my @fields=&csvupload_fields($url,$symb);
if ($ENV{'form.upfile_associate'} eq 'reverse') {
&Apache::loncommon::csv_print_samples($request,\@records);
@@ -2957,9 +3056,16 @@ sub displayPage {
} else {
my %responseType = ();
foreach my $partid (@{$parts}) {
- $responseType{$partid} = $curRes->responseType($partid);
+ my @responseIds =$curRes->responseIds($partid);
+ my @responseType =$curRes->responseType($partid);
+ my %responseIds;
+ for (my $i=0;$i<=$#responseIds;$i++) {
+ $responseIds{$responseIds[$i]}=$responseType[$i];
+ }
+ $responseType{$partid} = \%responseIds;
}
- $studentTable.= &displaySubByDates(\$symbx,\%record,$parts,\%responseType,$checkIcon);
+ $studentTable.= &displaySubByDates($symbx,\%record,$parts,\%responseType,$checkIcon,$uname,$udom);
+
}
} elsif ($ENV{'form.lastSub'} eq 'all') {
my $last = ($ENV{'form.lastSub'} eq 'last' ? 'last' : '');
@@ -2994,7 +3100,7 @@ sub displayPage {
}
sub displaySubByDates {
- my ($symbx,$record,$parts,$responseType,$checkIcon) = @_;
+ my ($symb,$record,$parts,$responseType,$checkIcon,$uname,$udom) = @_;
my $studentTable='
'.
'
'.
'
Date/Time
'.
@@ -3002,33 +3108,62 @@ sub displaySubByDates {
'
Status
';
my ($version);
my %mark;
+ my %orders;
$mark{'correct_by_student'} = $checkIcon;
- return ' Nothing submitted - no attempts '
- if (!exists($$record{'1:timestamp'}));
+ if (!exists($$record{'1:timestamp'})) {
+ return ' Nothing submitted - no attempts ';
+ }
for ($version=1;$version<=$$record{'version'};$version++) {
my $timestamp = scalar(localtime($$record{$version.':timestamp'}));
$studentTable.='
'.$timestamp.'
';
my @versionKeys = split(/\:/,$$record{$version.':keys'});
my @displaySub = ();
foreach my $partid (@{$parts}) {
- my @matchKey = grep /^resource\.$partid\..*?\.submission$/,@versionKeys;
+ my @matchKey = sort(grep /^resource\.\Q$partid\E\..*?\.submission$/,@versionKeys);
# next if ($$record{"$version:resource.$partid.solved"} eq '');
- $displaySub[0].=(exists $$record{$version.':'.$matchKey[0]}) ?
- 'Part '.$partid.' '.
- ($$record{"$version:resource.$partid.tries"} eq '' ? 'Trial not counted' :
- 'Trial '.$$record{"$version:resource.$partid.tries"}).' '.
- &cleanRecord($$record{$version.':'.$matchKey[0]},$$responseType{$partid},$$symbx).' ' : '';
- $displaySub[1].=(exists $$record{"$version:resource.$partid.award"}) ?
- 'Part '.$partid.' '.
- lc($$record{"$version:resource.$partid.award"}).' '.
- $mark{$$record{"$version:resource.$partid.solved"}}.' ' : '';
- $displaySub[2].=(exists $$record{"$version:resource.$partid.regrader"}) ?
- $$record{"$version:resource.$partid.regrader"}.' (Part: '.$partid.')' : '';
- }
- $displaySub[2].=(exists $$record{"$version:resource.regrader"}) ?
- $$record{"$version:resource.regrader"} : ''; # needed because old essay regrader has not parts info
- $studentTable.='