--- loncom/homework/grades.pm 2007/06/22 22:50:30 1.417
+++ loncom/homework/grades.pm 2007/11/01 00:47:42 1.474
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.417 2007/06/22 22:50:30 albertel Exp $
+# $Id: grades.pm,v 1.474 2007/11/01 00:47:42 albertel Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -35,6 +35,7 @@ use Apache::loncommon;
use Apache::lonhtmlcommon;
use Apache::lonnavmaps;
use Apache::lonhomework;
+use Apache::lonpickcode;
use Apache::loncoursedata;
use Apache::lonmsg();
use Apache::Constants qw(:common);
@@ -45,36 +46,104 @@ use LONCAPA;
use POSIX qw(floor);
-my %oldessays=();
+
my %perm=();
+my %bubble_lines_per_response = (); # no. bubble lines for each response.
+ # index is "symb.part_id"
+
+my %first_bubble_line = (); # First bubble line no. for each bubble.
+
+# Save and restore the bubble lines array to the form env.
+
+
+sub save_bubble_lines {
+ foreach my $line (keys(%bubble_lines_per_response)) {
+ $env{"form.scantron.bubblelines.$line"} = $bubble_lines_per_response{$line};
+ $env{"form.scantron.first_bubble_line.$line"} =
+ $first_bubble_line{$line};
+ }
+}
+
+
+sub restore_bubble_lines {
+ my $line = 0;
+ %bubble_lines_per_response = ();
+ while ($env{"form.scantron.bubblelines.$line"}) {
+ my $value = $env{"form.scantron.bubblelines.$line"};
+ $bubble_lines_per_response{$line} = $value;
+ $first_bubble_line{$line} =
+ $env{"form.scantron.first_bubble_line.$line"};
+ $line++;
+ }
+
+}
+
+# Given the parsed scanline, get the response for
+# 'answer' number n:
+
+sub get_response_bubbles {
+ my ($parsed_line, $response) = @_;
+
+
+ my $bubble_line = $first_bubble_line{$response-1} +1;
+ my $bubble_lines= $bubble_lines_per_response{$response-1};
+
+ my $selected = "";
+
+ for (my $bline = 0; $bline < $bubble_lines; $bline++) {
+ $selected .= $$parsed_line{"scantron.$bubble_line.answer"}.":";
+ $bubble_line++;
+ }
+ return $selected;
+}
+
# ----- These first few routines are general use routines.----
+
+# Return the number of occurences of a pattern in a string.
+
+sub occurence_count {
+ my ($string, $pattern) = @_;
+
+ my @matches = ($string =~ /$pattern/g);
+
+ return scalar(@matches);
+}
+
+
+# Take a string known to have digits and convert all the
+# digits into letters in the range J,A..I.
+
+sub digits_to_letters {
+ my ($input) = @_;
+
+ my @alphabet = ('J', 'A'..'I');
+
+ my @input = split(//, $input);
+ my $output ='';
+ for (my $i = 0; $i < scalar(@input); $i++) {
+ if ($input[$i] =~ /\d/) {
+ $output .= $alphabet[$input[$i]];
+ } else {
+ $output .= $input[$i];
+ }
+ }
+ return $output;
+}
+
#
# --- Retrieve the parts from the metadata file.---
sub getpartlist {
my ($symb) = @_;
- my (undef,undef,$url) = &Apache::lonnet::decode_symb($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);
- }
- }
- }
- }
+
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ my $res = $navmap->getBySymb($symb);
+ my $partlist = $res->parts();
+ my $url = $res->src();
+ my @metakeys = split(/,/,&Apache::lonnet::metadata($url,'keys'));
+
my @stores;
- foreach my $part (@parts) {
- my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));
+ foreach my $part (@{ $partlist }) {
foreach my $key (@metakeys) {
if ($key =~ m/^stores_\Q$part\E_/) { push(@stores,$key); }
}
@@ -93,6 +162,7 @@ sub get_symb {
return ();
}
}
+ &Apache::lonenc::check_decrypt(\$symb);
return ($symb);
}
@@ -194,22 +264,54 @@ sub showResourceInfo {
return $result,$responseType,$hdgrade,$partlist,$handgrade;
}
+sub reset_caches {
+ &reset_analyze_cache();
+ &reset_perm();
+}
-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"});
+{
+ my %analyze_cache;
+
+ sub reset_analyze_cache {
+ undef(%analyze_cache);
+ }
+
+ sub get_analyze {
+ my ($symb,$uname,$udom)=@_;
+ my $key = "$symb\0$uname\0$udom";
+ return $analyze_cache{$key} if (exists($analyze_cache{$key}));
+
+ 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_cache{$key} = \%analyze;
+ }
+
+ sub get_order {
+ my ($partid,$respid,$symb,$uname,$udom)=@_;
+ my $analyze = &get_analyze($symb,$uname,$udom);
+ return $analyze->{"$partid.$respid.shown"};
+ }
+
+ sub get_radiobutton_correct_foil {
+ my ($partid,$respid,$symb,$uname,$udom)=@_;
+ my $analyze = &get_analyze($symb,$uname,$udom);
+ foreach my $foil (@{&get_order($partid,$respid,$symb,$uname,$udom)}) {
+ if ($analyze->{"$partid.$respid.foil.value.$foil"} eq 'true') {
+ return $foil;
+ }
+ }
+ }
}
+
#--- Clean response type for display
#--- Currently filters option/rank/radiobutton/match/essay/Task
# response types only.
@@ -230,8 +332,8 @@ sub cleanRecord {
$bottomrow.='
'.$grayFont.$foil.'
';
}
return '
'.
- '
Answer
'.$toprow.'
'.
- '
'.$grayFont.'Option ID
'.
+ '
'.&mt('Answer').'
'.$toprow.'
'.
+ '
'.$grayFont.&mt('Option ID').'
'.
$grayFont.$bottomrow.'
'.'
';
} elsif ($response eq 'match') {
my %answer=&Apache::lonnet::str2hash($answer);
@@ -250,31 +352,31 @@ sub cleanRecord {
$bottomrow.='
'.$grayFont.$foil.'
';
}
return '
'.
- '
Answer
'.$toprow.'
'.
- '
'.$grayFont.'Item ID
'.
+ '
'.&mt('Answer').'
'.$toprow.'
'.
+ '
'.$grayFont.&mt('Item ID').'
'.
$middlerow.'
'.
- '
'.$grayFont.'Option ID
'.
+ '
'.$grayFont.&mt('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];
+ my $correct =
+ &get_radiobutton_correct_foil($partid,$respid,$symb,$uname,$udom);
+ foreach my $foil (@$order) {
if (exists($answer{$foil})) {
- if ($i == $correct) {
- $toprow.='
true
';
+ if ($foil eq $correct) {
+ $toprow.='
'.&mt('true').'
';
} else {
- $toprow.='
true
';
+ $toprow.='
'.&mt('true').'
';
}
} else {
- $toprow.='
false
';
+ $toprow.='
'.&mt('false').'
';
}
$bottomrow.='
'.$grayFont.$foil.'
';
}
return '
'.
- '
Answer
'.$toprow.'
'.
- '
'.$grayFont.'Option ID
'.
+ '
'.&mt('Answer').'
'.$toprow.'
'.
+ '
'.$grayFont.&mt('Option ID').'
'.
$grayFont.$bottomrow.'
'.'
';
} elsif ($response eq 'essay') {
if (! exists ($env{'form.'.$symb})) {
@@ -326,7 +428,10 @@ sub cleanRecord {
$result.='';
return $result;
}
-
+ } elsif ( $response =~ m/(?:numerical|formula)/) {
+ $answer =
+ &Apache::loncommon::format_previous_attempt_value('submission',
+ $answer);
}
return $answer;
}
@@ -370,8 +475,10 @@ COMMONJSFUNCTIONS
#--- Dumps the class list with usernames,list of sections,
#--- section, ids and fullnames for each user.
sub getclasslist {
- my ($getsec,$filterlist) = @_;
+ my ($getsec,$filterlist,$getgroup) = @_;
my @getsec;
+ my @getgroup;
+ my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
if (!ref($getsec)) {
if ($getsec ne '' && $getsec ne 'all') {
@getsec=($getsec);
@@ -380,10 +487,19 @@ sub getclasslist {
@getsec=@{$getsec};
}
if (grep(/^all$/,@getsec)) { undef(@getsec); }
+ if (!ref($getgroup)) {
+ if ($getgroup ne '' && $getgroup ne 'all') {
+ @getgroup=($getgroup);
+ }
+ } else {
+ @getgroup=@{$getgroup};
+ }
+ if (grep(/^all$/,@getgroup)) { undef(@getgroup); }
- my $classlist=&Apache::loncoursedata::get_classlist();
+ my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist();
# Bail out if we were unable to get the classlist
return if (! defined($classlist));
+ &Apache::loncoursedata::get_group_memberships($classlist,$keylist);
#
my %sections;
my %fullnames;
@@ -400,18 +516,40 @@ sub getclasslist {
$classlist->{$student}->[&Apache::loncoursedata::CL_FULLNAME()];
my $status =
$classlist->{$student}->[&Apache::loncoursedata::CL_STATUS()];
+ my $group =
+ $classlist->{$student}->[&Apache::loncoursedata::CL_GROUP()];
# filter students according to status selected
- if ($filterlist && $env{'form.Status'} ne 'Any') {
- if ($env{'form.Status'} ne $status) {
- delete ($classlist->{$student});
+ if ($filterlist && (!($stu_status =~ /Any/))) {
+ if (!($stu_status =~ $status)) {
+ delete($classlist->{$student});
next;
}
}
+ # filter students according to groups selected
+ my @stu_groups = split(/,/,$group);
+ if (@getgroup) {
+ my $exclude = 1;
+ foreach my $grp (@getgroup) {
+ foreach my $stu_group (@stu_groups) {
+ if ($stu_group eq $grp) {
+ $exclude = 0;
+ }
+ }
+ if (($grp eq 'none') && !$group) {
+ $exclude = 0;
+ }
+ }
+ if ($exclude) {
+ delete($classlist->{$student});
+ }
+ }
$section = ($section ne '' ? $section : 'none');
if (&canview($section)) {
if (!@getsec || grep(/^\Q$section\E$/,@getsec)) {
$sections{$section}++;
- $fullnames{$student}=$fullname;
+ if ($classlist->{$student}) {
+ $fullnames{$student}=$fullname;
+ }
} else {
delete($classlist->{$student});
}
@@ -484,6 +622,7 @@ sub student_gradeStatus {
# Shows a student's view of problem and submission
sub jscriptNform {
my ($symb) = @_;
+ my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
my $jscript=''."\n";
$jscript.= ''."\n";
@@ -890,7 +1032,7 @@ LISTJAVASCRIPT
' students checked for '.$submissions.') ';
}
} elsif ($ctr == 1) {
- $gradeTable =~ s/type=checkbox/type=checkbox checked/;
+ $gradeTable =~ s/type="checkbox"/type="checkbox" checked="checked"/;
}
$gradeTable.=&show_grading_menu_form($symb);
$request->print($gradeTable);
@@ -1342,43 +1484,43 @@ INNERJS
pDoc.write("");
+ pDoc.write("<\\/form>");
pDoc.write('$end_page_msg_central');
pDoc.close();
}
@@ -1427,32 +1569,32 @@ INNERJS
hDoc.$docopen;
hDoc.write('$start_page_highlight_central');
hDoc.write("");
+ hDoc.write("<\\/form>");
hDoc.write('$end_page_highlight_central');
hDoc.close();
}
@@ -1477,13 +1619,13 @@ sub gradeBox {
'" src="'.$request->dir_config('lonIconsURL').
'/check.gif" height="16" border="0" />';
my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb,$udom,$uname);
- my $wgtmsg = ($wgt > 0 ? '(problem weight)' :
- 'problem weight assigned by computer');
+ my $wgtmsg = ($wgt > 0) ? &mt('(problem weight)')
+ : ''.&mt('problem weight assigned by computer').'';
$wgt = ($wgt > 0 ? $wgt : '1');
my $score = ($$record{'resource.'.$partid.'.awarded'} eq '' ?
'' : &compute_points($$record{'resource.'.$partid.'.awarded'},$wgt));
my $result=''."\n";
- my $display_part=&get_display_part($partid,$symb);
+ my $display_part= &get_display_part($partid,$symb);
my %last_resets = &get_last_resets($symb,$env{'request.course.id'},
[$partid]);
my $aggtries = $$record{'resource.'.$partid.'.tries'};
@@ -1565,7 +1707,7 @@ sub handback_box {
''.$file_disp.'');
$result.=''."\n";
$result.=' ';
- $result.='(File will be uploaded when you click on Save & Next below.) ';
+ $result.='(File will be uploaded when you click on Save & Next below.) ';
$file_counter++;
}
}
@@ -1601,27 +1743,27 @@ sub show_problem {
$companswer=~s|||g;
$companswer=~s|name="submit"|name="would_have_been_submit"|g;
}
- my $result.='
';
- $result.='
';
- if ($viewon) {
- $result.='
';
- if ($mode eq 'both' or $mode eq 'text') {
- $result.='View of the problem - ';
- } else {
- $result.='Correct answer: ';
- }
- $result.=$env{'form.fullname'}.'
';
- }
+ $rendered=
+ '
'.
+ &mt('View of the problem').
+ '
'.
+ $rendered.
+ '
';
+ $companswer=
+ '
'.
+ &mt('Correct answer').
+ '
'.
+ $companswer.
+ '
';
+ my $result;
if ($mode eq 'both') {
- $result.='
';
return $result;
}
@@ -1662,15 +1804,26 @@ sub download_all_link {
return
}
+sub build_section_inputs {
+ my $section_inputs;
+ if ($env{'form.section'} eq '') {
+ $section_inputs .= ''."\n";
+ } else {
+ my @sections = &Apache::loncommon::get_env_multiple('form.section');
+ foreach my $section (@sections) {
+ $section_inputs .= ''."\n";
+ }
+ }
+ return $section_inputs;
+}
+
# --------------------------- show submissions of a student, option to grade
sub submission {
my ($request,$counter,$total) = @_;
-
my ($uname,$udom) = ($env{'form.student'},$env{'form.userdom'});
$udom = ($udom eq '' ? $env{'user.domain'} : $udom); #has form.userdom changed for a student?
my $usec = &Apache::lonnet::getsection($udom,$uname,$env{'request.course.id'});
$env{'form.fullname'} = &Apache::loncommon::plainname($uname,$udom,'lastname') if $env{'form.fullname'} eq '';
-
my $symb = &get_symb($request);
if ($symb eq '') { $request->print("Unable to handle ambiguous references:."); return ''; }
@@ -1690,6 +1843,7 @@ sub submission {
'" src="'.$request->dir_config('lonIconsURL').
'/check.gif" height="16" border="0" />';
+ my %old_essays;
# header info
if ($counter == 0) {
&sub_page_js($request);
@@ -1702,12 +1856,6 @@ sub submission {
$request->print('
Submission Record
'."\n".
'
Resource: '.$env{'form.probTitle'}.'
'."\n");
- if ($env{'form.handgrade'} eq 'no') {
- my $checkMark='
Note: Part(s) graded correct by the computer is marked with a '.
- $checkIcon.' symbol.'."\n";
- $request->print($checkMark);
- }
-
# option to display problem, only once else it cause problems
# with the form later since the problem has a form.
if ($env{'form.vProb'} eq 'yes' or $env{'form.vAns'} eq 'yes') {
@@ -1722,7 +1870,7 @@ sub submission {
&Apache::lonxml::clear_problem_counter();
$request->print(&show_problem($request,$symb,$uname,$udom,0,1,$mode));
}
-
+
# kwclr is the only variable that is guaranteed to be non blank
# if this subroutine has been called once.
my %keyhash = ();
@@ -1741,22 +1889,22 @@ sub submission {
$env{'form.savemsgN'} = $keyhash{$symb.'_savemsgN'} ne '' ? $keyhash{$symb.'_savemsgN'} : '0';
}
my $overRideScore = $env{'form.overRideScore'} eq '' ? 'no' : $env{'form.overRideScore'};
-
+ my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
$request->print('