--- loncom/homework/grades.pm 2007/08/21 18:48:18 1.431 +++ loncom/homework/grades.pm 2007/09/10 23:03:35 1.440 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.431 2007/08/21 18:48:18 banghart Exp $ +# $Id: grades.pm,v 1.440 2007/09/10 23:03:35 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -45,35 +45,26 @@ use LONCAPA; use POSIX qw(floor); + my %perm=(); +my %bubble_lines_per_response; # no. bubble lines for each response. + # index is "symb.part_id" + # ----- These first few routines are general use routines.---- # # --- 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); } } @@ -194,22 +185,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. @@ -258,11 +281,11 @@ sub cleanRecord { } 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) { + if ($foil eq $correct) { $toprow.='true'; } else { $toprow.='true'; @@ -326,7 +349,10 @@ sub cleanRecord { $result.=''; return $result; } - + } elsif ( $response =~ m/(?:numerical|formula)/) { + $answer = + &Apache::loncommon::format_previous_attempt_value('submission', + $answer); } return $answer; } @@ -723,7 +749,6 @@ LISTJAVASCRIPT my $saveStatus = $env{'form.Status'} eq '' ? 'Active' : $env{'form.Status'}; $env{'form.Status'} = $saveStatus; - $gradeTable.=''."\n". ''."\n". ''."\n". @@ -734,8 +759,7 @@ LISTJAVASCRIPT ''. ''. ''. - - ''."\n". + &build_section_inputs(). ''."\n". '
'."\n". '
'."\n". @@ -1661,6 +1685,19 @@ 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) = @_; @@ -1741,7 +1778,6 @@ sub submission { $env{'form.savemsgN'} = $keyhash{$symb.'_savemsgN'} ne '' ? $keyhash{$symb.'_savemsgN'} : '0'; } my $overRideScore = $env{'form.overRideScore'} eq '' ? 'no' : $env{'form.overRideScore'}; - $request->print('
'."\n". ''."\n". ''."\n". @@ -1756,7 +1792,7 @@ sub submission { ''."\n". ''."\n". ''."\n". - ''."\n". + &build_section_inputs(). ''."\n". ''."\n". ''."\n". ''."\n". - ''."\n". + &build_section_inputs(). ''."\n". ''."\n". ''."\n"; @@ -3085,8 +3121,11 @@ sub viewgrades { 'onClick="javascript:submit();" target="_self" />
'."\n"; if (scalar(%$fullname) eq 0) { my $colspan=3+scalar(@parts); - $result='There are no students in section "'.$env{'form.section'}. - '" with enrollment status "'.$env{'form.Status'}.'" to modify or grade.'; + my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section')); + $result=''. + &mt('There are no students in section(s) [_1] with enrollment status [_2] to modify or grade', + $section_display, $env{'form.Status'}). + ''; } $result.=&show_grading_menu_form($symb); return $result; @@ -3163,9 +3202,10 @@ sub editgrades { my ($request) = @_; my $symb=&get_symb($request); - my $title='

Current Grade Status

'; - $title.='

Current Resource: '.$env{'form.probTitle'}.'


'."\n"; - $title.='

Section: '.$env{'form.section'}.'

'."\n"; + my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section')); + my $title='

'.&mt('Current Grade Status').'

'; + $title.='

'.&mt('Current Resource: [_1]',$env{'form.probTitle'}).'


'."\n"; + $title.='

'.&mt('Section: [_1]',$section_display).'

'."\n"; my $result= '
'."\n"; $result.= ''. @@ -3363,7 +3403,7 @@ sub split_part_type { my ($partstr) = @_; my ($temp,@allparts)=split(/_/,$partstr); my $type=pop(@allparts); - my $part=join('.',@allparts); + my $part=join('_',@allparts); return ($part,$type); } @@ -3866,9 +3906,9 @@ LISTJAVASCRIPT ''."\n". ''."\n". ''."\n"; - - $result.=''."\n". - ''."\n". + + $result.=&build_section_inputs(); + $result.=''."\n". ''."\n". ''."\n". ''."
\n"; @@ -4382,7 +4422,7 @@ one of the predefined configurations for like. Next each scanline is checked for any errors of either 'missing -bubbles' (it's an error because it may have been missed scanned +bubbles' (it's an error because it may have been mis-scanned because too light bubbling), 'double bubble' (each bubble line should have no more that one letter picked), invalid or duplicated CODE, invalid student ID @@ -4393,7 +4433,7 @@ username:domain. During the validation phase the instructor can choose to skip scanlines. -After the validation phase, there is now 3 bubble sheet files +After the validation phase, there are now 3 bubble sheet files scantron_original_filename (unmodified original file) scantron_corrected_filename (file where the corrected information has replaced the original information) @@ -6463,6 +6503,7 @@ sub scantron_validate_doublebubble { =cut sub scantron_get_maxbubble { + if (defined($env{'form.scantron_maxbubble'}) && $env{'form.scantron_maxbubble'}) { return $env{'form.scantron_maxbubble'}; @@ -6477,14 +6518,40 @@ sub scantron_get_maxbubble { &Apache::lonxml::clear_problem_counter(); + my $uname = $env{'form.student'}; + my $udom = $env{'form.userdom'}; + my $cid = $env{'request.course.id'}; + my $total_lines = 0; + %bubble_lines_per_response = (); + foreach my $resource (@resources) { + my $symb = $resource->symb(); my $result=&Apache::lonnet::ssi($resource->src(), - ('symb' => $resource->symb())); + ('symb' => $resource->symb()), + ('grade_target' => 'analyze'), + ('grade_courseid' => $cid), + ('grade_domain' => $udom), + ('grade_username' => $uname)); + my (undef, $an) = + split(/_HASH_REF__/,$result, 2); + + my %analysis = &Apache::lonnet::str2hash($an); + + + + foreach my $part_id (@{$analysis{'parts'}}) { + my $bubble_lines = $analysis{"$part_id.bubble_lines"}[0]; + if (!$bubble_lines) { + $bubble_lines = 1; + } + $bubble_lines_per_response{"$symb.$part_id"} = $bubble_lines; + $total_lines = $total_lines + $bubble_lines; + } + } &Apache::lonnet::delenv('scantron\.'); $env{'form.scantron_maxbubble'} = - &Apache::lonxml::get_problem_counter()-1; - + $total_lines; return $env{'form.scantron_maxbubble'}; } @@ -7041,9 +7108,10 @@ sub gather_clicker_ids { # Set up a couple variables. my $username_idx = &Apache::loncoursedata::CL_SNAME(); my $domain_idx = &Apache::loncoursedata::CL_SDOM(); + my $status_idx = &Apache::loncoursedata::CL_STATUS(); foreach my $student (keys(%$classlist)) { - + if ($classlist->{$student}->[$status_idx] ne 'Active') { next; } my $username = $classlist->{$student}->[$username_idx]; my $domain = $classlist->{$student}->[$domain_idx]; my $clickers = @@ -7304,8 +7372,21 @@ ENDHEADER $result.="\n".''; $correct_count++; } elsif ($clicker_ids{$id}) { - $result.="\n".''; - $student_count++; + if ($clicker_ids{$id}=~/\,/) { +# More than one user with the same clicker! + $result.="\n
".&mt('Clicker registered more than once').": ".$id."
"; + $result.="\n".''. + "'; + $unknown_count++; + } else { +# Good: found one and only one user with the right clicker + $result.="\n".''; + $student_count++; + } } else { $result.="\n
".&mt('Unregistered Clicker')." ".$id."
"; $result.="\n".''. @@ -7456,6 +7537,8 @@ ENDHEADER my $id=$1; if (($env{'form.uname'.$id}) && ($env{'form.udom'.$id})) { $user=$env{'form.uname'.$id}.':'.$env{'form.udom'.$id}; + } elsif ($env{'form.multi'.$id}) { + $user=$env{'form.multi'.$id}; } } if ($user) { @@ -7501,7 +7584,7 @@ ENDHEADER sub handler { my $request=$_[0]; - &reset_perm(); + &reset_caches(); if ($env{'browser.mathml'}) { &Apache::loncommon::content_type($request,'text/xml'); } else { @@ -7545,10 +7628,6 @@ sub handler { } } else { &init_perm(); -# &Apache::lonnet::logthis("command is $command"); -# foreach my $key (keys %perm) { -# &Apache::lonnet::logthis("a key is $key"); -# } if ($command eq 'submission' && $perm{'vgr'}) { ($env{'form.student'} eq '' ? &listStudents($request) : &submission($request,0,0)); } elsif ($command eq 'pickStudentPage' && $perm{'vgr'}) { @@ -7618,6 +7697,7 @@ sub handler { } } $request->print(&Apache::loncommon::end_page()); + &reset_caches(); return ''; }