--- loncom/homework/grades.pm	2003/11/12 21:37:07	1.159
+++ loncom/homework/grades.pm	2004/02/09 22:16:32	1.173
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.159 2003/11/12 21:37:07 albertel Exp $
+# $Id: grades.pm,v 1.173 2004/02/09 22:16:32 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -48,6 +48,7 @@ use Apache::lonhomework;
 use Apache::loncoursedata;
 use Apache::lonmsg qw(:user_normal_msg);
 use Apache::Constants qw(:common);
+use Apache::lonlocal;
 use String::Similarity;
 
 my %oldessays=();
@@ -88,10 +89,15 @@ sub getpartlist {
 
 # --- Get the symbolic name of a problem and the url
 sub get_symb_and_url {
-    my ($request) = @_;
+    my ($request,$silent) = @_;
     (my $url=$ENV{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
     my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
-    if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
+    if ($symb eq '') { 
+	if (!$silent) {
+	    $request->print("Unable to handle ambiguous references:$url:.");
+	    return ();
+	}
+    }
     return ($symb,$url);
 }
 
@@ -168,7 +174,7 @@ sub showResourceInfo {
     my $col=3;
     if ($checkboxes) { $col=4; }
     my $result ='<table border="0">'.
-	'<tr><td colspan="'.$col.'"><font size="+1"><b>Current Resource: </b>'.
+	'<tr><td colspan="'.$col.'"><font size="+1"><b>'.&mt('Current Resource').': </b>'.
 	$probTitle.'</font></td></tr>'."\n";
     my ($partlist,$handgrade,$responseType) = &response_type($url);
     my %resptype = ();
@@ -290,7 +296,8 @@ 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.
 	}
-	return '<br /><br /><blockquote><pre>'.&keywords_highlight($answer).'</pre></blockquote>';
+	$answer =~ s-\n-<br />-g;
+	return '<br /><br /><blockquote><tt>'.&keywords_highlight($answer).'</tt></blockquote>';
     }
     return $answer;
 }
@@ -678,10 +685,11 @@ LISTJAVASCRIPT
 	if ($ENV{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {
 	    (%status) =&student_gradeStatus($url,$symb,$udom,$uname,$partlist);
 	    my $submitted = 0;
-	    my $graded = 1;
+	    my $graded = 0;
 	    foreach (keys(%status)) {
 		$submitted = 1 if ($status{$_} ne 'nothing');
-		$graded = 0 if ($status{$_} =~ /^correct/);
+		$graded = 1 if ($status{$_} !~ /^correct/);
+
 		my ($foo,$partid,$foo1) = split(/\./,$_);
 		if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
 		    $submitted = 0;
@@ -735,9 +743,12 @@ LISTJAVASCRIPT
 	if ($num_students eq 0) {
 	    $gradeTable='<br />&nbsp;<font color="red">There are no students currently enrolled.</font>';
 	} else {
+	    my $submissions='submissions';
+	    if ($submitonly eq 'incorrect') { $submissions = 'incorrect submissions'; }
+	    if ($submitonly eq 'graded'   ) { $submissions = 'ungraded submissions'; }
 	    $gradeTable='<br />&nbsp;<font color="red">'.
-		'No submissions found for this resource for any students. ('.$num_students.
-		' checked for submissions)</font><br />';
+		'No '.$submissions.' found for this resource for any students. ('.$num_students.
+		' students checked for '.$submissions.')</font><br />';
 	}
     } elsif ($ctr == 1) {
 	$gradeTable =~ s/type=checkbox/type=checkbox checked/;
@@ -1375,7 +1386,9 @@ sub submission {
 	return;
     }
 
-    $ENV{'form.lastSub'} = ($ENV{'form.lastSub'} eq '' ? 'datesub' : $ENV{'form.lastSub'});
+    if (!$ENV{'form.lastSub'}) { $ENV{'form.lastSub'} = 'datesub'; }
+    if (!$ENV{'form.vProb'}) { $ENV{'form.vProb'} = 'yes'; }
+    if (!$ENV{'form.vAns'}) { $ENV{'form.vAns'} = 'yes'; }
     my $last = ($ENV{'form.lastSub'} eq 'last' ? 'last' : '');
     my $checkIcon = '<img src="'.$request->dir_config('lonIconsURL').
 	'/check.gif" height="16" border="0" />';
@@ -1644,7 +1657,7 @@ KEYWORDS
 			    $partid.'</b> <font color="#999999">( ID '.$respid.
 			    ' )</font>&nbsp; &nbsp;';
 			if ($record{"resource.$partid.$respid.uploadedurl"}) {
-			    $lastsubonly.='<a href="'.&Apache::lonnet::tokenwrapper($record{"resource.$partid.$respid.uploadedurl"}).'"><img src="/adm/lonIcons/unknown.gif" border=0"> File uploaded by student</a> <font color="red" size="1">Like all files provided by users, this file may contain virusses</font><br />';
+			    $lastsubonly.='<a href="'.&Apache::lonnet::tokenwrapper($record{"resource.$partid.$respid.uploadedurl"}).'" target="lonGRDs"><img src="/adm/lonIcons/unknown.gif" border=0"> File uploaded by student</a> <font color="red" size="1">Like all files provided by users, this file may contain virusses</font><br />';
 			}
 			$lastsubonly.='<b>Submitted Answer: </b>'.
 			    &cleanRecord($subval,$responsetype,$symb,$partid,
@@ -1674,10 +1687,11 @@ KEYWORDS
 	my $toGrade.='<input type="button" value="Grade Student" '.
 	    'onClick="javascript:checksubmit(this.form,\'Grade Student\',\''
 	    .$counter.'\');" TARGET=_self> &nbsp;'."\n" if (&canmodify($usec));
-	$toGrade.='</td></tr></table></td></tr></table></form>'."\n";
-	$toGrade.=&show_grading_menu_form($symb,$url) 
-	    if (($ENV{'form.command'} eq 'submission') || 
-		($ENV{'form.command'} eq 'processGroup' && $counter == $total));
+	$toGrade.='</td></tr></table></td></tr></table>'."\n";
+	if (($ENV{'form.command'} eq 'submission') || 
+	    ($ENV{'form.command'} eq 'processGroup' && $counter == $total)) {
+	    $toGrade.='</form>'.&show_grading_menu_form($symb,$url) 
+	}
 	$request = print($toGrade);
 	return;
     }
@@ -2243,8 +2257,14 @@ sub viewgrades {
     &viewgrades_js($request);
 
     my ($symb,$url) = ($ENV{'form.symb'},$ENV{'form.url'}); 
-    my $result='<h3><font color="#339933">Manual Grading</font></h3>';
+    #need to make sure we have the correct data for later EXT calls, 
+    #thus invalidate the cache
+    &Apache::lonnet::devalidatecourseresdata(
+                 $ENV{'course.'.$ENV{'request.course.id'}.'.num'},
+                 $ENV{'course.'.$ENV{'request.course.id'}.'.domain'});
+    &Apache::lonnet::clear_EXT_cache_status();
 
+    my $result='<h3><font color="#339933">'.&mt('Manual Grading').'</font></h3>';
     $result.='<font size=+1><b>Current Resource: </b>'.$ENV{'form.probTitle'}.'</font>'."\n";
 
     #view individual student submission form - called using Javascript viewOneStudent
@@ -2840,7 +2860,9 @@ sub csvuploadassign {
     foreach my $grade (@gradedata) {
 	my %entries=&Apache::loncommon::record_sep($grade);
 	my $username=$entries{$fields{'username'}};
+	$username=~s/\s//g;
 	my $domain=$entries{$fields{'domain'}};
+	$domain=~s/\s//g;
 	if (!exists($$classlist{"$username:$domain"})) {
 	    push(@skipped,"$username:$domain");
 	    next;
@@ -3025,6 +3047,14 @@ sub displayPage {
     my ($classlist,undef,$fullname) = &getclasslist($getsec,'1');
     my ($uname,$udom) = split(/:/,$ENV{'form.student'});
     my $usec=$classlist->{$ENV{'form.student'}}[5];
+
+    #need to make sure we have the correct data for later EXT calls, 
+    #thus invalidate the cache
+    &Apache::lonnet::devalidatecourseresdata(
+                 $ENV{'course.'.$ENV{'request.course.id'}.'.num'},
+                 $ENV{'course.'.$ENV{'request.course.id'}.'.domain'});
+    &Apache::lonnet::clear_EXT_cache_status();
+
     if (!&canview($usec)) {
 	$request->print('<font color="red">Unable to view requested student.('.$ENV{'form.student'}.')</font>');
 	$request->print(&show_grading_menu_form($symb,$url));
@@ -3196,7 +3226,7 @@ sub displaySubByDates {
 	    }
 	    if (exists $$record{"$version:resource.$partid.regrader"}) {
 		$displaySub[2].=$$record{"$version:resource.$partid.regrader"}.
-		    ' (<b>Part:</b> '.$partid.')';
+		    ' (<b>'.&mt('Part').':</b> '.$partid.')';
 	    }
 	}
 	# needed because old essay regrader has not parts info
@@ -3377,7 +3407,7 @@ sub scantron_uploads {
     my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
     my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};
     my @files=&Apache::lonnet::dirlist('userfiles',$cdom,$cname,
-				    &Apache::locommon::propath($cdom,$cname));
+				    &Apache::loncommon::propath($cdom,$cname));
     foreach my $filename (@files) {
 	($filename)=split(/&/,$filename);
 	if ($filename!~/^scantron_orig_/) { next ; }
@@ -3414,12 +3444,12 @@ sub scantron_selectphase {
     #FIXME allow instructor to be able to download the scantron file
     # and to upload it,
     $result.= <<SCANTRONFORM;
-<form method="post" enctype="multipart/form-data" action="/adm/grades" name="scantro_process">
-  <input type="hidden" name="command" value="scantron_validate" />
-  $default_form_data
-  <table width="100%" border="0">
+    <table width="100%" border="0">
     <tr>
       <td bgcolor="#777777">
+       <form method="post" enctype="multipart/form-data" action="/adm/grades" name="scantro_process">
+       <input type="hidden" name="command" value="scantron_validate" />
+        $default_form_data
         <table width="100%" border="0">
           <tr bgcolor="#e6ffff">
             <td>
@@ -3448,16 +3478,52 @@ sub scantron_selectphase {
                 <input type="text" name="scantron_maxbubble" />
 	    </td>
           </tr>
+          <tr bgcolor="#ffffe6">
+            <td>
+              <input type="submit" value="Validate Scantron Records" />
+            </td>
+          </tr>
+        </table>
+       </form>
+      </td>
+    </tr>
+SCANTRONFORM
+   
+    $r->print($result);
+
+    if (&Apache::lonnet::allowed('usc',$ENV{'request.role.domain'}) ||
+        &Apache::lonnet::allowed('usc',$ENV{'request.course.id'})) {
+
+        $r->print(<<SCANTRONFORM);
+    <tr>
+      <td bgcolor="#777777">
+        <table width="100%" border="0">
+          <tr bgcolor="#e6ffff">
+            <td>
+              Specify a Scantron data file to upload.
+            </td>
+          </tr>
+          <tr bgcolor="#ffffe6">
+            <td>
+SCANTRONFORM
+        &scantron_upload_scantron_data($r);
+
+        $r->print(<<SCANTRONFORM);
+            </td>
+          </tr>
         </table>
       </td>
     </tr>
+SCANTRONFORM
+    }
+
+    $r->print(<<SCANTRONFORM);
   </table>
-  <input type="submit" value="Validate Scantron Records" />
 </form>
 $grading_menu_button
 SCANTRONFORM
 
-    return $result;
+    return
 }
 
 sub get_scantron_config {
@@ -3632,18 +3698,6 @@ sub scantron_filter {
     return 0;
 }
 
-#FIXME I think I am doing this in the wrong order, I think it would be
-#better to make a several passes analyzing all of the lines in the
-#file for common errors wrong/invalid PID/username duplicated
-#PID/username, missing bubbles, double bubbles, missing/invalid CODE
-#and then get the instructor to fix all of these errors, then grade
-#the corrected one, I'll still need to catch error conditions, but
-#maybe most will taken care even before we start
-
-sub scantron_validate_file {
-    my ($r) = @_;
-}
-
 sub scantron_process_corrections {
     my ($r) = @_;
     my %scantron_config=&get_scantron_config($ENV{'form.scantron_format'});
@@ -3753,10 +3807,6 @@ sub scantron_getfile {
     my $lines;
     $lines=&Apache::lonnet::getfile('/uploaded/'.$cdom.'/'.$cname.'/'.
 		       'scantron_orig_'.$ENV{'form.scantron_selectfile'});
-    if ($lines eq '-1') {
-	#FIXME need to actually replicate file to course space
-	#FIXME when replicating strip CRLF to LF or CR to LF
-    }
     my %scanlines;
     $scanlines{'orig'}=[(split("\n",$lines,-1))];
     my $temp=$scanlines{'orig'};
@@ -3896,7 +3946,7 @@ sub scantron_get_correction {
 #to show both the current line and the previous one and allow skipping
 #the previous one or the current one
 
-    $r->print("<p>An error was detected ($error) ");
+    $r->print("<p><b>An error was detected ($error)</b>");
     if ( defined($$scan_record{'scantron.PaperID'}) ) {
 	$r->print(" for PaperID <tt>".
 		  $$scan_record{'scantron.PaperID'}."</tt> \n");
@@ -4073,7 +4123,6 @@ SCANTRONFORM
  	($uname,$udom)=('','');
  	$i++;
  	my $line=&scantron_get_line($scanlines,$i);
-#	$r->print('<pre>line is'.$line.'</pre>');
  	if ($line=~/^[\s\cz]*$/) { next; }
  	my $scan_record=&scantron_parse_scanline($line,$i,\%scantron_config,
  						 $scan_data);
@@ -4088,15 +4137,11 @@ SCANTRONFORM
  				'Student '.$uname.' has multiple sheets',2);
  	    next;
  	}
-#	$r->print('<pre>doing studnet'.$uname.'</pre>');
   	($uname,$udom)=split(/:/,$uname);
   	&Apache::lonnet::delenv('form.counter');
   	&Apache::lonnet::appenv(%$scan_record);
-#    &Apache::lonhomework::showhash(%ENV);
-#    $Apache::lonxml::debug=1;
-#	&Apache::lonxml::debug("line is $line");
-  	
-	    my $i=0;
+	
+	my $i=0;
 	foreach my $resource (@resources) {
 	    $i++;
 	    my $result=&Apache::lonnet::ssi($resource->src(),
@@ -4106,23 +4151,6 @@ SCANTRONFORM
 				  'grade_domain'  =>$udom,
 				  'grade_courseid'=>$ENV{'request.course.id'},
 				  'grade_symb'    =>$resource->symb()));
-#	    my %score=&Apache::lonnet::restore($resource->symb(),
-#					       $ENV{'request.course.id'},
-#					       $udom,$uname);
-#	    foreach my $part ($resource->{PARTS}) {
-#		if ($score{'resource.'.$part.'.solved'} =~ /^correct/) {
-#		    $studentcorrect++;
-#		    $totalcorrect++;
-#		} else {
-#		    $studentincorrect++;
-#		    $totalincorrect++;
-#		}
-#	    }
-#	    $r->print('<pre>'.
-#		      $resource->symb().'-'.
-#		      $resource->src().'-'.'</pre>result is'.$result);
-#	    &Apache::lonhomework::showhash(%score);
-	#    if ($i eq 3) {last;}
 	}
 	$completedstudents{$uname}={'line'=>$line};
     } continue {
@@ -4130,34 +4158,13 @@ SCANTRONFORM
 	&Apache::lonnet::delenv('scantron\.');
 	&Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,
 						 'last student');
-	#last;
-	#FIXME
-	#get iterator for $sequence
-	#foreach question 'submit' the students answer to the server
-	#   through grade target {
-	#   generate data to pass back that includes grade recevied
-	#}
     }
     &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
-    my $lasttime = &Time::HiRes::time()-$start;
-    $r->print("<p>took $lasttime</p>");
+#    my $lasttime = &Time::HiRes::time()-$start;
+#    $r->print("<p>took $lasttime</p>");
 
-    #$Apache::lonxml::debug=0;
-    foreach my $delay (@delayqueue) {
-	#FIXME
-	#print out each delayed student with interface to select how
-	#  to repair student provided info
-	#Expected errors include
-	#  1 bad/no stuid/username
-	#  2 invalid bubblings
-	
-    }
-    #FIXME
-    # if delay queue exists 2 submits one to process delayed students one
-    #     to ignore delayed students, possibly saving the delay queue for later
-    
     $navmap->untieHashes();
-    $r->print("<p>Done</p>");
+    $r->print("</form><p>Done</p>");
     $r->print(&show_grading_menu_form($symb,$url));
     return '';
 }
@@ -4169,6 +4176,7 @@ sub scantron_upload_scantron_data {
 							  'domainid');
     my $domsel=&Apache::loncommon::select_dom_form($ENV{'request.role.domain'},
 						   'domainid');
+    my $default_form_data=&defaultFormData(&get_symb_and_url($r,1));
     $r->print(<<UPLOAD);
 <script type="text/javascript" language="javascript">
     function checkUpload(formname) {
@@ -4181,6 +4189,7 @@ sub scantron_upload_scantron_data {
 </script>
 
 <form enctype='multipart/form-data' action='/adm/grades' name='rules' method='post'>
+$default_form_data
 Course: <input name='courseid' type='text' />
 Domain: $domsel $select_link
 <br />
@@ -4195,7 +4204,14 @@ UPLOAD
 
 sub scantron_upload_scantron_data_save {
     my($r)=@_;
-    $r->print("Doing upload to ".$ENV{'form.courseid'});
+    if (!&Apache::lonnet::allowed('usc',$ENV{'form.domainid'}) &&
+	!&Apache::lonnet::allowed('usc',
+			    $ENV{'form.domainid'}.'_'.$ENV{'form.courseid'})) {
+	$r->print("You are not allowed to upload Scantron data to the requested course.<br />");
+	$r->print(&show_grading_menu_form(&get_symb_and_url($r)));
+	return '';
+    }
+    $r->print("Doing upload to ".$ENV{'form.courseid'}." <br />");
     my $home=&Apache::lonnet::homeserver($ENV{'form.courseid'},
 					 $ENV{'form.domainid'});
     my $fname=$ENV{'form.upfile.filename'};
@@ -4213,10 +4229,13 @@ sub scantron_upload_scantron_data_save {
     # See if there is anything left
     unless ($fname) { return 'error: no uploaded file'; }
     $fname='scantron_orig_'.$fname;
-    &Apache::lonnet::logthis("fname is $fname");
     $r->print(&Apache::lonnet::finishuserfileupload($ENV{'form.courseid'},
 						    $ENV{'form.domainid'},
 						    $home,'upfile',$fname));
+    $r->print('<br /><form action="/adm/grades" method="post">'."\n".
+	'<input type="hidden" name="command" value="scantronupload" />'."\n".
+	'<input type="submit" name="submit" value="Do Another Upload" />'."\n".
+	'</form>'."\n");
     return '';
 }
 
@@ -4323,7 +4342,7 @@ GRADINGMENUJS
 
     $result.='<table width="100%" border=0>';
     $result.='<tr bgcolor="#ffffe6" valign="top"><td>'."\n".
-	'&nbsp;Select Section: <select name="section">'."\n";
+	'&nbsp;'.&mt('Select Section').': <select name="section">'."\n";
     if (ref($sections)) {
 	foreach (sort (@$sections)) {
 	    $result.='<option value="'.$_.'" '.
@@ -4332,7 +4351,7 @@ GRADINGMENUJS
     }
     $result.= '<option value="all" '.($saveSec eq 'all' ? 'selected="on"' : ''). '>all</select> &nbsp; ';
 
-    $result.='Student Status:</b>'.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,undef);
+    $result.=&mt('Student Status').':</b>'.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,undef);
 
     if (ref($sections) && (grep /no/,@$sections)) {
 	$result.='&nbsp;(Section "no" implies the students were not assigned a section.)<br />';
@@ -4341,8 +4360,8 @@ GRADINGMENUJS
 
     $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.
 	'<input type="radio" name="radioChoice" value="submission" '.
-	($saveCmd eq 'submission' ? 'checked' : '').'> '.'<b>Current Resource:</b> For one or more students '.
-	'<select name="submitonly">'.
+	($saveCmd eq 'submission' ? 'checked' : '').'> '.'<b>'.&mt('Current Resource').':</b> '.&mt('For one or more students').
+	' <select name="submitonly">'.
 	'<option value="yes" '.
 	($saveSub eq 'yes' ? 'selected="on"' : '').'>with submissions</option>'.
 	'<option value="graded" '.
@@ -4405,7 +4424,11 @@ sub handler {
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});
     my $url=$ENV{'form.url'};
     my $symb=$ENV{'form.symb'};
-    my $command=$ENV{'form.command'};
+    my @commands=&Apache::loncommon::get_env_multiple('form.command');
+    my $command=$commands[0];
+    if ($#commands > 0) {
+	&Apache::lonnet::logthis("grades got multiple commands ".join(':',@commands));
+    }
     if (!$url) {
 	my ($temp1,$temp2);
 	($temp1,$temp2,$ENV{'form.url'})=&Apache::lonnet::decode_symb($symb);
@@ -4499,12 +4522,16 @@ sub handler {
 	} elsif ($command eq 'scantron_process' && $perm{'mgr'}) {
 	    $request->print(&scantron_process_students($request));
  	} elsif ($command eq 'scantronupload' && 
- 		 &Apache::lonnet::allowed('usc',$ENV{'request.role.domain'})) {
- 	    $request->print(&scantron_upload_scantron_data($request));
- 
+ 		 (&Apache::lonnet::allowed('usc',$ENV{'request.role.domain'})||
+		  &Apache::lonnet::allowed('usc',$ENV{'request.course.id'}))) {
+ 	    $request->print(&scantron_upload_scantron_data($request)); 
  	} elsif ($command eq 'scantronupload_save' &&
- 		 &Apache::lonnet::allowed('usc',$ENV{'request.role.domain'})) {
+ 		 (&Apache::lonnet::allowed('usc',$ENV{'request.role.domain'})||
+		  &Apache::lonnet::allowed('usc',$ENV{'request.course.id'}))) {
  	    $request->print(&scantron_upload_scantron_data_save($request));
+ 	} elsif ($command eq 'scantrondownload' &&
+		 &Apache::lonnet::allowed('usc',$ENV{'request.course.id'})) {
+ 	    $request->print(&scantron_download_scantron_data($request));
 	} elsif ($command) {
 	    $request->print("Access Denied ($command)");
 	}