--- loncom/homework/grades.pm 2003/11/04 19:38:09 1.146 +++ 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.146 2003/11/04 19:38:09 albertel Exp $ +# $Id: grades.pm,v 1.149 2003/11/07 18:05:33 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -133,9 +133,9 @@ 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)) { @@ -143,13 +143,15 @@ sub response_type { } $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 @@ -158,42 +160,104 @@ sub showResourceInfo { my ($url,$probTitle) = @_; my $result ='<table border="0">'. '<tr><td colspan=3><font size=+1><b>Current Resource: </b>'.$probTitle.'</font></td></tr>'."\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.='<tr><td><b>Part </b>'.$partID.'</td>'. + $result.='<tr><td><b>Part </b>'.$partID.' <font color="#999999">'. + $resID.'</font></td>'. '<td><b>Type: </b>'.$responsetype.'</td></tr>'; # '<td><b>Handgrade: </b>'.$handgrade.'</td></tr>'; } $result.='</table>'."\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.'</font>'; - push @ans,$ans; + my ($answer,$response,$symb,$partid,$respid,$record,$order,$version) = @_; + my $grayFont = '<font color="#999999">'; + 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.='<td><b>'.$answer{$foil}.' </b></td>'; + } else { + $toprow.='<td><i>'.$answer{$foil}.' </i></td>'; + } + $bottomrow.='<td>'.$grayFont.$foil.'</font> </td>'; } - my $grayFont = '<font color="#999999">'; return '<blockquote><table border="1">'. - '<tr valign="top"><td>Answer</td><td>'. - (join '</td><td>',@ans).'</td></tr>'. - '<tr valign="top"><td>'.$grayFont.'Option ID</font></td><td>'.$grayFont. - (join '</td><td>'.$grayFont,@IDs).'</font></td></tr>'. - '</table></blockquote>'; - } - if ($response eq 'essay') { + '<tr valign="top"><td>Answer</td>'.$toprow.'</tr>'. + '<tr valign="top"><td>'.$grayFont.'Option ID</font></td>'. + $grayFont.$bottomrow.'</tr>'.'</table></blockquote>'; + } 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.='<td><b>'.$item.' </b></td>'; + $middlerow.='<td><b>'.$grayFont.$answer{$foil}.' </font></b></td>'; + } else { + $toprow.='<td><i>'.$item.' </i></td>'; + $middlerow.='<td><i>'.$grayFont.$answer{$foil}.' </font></i></td>'; + } + $bottomrow.='<td>'.$grayFont.$foil.'</font> </td>'; + } + return '<blockquote><table border="1">'. + '<tr valign="top"><td>Answer</td>'.$toprow.'</tr>'. + '<tr valign="top"><td>'.$grayFont.'Item ID</font></td>'. + $middlerow.'</tr>'. + '<tr valign="top"><td>'.$grayFont.'Option ID</font></td>'. + $bottomrow.'</tr>'.'</table></blockquote>'; + } 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.='<td><b>true</b></td>'; + } else { + $toprow.='<td><i>true</i></td>'; + } + } else { + $toprow.='<td>false</td>'; + } + $bottomrow.='<td>'.$grayFont.$foil.'</font> </td>'; + } + return '<blockquote><table border="1">'. + '<tr valign="top"><td>Answer</td>'.$toprow.'</tr>'. + '<tr valign="top"><td>'.$grayFont.'Option ID</font></td>'. + $grayFont.$bottomrow.'</tr>'.'</table></blockquote>'; + } elsif ($response eq 'essay') { if (! exists ($ENV{'form.'.$symb})) { my (%keyhash) = &Apache::lonnet::dump('nohist_handgrade', $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, @@ -1421,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 ? '' : '<br />')); @@ -1504,7 +1568,7 @@ KEYWORDS $$fullname{$ENV{'form.'.$uname.':'.$udom.':submitted_by'}}.'</a>'; $request->print($submitby); } else { - my ($string,$timestamp)= &get_last_submission (\%record); + my ($string,$timestamp)= &get_last_submission(\%record); my $lastsubonly=''. ($$timestamp eq '' ? '' : '<b>Date Submitted:</b> '. $$timestamp)."</td></tr>\n"; @@ -1512,8 +1576,8 @@ KEYWORDS $lastsubonly.='<tr><td bgcolor="#ffffe6">'.$$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.='<tr><td bgcolor="#ffffe6"><b>Part '. $partid.'</b> <font color="#999999">( ID '.$respid. @@ -1521,7 +1585,7 @@ KEYWORDS '<font color="red">Nothing submitted - no attempts</font><br /><br />'; } 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 @@ -1541,6 +1605,7 @@ KEYWORDS &keywords_highlight($oessay).'</i></blockquote><hr />'; } } + my $order=&get_order($partid,$respid,$symb,$uname,$udom); $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part '. $partid.'</b> <font color="#999999">( ID '.$respid. ' )</font> '. @@ -1551,11 +1616,11 @@ KEYWORDS '<font color="red" size="1">Like all files provided by users, '. 'this file may contain virusses</font><br />':''). '<b>Submitted Answer: </b>'. - &cleanRecord($subval,$responsetype,$symb). + &cleanRecord($subval,$responsetype,$symb,$partid,$respid,\%record,$order). '<br /><br />'.$similar."\n" if ($ENV{'form.lastSub'} eq 'lastonly' || ($ENV{'form.lastSub'} eq 'hdgrade' && - $$handgrade{$part} =~ /:yes$/)); + $$handgrade{$part} eq 'yes')); } } } @@ -1566,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'}, @@ -2172,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; @@ -2991,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' : ''); @@ -3028,7 +3100,7 @@ sub displayPage { } sub displaySubByDates { - my ($symbx,$record,$parts,$responseType,$checkIcon) = @_; + my ($symb,$record,$parts,$responseType,$checkIcon,$uname,$udom) = @_; my $studentTable='<table border="0" width="100%"><tr><td bgcolor="#777777">'. '<table border="0" width="100%"><tr bgcolor="#e6ffff">'. '<td><b>Date/Time</b></td>'. @@ -3036,33 +3108,62 @@ sub displaySubByDates { '<td><b>Status </b></td></tr>'; my ($version); my %mark; + my %orders; $mark{'correct_by_student'} = $checkIcon; - return '<br /> <font color="red">Nothing submitted - no attempts</font><br />' - if (!exists($$record{'1:timestamp'})); + if (!exists($$record{'1:timestamp'})) { + return '<br /> <font color="red">Nothing submitted - no attempts</font><br />'; + } for ($version=1;$version<=$$record{'version'};$version++) { my $timestamp = scalar(localtime($$record{$version.':timestamp'})); $studentTable.='<tr bgcolor="#ffffff" valign="top"><td>'.$timestamp.'</td>'; 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]}) ? - '<b>Part '.$partid.' '. - ($$record{"$version:resource.$partid.tries"} eq '' ? 'Trial not counted' : - 'Trial '.$$record{"$version:resource.$partid.tries"}).'</b> '. - &cleanRecord($$record{$version.':'.$matchKey[0]},$$responseType{$partid},$$symbx).'<br />' : ''; - $displaySub[1].=(exists $$record{"$version:resource.$partid.award"}) ? - '<b>Part '.$partid.'</b> '. - lc($$record{"$version:resource.$partid.award"}).' '. - $mark{$$record{"$version:resource.$partid.solved"}}.'<br />' : ''; - $displaySub[2].=(exists $$record{"$version:resource.$partid.regrader"}) ? - $$record{"$version:resource.$partid.regrader"}.' (<b>Part:</b> '.$partid.')' : ''; - } - $displaySub[2].=(exists $$record{"$version:resource.regrader"}) ? - $$record{"$version:resource.regrader"} : ''; # needed because old essay regrader has not parts info - $studentTable.='<td>'.$displaySub[0].' </td><td>'.$displaySub[1]. - ($displaySub[2] eq '' ? '' : 'Manually graded by '.$displaySub[2]).' </td></tr>'; + foreach my $matchKey (@matchKey) { + if (exists $$record{$version.':'.$matchKey}) { + my ($responseId)=($matchKey=~ /^resource\.\Q$partid\E\.(.*?)\.submission$/); + $displaySub[0].='<b>Part '.$partid.' '; + $displaySub[0].='<font color="#999999">(ID '. + $responseId.')</font> '; + if ($$record{"$version:resource.$partid.tries"} eq '') { + $displaySub[0].='Trial not counted'; + } else { + $displaySub[0].='Trial '. + $$record{"$version:resource.$partid.tries"}; + } + my $responseType=$responseType->{$partid}->{$responseId}; + if (!exists($orders{$partid})) { $orders{$partid}={}; } + if (!exists($orders{$partid}->{$responseId})) { + $orders{$partid}->{$responseId}= + &get_order($partid,$responseId,$symb,$uname,$udom); + } + $displaySub[0].='</b> '. + &cleanRecord($$record{$version.':'.$matchKey},$responseType,$symb,$partid,$responseId,$record,$orders{$partid}->{$responseId},"$version:").'<br />'; + } + } + if (exists $$record{"$version:resource.$partid.award"}) { + $displaySub[1].='<b>Part '.$partid.'</b> '. + lc($$record{"$version:resource.$partid.award"}).' '. + $mark{$$record{"$version:resource.$partid.solved"}}. + '<br />'; + } + if (exists $$record{"$version:resource.$partid.regrader"}) { + $displaySub[2].=$$record{"$version:resource.$partid.regrader"}. + ' (<b>Part:</b> '.$partid.')'; + } + } + # needed because old essay regrader has not parts info + if (exists $$record{"$version:resource.regrader"}) { + $displaySub[2].=$$record{"$version:resource.regrader"}; + } + $studentTable.='<td>'.$displaySub[0].' </td><td>'.$displaySub[1]; + if ($displaySub[2]) { + $studentTable.='Manually graded by '.$displaySub[2]; + } + $studentTable.=' </td></tr>'; + } $studentTable.='</table></td></tr></table>'; return $studentTable;