--- loncom/homework/grades.pm 2009/03/19 21:00:42 1.560 +++ loncom/homework/grades.pm 2009/05/04 22:41:37 1.567 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.560 2009/03/19 21:00:42 raeburn Exp $ +# $Id: grades.pm,v 1.567 2009/05/04 22:41:37 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -889,16 +889,17 @@ LISTJAVASCRIPT my $gradeTable='<form action="/adm/grades" method="post" name="gradesub">'. "\n".$table; - $gradeTable .= - ' <b>'.&mt('View Problem Text').': </b>'. - '<label><input type="radio" name="vProb" value="no" checked="checked" /> '.&mt('no').' </label>'."\n". - '<label><input type="radio" name="vProb" value="yes" /> '.&mt('one student').' </label>'."\n". - '<label><input type="radio" name="vProb" value="all" /> '.&mt('all students').' </label><br />'."\n"; - $gradeTable .= - ' <b>'.&mt('View Answer').': </b>'. - '<label><input type="radio" name="vAns" value="no" /> '.&mt('no').' </label>'."\n". - '<label><input type="radio" name="vAns" value="yes" /> '.&mt('one student').' </label>'."\n". - '<label><input type="radio" name="vAns" value="all" checked="checked" /> '.&mt('all students').' </label><br />'."\n"; + $gradeTable .= &Apache::lonhtmlcommon::start_pick_box(); + $gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('View Problem Text')) + .'<label><input type="radio" name="vProb" value="no" checked="checked" /> '.&mt('no').' </label>'."\n" + .'<label><input type="radio" name="vProb" value="yes" /> '.&mt('one student').' </label>'."\n" + .'<label><input type="radio" name="vProb" value="all" /> '.&mt('all students').' </label><br />'."\n" + .&Apache::lonhtmlcommon::row_closure(); + $gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('View Answer')) + .'<label><input type="radio" name="vAns" value="no" /> '.&mt('no').' </label>'."\n" + .'<label><input type="radio" name="vAns" value="yes" /> '.&mt('one student').' </label>'."\n" + .'<label><input type="radio" name="vAns" value="all" checked="checked" /> '.&mt('all students').' </label><br />'."\n" + .&Apache::lonhtmlcommon::row_closure(); my $submission_options; if ($env{'form.handgrade'} eq 'yes' && scalar(@$partlist) > 1) { @@ -913,19 +914,20 @@ LISTJAVASCRIPT '<label><input type="radio" name="lastSub" value="last" /> '.&mt('last submission & parts info').' </label>'."\n". '<label><input type="radio" name="lastSub" value="datesub" /> '.&mt('by dates and submissions').' </label>'."\n". '<label><input type="radio" name="lastSub" value="all" /> '.&mt('all details').'</label>'; - $gradeTable .= - ' <b>'.&mt('Submissions').': </b>'.$submission_options.'<br />'."\n"; + $gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('Submissions')) + .$submission_options + .&Apache::lonhtmlcommon::row_closure(); + + $gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('Grading Increments')) + .'<select name="increment">' + .'<option value="1">'.&mt('Whole Points').'</option>' + .'<option value=".5">'.&mt('Half Points').'</option>' + .'<option value=".25">'.&mt('Quarter Points').'</option>' + .'<option value=".1">'.&mt('Tenths of a Point').'</option>' + .'</select>' + .&Apache::lonhtmlcommon::row_closure(); $gradeTable .= - ' <b>'.&mt('Grading Increments').': </b>'. - '<select name="increment">'. - '<option value="1">'.&mt('Whole Points').'</option>'. - '<option value=".5">'.&mt('Half Points').'</option>'. - '<option value=".25">'.&mt('Quarter Points').'</option>'. - '<option value=".1">'.&mt('Tenths of a Point').'</option>'. - '</select>'; - - $gradeTable .= &build_section_inputs(). '<input type="hidden" name="submitonly" value="'.$submitonly.'" />'."\n". '<input type="hidden" name="handgrade" value="'.$env{'form.handgrade'}.'" /><br />'."\n". @@ -936,14 +938,23 @@ LISTJAVASCRIPT '<input type="hidden" name="saveStatusOld" value="'.$saveStatus.'" />'."\n"; if (exists($env{'form.gradingMenu'}) && exists($env{'form.Status'})) { - $gradeTable.='<input type="hidden" name="Status" value="'.$stu_status.'" />'."\n"; + $gradeTable .= '<input type="hidden" name="Status" value="'.$stu_status.'" />'."\n"; } else { - $gradeTable.=&mt('<b>Student Status:</b> [_1]', - &Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,'javascript:reLoadList(this.form);')).'<br />'; + $gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('Student Status')) + .&Apache::lonhtmlcommon::StatusOptions( + $saveStatus,undef,1,'javascript:reLoadList(this.form);') + .&Apache::lonhtmlcommon::row_closure(); } - $gradeTable.=&mt('To '.lc($viewgrade)." a submission or a group of submissions, click on the check box(es) next to the student's name(s). Then click on the Next button.").'<br />'."\n". - '<input type="hidden" name="command" value="processGroup" />'."\n"; + $gradeTable .= &Apache::lonhtmlcommon::row_title(&mt('Check For Plagiarism')) + .'<input type="checkbox" name="checkPlag" checked="checked" />' + .&Apache::lonhtmlcommon::row_closure(1) + .&Apache::lonhtmlcommon::end_pick_box(); + + $gradeTable .= '<p>' + .&mt('To '.lc($viewgrade)." a submission or a group of submissions, click on the check box(es) next to the student's name(s). Then click on the Next button.")."\n" + .'<input type="hidden" name="command" value="processGroup" />' + .'</p>'; # checkall buttons $gradeTable.=&check_script('gradesub', 'stuinfo'); @@ -951,7 +962,6 @@ LISTJAVASCRIPT 'onClick="javascript:checkSelect(this.form.stuinfo);" '."\n". 'value="'.&mt('Next').' →" /> <br />'."\n"; $gradeTable.=&check_buttons(); - $gradeTable.='<label><input type="checkbox" name="checkPlag" checked="checked" />'.&mt('Check For Plagiarism').'</label>'; my ($classlist, undef, $fullname) = &getclasslist($getsec,'1',$getgroup); $gradeTable.= &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(); @@ -1034,7 +1044,7 @@ LISTJAVASCRIPT $gradeTable.= &Apache::loncommon::start_data_table_row(); } $gradeTable.='<td align="right">'.$ctr.' </td>'. - '<td align="center"><label><input type=checkbox name="stuinfo" value="'. + '<td align="center"><label><input type="checkbox" name="stuinfo" value="'. $student.':'.$$fullname{$student}.':::SECTION'.$section. ') " /> </label></td>'."\n".'<td>'. &nameUserString(undef,$$fullname{$student},$uname,$udom). @@ -1541,8 +1551,8 @@ INNERJS pDoc.write("<input value=\\""+usrctr+"\\" name=\\"usrctr\\" type=\\"hidden\\">"); pDoc.write("<h3><span class=\\"LC_info\\"> Compose Message for \"+fullname+\"<\\/span><\\/h3><br /><br />"); - pDoc.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">"); - pDoc.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">"); + pDoc.write('<table border="0" width="100%"><tr><td bgcolor="#777777">'); + pDoc.write('<table border="0" width="100%"><tr bgcolor="#DDFFFF">'); pDoc.write("<td><b>Type<\\/b><\\/td><td><b>Include<\\/b><\\/td><td><b>Message<\\/td><\\/tr>"); } function displaySubject(msg,shwsel) { @@ -1626,8 +1636,8 @@ INNERJS hDoc.write("<form action=\\"inactive\\" name=\\"hlCenter\\">"); hDoc.write("<h3><span class=\\"LC_info\\"> Keyword Highlight Options<\\/span><\\/h3><br /><br />"); - hDoc.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">"); - hDoc.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">"); + hDoc.write('<table border="0" width="100%"><tr><td bgcolor="#777777">'); + hDoc.write('<table border="0" width="100%"><tr bgcolor="#DDFFFF">'); hDoc.write("<td><b>Text Color<\\/b><\\/td><td><b>Font Size<\\/b><\\/td><td><b>Font Style<\\/td><\\/tr>"); } @@ -2152,7 +2162,7 @@ KEYWORDS foreach my $file (@$files) { $file_counter++; &Apache::lonnet::allowuploaded('/adm/grades',$file); - $lastsubonly.='<br /><a href="'.$file.'?rawmode=1" target="lonGRDs"><img src="'.&Apache::loncommon::icon($file).'" border=0"> '.$file.'</a>'; + $lastsubonly.='<br /><a href="'.$file.'?rawmode=1" target="lonGRDs"><img src="'.&Apache::loncommon::icon($file).'" border="0" /> '.$file.'</a>'; } $lastsubonly.='<br />'; } @@ -7691,12 +7701,14 @@ sub grade_student_bubbles { sub scantron_upload_scantron_data { my ($r)=@_; - $r->print(&Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'})); + my $dom = $env{'request.role.domain'}; + my $domdesc = &Apache::lonnet::domain($dom,'description'); + $r->print(&Apache::loncommon::coursebrowser_javascript($dom)); my $select_link=&Apache::loncommon::selectcourse_link('rules','courseid', 'domainid', - 'coursename'); - my $domsel=&Apache::loncommon::select_dom_form($env{'request.role.domain'}, - 'domainid'); + 'coursename',$dom); + my $syllabuslink = '<a href="javascript:ToSyllabus();">'.&mt('Syllabus').'</a>'. + (' 'x2).&mt('(shows course personnel)'); my $default_form_data=&defaultFormData(&get_symb($r,1)); $r->print(' <script type="text/javascript" language="javascript"> @@ -7705,23 +7717,48 @@ sub scantron_upload_scantron_data { alert("'.&mt('Please use the browse button to select a file from your local directory.').'"); return false; } + if (formname.courseid.value == "") { + alert("'.&mt('Please use the \"Select Course\" link to open a separate window where you can search for a course to which a file can be uploaded.').'"); + return false; + } formname.submit(); } + + function ToSyllabus() { + var cdom = '."'$dom'".'; + var cnum = document.rules.courseid.value; + if (cdom == "" || cdom == null) { + return; + } + if (cnum == "" || cnum == null) { + return; + } + syllwin=window.open("/public/"+cdom+"/"+cnum+"/syllabus","LONCAPASyllabus", + "height=350,width=350,scrollbars=yes,menubar=no"); + return; + } + </script> +<h3>'.&mt('Send scanned bubblesheet data to a course').'</h3> + <form enctype="multipart/form-data" action="/adm/grades" name="rules" method="post"> -'.$default_form_data.' -<table> -<tr><td>'.$select_link.' </td></tr> -<tr><td>'.&mt('Course ID:').' </td> - <td><input name="courseid" type="text" /> </td></tr> -<tr><td>'.&mt('Course Name:').' </td> - <td><input name="coursename" type="text" /> </td></tr> -<tr><td>'.&mt('Domain:').' </td> - <td>'.$domsel.' </td></tr> -<tr><td>'.&mt('File to upload:').'</td> - <td><input type="file" name="upfile" size="50" /></td></tr> -</table> +'.$default_form_data. + &Apache::lonhtmlcommon::start_pick_box(). + &Apache::lonhtmlcommon::row_title(&mt('Course ID')). + '<input name="courseid" type="text" size="30" />'.$select_link. + &Apache::lonhtmlcommon::row_closure(). + &Apache::lonhtmlcommon::row_title(&mt('Course Name')). + '<input name="coursename" type="text" size="30" />'.$syllabuslink. + &Apache::lonhtmlcommon::row_closure(). + &Apache::lonhtmlcommon::row_title(&mt('Domain')). + '<input name="domainid" type="hidden" />'.$domdesc. + &Apache::lonhtmlcommon::row_closure(). + &Apache::lonhtmlcommon::row_title(&mt('File to upload')). + '<input type="file" name="upfile" size="50" />'. + &Apache::lonhtmlcommon::row_closure(1). + &Apache::lonhtmlcommon::end_pick_box().'<br /> + <input name="command" value="scantronupload_save" type="hidden" /> <input type="button" onClick="javascript:checkUpload(this.form);" value="'.&mt('Upload Scantron Data').'" /> </form> @@ -7750,7 +7787,7 @@ sub scantron_upload_scantron_data_save { return ''; } my %coursedata=&Apache::lonnet::coursedescription($env{'form.domainid'}.'_'.$env{'form.courseid'}); - $r->print(&mt("Doing upload to [_1]",$coursedata{'description'})." <br />"); + $r->print('<h3>'.&mt("Uploading file to [_1]",$coursedata{'description'}).'</h3>'); my $fname=$env{'form.upfile.filename'}; #FIXME #copied from lonnet::userfileupload() @@ -7772,14 +7809,15 @@ sub scantron_upload_scantron_data_save { } else { my $result=&Apache::lonnet::finishuserfileupload($env{'form.courseid'},$env{'form.domainid'},'upfile',$fname); if ($result =~ m|^/uploaded/|) { - $r->print(&mt("<span class=\"LC_success\">Success:</span> Successfully uploaded [_1] bytes of data into location [_2]", - (length($env{'form.upfile'})-1), - '<span class="LC_filename">'.$result."</span>")); + $r->print(&mt('[_1]Success:[_2] Successfully uploaded [_3] bytes of data into location: [_4]', + '<span class="LC_success">','</span>',(length($env{'form.upfile'})-1), + '<span class="LC_filename">'.$result.'</span>')); + $r->print(&validate_uploaded_scantron_file($env{'form.domainid'}, + $env{'form.courseid'},$fname)); } else { - $r->print(&mt("<span class=\"LC_error\">Error:</span> An error ([_1]) occurred when attempting to upload the file, [_2]", - $result, + $r->print(&mt('[_1]Error:[_2] An error ([_3]) occurred when attempting to upload the file, [_4]', + '<span class="LC_error">','</span>',$result, '<span class="LC_filename">'.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"')."</span>")); - } } if ($symb) { @@ -7790,6 +7828,92 @@ sub scantron_upload_scantron_data_save { return ''; } +sub validate_uploaded_scantron_file { + my ($cdom,$cname,$fname) = @_; + my $scanlines=&Apache::lonnet::getfile('/uploaded/'.$cdom.'/'.$cname.'/'.$fname); + my @lines; + if ($scanlines ne '-1') { + @lines=split("\n",$scanlines,-1); + } + my $output; + if (@lines) { + my (%counts,$max_match_format); + my ($max_match_count,$max_match_pct) = (0,0); + my $classlist = &Apache::loncoursedata::get_classlist($cdom,$cname); + my %idmap = &username_to_idmap($classlist); + foreach my $key (keys(%idmap)) { + my $lckey = lc($key); + $idmap{$lckey} = $idmap{$key}; + } + my %unique_formats; + my @formatlines = &get_scantronformat_file(); + foreach my $line (@formatlines) { + chomp($line); + my @config = split(/:/,$line); + my $idstart = $config[5]; + my $idlength = $config[6]; + if (($idstart ne '') && ($idlength > 0)) { + if (ref($unique_formats{$idstart.':'.$idlength}) eq 'ARRAY') { + push(@{$unique_formats{$idstart.':'.$idlength}},$config[0].':'.$config[1]); + } else { + $unique_formats{$idstart.':'.$idlength} = [$config[0].':'.$config[1]]; + } + } + } + foreach my $key (keys(%unique_formats)) { + my ($idstart,$idlength) = split(':',$key); + %{$counts{$key}} = ( + 'found' => 0, + 'total' => 0, + ); + foreach my $line (@lines) { + next if ($line =~ /^#/); + next if ($line =~ /^[\s\cz]*$/); + my $id = substr($line,$idstart-1,$idlength); + $id = lc($id); + if (exists($idmap{$id})) { + $counts{$key}{'found'} ++; + } + $counts{$key}{'total'} ++; + } + if ($counts{$key}{'total'}) { + my $percent_match = (100*$counts{$key}{'found'})/($counts{$key}{'total'}); + if (($max_match_format eq '') || ($percent_match > $max_match_pct)) { + $max_match_pct = $percent_match; + $max_match_format = $key; + $max_match_count = $counts{$key}{'total'}; + } + } + } + if (ref($unique_formats{$max_match_format}) eq 'ARRAY') { + my $format_descs; + my $numwithformat = @{$unique_formats{$max_match_format}}; + for (my $i=0; $i<$numwithformat; $i++) { + my ($name,$desc) = split(':',$unique_formats{$max_match_format}[$i]); + if ($i<$numwithformat-2) { + $format_descs .= '"<i>'.$desc.'</i>", '; + } elsif ($i==$numwithformat-2) { + $format_descs .= '"<i>'.$desc.'</i>" '.&mt('and').' '; + } elsif ($i==$numwithformat-1) { + $format_descs .= '"<i>'.$desc.'</i>"'; + } + } + my $showpct = sprintf("%.0f",$max_match_pct).'%'; + $output .= '<br />'.&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]).','<b>'.$showpct.'</b>','<b>'.$max_match_count.'</b>',$format_descs). + '<br />'.&mt('A low percentage of matches results from one of the following:').'<ul>'. + '<li>'.&mt('The file was uploaded to the wrong course').'</li>'. + '<li>'.&mt('The data are not in the format expected for the domain: [_1]', + '<i>'.$cdom.'</i>').'</li>'. + '<li>'.&mt('Students did not bubble their IDs, or mis-bubbled them').'</li>'. + '<li>'.&mt('The course roster is not up to date').'</li>'. + '</ul>'; + } + } else { + $output = '<span class="LC_warning">'.&mt('Uploaded file contained no data').'</span>'; + } + return $output; +} + sub valid_file { my ($requested_file)=@_; foreach my $filename (sort(&scantron_filenames())) { @@ -9092,7 +9216,7 @@ sub handler { } elsif ($command eq 'checksubmissions' && $perm{'vgr'}) { $request->print(&checkscantron_results($request)); } elsif ($command) { - $request->print("Access Denied ($command)"); + $request->print('<p class="LC_error">'.&mt('Access Denied ([_1])',$command).'</p>'); } } if ($ssi_error) {