--- loncom/homework/grades.pm 2013/08/14 03:33:54 1.596.2.12.2.18 +++ loncom/homework/grades.pm 2015/03/17 12:37:40 1.596.2.12.2.34 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.596.2.12.2.18 2013/08/14 03:33:54 raeburn Exp $ +# $Id: grades.pm,v 1.596.2.12.2.34 2015/03/17 12:37:40 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -391,6 +391,8 @@ sub cleanRecord { 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) { @@ -407,6 +409,8 @@ sub cleanRecord { $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); @@ -461,10 +465,10 @@ 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-
-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; @@ -498,12 +502,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 @@ -811,7 +817,7 @@ sub verifyreceipt { '

'. &mt('Verifying Receipt No. [_1]',$receipt). '

'."\n". - '

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

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

'."\n"; my ($string,$contents,$matches) = ('','',0); @@ -1162,7 +1168,7 @@ LISTJAVASCRIPT if ($submitonly eq 'graded' ) { $submissions = 'ungraded submissions'; } if ($submitonly eq 'queued' ) { $submissions = 'queued submissions'; } $gradeTable='
 '. - &mt('No '.$submissions.' found for this resource for any students. ([_1] students checked for '.$submissions.')', + &mt('No '.$submissions.' found for this resource for any students. ([quant,_1,student] checked for '.$submissions.')', $num_students). '
'; } @@ -1366,10 +1372,8 @@ sub sub_page_js { } } } - } } - } if (val == "Grade Student") { formname.showgrading.value = "yes"; @@ -1519,6 +1523,15 @@ INNERJS txtc => 'Text Color', font => 'Font Size', fnst => 'Font Style', + col1 => 'red', + col2 => 'green', + col3 => 'blue', + siz1 => 'normal', + siz2 => '+1', + siz3 => '+2', + sty1 => 'normal', + sty2 => 'italic', + sty3 => 'bold', ); $request->print(< @@ -1684,25 +1697,34 @@ INNERJS var redsel = ""; var grnsel = ""; var blusel = ""; - if (kwclr=="red") {var redsel="checked"}; - if (kwclr=="green") {var grnsel="checked"}; - if (kwclr=="blue") {var blusel="checked"}; + var txtcol1 = "$lt{'col1'}"; + var txtcol2 = "$lt{'col2'}"; + var txtcol3 = "$lt{'col3'}"; + var txtsiz1 = "$lt{'siz1'}"; + var txtsiz2 = "$lt{'siz2'}"; + var txtsiz3 = "$lt{'siz3'}"; + var txtsty1 = "$lt{'sty1'}"; + var txtsty2 = "$lt{'sty2'}"; + var txtsty3 = "$lt{'sty3'}"; + if (kwclr=="red") {var redsel="checked='checked'"}; + if (kwclr=="green") {var grnsel="checked='checked'"}; + if (kwclr=="blue") {var blusel="checked='checked'"}; var sznsel = ""; var sz1sel = ""; var sz2sel = ""; - if (kwsize=="0") {var sznsel="checked"}; - if (kwsize=="+1") {var sz1sel="checked"}; - if (kwsize=="+2") {var sz2sel="checked"}; + if (kwsize=="0") {var sznsel="checked='checked'"}; + if (kwsize=="+1") {var sz1sel="checked='checked'"}; + if (kwsize=="+2") {var sz2sel="checked='checked'"}; var synsel = ""; var syisel = ""; var sybsel = ""; - if (kwstyle=="") {var synsel="checked"}; - if (kwstyle=="") {var syisel="checked"}; - if (kwstyle=="") {var sybsel="checked"}; + if (kwstyle=="") {var synsel="checked='checked'"}; + if (kwstyle=="") {var syisel="checked='checked'"}; + if (kwstyle=="") {var sybsel="checked='checked'"}; highlightCentral(); - highlightbody('red','red',redsel,'0','normal',sznsel,'','normal',synsel); - highlightbody('green','green',grnsel,'+1','+1',sz1sel,'','italic',syisel); - highlightbody('blue','blue',blusel,'+2','+2',sz2sel,'','bold',sybsel); + highlightbody('red',txtcol1,redsel,'0',txtsiz1,sznsel,'',txtsty1,synsel); + highlightbody('green',txtcol2,grnsel,'+1',txtsiz2,sz1sel,'',txtsty2,syisel); + highlightbody('blue',txtcol3,blusel,'+2',txtsiz3,sz2sel,'',txtsty3,sybsel); highlightend(); return; } @@ -1720,31 +1742,29 @@ INNERJS hDoc.$docopen; hDoc.write('$start_page_highlight_central'); hDoc.write("
"); - hDoc.write("

 $lt{'kehi'}<\\/span><\\/h3>

"); + hDoc.write("

$lt{'kehi'}<\\/h1>"); - hDoc.write('
'); - hDoc.write(''); - hDoc.write("
$lt{'txtc'}<\\/b><\\/td>$lt{'font'}<\\/b><\\/td>$lt{'fnst'}<\\/td><\\/tr>"); + hDoc.write(''); + hDoc.write(""); + hDoc.write(""); hDoc.write("'."\n"; - $line.= ''; @@ -6723,7 +6842,7 @@ sub scantron_warning_screen { return ('

-'.&mt('Please double check the information below before clicking on \'[_1]\'',&mt($button_text)).' +'.&mt("Please double check the information below before clicking on '[_1]'",&mt($button_text)).'

$lt{'txtc'}<\\/th>$lt{'font'}<\\/th>$lt{'fnst'}<\\/th><\\/tr>"); } function highlightbody(clrval,clrtxt,clrsel,szval,sztxt,szsel,syval,sytxt,sysel) { var hDoc = hwdWin.document; - hDoc.write("
"); - hDoc.write(" "+clrtxt+"<\\/td>"); + hDoc.write(" "+clrtxt+"<\\/td>"); hDoc.write(""); - hDoc.write(" "+sztxt+"<\\/td>"); + hDoc.write(" "+sztxt+"<\\/td>"); hDoc.write(""); - hDoc.write(" "+sytxt+"<\\/td>"); + hDoc.write(" "+sytxt+"<\\/td>"); hDoc.write("<\\/tr>"); } function highlightend() { var hDoc = hwdWin.document; - hDoc.write("<\\/table>"); - hDoc.write("<\\/td><\\/tr><\\/table> "); - hDoc.write("  "); - hDoc.write("

"); + hDoc.write("<\\/table>
"); + hDoc.write("  "); + hDoc.write("

"); hDoc.write("<\\/form>"); hDoc.write('$end_page_highlight_central'); hDoc.close(); @@ -2019,9 +2039,12 @@ sub submission { if ($symb eq '') { $request->print("Unable to handle ambiguous references:."); return ''; } if (!&canview($usec)) { - $request->print('Unable to view requested student.('. - $uname.':'.$udom.' in section '.$usec.' in course id '. - $env{'request.course.id'}.')'); + $request->print( + ''. + &mt('Unable to view requested student.'). + ' '.&mt('([_1] in section [_2] in course id [_3])', + $uname.':'.$udom,$usec,$env{'request.course.id'}). + ''); $request->print(&show_grading_menu_form($symb)); return; } @@ -2044,7 +2067,7 @@ sub submission { &download_all_link($request, $symb); } $request->print('

 '.&mt('Submission Record').'

'."\n". - '

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

'."\n"); + '

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

'."\n"); # option to display problem, only once else it cause problems # with the form later since the problem has a form. @@ -2061,7 +2084,7 @@ sub submission { $request->print(&show_problem($request,$symb,$uname,$udom,0,1,$mode)); } - # kwclr is the only variable that is guaranteed to be non blank + # kwclr is the only variable that is guaranteed not to be blank # if this subroutine has been called once. my %keyhash = (); if ($env{'form.kwclr'} eq '' && $env{'form.handgrade'} eq 'yes') { @@ -2127,6 +2150,7 @@ sub submission { if ($env{'form.handgrade'} eq 'yes' && $env{'form.showgrading'} eq 'yes') { my %lt = &Apache::lonlocal::texthash( + keyh => 'Keyword Highlighting for Essays', keyw => 'Keyword Options', list => 'List', past => 'Paste Selection to List', @@ -2135,13 +2159,18 @@ sub submission { # # Print out the keyword options line # - $request->print(<$lt{'keyw'}:  -$lt{'list'}    -$lt{'past'}    -$lt{'high'}

-KEYWORDS + $request->print( + '
' + .'
'.$lt{'keyh'}.'' + .&Apache::lonhtmlcommon::funclist_from_array( + [''.$lt{'list'}.'', + ''.$lt{'past'}.'', + ''.$lt{'high'}.''], + {legend => $lt{'keyw'}}) + .'
' + ); + # # Load the other essays for similarity check # @@ -2166,7 +2195,7 @@ KEYWORDS if ($perm{'vgr'}) { $request->print( &Apache::loncommon::track_student_link( - &mt('View recent activity'), + 'View recent activity', $uname,$udom,'check') .' ' ); @@ -2230,7 +2259,7 @@ KEYWORDS # (for multi-response type part) # (3) Last submission plus the parts info # (4) The whole record for this student - if ($env{'form.lastSub'} =~ /^(lastonly|hdgrade)$/) { + my ($string,$timestamp)= &get_last_submission(\%record); my $lastsubonly; @@ -2276,7 +2305,7 @@ KEYWORDS foreach my $submission (@$string) { my ($partid,$respid) = ($submission =~ /^resource\.([^\.]*)\.([^\.]*)\.submission/); if (join('_',@{$part}) ne ($partid.'_'.$respid)) { next; } - my ($ressub,$hide,$subval) = split(/:/,$submission,3); + my ($ressub,$hide,$draft,$subval) = split(/:/,$submission,4); # Similarity check my $similar=''; my ($type,$trial,$rndseed); @@ -2285,7 +2314,7 @@ KEYWORDS $trial = $record{"resource.$partid.tries"}; $rndseed = $record{"resource.$partid.rndseed"}; } - if($env{'form.checkPlag'}){ + if ($env{'form.checkPlag'}) { my ($oname,$odom,$ocrsid,$oessay,$osim)= &most_similar($uname,$udom,$symb,$subval); if ($osim) { @@ -2313,9 +2342,8 @@ KEYWORDS } my $order=&get_order($partid,$respid,$symb,$uname,$udom, undef,$type,$trial,$rndseed); - if ($env{'form.lastSub'} eq 'lastonly' || - ($env{'form.lastSub'} eq 'hdgrade' && - $$handgrade{$$part[0].'_'.$$part[1]} eq 'yes')) { + if ($env{'form.lastSub'} eq 'lastonly' || $env{'form.lastSub'} eq 'datesub' || $env{'form.lastSub'} =~ /^(last|all)$/ || ($env{'form.lastSub'} eq 'hdgrade' && + $$handgrade{$$part[0].'_'.$$part[1]} eq 'yes')) { my $display_part=&get_display_part($partid,$symb); $lastsubonly.='
'. ''.&mt('Part: [_1]',$display_part).''. @@ -2346,9 +2374,17 @@ KEYWORDS if ($hide eq 'anon') { $lastsubonly.='
'.&mt('Anonymous Survey').''; } else { - $lastsubonly.='
'.&mt('Submitted Answer:').' '. + $lastsubonly.='
'.&mt('Submitted Answer:').' '; + if ($draft) { + $lastsubonly.= ' '.&mt('Draft Copy').''; + } + $subval = &cleanRecord($subval,$responsetype,$symb,$partid, $respid,\%record,$order,undef,$uname,$udom,$type,$trial,$rndseed); + if ($responsetype eq 'essay') { + $subval =~ s{\n}{
}g; + } + $lastsubonly.=$subval."\n"; } if ($similar) {$lastsubonly.="

$similar\n";} $lastsubonly.='
'; @@ -2358,14 +2394,17 @@ KEYWORDS $lastsubonly.=''."\n"; # End: LC_grade_submissions_body } $request->print($lastsubonly); - } elsif ($env{'form.lastSub'} eq 'datesub') { + if ($env{'form.lastSub'} eq 'datesub') { my (undef,$responseType,undef,$parts) = &showResourceInfo($symb); $request->print(&displaySubByDates($symb,\%record,$parts,$responseType,$checkIcon,$uname,$udom)); - } elsif ($env{'form.lastSub'} =~ /^(last|all)$/) { + } + if ($env{'form.lastSub'} =~ /^(last|all)$/) { + my $identifier = (&canmodify($usec)? $counter : ''); $request->print(&Apache::loncommon::get_previous_attempt($symb,$uname,$udom, $env{'request.course.id'}, $last,'.submission', - 'Apache::grades::keywords_highlight')); + 'Apache::grades::keywords_highlight', + $usec,$identifier)); } $request->print('Draft Copy ' : ''; - push(@string, join(':', $key, $hide, $draft.$lasthash{$key})); + my $draft = $lasthash{$partid.'awarddetail'} eq 'DRAFT' ? 1: 0; + push(@string, join(':', $key, $hide, $draft, ( + ref($lasthash{$key}) eq 'ARRAY' ? + join(',', @{$lasthash{$key}}) : $lasthash{$key}) )); } } if (!@string) { @@ -2632,16 +2672,20 @@ sub keywords_highlight { sub show_previous_task_version { my ($request,$symb) = @_; if ($symb eq '') { - $request->print("Unable to handle ambiguous references."); - + $request->print( + ''. + &mt('Unable to handle ambiguous references.'). + ''); return ''; } my ($uname,$udom) = ($env{'form.student'},$env{'form.userdom'}); my $usec = &Apache::lonnet::getsection($udom,$uname,$env{'request.course.id'}); if (!&canview($usec)) { - $request->print('Unable to view previous version for requested student.('. - $uname.':'.$udom.' in section '.$usec.' in course id '. - $env{'request.course.id'}.')'); + $request->print(''. + &mt('Unable to view previous version for requested student.'). + ' '.&mt('([_1] in section [_2] in course id [_3])', + $uname.':'.$udom,$usec,$env{'request.course.id'}). + ''); return; } my $mode = 'both'; @@ -2819,16 +2863,26 @@ sub processHandGrade { my $ctr = 0; while ($ctr < $ngrade) { my ($uname,$udom) = split(/:/,$env{'form.unamedom'.$ctr}); - my ($errorflag,$pts,$wgt) = &saveHandGrade($request,$symb,$uname,$udom,$ctr); + my ($errorflag,$pts,$wgt,$numhidden) = + &saveHandGrade($request,$symb,$uname,$udom,$ctr); if ($errorflag eq 'no_score') { $ctr++; next; } if ($errorflag eq 'not_allowed') { - $request->print("Not allowed to modify grades for $uname:$udom"); + $request->print( + '' + .&mt('Not allowed to modify grades for [_1]',"$uname:$udom") + .''); $ctr++; next; } + if ($numhidden) { + $request->print( + '' + .&mt('For [_1]: [quant,_2,transaction] hidden',"$uname:$udom",$numhidden) + .'
'); + } my $includemsg = $env{'form.includemsg'.$ctr}; my ($subject,$message,$msgstatus) = ('','',''); my $restitle = &Apache::lonnet::gettitle($symb); @@ -3060,9 +3114,14 @@ sub saveHandGrade { my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},$domain,$stuname); my @parts_graded; my %newrecord = (); - my ($pts,$wgt) = ('',''); + my ($pts,$wgt,$totchg) = ('','',0); my %aggregate = (); my $aggregateflag = 0; + if ($env{'form.HIDE'.$newflg}) { + my ($version,$parts) = split(/:/,$env{'form.HIDE'.$newflg},2); + my $numchgs = &makehidden($version,$parts,\%record,$symb,$domain,$stuname,1); + $totchg += $numchgs; + } my @parts = split(/:/,$env{'form.partlist'.$newflg}); foreach my $new_part (@parts) { #collaborator ($submi may vary for different parts @@ -3165,7 +3224,37 @@ sub saveHandGrade { &Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate, $cdom,$cnum); } - return ('',$pts,$wgt); + return ('',$pts,$wgt,$totchg); +} + +sub makehidden { + my ($version,$parts,$record,$symb,$domain,$stuname,$tolog) = @_; + return unless (ref($record) eq 'HASH'); + my %modified; + my $numchanged = 0; + if (exists($record->{$version.':keys'})) { + my $partsregexp = $parts; + $partsregexp =~ s/,/|/g; + foreach my $key (split(/\:/,$record->{$version.':keys'})) { + if ($key =~ /^resource\.(?:$partsregexp)\.([^\.]+)$/) { + my $item = $1; + unless (($item eq 'solved') || ($item =~ /^award(|msg|ed)$/)) { + $modified{$key} = $record->{$version.':'.$key}; + } + } elsif ($key =~ m{^(resource\.(?:$partsregexp)\.[^\.]+\.)(.+)$}) { + $modified{$1.'hidden'.$2} = $record->{$version.':'.$key}; + } elsif ($key =~ /^(ip|timestamp|host)$/) { + $modified{$key} = $record->{$version.':'.$key}; + } + } + if (keys(%modified)) { + if (&Apache::lonnet::putstore($env{'request.course.id'},$symb,$version,\%modified, + $domain,$stuname,$tolog) eq 'ok') { + $numchanged ++; + } + } + } + return $numchanged; } sub check_and_remove_from_queue { @@ -3642,7 +3731,7 @@ sub viewgrades { &Apache::lonnet::clear_EXT_cache_status(); my $result='

'.&mt('Manual Grading').'

'; - $result.='

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

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

'.&mt('Current Resource').': '.$env{'form.probTitle'}.'

'."\n"; #view individual student submission form - called using Javascript viewOneStudent $result.=&jscriptNform($symb); @@ -3705,8 +3794,9 @@ sub viewgrades { $partid.'" size="4" '.'onchange="javascript:writePoint(\''. $partid.'\','.$weight{$partid}.',\'textval\')" /> /'. $weight{$partid}.' '.&mt('(problem weight)').'
'.&mt('Grade Status').': -
+
ENDPICK } @@ -4412,7 +4503,7 @@ ENDPICK } # FIXME do a check for any duplicated user ids... # FIXME do a check for any invalid user ids?... - $request->print('
+ $request->print('

'."\n"); $request->print(&show_grading_menu_form($symb)); return ''; @@ -4746,9 +4837,12 @@ sub displayPage { &Apache::lonnet::clear_EXT_cache_status(); if (!&canview($usec)) { - $request->print(''.&mt('Unable to view requested student. ([_1])',$env{'form.student'}).''); - $request->print(&show_grading_menu_form($symb)); - return; + $request->print(''. + &mt('Unable to view requested student. ([_1])', + $env{'form.student'}). + ''); + $request->print(&show_grading_menu_form($symb)); + return; } my $result='

 '.$env{'form.title'}.'

'; $result.='

 '.&mt('Student: [_1]',&nameUserString(undef,$$fullname{$env{'form.student'}},$uname,$udom)). @@ -4862,9 +4956,11 @@ sub displayPage { } } elsif ($env{'form.lastSub'} eq 'all') { my $last = ($env{'form.lastSub'} eq 'last' ? 'last' : ''); + my $identifier = (&canmodify($usec)? $prob : ''); $studentTable.=&Apache::loncommon::get_previous_attempt($symbx,$uname,$udom, $env{'request.course.id'}, - '','.submission'); + '','.submission',undef, + $usec,$identifier); } if (&canmodify($usec)) { @@ -4975,11 +5071,12 @@ sub displaySubByDates { } else { $displaySub[0].=&mt('Trial: [_1]', $$record{"$where.$partid.tries"}); - if ($rndseed || $lastrndseed{$partid}) { + if (($rndseed ne '') && ($lastrndseed{$partid} ne '')) { if ($rndseed ne $lastrndseed{$partid}) { $newvariation = ' ('.&mt('New variation this try').')'; } } + $lastrndseed{$partid} = $rndseed; } my $responseType=($isTask ? 'Task' : $responseType->{$partid}->{$responseId}); @@ -5080,7 +5177,7 @@ sub updateGradeByPage { $iterator->next(); # skip the first BEGIN_MAP my $curRes = $iterator->next(); # for "current resource" - my ($depth,$question,$prob,$changeflag)= (1,1,1,0); + my ($depth,$question,$prob,$changeflag,$hideflag)= (1,1,1,0,0); while ($depth > 0) { if($curRes == $iterator->BEGIN_MAP) { $depth++; } if($curRes == $iterator->END_MAP) { $depth--; } @@ -5101,6 +5198,12 @@ sub updateGradeByPage { my @displayPts=(); my %aggregate = (); my $aggregateflag = 0; + if ($env{'form.HIDE'.$prob}) { + my %record = &Apache::lonnet::restore($symbx,$env{'request.course.id'},$udom,$uname); + my ($version,$parts) = split(/:/,$env{'form.HIDE'.$prob},2); + my $numchgs = &makehidden($version,$parts,\%record,$symbx,$udom,$uname,1); + $hideflag += $numchgs; + } foreach my $partid (@{$parts}) { my $newpts = $env{'form.GD_BOX'.$question.'_'.$partid}; my $oldpts = $env{'form.oldpts'.$question.'_'.$partid}; @@ -5192,8 +5295,11 @@ sub updateGradeByPage { $studentTable.=&show_grading_menu_form($env{'form.symb'}); my $grademsg=($changeflag == 0 ? &mt('No score was changed or updated.') : &mt('The scores were changed for [quant,_1,problem].', - $changeflag)); - $request->print($grademsg.$studentTable); + $changeflag).'
'); + my $hidemsg=($hideflag == 0 ? '' : + &mt('Submissions were marked "hidden" for [quant,_1,transaction].', + $hideflag).'
'); + $request->print($hidemsg.$grademsg.$studentTable); return ''; } @@ -5228,7 +5334,7 @@ like. Next each scanline is checked for any errors of either 'missing 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, +have no more than one letter picked), invalid or duplicated CODE, invalid student/employee ID If the CODE option is used that determines the randomization of the @@ -5842,8 +5948,17 @@ sub username_to_idmap { my ($classlist)= @_; my %idmap; foreach my $student (keys(%$classlist)) { - $idmap{$classlist->{$student}->[&Apache::loncoursedata::CL_ID]}= - $student; + my $id = $classlist->{$student}->[&Apache::loncoursedata::CL_ID]; + unless ($id eq '') { + if (!exists($idmap{$id})) { + $idmap{$id} = $student; + } else { + my $status = $classlist->{$student}->[&Apache::loncoursedata::CL_STATUS]; + if ($status eq 'Active') { + $idmap{$id} = $student; + } + } + } } return %idmap; } @@ -6587,7 +6702,11 @@ sub scantron_process_corrections { } } if ($err) { - $r->print("Unable to accept last correction, an error occurred :$errmsg:"); + $r->print( + '

' + .&mt('Unable to accept last correction, an error occurred: [_1]', + $errmsg) + .'

'); } else { &scantron_put_line($scanlines,$scan_data,$which,$line,$skip); &scantron_putfile($scanlines,$scan_data); @@ -6709,7 +6828,7 @@ sub scantron_warning_screen { $scantron_config{'CODEstart'} && $scantron_config{'CODElength'}) { $CODElist=$env{'form.scantron_CODElist'}; - if ($env{'form.scantron_CODElist'} eq '') { $CODElist='None'; } + if ($env{'form.scantron_CODElist'} eq '') { $CODElist=''.&mt('None').''; } $CODElist= '

'.&mt('List of CODES to validate against:').''. $env{'form.scantron_CODElist'}.'
@@ -6838,7 +6957,7 @@ sub scantron_validate_file { if (!$symb) {return '';} my $default_form_data=&defaultFormData($symb); - # do the detection of only doing skipped records first befroe we delete + # do the detection of only doing skipped records first before we delete # them when doing the corrections reset if ($env{'form.scantron_options_redo'} ne 'redo_skipped_ready') { &reset_skipping_status(); @@ -7726,7 +7845,7 @@ sub prompt_for_corrections { } } else { $responsenum = $question-1; - $first = $first_bubble_line{$responsenum} + 1; + $first = $first_bubble_line{$responsenum}; } $current_line = $first + 1 ; my @subans = split(/,/,$subdivided_bubble_lines{$responsenum}); @@ -8338,7 +8457,7 @@ sub hand_bubble_option { return &mt('The sequence to be graded contains response types which are handgraded.').'

'. &mt('If you have already graded these by bubbling sheets to indicate points awarded, [_1]what point value is assigned to a filled last bubble in each row?','
'). ' '.&mt('or').' '. - '

'; + '

'; } return; } @@ -8375,7 +8494,6 @@ sub scantron_process_students { } my $nav_error; my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0); - my (%grader_partids_by_symb,%grader_randomlists_by_symb,%ordered); if ($randomorder || $randompick) { $nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource); if ($nav_error) { @@ -8594,11 +8712,11 @@ SCANTRONFORM &Apache::loncommon::end_data_table_header_row()."\n". &Apache::loncommon::start_data_table_row(). ''. - ''. + ''. &Apache::loncommon::end_data_table_row(). &Apache::loncommon::start_data_table_row(). ''. - ''."\n". + ''."\n". &Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table().'

'); } else { @@ -8839,23 +8957,30 @@ sub scantron_upload_scantron_data_save { } my %coursedata=&Apache::lonnet::coursedescription($env{'form.domainid'}.'_'.$env{'form.courseid'}); my $uploadedfile; - $r->print('

'.&mt("Uploading file to [_1]",$coursedata{'description'}).'

'); + $r->print('

'.&mt("Uploading file to [_1]",$coursedata{'description'}).'

'); if (length($env{'form.upfile'}) < 2) { - $r->print(&mt('[_1]Error:[_2] The file you attempted to upload, [_3] contained no information. Please check that you entered the correct filename.','','',''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').'')); + $r->print( + &Apache::lonhtmlcommon::confirm_success( + &mt('The file: [_1] you attempted to upload contained no information. Please check that you entered the correct filename.', + ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').''),1)); } else { my $result = &Apache::lonnet::userfileupload('upfile','','scantron','','','', $env{'form.courseid'},$env{'form.domainid'}); if ($result =~ m{^/uploaded/}) { - $r->print(&mt('[_1]Success:[_2] Successfully uploaded [_3] bytes of data into location: [_4]', - '','',(length($env{'form.upfile'})-1), - ''.$result.'')); + $r->print( + &Apache::lonhtmlcommon::confirm_success(&mt('Upload successful')).'
'. + &mt('Uploaded [_1] bytes of data into location: [_2]', + (length($env{'form.upfile'})-1), + ''.$result.'')); ($uploadedfile) = ($result =~ m{/([^/]+)$}); $r->print(&validate_uploaded_scantron_file($env{'form.domainid'}, $env{'form.courseid'},$uploadedfile)); } else { - $r->print(&mt('[_1]Error:[_2] An error ([_3]) occurred when attempting to upload the file, [_4]', - '','',$result, + $r->print( + &Apache::lonhtmlcommon::confirm_success(&mt('Upload failed'),1).'
'. + &mt('An error ([_1]) occurred when attempting to upload the file: [_2]', + $result, ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').'')); } } @@ -8877,7 +9002,7 @@ sub validate_uploaded_scantron_file { my $output; if (@lines) { my (%counts,$max_match_format); - my ($max_match_count,$max_match_pct) = (0,0); + my ($found_match_count,$max_match_count,$max_match_pct) = (0,0,0); my $classlist = &Apache::loncoursedata::get_classlist($cdom,$cname); my %idmap = &username_to_idmap($classlist); foreach my $key (keys(%idmap)) { @@ -8920,6 +9045,7 @@ sub validate_uploaded_scantron_file { if (($max_match_format eq '') || ($percent_match > $max_match_pct)) { $max_match_pct = $percent_match; $max_match_format = $key; + $found_match_count = $counts{$key}{'found'}; $max_match_count = $counts{$key}{'total'}; } } @@ -8938,17 +9064,40 @@ sub validate_uploaded_scantron_file { } } my $showpct = sprintf("%.0f",$max_match_pct).'%'; - $output .= '
'.&mt('Comparison of student IDs in the uploaded file with the course roster found matches for [_1] of the [_2] entries in the file (for the format defined for [_3]).',''.$showpct.'',''.$max_match_count.'',$format_descs). - '
'.&mt('A low percentage of matches results from one of the following:').'
    '. - '
  • '.&mt('The file was uploaded to the wrong course').'
  • '. - '
  • '.&mt('The data are not in the format expected for the domain: [_1]', - ''.$cdom.'').'
  • '. - '
  • '.&mt('Students did not bubble their IDs, or mis-bubbled them').'
  • '. - '
  • '.&mt('The course roster is not up to date').'
  • '. - '
'; + $output .= '
'; + if ($found_match_count == $max_match_count) { + # 100% matching entries + $output .= &Apache::lonhtmlcommon::confirm_success( + &mt('Comparison of student IDs: [_1] matching ([quant,_2,entry,entries])', + ''.$showpct.'',$found_match_count)).'
'. + &mt('Comparison of student IDs in the uploaded file with'. + ' the course roster found matches for [_1] of the [_2] entries'. + ' in the file (for the format defined for [_3]).', + ''.$showpct.'',''.$max_match_count.'',$format_descs); + } else { + # Not all entries matching? -> Show warning and additional info + $output .= + &Apache::lonhtmlcommon::confirm_success( + &mt('Comparison of student IDs: [_1] matching ([_2]/[quant,_3,entry,entries])', + ''.$showpct.'',$found_match_count,$max_match_count).'
'. + &mt('Not all entries could be matched!'),1).'
'. + &mt('Comparison of student IDs in the uploaded file with'. + ' the course roster found matches for [_1] of the [_2] entries'. + ' in the file (for the format defined for [_3]).', + ''.$showpct.'',''.$max_match_count.'',$format_descs). + '

'. + &mt('A low percentage of matches results from one of the following:'). + '

    '. + '
  • '.&mt('The file was uploaded to the wrong course.').'
  • '. + '
  • '.&mt('The data is not in the format expected for the domain: [_1]', + ''.$cdom.'').'
  • '. + '
  • '.&mt('Students did not bubble their IDs, or mis-bubbled them').'
  • '. + '
  • '.&mt('The course roster is not up to date.').'
  • '. + '
'; + } } } else { - $output = ''.&mt('Uploaded file contained no data').''; + $output = '

'.&mt('Uploaded file contained no data').'

'; } return $output; } @@ -8985,7 +9134,7 @@ sub scantron_download_scantron_data { &Apache::lonnet::allowuploaded('/adm/grades',$skipped); $r->print('

- '.&mt('[_1]Original[_2] file as uploaded by the scantron office.', + '.&mt('[_1]Original[_2] file as uploaded by bubblesheet scanning office.', '','').'

@@ -9049,7 +9198,7 @@ sub checkscantron_results { my $count=&get_todo_count($scanlines,$scan_data); my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,$count); - my ($username,$domain,$started,%ordered); + my ($username,$domain,$started); &scantron_get_maxbubble(\$nav_error,\%scantron_config); # Need the bubble lines array to parse. if ($nav_error) { $r->print(&navmap_errormsg()); @@ -9161,14 +9310,14 @@ sub checkscantron_results { '

'."\n". ''."\n". ''."\n". -''."\n"; +''."\n"; $passed ++; } else { my $css_class = ($failed % 2)?'LC_odd_row':'LC_even_row'; $badstudents .= ''."\n". ''."\n". ''."\n". -''."\n". +''."\n". ''."\n"; $failed ++; } @@ -9941,16 +10090,18 @@ sub process_clicker_file { $number++; } $result.="

\n"; - if ($number==0) { - $result.=''.&mt('No IDs found to determine correct answer').''; - return $result.&show_grading_menu_form($symb); - } + if ($number==0) { + $result .= + &Apache::lonhtmlcommon::confirm_success( + &mt('No IDs found to determine correct answer'),1); + return $result,.&show_grading_menu_form($symb); + } } if (length($env{'form.upfile'}) < 2) { - $result.=&mt('[_1] Error: [_2] The file you attempted to upload, [_3] contained no information. Please check that you entered the correct filename.', - '', - '', - ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').''); + $result .= + &Apache::lonhtmlcommon::confirm_success( + &mt('The file: [_1] you attempted to upload contained no information. Please check that you entered the correct filename.', + ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').''),1); return $result.&show_grading_menu_form($symb); } @@ -10508,11 +10659,11 @@ At least the logic that drives this has ssi_with_retries - Does the server side include of a resource. if the ssi call returns an error we'll retry it up to the number of times requested by the caller. - If we still have a proble, no text is appended to the + If we still have a problem, no text is appended to the output and we set some global variables. to indicate to the caller an SSI error occurred. All of this is supposed to deal with the issues described - in LonCAPA BZ 5631 see: + in LON-CAPA BZ 5631 see: http://bugs.lon-capa.org/show_bug.cgi?id=5631 by informing the user that this happened.
'.&mt('Sequence to be Graded:').''.$title.'
'.&mt('Bubblesheet').''.$studentdata.''.$studentdata.''.&mt('Stored submissions').''.$studentrecord.''.$studentrecord.' '.&mt('Bubblesheet').''.$showscandata.''.$last.''.$pid.'
Submissions'.$showrecord.'
'.&mt('Submissions').''.$showrecord.'
'.&mt('Bubblesheet').''.$scandata{$pid}.''.$last.''.$pid.'
Submissions'.$record{$pid}.''.&mt('Submissions').''.$record{$pid}.'